diff --git a/.claude/skills/playwright-dev/SKILL.md b/.claude/skills/playwright-dev/SKILL.md index 8a9e0ca5f8de7..56f7165fbd3ca 100644 --- a/.claude/skills/playwright-dev/SKILL.md +++ b/.claude/skills/playwright-dev/SKILL.md @@ -14,5 +14,6 @@ See [CLAUDE.md](../../../CLAUDE.md) for monorepo structure, build/test/lint comm - [MCP Tools and CLI Commands](tools.md) — add MCP tools, CLI commands, config options - [Vendor Dependencies & Bundling](vendor.md) — utilsBundle, coreBundle, babelBundle; adding vendored npm packages; DEPS.list; `check_deps` - [Updating WebKit Safari Version](webkit-safari-version.md) — update the Safari version string in the WebKit user-agent +- [WebView (iOS Safari) Backend](webview.md) — `webkit/webview/` against stock Mobile Safari; provisional-target pause/resume; what's upstream vs Playwright patches; local + CI test setup - [Bisecting Across Published Versions](bisect-published-versions.md) — reproduce regressions side-by-side from npm and diff `node_modules/playwright/lib/` between versions - [Dashboard](dashboard.md) - the UI powering the "playwright cli show" command, and how to work on it diff --git a/.claude/skills/playwright-dev/library.md b/.claude/skills/playwright-dev/library.md index 2b3846847e289..1a6fa28946cef 100644 --- a/.claude/skills/playwright-dev/library.md +++ b/.claude/skills/playwright-dev/library.md @@ -145,10 +145,6 @@ Manages the client-server transport: | `Locator` | `locator.ts` | Delegates to `Frame` methods with selector + `strict: true` | | `ElementHandle` | `elementHandle.ts` | DOM element reference | -### Public API Exports - -`packages/playwright-core/src/client/api.ts` exports all public classes. - ## Server Layer ### SdkObject — Base Class diff --git a/.claude/skills/playwright-dev/webview.md b/.claude/skills/playwright-dev/webview.md new file mode 100644 index 0000000000000..680cf0100f031 --- /dev/null +++ b/.claude/skills/playwright-dev/webview.md @@ -0,0 +1,149 @@ +# WebView (iOS Safari) Backend Reference + +Notes for developing the **stock-Mobile-Safari** backend in +[packages/playwright-core/src/server/webkit/webview/](../../../packages/playwright-core/src/server/webkit/webview/). +The regular WebKit backend one level up (`webkit/`) runs against a +Playwright-patched WebKit build; the `webview/` folder targets unmodified +Safari on real iOS/iPadOS or the iOS Simulator over the standard Web Inspector +Protocol. + +## What is and isn't available + +Stock Mobile Safari only exposes the upstream Web Inspector Protocol. Anything +Playwright added to its forked WebKit is not available here. + +**Available** — methods/events in `Source/JavaScriptCore/inspector/protocol/*.json` +on `browser_upstream/main`: + +```bash +git -C ~/webkit show browser_upstream/main:Source/JavaScriptCore/inspector/protocol/.json +``` + +**Not available** — anything added by the Playwright WebKit patches: + +```bash +ls ~/playwright-browsers/browser_patches/webkit/patches/ # bootstrap.diff lives here +``` + +Quick provenance check for a symbol — in `~/webkit`: + +```bash +git log --all -S "" -- +``` + +If every hit is a `chore(webkit): bootstrap build` commit, it's a Playwright +patch. Some traps where the upstream name overlaps with a Playwright-only +helper of similar intent: + +- `Target.setPauseOnStart` / `Target.resume` (**upstream**, gates loading of + provisional process-swap targets) vs `PageInspectorController::pauseOnStart` + / `resumeIfPausedInNewWindow` (**Playwright patch**, for `window.open` + popups). They sound the same; they aren't. +- `Playwright.*` domain (cookies, navigate, all global controls) — entirely + Playwright. Use stock equivalents on the page session (e.g. `Page.getCookies`). +- `Network.continueWithAuth`, intercepted-response body access via Network — + Playwright extensions. + +## Architecture + +This backend deliberately mirrors the regular WebKit backend one level up +(`wkConnection.ts` / `wkPage.ts` / `wkProvisionalPage.ts`). When in doubt, +read the WK equivalent — the WV class should look almost the same. The +`outerSession` is the WV analogue of WK's page-proxy session. + +``` +WebSocketTransport (ws://localhost:9222/devtools/page/, via ios_webkit_debug_proxy) + → WVConnection — dumb transport; owns only outerSession + → WVConnection.outerSession (sessionId "") — Target.sendMessageToTarget bridge + → WVPage — owns per-target WVSessions, routes + Target.dispatchMessageFromTarget, manages swaps + → _session (current) + WVProvisionalPage (during a swap) + → WVExecutionContext, WVWorkers, RawKeyboard/Mouse/Touchscreen + (all hold a session reference, all have setSession() for swap) +``` + +`WVConnection` is intentionally minimal: it pumps the transport into +`outerSession` and back. `WVPage` creates the per-target `WVSession`s +(`_createSession`), routes `Target.dispatchMessageFromTarget` by `targetId` to +either `_session` or `_provisionalPage._session`, and handles +`Target.targetCreated/targetDestroyed/didCommitProvisionalTarget` — exactly +like `WKPage`. `WVPage` is constructed with the outer session (not a target +session); `_session` starts undefined and is bound on the first +`Target.targetCreated` via `_setSession`. `WVBrowser._attachTab` awaits +`page.waitForInitialized()` (resolves after the first target is reported as +new) instead of waiting on the connection. + +## Process swap / provisional targets + +Cross-origin navigation in an existing tab can make Mobile Safari spawn a new +process. The protocol sequence is: + +``` +Target.targetCreated targetInfo:{ isProvisional:true, isPaused:true } +... events on the provisional target during the navigation ... +Target.didCommitProvisionalTarget oldTargetId, newTargetId +Target.targetDestroyed oldTargetId +``` + +Handling mirrors WK — `WVProvisionalPage` ≈ `WKProvisionalPage`, swapped in by +`WVPage._onDidCommitProvisionalTarget`. The one essential trick: +`Target.setPauseOnStart` (sent in `WVBrowser._attachTab`) makes provisional +targets arrive `isPaused`, so `WVPage` can set up interception / bootstrap +before resuming them with `Target.resume`; otherwise the new process races +ahead and `page.route(...)` never fires. + +Not to be confused with the **popup-pause** path (`window.open`), which is a +Playwright patch (`PageInspectorController::pauseOnStart`) with no stock-Safari +equivalent. + +## Test infrastructure + +``` +tests/webview/ + playwright.config.ts — single project "webkit-webview-page", runs tests/page/ + webviewTest.ts — fixture: discovers tab via ios_webkit_debug_proxy /json, + resets Mobile Safari between tests + expectations/ + webkit-webview-page.txt — ` [fail|flaky|timeout|skip]` + expectationUtil.ts — loader + skip-decision logic +``` + +`[fail]` entries cause `it.skip()` to fire before the test body runs — so a +formerly-failing test that now passes won't be flagged automatically, you have +to remove the line and re-run. The marker also has prefix-match semantics for +`it.step` children. + +### Running locally + +```bash +./utils/run_webview_tests.sh # ensures ios_webkit_debug_proxy is up on 9222 +npm run wvtest -- -g "" # single test +npm run wvtest -- tests/page/foo.spec.ts +DEBUG=pw:protocol npm run wvtest -- -g "" > /tmp/log 2>&1 +``` + +The simulator needs to be booted with one Mobile Safari tab. The script's only +job is keeping a single +`ios_webkit_debug_proxy -F -d -s unix:<socket> -c null:9221,:9222-9322` alive; +everything else is done by the fixture. + +### Common local pitfalls + +- **Multiple `ios_webkit_debug_proxy` processes** — every protocol event is + delivered through each instance, so debug logs show events duplicated and + some tests flake. `pgrep -lf ios_webkit_debug_proxy` and clean up. +- **Chrome bound to `127.0.0.1:9222`** — Chrome's `--remote-debugging-port=9222` + shadows iwdp's `*:9222` listener for traffic addressed to `localhost`. + Kill the Chrome instance (`lsof -nP -iTCP -sTCP:LISTEN | grep 9222`). +- **Stale launchd socket** — `lsof -aUc launchd_sim` should show + `com.apple.webinspectord_sim.socket` for the currently booted simulator. If + iwdp was started against an older `launchd_sim` socket path it will silently + serve nothing. + +## CI + +[.github/workflows/tests_webview_simulator.yml](../../../.github/workflows/tests_webview_simulator.yml) +runs the same suite on `macos-15` (booted iOS Simulator + +`brew install ios-webkit-debug-proxy`). Triggers: `workflow_dispatch`, and +`pull_request` only when paths under `tests/webview/**`, the `webview/` source +folder, or the workflow file itself change. diff --git a/.github/actions/enable-microphone-access/action.yml b/.github/actions/enable-microphone-access/action.yml deleted file mode 100644 index 76ca24eebfc6d..0000000000000 --- a/.github/actions/enable-microphone-access/action.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Enable Microphone Access (macOS) -description: 'Allow microphone access to all apps on macOS' - -runs: - using: composite - steps: - # https://github.com/actions/runner-images/issues/9330 - - name: Allow microphone access to all apps - shell: bash - run: | - if [[ "$(uname)" != "Darwin" ]]; then - echo "Not macOS, exiting" - exit 0 - fi - echo "Allowing microphone access to all apps" - version=$(sw_vers -productVersion | cut -d. -f1) - if [[ "$version" == "14" || "$version" == "15" ]]; then - sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);" - elif [[ "$version" == "12" || "$version" == "13" ]]; then - sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR REPLACE INTO access VALUES('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159);" - else - echo "Skipping unsupported macOS version $version" - exit 0 - fi - echo "Successfully allowed microphone access" diff --git a/.github/actions/run-test/action.yml b/.github/actions/run-test/action.yml index 1798e13fe2ff2..48c60261c1192 100644 --- a/.github/actions/run-test/action.yml +++ b/.github/actions/run-test/action.yml @@ -39,7 +39,6 @@ runs: - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} - - uses: ./.github/actions/enable-microphone-access - run: | echo "::group::npm ci" npm ci diff --git a/.github/actions/upload-blob-report/action.yml b/.github/actions/upload-blob-report/action.yml index 2ada681ee3789..658145fcf0e9d 100644 --- a/.github/actions/upload-blob-report/action.yml +++ b/.github/actions/upload-blob-report/action.yml @@ -14,7 +14,10 @@ runs: steps: - name: Integrity check shell: bash - run: find "${{ inputs.report_dir }}" -name "*.zip" -exec unzip -t {} \; + run: | + echo "::group::extracting blob archives" + find "${{ inputs.report_dir }}" -name "*.zip" -exec unzip -t {} \; + echo "::endgroup::" - name: Upload blob report to GitHub if: ${{ !cancelled() }} uses: actions/upload-artifact@v7 diff --git a/.github/workflows/tests_docker.yml b/.github/workflows/tests_docker.yml new file mode 100644 index 0000000000000..e78d43c473050 --- /dev/null +++ b/.github/workflows/tests_docker.yml @@ -0,0 +1,131 @@ +name: tests docker + +on: + workflow_call: + +env: + FORCE_COLOR: 1 + +jobs: + test_linux_docker: + name: "Docker ${{ matrix.docker_tag }} ${{ matrix.docker_arch }}" + environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} + strategy: + fail-fast: false + matrix: + include: + - docker_tag: jammy + docker_arch: amd64 + host_os: ubuntu-22.04 + - docker_tag: jammy + docker_arch: arm64 + host_os: ubuntu-22.04-arm + - docker_tag: noble + docker_arch: amd64 + host_os: ubuntu-22.04 + - docker_tag: noble + docker_arch: arm64 + host_os: ubuntu-22.04-arm + runs-on: ${{ matrix.host_os }} + permissions: + id-token: write # This is required for OIDC login (azure/login) to succeed + contents: read # This is required for actions/checkout to succeed + steps: + - name: Create ~/.azure directory + run: mkdir -p ~/.azure + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: 22 + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + - run: npm ci + - run: npm run build + # Used as a Pull-through cache for the Docker images. Only available on the + # main repo, where the secrets are present; forks fall back to Docker Hub. + - name: Azure Login + if: ${{ github.event_name == 'push' && github.repository == 'microsoft/playwright' }} + uses: azure/login@v3 + with: + client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} + - name: Login to ACR via OIDC + if: ${{ github.event_name == 'push' && github.repository == 'microsoft/playwright' }} + run: az acr login --name playwright + - name: Add Dockerfile cache + if: ${{ github.event_name == 'push' && github.repository == 'microsoft/playwright' }} + run: sed -i 's/FROM ubuntu/FROM playwright.azurecr.io\/cached\/ubuntu/' utils/docker/Dockerfile.${{matrix.docker_tag}} + - run: ./utils/docker/build.sh --${{ matrix.docker_arch }} ${{ matrix.docker_tag }} playwright:localbuild + shell: bash + - name: Launch container + run: | + docker run \ + --rm \ + --name docker-tests \ + --platform linux/${{ matrix.docker_arch }} \ + --user=pwuser \ + --workdir /home/pwuser \ + --env CI \ + --env INSIDE_DOCKER=1 \ + -v ~/.azure:/root/.azure \ + -d \ + -t \ + playwright:localbuild /bin/bash + - name: Copy repository inside docker container + run: | + # Note: we cannot do explicit `git clone` inside container because it requires some smarts to decide if github.sha or + # github.ref should be used for checkout. + # The actions/checkout action already handled this complexity for us, so we'll just copy checkout. + docker cp . docker-tests:/home/pwuser/playwright + docker exec --user root docker-tests chown -R pwuser /home/pwuser/playwright + + # GIT is now picky on directory ownership + # See https://github.blog/2022-04-12-git-security-vulnerability-announced/ + docker exec \ + --user root \ + --workdir /home/pwuser/playwright docker-tests /bin/bash -c ' + git config --global --add safe.directory /home/pwuser/playwright + ' + - name: Run "npm ci" inside docker + run: docker exec --workdir /home/pwuser/playwright docker-tests npm ci + + - name: Run "npm run build" inside docker + run: docker exec --workdir /home/pwuser/playwright docker-tests npm run build + + - name: "Run @smoke tests inside docker" + run: docker exec --workdir /home/pwuser/playwright docker-tests xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" npm run test -- --grep "@smoke" + + - name: Azure Login + if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} + uses: azure/login@v3 + with: + client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} + - name: Upload Flakiness dashboard + if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} + run: | + # Flakiness dashboard has to be uploaded from-inside docker container so that it can collect meta information, e.g. arch + # See https://github.com/microsoft/playwright/blob/13b1e52d95df416fdfa7846c8a840aad8df263af/utils/upload_flakiness_dashboard.sh#L71-L86 + docker exec \ + --env GITHUB_REPOSITORY \ + --env GITHUB_REF \ + --env GITHUB_RUN_ID \ + --user root \ + --workdir /home/pwuser/playwright docker-tests /bin/bash -c ' + set -e + # Azure-CLI is needed for upload_flakiness_dashboard.sh script. + curl -sL https://aka.ms/InstallAzureCLIDeb | bash + ./utils/upload_flakiness_dashboard.sh "./test-results/report.json" + ' + - name: Copy blob report from container + if: ${{ !cancelled() && (github.event_name == 'pull_request' || failure()) }} + run: docker cp "docker-tests:/home/pwuser/playwright/blob-report" "./blob-report" + + - name: Upload blob report + if: ${{ !cancelled() && (github.event_name == 'pull_request' || failure()) }} + uses: ./.github/actions/upload-blob-report + with: + report_dir: blob-report + job_name: docker-${{ matrix.docker_tag }}-${{ matrix.docker_arch }} diff --git a/.github/workflows/tests_docker_changes.yml b/.github/workflows/tests_docker_changes.yml new file mode 100644 index 0000000000000..8807d32ae6788 --- /dev/null +++ b/.github/workflows/tests_docker_changes.yml @@ -0,0 +1,24 @@ +name: tests docker (changes) + +on: + push: + branches: + - main + paths: + - 'utils/docker/**' + - '.github/workflows/tests_docker*.yml' + pull_request: + branches: + - main + - release-* + paths: + - 'utils/docker/**' + - '.github/workflows/tests_docker*.yml' + +jobs: + test_linux_docker: + uses: ./.github/workflows/tests_docker.yml + permissions: + id-token: write + contents: read + secrets: inherit diff --git a/.github/workflows/tests_docker_release.yml b/.github/workflows/tests_docker_release.yml new file mode 100644 index 0000000000000..d9e22f16550a2 --- /dev/null +++ b/.github/workflows/tests_docker_release.yml @@ -0,0 +1,14 @@ +name: tests docker (release) + +on: + push: + branches: + - release-* + +jobs: + test_linux_docker: + uses: ./.github/workflows/tests_docker.yml + permissions: + id-token: write + contents: read + secrets: inherit diff --git a/.github/workflows/tests_others.yml b/.github/workflows/tests_others.yml index 8444c353fdb66..5e218e165c2cf 100644 --- a/.github/workflows/tests_others.yml +++ b/.github/workflows/tests_others.yml @@ -21,42 +21,6 @@ env: ELECTRON_SKIP_BINARY_DOWNLOAD: 1 jobs: - test_stress: - name: Stress - ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 - with: - node-version: 20 - - run: npm ci - - run: npm run build - - run: npx playwright install --with-deps - - run: npm run stest contexts -- --project=chromium - if: ${{ !cancelled() }} - - run: npm run stest browsers -- --project=chromium - if: ${{ !cancelled() }} - - run: npm run stest frames -- --project=chromium - if: ${{ !cancelled() }} - - run: npm run stest contexts -- --project=webkit - if: ${{ !cancelled() }} - - run: npm run stest browsers -- --project=webkit - if: ${{ !cancelled() }} - - run: npm run stest frames -- --project=webkit - if: ${{ !cancelled() }} - - run: npm run stest contexts -- --project=firefox - if: ${{ !cancelled() }} - - run: npm run stest browsers -- --project=firefox - if: ${{ !cancelled() }} - - run: npm run stest frames -- --project=firefox - if: ${{ !cancelled() }} - - run: npm run stest heap -- --project=chromium - if: ${{ !cancelled() }} - test_clock_frozen_time_linux: name: time library - ${{ matrix.clock }} environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} diff --git a/.github/workflows/tests_primary.yml b/.github/workflows/tests_primary.yml index 46ee8c283ec18..142cab8343aff 100644 --- a/.github/workflows/tests_primary.yml +++ b/.github/workflows/tests_primary.yml @@ -66,30 +66,6 @@ jobs: flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - test_linux_chromium_tot: - name: ${{ matrix.os }} (chromium tip-of-tree) - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-22.04] - runs-on: ${{ matrix.os }} - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - steps: - - uses: actions/checkout@v6 - - uses: ./.github/actions/run-test - with: - browsers-to-install: chromium-tip-of-tree - command: npm run test -- --project=chromium-* - bot-name: "${{ matrix.os }}-chromium-tip-of-tree" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_CHANNEL: chromium-tip-of-tree - test_test_runner: name: Test Runner environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} @@ -97,33 +73,33 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - node-version: [20] + node-version: [22] shardIndex: [1, 2] shardTotal: [2] shardWeights: ['58:42'] include: - os: windows-latest - node-version: 20 + node-version: 22 shardIndex: 1 shardTotal: 3 shardWeights: '44:33:23' - os: windows-latest - node-version: 20 + node-version: 22 shardIndex: 2 shardTotal: 3 shardWeights: '44:33:23' - os: windows-latest - node-version: 20 + node-version: 22 shardIndex: 3 shardTotal: 3 shardWeights: '44:33:23' - os: ubuntu-latest - node-version: 22 + node-version: 20 shardIndex: 1 shardTotal: 2 shardWeights: '58:42' - os: ubuntu-latest - node-version: 22 + node-version: 20 shardIndex: 2 shardTotal: 2 shardWeights: '58:42' @@ -137,6 +113,16 @@ jobs: shardIndex: 2 shardTotal: 2 shardWeights: '58:42' + - os: ubuntu-latest + node-version: 26 + shardIndex: 1 + shardTotal: 2 + shardWeights: '58:42' + - os: ubuntu-latest + node-version: 26 + shardIndex: 2 + shardTotal: 2 + shardWeights: '58:42' runs-on: ${{ matrix.os }} permissions: id-token: write # This is required for OIDC login (azure/login) to succeed @@ -153,7 +139,6 @@ jobs: flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} env: - PWTEST_CHANNEL: firefox-beta PWTEST_SHARD_WEIGHTS: ${{ matrix.shardWeights }} test_vscode_extension: @@ -221,6 +206,7 @@ jobs: - uses: ./.github/actions/run-test with: command: npm run itest + node-version: 22 bot-name: "package-installations-${{ matrix.os }}" shell: ${{ matrix.os == 'windows-latest' && 'pwsh' || 'bash' }} flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} diff --git a/.github/workflows/tests_secondary.yml b/.github/workflows/tests_secondary.yml index e793291e12c4b..401ff521c67d2 100644 --- a/.github/workflows/tests_secondary.yml +++ b/.github/workflows/tests_secondary.yml @@ -21,26 +21,6 @@ permissions: contents: read # This is required for actions/checkout to succeed jobs: - test_linux: - name: ${{ matrix.os }} (${{ matrix.browser }}) - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - browser: [chromium, firefox, webkit] - os: [ubuntu-24.04] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - uses: ./.github/actions/run-test - with: - browsers-to-install: ${{ matrix.browser }} chromium - command: npm run test -- --project=${{ matrix.browser }}-* - bot-name: "${{ matrix.browser }}-${{ matrix.os }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - test_mac: name: ${{ matrix.os }} (${{ matrix.browser }}) environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} @@ -49,7 +29,7 @@ jobs: matrix: # Intel: *-large # Arm64: *-xlarge - os: [macos-15-large, macos-15-xlarge, macos-26-large, macos-26-xlarge] + os: [macos-15-large, macos-15-xlarge] browser: [chromium, firefox, webkit] include: - os: macos-14-xlarge @@ -95,10 +75,10 @@ jobs: include: - os: ubuntu-latest node_version: 20 - - os: ubuntu-latest - node_version: 22 - os: ubuntu-latest node_version: 24 + - os: ubuntu-latest + node_version: 26 timeout-minutes: 30 steps: - uses: actions/checkout@v6 @@ -120,30 +100,6 @@ jobs: flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - headed_tests: - name: "headed ${{ matrix.browser }} (${{ matrix.os }})" - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - browser: [chromium, firefox, webkit] - os: [ubuntu-24.04, macos-15-xlarge, windows-latest] - include: - # We have different binaries per Ubuntu version for WebKit. - - browser: webkit - os: ubuntu-22.04 - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - uses: ./.github/actions/run-test - with: - browsers-to-install: ${{ matrix.browser }} chromium - command: npm run test -- --project=${{ matrix.browser }}-* --headed --workers=2 - bot-name: "${{ matrix.browser }}-headed-${{ matrix.os }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - driver_linux: name: "Driver" environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} @@ -164,7 +120,7 @@ jobs: PWTEST_MODE: driver tracing_linux: - name: Tracing ${{ matrix.browser }} ${{ matrix.channel }} + name: Tracing ${{ matrix.browser }} environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} strategy: fail-fast: false @@ -177,23 +133,19 @@ jobs: # See https://github.com/microsoft/playwright/issues/35586 - browser: webkit runs-on: ubuntu-24.04 - - browser: chromium - runs-on: ubuntu-22.04 - channel: chromium-tip-of-tree runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v6 - uses: ./.github/actions/run-test with: - browsers-to-install: ${{ matrix.browser }} chromium ${{ matrix.channel }} + browsers-to-install: ${{ matrix.browser }} chromium command: npm run test -- --project=${{ matrix.browser }}-* - bot-name: "tracing-${{ matrix.channel || matrix.browser }}" + bot-name: "tracing-${{ matrix.browser }}" flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} env: PWTEST_TRACE: 1 - PWTEST_CHANNEL: ${{ matrix.channel }} test_chromium_channels: name: Test ${{ matrix.channel }} on ${{ matrix.runs-on }} @@ -202,8 +154,19 @@ jobs: strategy: fail-fast: false matrix: - channel: [chrome, chrome-beta, msedge, msedge-beta, msedge-dev] - runs-on: [ubuntu-22.04, macos-latest, windows-latest] + include: + - channel: chrome + runs-on: ubuntu-22.04 + - channel: chrome + runs-on: macos-latest + - channel: chrome + runs-on: windows-latest + - channel: chrome-beta + runs-on: ubuntu-22.04 + - channel: msedge + runs-on: windows-latest + - channel: msedge-dev + runs-on: windows-latest steps: - uses: actions/checkout@v6 - uses: ./.github/actions/run-test @@ -217,75 +180,6 @@ jobs: env: PWTEST_CHANNEL: ${{ matrix.channel }} - chromium_tot: - name: Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - # Note: we keep older versions here, assuming they are more likely to break with ToT builds. - os: [ubuntu-22.04, macos-15, windows-latest] - headed: ['--headed', ''] - exclude: - # Tested in tests_primary.yml already - - os: ubuntu-22.04 - headed: '' - steps: - - uses: actions/checkout@v6 - - uses: ./.github/actions/run-test - with: - browsers-to-install: chromium-tip-of-tree - command: npm run ctest -- ${{ matrix.headed }} - bot-name: "chromium-tip-of-tree-${{ matrix.os }}${{ matrix.headed }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_CHANNEL: chromium-tip-of-tree - - chromium_tot_headless_shell: - name: Chromium tip-of-tree headless-shell-${{ matrix.os }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-22.04] - steps: - - uses: actions/checkout@v6 - - uses: ./.github/actions/run-test - with: - browsers-to-install: chromium-tip-of-tree-headless-shell - command: npm run ctest - bot-name: "chromium-tip-of-tree-headless-shell-${{ matrix.os }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_CHANNEL: chromium-tip-of-tree-headless-shell - - firefox_beta: - name: Firefox Beta ${{ matrix.os }} - environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-22.04, windows-latest, macos-latest] - steps: - - uses: actions/checkout@v6 - - uses: ./.github/actions/run-test - with: - browsers-to-install: firefox-beta chromium - command: npm run ftest - bot-name: "firefox-beta-${{ matrix.os }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_CHANNEL: firefox-beta - build-playwright-driver: name: "build-playwright-driver" runs-on: ubuntu-24.04 @@ -298,25 +192,33 @@ jobs: - run: npm run build - run: utils/build/build-playwright-driver.sh - test_channel_chromium: - name: Test channel=chromium + test_android: + name: Android environment: ${{ github.event_name == 'push' && 'allow-uploading-flakiness-results' || null }} - strategy: - fail-fast: false - matrix: - runs-on: [ubuntu-latest, windows-latest, macos-latest] - runs-on: ${{ matrix.runs-on }} + runs-on: playwright-x64-ubuntu24-64-core steps: - uses: actions/checkout@v6 + - uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '21' + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Create Android Emulator + run: utils/avd_recreate.sh + - name: Start Android Emulator + run: utils/avd_start.sh - uses: ./.github/actions/run-test with: - # TODO: this should pass --no-shell. - # However, codegen tests do not inherit the channel and try to launch headless shell. - browsers-to-install: chromium - command: npm run ctest - bot-name: "channel-chromium-${{ matrix.runs-on }}" + browsers-to-install: android + command: npm run atest + bot-name: "android" flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_CHANNEL: chromium diff --git a/.github/workflows/tests_video.yml b/.github/workflows/tests_video.yml deleted file mode 100644 index 170c7cf17de56..0000000000000 --- a/.github/workflows/tests_video.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: "tests Video" - -on: - push: - branches: - - main - - release-* - -env: - # Force terminal colors. @see https://www.npmjs.com/package/colors - FORCE_COLOR: 1 - ELECTRON_SKIP_BINARY_DOWNLOAD: 1 - -jobs: - video_linux: - name: "Video Linux" - environment: allow-uploading-flakiness-results - strategy: - fail-fast: false - matrix: - browser: [chromium, firefox, webkit] - os: [ubuntu-22.04, ubuntu-24.04] - permissions: - id-token: write # This is required for OIDC login (azure/login) to succeed - contents: read # This is required for actions/checkout to succeed - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - uses: ./.github/actions/run-test - with: - browsers-to-install: ${{ matrix.browser }} chromium - command: npm run test -- --project=${{ matrix.browser }}-* - bot-name: "${{ matrix.browser }}-${{ matrix.os }}" - flakiness-client-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_CLIENT_ID }} - flakiness-tenant-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_TENANT_ID }} - flakiness-subscription-id: ${{ secrets.AZURE_FLAKINESS_DASHBOARD_SUBSCRIPTION_ID }} - env: - PWTEST_VIDEO: 1 diff --git a/.github/workflows/tests_webview_simulator.yml b/.github/workflows/tests_webview_simulator.yml new file mode 100644 index 0000000000000..607e5ddd0a5a7 --- /dev/null +++ b/.github/workflows/tests_webview_simulator.yml @@ -0,0 +1,161 @@ +name: "tests WebView (iOS Simulator)" + +on: + workflow_dispatch: + pull_request: + paths: + - 'tests/webview/**' + - 'packages/playwright-core/src/server/webkit/webview/**' + - '.github/workflows/tests_webview_simulator.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + FORCE_COLOR: 1 + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + +jobs: + test_webview_simulator: + name: "WebView on iOS Simulator (${{ matrix.shard }}/4)" + runs-on: macos-15 + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Runner environment + run: | + echo "::group::OS / Xcode" + sw_vers + uname -a + xcode-select -p + xcodebuild -version + echo "::endgroup::" + echo "::group::Available iOS runtimes" + xcrun simctl list runtimes + echo "::endgroup::" + echo "::group::Available device types" + xcrun simctl list devicetypes | grep -i 'iPhone\|iPad' | head -40 + echo "::endgroup::" + echo "::group::Network config" + cat /etc/hosts + ifconfig lo0 + echo "::endgroup::" + + - name: Ensure ::1 localhost in /etc/hosts + run: | + if grep -qE '^::1[[:space:]]+localhost' /etc/hosts; then + echo "::1 localhost already present" + else + echo "::1 localhost" | sudo tee -a /etc/hosts + echo "Added ::1 localhost" + fi + echo "--- /etc/hosts after ---" + cat /etc/hosts + + - name: npm ci + run: | + echo "::group::npm ci" + npm ci + echo "::endgroup::" + + - name: npm run build + run: | + echo "::group::npm run build" + npm run build + echo "::endgroup::" + + - name: Install ios-webkit-debug-proxy + run: | + echo "::group::brew install ios-webkit-debug-proxy" + brew install ios-webkit-debug-proxy + which ios_webkit_debug_proxy + ios_webkit_debug_proxy --help 2>&1 | head -40 || true + echo "::endgroup::" + + - name: Boot iOS Simulator + uses: futureware-tech/simulator-action@v5 + with: + # Per wiki/Devices-macos-15.md only iPhone 16/17 series ship pre-installed; iPhone 15 isn't. + model: 'iPhone 16' + os_version: '18.6' + wait_for_boot: true + boot_timeout_seconds: 300 + + - name: Simulator state after boot + run: | + echo "::group::Booted devices" + xcrun simctl list devices booted + echo "::endgroup::" + echo "::group::Simulator processes" + pgrep -lf Simulator || true + pgrep -lf launchd_sim || true + echo "::endgroup::" + + - name: Locate simulator webinspectord socket + run: | + echo "::group::Locating com.apple.webinspectord_sim.socket" + # On modern macOS, ios_webkit_debug_proxy can no longer auto-discover the simulator; + # we have to point -s at the launchd-owned unix socket. + for i in $(seq 1 15); do + SOCK=$(lsof -aUc launchd_sim 2>/dev/null | awk '/com\.apple\.webinspectord_sim\.socket/{print $NF; exit}') + [[ -n "$SOCK" ]] && break + echo "attempt $i: socket not found yet" + sleep 1 + done + if [[ -z "$SOCK" ]]; then + echo "Failed to locate webinspectord_sim.socket" + echo "--- launchd_sim file table ---" + lsof -aUc launchd_sim 2>/dev/null || true + exit 1 + fi + echo "socket: $SOCK" + echo "SIM_WI_SOCKET=unix:$SOCK" >> $GITHUB_ENV + echo "::endgroup::" + + - name: Start ios-webkit-debug-proxy + run: | + echo "::group::Starting proxy (SIM_WI_SOCKET=$SIM_WI_SOCKET)" + ios_webkit_debug_proxy -F -d -s "$SIM_WI_SOCKET" -c "null:9221,:9222-9322" > "$RUNNER_TEMP/iwdp.log" 2>&1 & + PID=$! + echo "IWDP_PID=$PID" >> $GITHUB_ENV + echo "proxy pid=$PID" + sleep 3 + if ! kill -0 "$PID" 2>/dev/null; then + echo "Proxy died immediately. Log:" + cat "$RUNNER_TEMP/iwdp.log" + exit 1 + fi + echo "::endgroup::" + echo "::group::Listening ports" + lsof -nP -iTCP -sTCP:LISTEN | grep -E "9221|9222|ios_webkit" || true + echo "::endgroup::" + + - name: Run WebView tests + run: | + echo "::group::Test run (shard ${{ matrix.shard }}/4)" + npx playwright test --config tests/webview/playwright.config.ts --shard=${{ matrix.shard }}/4 + echo "::endgroup::" + + - name: Stop proxy + if: always() + run: | + [[ -n "$IWDP_PID" ]] && kill "$IWDP_PID" 2>/dev/null || true + # Simulator shutdown is owned by futureware-tech/simulator-action's post step. + + - name: Upload artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: webview-simulator-logs-${{ matrix.shard }} + path: | + ${{ github.workspace }}/test-results/** + if-no-files-found: ignore diff --git a/.github/workflows/trigger_tests.yml b/.github/workflows/trigger_tests.yml deleted file mode 100644 index 761c11f395dcb..0000000000000 --- a/.github/workflows/trigger_tests.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: "Internal Tests" - -on: - push: - branches: - - main - - release-* - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-24.04 - steps: - - uses: actions/create-github-app-token@v3 - id: app-token - with: - app-id: ${{ vars.PLAYWRIGHT_APP_ID }} - private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }} - repositories: playwright-browsers - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data "{\"event_type\": \"playwright_tests\", \"client_payload\": {\"ref\": \"${GITHUB_SHA}\"}}" \ - https://api.github.com/repos/microsoft/playwright-browsers/dispatches - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/README.md b/README.md index 6db18b45b336e..f18a4960e7474 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🎭 Playwright -[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-148.0.7778.96-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-150.0.1-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-26.4-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop --> [![Join Discord](https://img.shields.io/badge/join-discord-informational)](https://aka.ms/playwright/discord) +[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-149.0.7827.22-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-151.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-26.4-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop --> [![Join Discord](https://img.shields.io/badge/join-discord-informational)](https://aka.ms/playwright/discord) ## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright) @@ -152,7 +152,7 @@ playwright-cli show <!-- TODO: screenshot of playwright-cli show dashboard --> -[Full CLI documentation](https://playwright.dev/docs/cli-agent) | [GitHub](https://github.com/microsoft/playwright-cli) +[Full CLI documentation](https://playwright.dev/agent-cli/introduction) | [GitHub](https://github.com/microsoft/playwright-cli) --- @@ -205,7 +205,7 @@ The agent sees the page as a structured accessibility tree: It uses element refs like `e5` and `e10` to click, type, and interact — deterministically and without visual ambiguity. Tools cover navigation, form filling, screenshots, network mocking, storage management, and more. -[Full MCP documentation](https://playwright.dev/docs/mcp) | [GitHub](https://github.com/microsoft/playwright-mcp) +[Full MCP documentation](https://playwright.dev/mcp/introduction) | [GitHub](https://github.com/microsoft/playwright-mcp) --- @@ -296,9 +296,9 @@ The [Playwright VS Code extension](https://marketplace.visualstudio.com/items?it | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium<sup>1</sup> <!-- GEN:chromium-version -->148.0.7778.96<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Chromium<sup>1</sup> <!-- GEN:chromium-version -->149.0.7827.22<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: | | WebKit <!-- GEN:webkit-version -->26.4<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Firefox <!-- GEN:firefox-version -->150.0.1<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Firefox <!-- GEN:firefox-version -->151.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: | Headless and headed execution on all platforms. <sup>1</sup> Uses [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing) by default. diff --git a/browser_patches/firefox/UPSTREAM_CONFIG.sh b/browser_patches/firefox/UPSTREAM_CONFIG.sh index 3f4d29cfd48cc..b2cb184ed21ba 100644 --- a/browser_patches/firefox/UPSTREAM_CONFIG.sh +++ b/browser_patches/firefox/UPSTREAM_CONFIG.sh @@ -1,3 +1,3 @@ REMOTE_URL="https://github.com/mozilla-firefox/firefox" BASE_BRANCH="release" -BASE_REVISION="4eb5a4f7e5a3bea3de2e2bfc541e1bc122731518" +BASE_REVISION="c7fa3c91990bac266ee99a9e31863c202469f369" diff --git a/browser_patches/firefox/juggler/JugglerFrameParent.jsm b/browser_patches/firefox/juggler/JugglerFrameParent.jsm index 9d41842a3b896..7705217def1dd 100644 --- a/browser_patches/firefox/juggler/JugglerFrameParent.jsm +++ b/browser_patches/firefox/juggler/JugglerFrameParent.jsm @@ -20,21 +20,10 @@ export class JugglerFrameParent extends JSWindowActorParent { if (!this.manager?.isCurrentGlobal) return; - // Only interested in main frames for now. - if (this.browsingContext.parent) - return; - - this._target = TargetRegistry.instance()?.targetForBrowserId(this.browsingContext.browserId); - if (!this._target) - return; - - this.actorName = `browser::page[${this._target.id()}]/${this.browsingContext.browserId}/${this.browsingContext.id}/${this._target.nextActorSequenceNumber()}`; - this._target.setActor(this); + TargetRegistry.instance()?.onActorCreated(this); } didDestroy() { - if (!this._target) - return; - this._target.removeActor(this); + TargetRegistry.instance()?.onActorDestroyed(this); } } diff --git a/browser_patches/firefox/juggler/TargetRegistry.js b/browser_patches/firefox/juggler/TargetRegistry.js index f28e675c0bee6..1f3c79f1d5924 100644 --- a/browser_patches/firefox/juggler/TargetRegistry.js +++ b/browser_patches/firefox/juggler/TargetRegistry.js @@ -117,6 +117,8 @@ export class TargetRegistry { this._browserToTarget = new Map(); this._browserIdToTarget = new Map(); + this._browserIdToActor = new Map(); + this._proxiesWithClashingAuthCacheKeys = new Set(); this._browserProxy = null; @@ -192,7 +194,7 @@ export class TargetRegistry { // // 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') { + if (domWindow.document.readyState === 'uninitialized' || domWindow.document.readyState === 'loading' || domWindow.document.isUncommittedInitialDocument) { // 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 @@ -234,6 +236,27 @@ export class TargetRegistry { onOpenWindow(win); } + onActorCreated(actor) { + // Only interested in main frames for now. + if (actor.browsingContext.parent) + return; + + const browserId = actor.browsingContext.browserId; + this._browserIdToActor.set(browserId, actor); + + const target = this._browserIdToTarget.get(browserId); + target?.setActor(actor); + } + + onActorDestroyed(actor) { + const browserId = actor.browsingContext.browserId; + const target = this._browserIdToTarget.get(browserId); + target?.removeActor(actor); + if (this._browserIdToActor.get(browserId) === actor) + this._browserIdToActor.delete(browserId); + } + + // Firefox uses nsHttpAuthCache to cache authentication to the proxy. // If we're provided with a single proxy with a multiple different authentications, then // we should clear the nsHttpAuthCache on every request. @@ -390,12 +413,12 @@ export class PageTarget { this._linkedBrowser = tab.linkedBrowser; this._browserContext = browserContext; this._viewportSize = undefined; + this._deviceScaleFactor = undefined; this._zoom = 1; this._initialDPPX = this._linkedBrowser.browsingContext.overrideDPPX; this._url = 'about:blank'; this._openerId = opener ? opener.id() : undefined; this._actor = undefined; - this._actorSequenceNumber = 0; this._channel = new SimpleChannel(`browser::page[${this._targetId}]`, 'target-' + this._targetId); this._screencastId = undefined; this._dialogs = new Map(); @@ -422,7 +445,12 @@ export class PageTarget { this._disposed = false; browserContext.pages.add(this); this._registry._browserToTarget.set(this._linkedBrowser, this); - this._registry._browserIdToTarget.set(this._linkedBrowser.browsingContext.browserId, this); + + const browserId = this._linkedBrowser.browsingContext.browserId; + this._registry._browserIdToTarget.set(browserId, this); + const actor = this._registry._browserIdToActor.get(browserId); + if (actor) + this.setActor(actor); this._registry.emit(TargetRegistry.Events.TargetCreated, this); } @@ -455,10 +483,6 @@ export class PageTarget { return helper.collectAllBrowsingContexts(this._linkedBrowser.browsingContext).find(bc => helper.browsingContextToFrameId(bc) === frameId); } - nextActorSequenceNumber() { - return ++this._actorSequenceNumber; - } - setActor(actor) { this._actor = actor; this._channel.bindToActor(actor); @@ -553,7 +577,8 @@ export class PageTarget { updateDPPXOverride(browsingContext = undefined) { browsingContext ||= this._linkedBrowser.browsingContext; - const dppx = this._zoom * (this._browserContext.deviceScaleFactor || this._initialDPPX); + const deviceScaleFactor = this._deviceScaleFactor ?? this._browserContext.deviceScaleFactor; + const dppx = this._zoom * (deviceScaleFactor || this._initialDPPX); browsingContext.overrideDPPX = dppx; } @@ -681,8 +706,9 @@ export class PageTarget { await this._channel.connect('').send('setInterceptFileChooserDialog', enabled).catch(e => {}); } - async setViewportSize(viewportSize) { + async setViewportSize(viewportSize, deviceScaleFactor) { this._viewportSize = viewportSize; + this._deviceScaleFactor = deviceScaleFactor; await this.updateViewportSize(); } diff --git a/browser_patches/firefox/juggler/content/PageAgent.js b/browser_patches/firefox/juggler/content/PageAgent.js index 0a48ac3e4d379..7e6e072c76157 100644 --- a/browser_patches/firefox/juggler/content/PageAgent.js +++ b/browser_patches/firefox/juggler/content/PageAgent.js @@ -126,7 +126,7 @@ export class PageAgent { } }), helper.addObserver(this._onWindowOpen.bind(this), 'webNavigation-createdNavigationTarget-from-js'), - this._runtime.events.onErrorFromWorker((domWindow, message, stack) => { + this._runtime.events.onErrorFromWorker((domWindow, message, stack, location) => { const frame = this._frameTree.frameForDocShell(domWindow.docShell); if (!frame) return; @@ -134,6 +134,7 @@ export class PageAgent { frameId: frame.id(), message, stack, + location, }); }), this._runtime.events.onConsoleMessage(msg => this._browserPage.emit('runtimeConsole', msg)), @@ -262,11 +263,12 @@ export class PageAgent { }); } - _onRuntimeError({ executionContext, message, stack }) { + _onRuntimeError({ executionContext, message, stack, location }) { this._browserPage.emit('pageUncaughtError', { frameId: executionContext.auxData().frameId, message: message.toString(), stack: stack.toString(), + location, }); } @@ -307,6 +309,9 @@ export class PageAgent { } _onNavigationCommitted(frame) { + if (frame.domWindow().document.isUncommittedInitialDocument) + return; + this._browserPage.emit('pageNavigationCommitted', { frameId: frame.id(), navigationId: frame.lastCommittedNavigationId() || undefined, @@ -489,19 +494,22 @@ export class PageAgent { async _dispatchTouchEvent({type, touchPoints, modifiers}) { const frame = this._frameTree.mainFrame(); - const defaultPrevented = frame.domWindow().windowUtils.sendTouchEvent( + const defaultPrevented = frame.domWindow().synthesizeTouchEvent( 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.map(point => 0), - touchPoints.map(point => 0), - touchPoints.map(point => 0), - modifiers); + touchPoints.map((point, id) => ({ + identifier: id, + offsetX: point.x, + offsetY: point.y, + radiiX: point.radiusX ?? 1.0, + radiiY: point.radiusY ?? 1.0, + rotationAngle: point.rotationAngle ?? 0.0, + pressure: point.force ?? 1.0, + tiltX: 0, + tiltY: 0, + twist: 0, + })), + modifiers + ); return {defaultPrevented}; } diff --git a/browser_patches/firefox/juggler/content/Runtime.js b/browser_patches/firefox/juggler/content/Runtime.js index 81fc59e146b42..a29af41b2038c 100644 --- a/browser_patches/firefox/juggler/content/Runtime.js +++ b/browser_patches/firefox/juggler/content/Runtime.js @@ -133,8 +133,15 @@ class Runtime { return; } const errorWindow = Services.wm.getOuterWindowWithId(message.outerWindowID); + // Note: error locations are one-based, while console locations are zero-based in Firefox. + // We want to report all of them as zero-based. + const errorLocation = { + lineNumber: message.lineNumber - 1, + columnNumber: message.columnNumber - 1, + url: message.sourceName, + }; if (message.category === 'Web Worker' && message.logLevel === Ci.nsIConsoleMessage.error) { - emitEvent(this.events.onErrorFromWorker, errorWindow, message.message, '' + message.stack); + emitEvent(this.events.onErrorFromWorker, errorWindow, message.message, '' + message.stack, errorLocation); return; } const executionContext = this._windowToExecutionContext.get(errorWindow); @@ -165,6 +172,7 @@ class Runtime { executionContext, message: message.errorMessage, stack: message.stack ? message.stack.toString() : '', + location: errorLocation, }); } }, @@ -239,8 +247,9 @@ class Runtime { return {success: true, obj: obj.promiseValue}; if (obj.promiseState === 'rejected') { const debuggee = executionContext._debuggee; - exceptionDetails.text = debuggee.executeInGlobalWithBindings('e.message', {e: obj.promiseReason}, {useInnerBindings: true}).return; - exceptionDetails.stack = debuggee.executeInGlobalWithBindings('e.stack', {e: obj.promiseReason}, {useInnerBindings: true}).return; + const errorInfo = debuggee.executeInGlobalWithBindings('({m: e?.message, s: e?.stack})', {e: obj.promiseReason}, {useInnerBindings: true}).return; + exceptionDetails.text = errorInfo.getOwnPropertyDescriptor('m').value; + exceptionDetails.stack = errorInfo.getOwnPropertyDescriptor('s').value; return {success: false, obj: null}; } let resolve, reject; @@ -267,8 +276,9 @@ class Runtime { return; }; const debuggee = pendingPromise.executionContext._debuggee; - pendingPromise.exceptionDetails.text = debuggee.executeInGlobalWithBindings('e.message', {e: obj.promiseReason}, {useInnerBindings: true}).return; - pendingPromise.exceptionDetails.stack = debuggee.executeInGlobalWithBindings('e.stack', {e: obj.promiseReason}, {useInnerBindings: true}).return; + const errorInfo = debuggee.executeInGlobalWithBindings('({m: e?.message, s: e?.stack})', {e: obj.promiseReason}, {useInnerBindings: true}).return; + pendingPromise.exceptionDetails.text = errorInfo.getOwnPropertyDescriptor('m').value; + pendingPromise.exceptionDetails.stack = errorInfo.getOwnPropertyDescriptor('s').value; pendingPromise.resolve({success: false, obj: null}); } @@ -357,7 +367,7 @@ class ExecutionContext { if (this._domWindow && this._domWindow.document) this._domWindow.document.notifyUserGestureActivation(); - let {success, obj} = this._getResult(this._debuggee.executeInGlobal(script), exceptionDetails); + let {success, obj} = this._getResult(this._debuggee.executeInGlobal(script, {bypassCSP: true}), exceptionDetails); userInputHelper && userInputHelper.destruct(); if (!success) return null; @@ -372,18 +382,13 @@ class ExecutionContext { evaluateScriptSafely(script) { try { - this._debuggee.executeInGlobal(script); + this._debuggee.executeInGlobal(script, {bypassCSP: true}); } catch (e) { dump(`WARNING: ${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)) @@ -401,7 +406,15 @@ class ExecutionContext { 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); + // Invoke via executeInGlobalWithBindings so bypassCSP scopes the call (Debugger.Object.apply has no bypassCSP option). + const callBindings = {}; + const argNames = []; + for (let i = 0; i < args.length; i++) { + const name = '__pwArg' + i; + callBindings[name] = args[i]; + argNames.push(name); + } + let {success, obj} = this._getResult(this._debuggee.executeInGlobalWithBindings('(' + functionText + ')(' + argNames.join(',') + ')', callBindings, {useInnerBindings: true, bypassCSP: true}), exceptionDetails); userInputHelper && userInputHelper.destruct(); if (!success) return null; @@ -438,12 +451,6 @@ class ExecutionContext { 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)}, {useInnerBindings: true}).return; - } - _createRemoteObject(debuggerObj) { if (debuggerObj instanceof Debugger.Object) { const objectId = generateId(); @@ -451,36 +458,33 @@ class ExecutionContext { const rawObj = debuggerObj.unsafeDereference(); const type = typeof rawObj; let subtype = undefined; - if (debuggerObj.isProxy) + if (debuggerObj.isProxy) { subtype = 'proxy'; - else if (Array.isArray(rawObj)) - subtype = 'array'; - else if (Object.is(rawObj, null)) - subtype = 'null'; - else if (typeof Node !== 'undefined' && Node.isInstance(rawObj)) + } else if (typeof Node !== 'undefined' && Node.isInstance(rawObj)) { 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'; + } else { + switch (debuggerObj.class) { + case 'Array': subtype = 'array'; break; + case 'RegExp': subtype = 'regexp'; break; + case 'Date': subtype = 'date'; break; + case 'Map': subtype = 'map'; break; + case 'Set': subtype = 'set'; break; + case 'WeakMap': subtype = 'weakmap'; break; + case 'WeakSet': subtype = 'weakset'; break; + case 'Error': subtype = 'error'; break; + case 'Promise': subtype = 'promise'; break; + case 'Int8Array': + case 'Uint8Array': + case 'Uint8ClampedArray': + case 'Int16Array': + case 'Uint16Array': + case 'Int32Array': + case 'Uint32Array': + case 'Float32Array': + case 'Float64Array': + subtype = 'typedarray'; + break; + } } return {objectId, type, subtype}; } @@ -563,9 +567,10 @@ class ExecutionContext { if (!completionValue) throw new Error('evaluation terminated'); if (completionValue.throw) { - if (this._debuggee.executeInGlobalWithBindings('e instanceof Error', {e: completionValue.throw}, {useInnerBindings: true}).return) { - exceptionDetails.text = this._debuggee.executeInGlobalWithBindings('e.message', {e: completionValue.throw}, {useInnerBindings: true}).return; - exceptionDetails.stack = this._debuggee.executeInGlobalWithBindings('e.stack', {e: completionValue.throw}, {useInnerBindings: true}).return; + const errorInfo = this._debuggee.executeInGlobalWithBindings('e instanceof Error ? ({m: e.message, s: e.stack}) : null', {e: completionValue.throw}, {useInnerBindings: true}).return; + if (errorInfo) { + exceptionDetails.text = errorInfo.getOwnPropertyDescriptor('m').value; + exceptionDetails.stack = errorInfo.getOwnPropertyDescriptor('s').value; } else { exceptionDetails.value = this._serialize(completionValue.throw); } diff --git a/browser_patches/firefox/juggler/protocol/PageHandler.js b/browser_patches/firefox/juggler/protocol/PageHandler.js index 267358890f0b6..cec3c08e28e4f 100644 --- a/browser_patches/firefox/juggler/protocol/PageHandler.js +++ b/browser_patches/firefox/juggler/protocol/PageHandler.js @@ -227,8 +227,8 @@ export class PageHandler { }); } - async ['Page.setViewportSize']({viewportSize}) { - await this._pageTarget.setViewportSize(viewportSize === null ? undefined : viewportSize); + async ['Page.setViewportSize']({viewportSize, deviceScaleFactor}) { + await this._pageTarget.setViewportSize(viewportSize === null ? undefined : viewportSize, deviceScaleFactor); } async ['Page.setZoom']({zoom}) { diff --git a/browser_patches/firefox/juggler/protocol/Protocol.js b/browser_patches/firefox/juggler/protocol/Protocol.js index e1589b0cf74ca..6aca7c22fced5 100644 --- a/browser_patches/firefox/juggler/protocol/Protocol.js +++ b/browser_patches/firefox/juggler/protocol/Protocol.js @@ -631,6 +631,7 @@ const Page = { frameId: t.String, message: t.String, stack: t.String, + location: runtimeTypes.ScriptLocation, }, 'frameAttached': { frameId: t.String, @@ -753,6 +754,7 @@ const Page = { 'setViewportSize': { params: { viewportSize: t.Nullable(pageTypes.Size), + deviceScaleFactor: t.Optional(t.Number), }, }, 'setZoom': { diff --git a/browser_patches/firefox/patches/bootstrap.diff b/browser_patches/firefox/patches/bootstrap.diff index f273772e72120..f5485ca04b46c 100644 --- a/browser_patches/firefox/patches/bootstrap.diff +++ b/browser_patches/firefox/patches/bootstrap.diff @@ -1,8 +1,8 @@ diff --git a/browser/app/winlauncher/LauncherProcessWin.cpp b/browser/app/winlauncher/LauncherProcessWin.cpp -index 2d77838b90601a71d6789e9ff3064cf24ddbde7e..9199ef1e8cb5d7988b98e119b68be38dbfd5f3b0 100644 +index c63afe6dc5e00fadbc57ef556505a313728981f7..19d27fac991c44a3e8a6f28eb1b7aa51c30c1672 100644 --- a/browser/app/winlauncher/LauncherProcessWin.cpp +++ b/browser/app/winlauncher/LauncherProcessWin.cpp -@@ -22,6 +22,7 @@ +@@ -20,6 +20,7 @@ #include "mozilla/WinHeaderOnlyUtils.h" #include "nsWindowsHelpers.h" @@ -10,7 +10,7 @@ index 2d77838b90601a71d6789e9ff3064cf24ddbde7e..9199ef1e8cb5d7988b98e119b68be38d #include <windows.h> #include <processthreadsapi.h> #include <shlwapi.h> -@@ -468,8 +469,18 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[]) { +@@ -492,8 +493,18 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[]) { HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE), ::GetStdHandle(STD_OUTPUT_HANDLE), ::GetStdHandle(STD_ERROR_HANDLE)}; @@ -31,10 +31,10 @@ index 2d77838b90601a71d6789e9ff3064cf24ddbde7e..9199ef1e8cb5d7988b98e119b68be38d DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn -index 0e195e47d97b05caedeab65679e8e32a501ac629..d7ecbe4648684e9afa368c63da7795aef4494c9b 100644 +index 1f3a406c8714a65ec1437109921e862ff738bd0a..d3d90bf19771652af107bd79dac01929fe43320c 100644 --- a/browser/installer/allowed-dupes.mn +++ b/browser/installer/allowed-dupes.mn -@@ -61,6 +61,12 @@ browser/chrome/browser/builtin-addons/webcompat/shims/empty-shim.txt +@@ -66,6 +66,12 @@ browser/chrome/browser/builtin-addons/webcompat/shims/empty-shim.txt removed-files #endif @@ -48,10 +48,10 @@ index 0e195e47d97b05caedeab65679e8e32a501ac629..d7ecbe4648684e9afa368c63da7795ae browser/chrome/browser/content/activity-stream/data/content/tippytop/favicons/allegro-pl.ico browser/defaults/settings/main/search-config-icons/96327a73-c433-5eb4-a16d-b090cadfb80b diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index dbfb287747ed9059cfb46838800421ac9ffe78c1..3e9ce7c6405578c900d0f13755db1db3f50e8f3f 100644 +index 36eafe35063f02fe3d4acaab24a08dc1b7b0ae24..33fe25fc507ff32b532c8e1d429b5bc05c8d6f94 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in -@@ -196,6 +196,9 @@ +@@ -200,6 +200,9 @@ @RESPATH@/chrome/remote.manifest #endif @@ -109,10 +109,10 @@ index 257e87fe0c618684eb4216c8028ac886ef2d5562..8c13f020100dad9bc4e093d50bd3a1f9 const transportProvider = { setListener(upgradeListener) { diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp -index 663b8d827f37671044cdf799abe4842f50dc3fc1..d44d4a6e874838920ceaeacbaeb458219322f37e 100644 +index a469a6fffc489a0927a748d347bf7bdde98570b4..f92cb8162ba6b93b04ae6b7a55ff8d964eb442e2 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp -@@ -116,8 +116,15 @@ struct ParamTraits<mozilla::dom::DisplayMode> +@@ -117,8 +117,15 @@ struct ParamTraits<mozilla::dom::DisplayMode> template <> struct ParamTraits<mozilla::dom::PrefersColorSchemeOverride> @@ -130,7 +130,7 @@ index 663b8d827f37671044cdf799abe4842f50dc3fc1..d44d4a6e874838920ceaeacbaeb45821 template <> struct ParamTraits<mozilla::dom::ForcedColorsOverride> -@@ -3324,6 +3331,32 @@ void BrowsingContext::DidSet(FieldIndex<IDX_LanguageOverride>, +@@ -3355,6 +3362,32 @@ void BrowsingContext::DidSet(FieldIndex<IDX_LanguageOverride>, }); } @@ -163,7 +163,7 @@ index 663b8d827f37671044cdf799abe4842f50dc3fc1..d44d4a6e874838920ceaeacbaeb45821 void BrowsingContext::DidSet(FieldIndex<IDX_MediumOverride>, nsString&& aOldValue) { MOZ_ASSERT(IsTop()); -@@ -3671,7 +3704,7 @@ void BrowsingContext::SetGeolocationServiceOverride( +@@ -3702,7 +3735,7 @@ void BrowsingContext::SetGeolocationServiceOverride( if (aGeolocationOverride.WasPassed()) { if (!mGeolocationServiceOverride) { mGeolocationServiceOverride = new nsGeolocationService(); @@ -173,7 +173,7 @@ index 663b8d827f37671044cdf799abe4842f50dc3fc1..d44d4a6e874838920ceaeacbaeb45821 mGeolocationServiceOverride->Update(aGeolocationOverride.Value()); } else if (RefPtr<nsGeolocationService> serviceOverride = diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index 42e3b22a366db0a8c470b458696d81e4bdbd537c..72d37a4a6ff183c11a493794a44ef9420056e728 100644 +index e86ce5dd594315898c21e8b9016145358b026106..0aad51333679f94fe2cc28ad7f512e958297ee72 100644 --- a/docshell/base/BrowsingContext.h +++ b/docshell/base/BrowsingContext.h @@ -212,11 +212,11 @@ struct EmbedderColorSchemes { @@ -190,7 +190,7 @@ index 42e3b22a366db0a8c470b458696d81e4bdbd537c..72d37a4a6ff183c11a493794a44ef942 FIELD(EmbedderElementType, Maybe<nsString>) \ FIELD(MessageManagerGroup, nsString) \ FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -257,6 +257,9 @@ struct EmbedderColorSchemes { +@@ -259,6 +259,9 @@ struct EmbedderColorSchemes { * <browser> embedder element. */ \ FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ FIELD(DisplayMode, dom::DisplayMode) \ @@ -200,8 +200,8 @@ index 42e3b22a366db0a8c470b458696d81e4bdbd537c..72d37a4a6ff183c11a493794a44ef942 /* The number of entries added to the session history because of this \ * browsing context. */ \ FIELD(HistoryEntryCount, uint32_t) \ -@@ -1097,6 +1100,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetForcedColorsOverride(); +@@ -1110,6 +1113,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + return Top()->GetAnimationsPlayBackRateMultiplier(); } + dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { @@ -215,7 +215,7 @@ index 42e3b22a366db0a8c470b458696d81e4bdbd537c..72d37a4a6ff183c11a493794a44ef942 bool IsInBFCache() const; bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1278,6 +1289,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { +@@ -1291,6 +1302,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { return IsTop(); } @@ -227,9 +227,9 @@ index 42e3b22a366db0a8c470b458696d81e4bdbd537c..72d37a4a6ff183c11a493794a44ef942 bool CanSet(FieldIndex<IDX_ForcedColorsOverride>, dom::ForcedColorsOverride, ContentParent*) { return IsTop(); -@@ -1297,6 +1313,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - void DidSet(FieldIndex<IDX_ForcedColorsOverride>, - dom::ForcedColorsOverride aOldValue); +@@ -1319,6 +1335,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + void DidSet(FieldIndex<IDX_AnimationsPlayBackRateMultiplier>, + double aOldValue); + void DidSet(FieldIndex<IDX_PrefersContrastOverride>, + dom::PrefersContrastOverride aOldValue); @@ -237,7 +237,7 @@ index 42e3b22a366db0a8c470b458696d81e4bdbd537c..72d37a4a6ff183c11a493794a44ef942 template <typename Callback> void WalkPresContexts(Callback&&); void PresContextAffectingFieldChanged(); -@@ -1305,6 +1324,15 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { +@@ -1327,6 +1346,15 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { void DidSet(FieldIndex<IDX_TimezoneOverride>, nsString&& aOldValue); @@ -254,11 +254,11 @@ index 42e3b22a366db0a8c470b458696d81e4bdbd537c..72d37a4a6ff183c11a493794a44ef942 bool CanSet(FieldIndex<IDX_SuspendMediaWhenInactive>, bool, ContentParent*) { diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp -index fcebff1e344083e6261ad728c97d8b10434cf8d2..d01513cfa30dc74954ea38bcceda6dc100b44194 100644 +index 43e87830dd3c9b4083b66d87856fcc30f8ed42c6..a984087b80e0da01f51edbc1d09dc46304996963 100644 --- a/docshell/base/CanonicalBrowsingContext.cpp +++ b/docshell/base/CanonicalBrowsingContext.cpp @@ -272,6 +272,8 @@ void CanonicalBrowsingContext::ReplacedBy( - txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP()); + txn.SetInnerSizeSpoofedForRFP(GetInnerSizeSpoofedForRFP()); txn.SetIPAddressSpace(GetIPAddressSpace()); txn.SetParentalControlsEnabled(GetParentalControlsEnabled()); + txn.SetPrefersReducedMotionOverride(GetPrefersReducedMotionOverride()); @@ -266,7 +266,7 @@ index fcebff1e344083e6261ad728c97d8b10434cf8d2..d01513cfa30dc74954ea38bcceda6dc1 if (!GetLanguageOverride().IsEmpty()) { // Reapply language override to update the corresponding realm. -@@ -1969,6 +1971,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, +@@ -1885,6 +1887,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, (void)SetIsCaptivePortalTab(true); } @@ -280,7 +280,7 @@ index fcebff1e344083e6261ad728c97d8b10434cf8d2..d01513cfa30dc74954ea38bcceda6dc1 } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a0c7b3148 100644 +index b87acffba7db71c1312194e11d2339aae3252103..fe1d61f2ae10b452b012c6d4072bfe62e9a1c026 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -17,6 +17,12 @@ @@ -320,7 +320,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a #include "nsIDocumentLoaderFactory.h" #include "nsIDOMWindow.h" #include "nsIEditingSession.h" -@@ -215,6 +224,7 @@ +@@ -216,6 +225,7 @@ #include "nsGlobalWindowInner.h" #include "nsGlobalWindowOuter.h" #include "nsJSEnvironment.h" @@ -328,7 +328,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsObjectLoadingContent.h" -@@ -354,6 +364,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, +@@ -357,6 +367,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, mAllowDNSPrefetch(true), mAllowWindowControl(true), mCSSErrorReportingEnabled(false), @@ -343,7 +343,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a mAllowAuth(mItemType == typeContent), mAllowKeywordFixup(false), mDisableMetaRefreshWhenInactive(false), -@@ -3041,6 +3059,174 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { +@@ -3107,6 +3125,174 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { return NS_OK; } @@ -518,7 +518,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a NS_IMETHODIMP nsDocShell::GetIsNavigating(bool* aOut) { *aOut = mIsNavigating; -@@ -4817,7 +5003,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { +@@ -4895,7 +5081,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { } void nsDocShell::ActivenessMaybeChanged() { @@ -527,7 +527,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a if (RefPtr<PresShell> presShell = GetPresShell()) { presShell->ActivenessMaybeChanged(); } -@@ -6886,6 +7072,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, +@@ -7054,6 +7240,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, return false; // no entry to save into } @@ -538,7 +538,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a MOZ_ASSERT(!mozilla::SessionHistoryInParent(), "mOSHE cannot be non-null with SHIP"); nsCOMPtr<nsIDocumentViewer> viewer = mOSHE->GetDocumentViewer(); -@@ -8587,6 +8777,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { +@@ -8755,6 +8945,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { true, // aForceNoOpener getter_AddRefs(newBC)); MOZ_ASSERT(!newBC); @@ -551,8 +551,8 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a return rv; } -@@ -9988,6 +10184,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, - nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); +@@ -10164,6 +10360,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, + attrs.SetFirstPartyDomain(isTopLevelDoc, aLoadState->URI()); nsCOMPtr<nsIRequest> req; + @@ -568,7 +568,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); if (NS_SUCCEEDED(rv)) { -@@ -13404,6 +13610,9 @@ class OnLinkClickEvent : public Runnable { +@@ -13835,6 +14041,9 @@ class OnLinkClickEvent : public Runnable { mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, mTriggeringPrincipal); } @@ -578,7 +578,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a return NS_OK; } -@@ -13521,6 +13730,8 @@ nsresult nsDocShell::OnLinkClick( +@@ -13952,6 +14161,8 @@ nsresult nsDocShell::OnLinkClick( nsCOMPtr<nsIRunnable> ev = new OnLinkClickEvent( this, aContent, loadState, noOpenerImplied, aTriggeringPrincipal); @@ -588,7 +588,7 @@ index 51bbec50a67621ea429411e10c4aea54d8dbc3f8..981ec35569d3f0d3e75d6ea69bea417a } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 1ce29a1afe5f0147fc9dc7b8fb20a3c5c619beb6..a9dff3bd2ffb9852cc7dfb48f7397187b170b622 100644 +index 7ca79a65b91dcd317d852ace29786f4d139d60ed..4070b70f35f401a66c21f05db1c143caf78ee560 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -16,6 +16,7 @@ @@ -599,7 +599,7 @@ index 1ce29a1afe5f0147fc9dc7b8fb20a3c5c619beb6..a9dff3bd2ffb9852cc7dfb48f7397187 #include "mozilla/dom/WindowProxyHolder.h" #include "nsCOMPtr.h" #include "nsCharsetSource.h" -@@ -82,6 +83,7 @@ class nsCommandManager; +@@ -85,6 +86,7 @@ class nsCommandManager; class nsDocShellEditorData; class nsDOMNavigationTiming; class nsDSURIContentListener; @@ -607,7 +607,7 @@ index 1ce29a1afe5f0147fc9dc7b8fb20a3c5c619beb6..a9dff3bd2ffb9852cc7dfb48f7397187 class nsGlobalWindowOuter; class FramingChecker; -@@ -414,6 +416,15 @@ class nsDocShell final : public nsDocLoader, +@@ -424,6 +426,15 @@ class nsDocShell final : public nsDocLoader, void SetWillChangeProcess() { mWillChangeProcess = true; } bool WillChangeProcess() { return mWillChangeProcess; } @@ -620,10 +620,10 @@ index 1ce29a1afe5f0147fc9dc7b8fb20a3c5c619beb6..a9dff3bd2ffb9852cc7dfb48f7397187 + + RefPtr<nsGeolocationService> GetGeolocationServiceOverride(); + - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateDocumentViewerForActor( -@@ -1059,6 +1070,8 @@ class nsDocShell final : public nsDocLoader, + // Creates a real network channel (not a DocumentChannel) using the specified + // parameters. + // Used by nsDocShell when not using DocumentChannel, by DocumentLoadListener +@@ -1084,6 +1095,8 @@ class nsDocShell final : public nsDocLoader, bool CSSErrorReportingEnabled() const { return mCSSErrorReportingEnabled; } @@ -632,7 +632,7 @@ index 1ce29a1afe5f0147fc9dc7b8fb20a3c5c619beb6..a9dff3bd2ffb9852cc7dfb48f7397187 // 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 -@@ -1390,6 +1403,16 @@ class nsDocShell final : public nsDocLoader, +@@ -1415,6 +1428,16 @@ class nsDocShell final : public nsDocLoader, bool mAllowDNSPrefetch : 1; bool mAllowWindowControl : 1; bool mCSSErrorReportingEnabled : 1; @@ -704,10 +704,10 @@ index 888d99bae849fcd2988388489edcfc56443d3e23..75d8bd5e9f20b4ea4d2b198c13ec3c1b * 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 7bbbaf6fb936eda9cf87f164f93f4a96a50cf733..ef8141e69db2cb648419c7e45e033af8bbcf53ab 100644 +index b837e66d4fd5b6a96ad3d9c35f8e50e911cd168b..bfc4d2d58af06169cdb1167a38507abdaab3d608 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp -@@ -3937,6 +3937,9 @@ void Document::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) { +@@ -3812,6 +3812,9 @@ void Document::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) { } void Document::ApplySettingsFromCSP(bool aSpeculative) { @@ -717,7 +717,7 @@ index 7bbbaf6fb936eda9cf87f164f93f4a96a50cf733..ef8141e69db2cb648419c7e45e033af8 nsresult rv = NS_OK; if (!aSpeculative) { nsIContentSecurityPolicy* csp = PolicyContainer::GetCSP(mPolicyContainer); -@@ -4025,6 +4028,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { +@@ -3900,6 +3903,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { MOZ_ASSERT(mPolicyContainer, "Policy container must be initialized before CSP!"); @@ -729,7 +729,7 @@ index 7bbbaf6fb936eda9cf87f164f93f4a96a50cf733..ef8141e69db2cb648419c7e45e033af8 // If this is a data document - no need to set CSP. if (mLoadedAsData) { return NS_OK; -@@ -4903,6 +4911,10 @@ bool Document::HasFocus(ErrorResult& rv) const { +@@ -4818,6 +4826,10 @@ bool Document::HasFocus(ErrorResult& rv) const { return false; } @@ -740,7 +740,7 @@ index 7bbbaf6fb936eda9cf87f164f93f4a96a50cf733..ef8141e69db2cb648419c7e45e033af8 if (!fm->IsInActiveWindow(bc)) { return false; } -@@ -20513,6 +20525,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { +@@ -20473,6 +20485,35 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { return PreferenceSheet::PrefsFor(*this).mColorScheme; } @@ -777,10 +777,10 @@ index 7bbbaf6fb936eda9cf87f164f93f4a96a50cf733..ef8141e69db2cb648419c7e45e033af8 if (!sLoadingForegroundTopLevelContentDocument) { return false; diff --git a/dom/base/Document.h b/dom/base/Document.h -index 1d4d4c840dcb6222d9f17f3a2e970f600a5d9252..15448c18c55c54c16b2debec3b9c16f551931842 100644 +index a902c1ac14dd5a3345695ee64845abe754abc112..60b6e8acce1c430133393d8c68be32d65a158e9a 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h -@@ -4329,6 +4329,8 @@ class Document : public nsINode, +@@ -4395,6 +4395,8 @@ class Document : public nsINode, // color-scheme meta tag. ColorScheme DefaultColorScheme() const; @@ -804,10 +804,10 @@ index df1ff164347bc1672c36e87184b2804ee0712537..56543649b9a6ff6f5b0f961cd26c4ca3 AutoplayPolicy Navigator::GetAutoplayPolicy(AutoplayPolicyMediaType aType) { diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 32eb5998645d749bdc711d25abc1b4919a4d737c..ae76b3c942a87593d49f18b2f76408be7517033f 100644 +index c0db239852ce2d8d28a9abb6cf2c3abdf4b9896a..a2911baa33ac2868543d4d7fc3d93305993da705 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp -@@ -9524,6 +9524,7 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( +@@ -9769,6 +9769,7 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( EventMessage msg; Maybe<WidgetMouseEvent::ExitFrom> exitFrom; bool contextMenuKey = false; @@ -815,7 +815,7 @@ index 32eb5998645d749bdc711d25abc1b4919a4d737c..ae76b3c942a87593d49f18b2f76408be if (aType.EqualsLiteral("mousedown")) { msg = eMouseDown; } else if (aType.EqualsLiteral("mouseup")) { -@@ -9550,13 +9551,26 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( +@@ -9795,13 +9796,26 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( msg = eMouseHitTest; } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { msg = eMouseExploreByTouch; @@ -843,7 +843,7 @@ index 32eb5998645d749bdc711d25abc1b4919a4d737c..ae76b3c942a87593d49f18b2f76408be if (MOZ_UNLIKELY(aOptions.mIsWidgetEventSynthesized)) { MOZ_ASSERT_UNREACHABLE( "The event shouldn't be dispatched as a synthesized event"); -@@ -9584,6 +9598,7 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( +@@ -9829,6 +9843,7 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( mozilla::widget::AutoSynthesizedEventCallbackNotifier notifier(callback); WidgetMouseEvent& mouseOrPointerEvent = @@ -851,7 +851,7 @@ index 32eb5998645d749bdc711d25abc1b4919a4d737c..ae76b3c942a87593d49f18b2f76408be pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref(); mouseOrPointerEvent.pointerId = aMouseEventData.mIdentifier; mouseOrPointerEvent.mModifiers = -@@ -9605,6 +9620,7 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( +@@ -9850,6 +9865,7 @@ Result<bool, nsresult> nsContentUtils::SynthesizeMouseEvent( aOptions.mIsDOMEventSynthesized; mouseOrPointerEvent.mExitFrom = exitFrom; mouseOrPointerEvent.mCallbackId = notifier.SaveCallback(); @@ -860,7 +860,7 @@ index 32eb5998645d749bdc711d25abc1b4919a4d737c..ae76b3c942a87593d49f18b2f76408be nsPresContext* presContext = aPresShell->GetPresContext(); if (!presContext) { diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index fa2125fa662b79a939d379627e1e4040fcdc9afd..6bb0c72796f0a9d85f4473c2c6bb1e62573fc2c0 100644 +index 1a373169b3be65f45571eff08879efe1127c3fdf..f972450bc3f4566a8ab29dad5269f3451a286392 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1840,6 +1840,10 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent, @@ -874,7 +874,7 @@ index fa2125fa662b79a939d379627e1e4040fcdc9afd..6bb0c72796f0a9d85f4473c2c6bb1e62 // Exit fullscreen if a website focuses another window if (StaticPrefs::full_screen_api_exit_on_windowRaise() && !isElementInActiveWindow && (aFlags & FLAG_RAISE)) { -@@ -2427,6 +2431,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, +@@ -2401,6 +2405,7 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, bool aIsLeavingDocument, bool aAdjustWidget, bool aRemainActive, Element* aElementToFocus, uint64_t aActionId) { @@ -882,7 +882,7 @@ index fa2125fa662b79a939d379627e1e4040fcdc9afd..6bb0c72796f0a9d85f4473c2c6bb1e62 LOGFOCUS(("<<Blur begin actionid: %" PRIu64 ">>", aActionId)); // hold a reference to the focused content, which may be null -@@ -2470,6 +2475,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, +@@ -2444,6 +2449,11 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, return true; } @@ -894,7 +894,7 @@ index fa2125fa662b79a939d379627e1e4040fcdc9afd..6bb0c72796f0a9d85f4473c2c6bb1e62 // Keep a ref to presShell since dispatching the DOM event may cause // the document to be destroyed. RefPtr<PresShell> presShell = docShell->GetPresShell(); -@@ -3169,7 +3179,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, +@@ -3143,7 +3153,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, } } @@ -906,13 +906,13 @@ index fa2125fa662b79a939d379627e1e4040fcdc9afd..6bb0c72796f0a9d85f4473c2c6bb1e62 // 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 4b859af72ff2d1caf614bce7025418effce09858..57c4dde59982e84ca4b1628bd63a94a0d24f3d48 100644 +index 81c0df391ec757f310b73885d4dab2620400abb8..406b3d96f1fe0ebe8fa626c26c700e0a897b3813 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2514,10 +2514,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, +@@ -2515,10 +2515,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, }(); - if (!isContentAboutBlankInChromeDocshell) { + if (!isAboutBlankInChromeDocshell) { - newInnerWindow->mHasNotifiedGlobalCreated = true; - nsContentUtils::AddScriptRunner(NewRunnableMethod( - "nsGlobalWindowOuter::DispatchDOMWindowCreated", this, @@ -930,7 +930,7 @@ index 4b859af72ff2d1caf614bce7025418effce09858..57c4dde59982e84ca4b1628bd63a94a0 } } -@@ -2637,6 +2643,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { +@@ -2638,6 +2644,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { } } @@ -951,10 +951,10 @@ index 4b859af72ff2d1caf614bce7025418effce09858..57c4dde59982e84ca4b1628bd63a94a0 void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index b6226ff10fc43b861092732b87d96045ab719d6c..87fae2cff5037e5fa9febee5603883a4ec782fff 100644 +index 4eadbdaef2e2a6c8fb980b715bcd7f0b14084314..b28a9b339d22c44bc95221324ca64b892cafa40d 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h -@@ -315,6 +315,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, +@@ -312,6 +312,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, // Outer windows only. void DispatchDOMWindowCreated(); @@ -963,10 +963,10 @@ index b6226ff10fc43b861092732b87d96045ab719d6c..87fae2cff5037e5fa9febee5603883a4 // Outer windows only. virtual void EnsureSizeAndPositionUpToDate() override; diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp -index 43987ca13062ce9b9d911c16ddfefc928776a76f..d41f167709f729d49cebfff6cff6e99b9deaa4fc 100644 +index b99f4aa5507ea5414346156d85f5b54353915e7c..b06b512688cc77f30b1cb5398f260d3cea713fdc 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp -@@ -1507,6 +1507,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, +@@ -1536,6 +1536,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); } @@ -1029,10 +1029,10 @@ index 43987ca13062ce9b9d911c16ddfefc928776a76f..d41f167709f729d49cebfff6cff6e99b DOMQuad& aQuad, const GeometryNode& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h -index 1611ea9eb23a7b9a2885b7f870da4a7a974e52f3..6511777068ed465cc439a5e13d76fd2853cf3007 100644 +index 169c7149364a92d03fa360fcafe71941023d339c..fd53ee27538ce8e721000dbe78a1b94bee20c67f 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h -@@ -2499,6 +2499,10 @@ class nsINode : public mozilla::dom::EventTarget { +@@ -2518,6 +2518,10 @@ class nsINode : public mozilla::dom::EventTarget { nsTArray<RefPtr<DOMQuad>>& aResult, ErrorResult& aRv); @@ -1044,10 +1044,10 @@ index 1611ea9eb23a7b9a2885b7f870da4a7a974e52f3..6511777068ed465cc439a5e13d76fd28 DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl -index 3bb17157c1dba1ca75ad9cfee2c21fcafb2dd0ee..550d4d94dfc4e0072bc7935eb8501f2785135c50 100644 +index d80abcf58e0c684487772f1f85f4100a27eeba14..fd4fbce8c9cdf4556188ec40919ee96abcdb5009 100644 --- a/dom/chrome-webidl/BrowsingContext.webidl +++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -62,6 +62,26 @@ enum ForcedColorsOverride { +@@ -63,6 +63,26 @@ enum ForcedColorsOverride { "active", }; @@ -1074,9 +1074,9 @@ index 3bb17157c1dba1ca75ad9cfee2c21fcafb2dd0ee..550d4d94dfc4e0072bc7935eb8501f27 /** * Allowed overrides of platform/pref default behaviour for touch events. */ -@@ -242,6 +262,12 @@ interface BrowsingContext { - // Forced-colors simulation, for DevTools - [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; +@@ -246,6 +266,12 @@ interface BrowsingContext { + // Animation playbackRate multiplier, for Devtools + [SetterThrows] attribute double animationsPlayBackRateMultiplier; + // Reduced-Motion simulation, for DevTools. + [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; @@ -1088,7 +1088,7 @@ index 3bb17157c1dba1ca75ad9cfee2c21fcafb2dd0ee..550d4d94dfc4e0072bc7935eb8501f27 * 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/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp -index 13ad1f24ab1fd55737438ac8013d831c6a03dffe..bcc08d1843d5c1e4da437c9b66641582f5d8f403 100644 +index 14c8fb1a2657d0880666acf365223baeb1b399f3..aa8801e345b1653b22316e9fb57b5677c85676c7 100644 --- a/dom/fetch/FetchService.cpp +++ b/dom/fetch/FetchService.cpp @@ -267,6 +267,14 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() { @@ -1107,7 +1107,7 @@ index 13ad1f24ab1fd55737438ac8013d831c6a03dffe..bcc08d1843d5c1e4da437c9b66641582 auto& args = mArgs.as<WorkerFetchArgs>(); mFetchDriver->SetWorkerScript(args.mWorkerScript); diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 33832d190f96b791ec38aaa1798e99399a195d86..f0d776bb3d7aa946d843c96bab8f52c6adc21a93 100644 +index 001d064b2d94fa5a4bf22e8b268e2ccafe628f73..ef8353a10443c90aa5f5a37a2948c82c11143a16 100644 --- a/dom/geolocation/Geolocation.cpp +++ b/dom/geolocation/Geolocation.cpp @@ -393,7 +393,10 @@ nsGeolocationRequest::Allow(JS::Handle<JS::Value> aChoices) { @@ -1131,7 +1131,7 @@ index 33832d190f96b791ec38aaa1798e99399a195d86..f0d776bb3d7aa946d843c96bab8f52c6 bool canUseCache = false; CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); if (lastPosition.position) { -@@ -709,11 +710,16 @@ NS_INTERFACE_MAP_END +@@ -713,11 +714,16 @@ NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsGeolocationService) NS_IMPL_RELEASE(nsGeolocationService) @@ -1149,7 +1149,7 @@ index 33832d190f96b791ec38aaa1798e99399a195d86..f0d776bb3d7aa946d843c96bab8f52c6 if (XRE_IsContentProcess()) { return NS_OK; } -@@ -792,6 +798,10 @@ nsresult nsGeolocationService::Init() { +@@ -796,6 +802,10 @@ nsresult nsGeolocationService::Init() { return NS_OK; } @@ -1160,7 +1160,7 @@ index 33832d190f96b791ec38aaa1798e99399a195d86..f0d776bb3d7aa946d843c96bab8f52c6 nsGeolocationService::~nsGeolocationService() = default; NS_IMETHODIMP -@@ -935,6 +945,10 @@ bool nsGeolocationService::HighAccuracyRequested() { +@@ -939,6 +949,10 @@ bool nsGeolocationService::HighAccuracyRequested() { } void nsGeolocationService::UpdateAccuracy(bool aForceHigh) { @@ -1203,10 +1203,10 @@ index d46e2e88b121688f62bbd43755791a077cfa1fe8..e69d62ffb4e732137b7a0ec0385358f3 namespace mozilla::dom { diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index 4208fa72fbab3faeaf2e30480767c3bb38642ad8..c76dd6ed1a99fc19520833804d09b2e15d7e83d4 100644 +index 8074eb6f2507538d2c78068295bfca5c16a5fd0a..c6cef9f3b03d68e4a59345d0cae3c557474c20d4 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp -@@ -59,6 +59,7 @@ +@@ -61,6 +61,7 @@ #include "nsBaseCommandController.h" #include "nsCRTGlue.h" #include "nsColorControlFrame.h" @@ -1214,7 +1214,7 @@ index 4208fa72fbab3faeaf2e30480767c3bb38642ad8..c76dd6ed1a99fc19520833804d09b2e1 #include "nsError.h" #include "nsFileControlFrame.h" #include "nsFocusManager.h" -@@ -848,6 +849,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { +@@ -934,6 +935,13 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { return NS_ERROR_FAILURE; } @@ -1460,7 +1460,7 @@ index f22e318c063870443f3f849a990aa5139cd33acf..b0034cfc1ccecf8765ab239a4ccc2232 return aGlobalOrNull; diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp -index fb7533f06411d871de7e238ffdbb8bff1be6877c..420383cefa0a06c0cbe287ec3fa20e20b227f425 100644 +index 39c210e7b444384fbb55145ac448def3ef540edc..11be3082d6f96a397c5e78d867143a0e6bdc8deb 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -33,6 +33,7 @@ @@ -1507,19 +1507,20 @@ index aee376e971ae01ac1e512c3920b115bfaf06afa8..1701311534bf77e6cd9bafc0e3a28361 * returned quads are further translated relative to the window * origin -- which is not the layout origin. Further translation diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl -index 7c509eb87ec87fc43e3540337dff9d4289f83233..a22a12a6a165927d5fde97a629786249e0caaae2 100644 +index 129bec94e2f69cbe4e9f90769d582d03a1e36639..f61df8c851e76fa7f06128c38e5943b1519b5008 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl -@@ -424,6 +424,7 @@ dictionary SynthesizeMouseEventOptions { - // Set this to true to ensure that the event is dispatched to this DOM window - // or one of its children. - boolean toWindow = false; +@@ -463,6 +463,8 @@ dictionary SynthesizeMouseEventOptions : SynthesizeEventOptions { + boolean ignoreRootScrollFrame = false; + // Controls WidgetMouseEvent.mReason value. + boolean isWidgetEventSynthesized = false; ++ // Playwright + boolean jugglerConvertToPointer = true; }; // Mozilla-specific stuff diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp -index 023ddc5a84ae1788608c17eb34bb7bf9a388d9eb..928a59e3e3ff960e049a2e8fb1d54872172a530e 100644 +index e8270a137ac58342daba109c24a3995ff99a85a1..de48226281fb0286e66049c717c5297cc3c11773 100644 --- a/js/src/debugger/Object.cpp +++ b/js/src/debugger/Object.cpp @@ -2515,7 +2515,11 @@ Maybe<Completion> DebuggerObject::call(JSContext* cx, @@ -1598,10 +1599,10 @@ index 67673c5c306e7237613b0560c7b3f888bd6ad1b8..fe4a278dad4b1747b41b5a824978636a // No boxes to return return; diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index f89e8a1376c87ae1bd2493aa717930c9a1f46986..9d9883bb4aeb0ba1c9fc2d5288f93355ba627a1d 100644 +index d96107f892f09d1b036769cefe30d11989109add..6797255a8e4c7cc8e42ba08c948a71e8f0a9be8c 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp -@@ -11878,7 +11878,9 @@ bool PresShell::ComputeActiveness() const { +@@ -11660,7 +11660,9 @@ bool PresShell::ComputeActiveness() const { if (!browserChild->IsVisible()) { MOZ_LOG(gLog, LogLevel::Debug, (" > BrowserChild %p is not visible", browserChild)); @@ -1613,10 +1614,10 @@ index f89e8a1376c87ae1bd2493aa717930c9a1f46986..9d9883bb4aeb0ba1c9fc2d5288f93355 // If the browser is visible but just due to be preserving layers diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp -index 5853a83d5dd2896e72e8c31169487d43fcd030d1..c2432874b15663d907c47cd334cf69a93fb302f6 100644 +index 8533e0494f1ed552d0a1b9abd09e2852efaf7628..0d8439203e02cbca1230de7eecc204a2b6be955c 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp -@@ -703,6 +703,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( +@@ -702,6 +702,10 @@ bool nsLayoutUtils::AllowZoomingForDocument( !aDocument->GetPresShell()->AsyncPanZoomEnabled()) { return false; } @@ -1627,7 +1628,7 @@ index 5853a83d5dd2896e72e8c31169487d43fcd030d1..c2432874b15663d907c47cd334cf69a9 // True if we allow zooming for all documents on this platform, or if we are // in RDM. BrowsingContext* bc = aDocument->GetBrowsingContext(); -@@ -9713,6 +9717,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, +@@ -9768,6 +9772,9 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, /* static */ bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) { @@ -1638,10 +1639,10 @@ index 5853a83d5dd2896e72e8c31169487d43fcd030d1..c2432874b15663d907c47cd334cf69a9 return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane()); } diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 05ffe79600949dbebf243b4b53e18580f17bb17c..1928bb27ca5ec542106ebde6785cbf31d5389d4a 100644 +index 8f07ee0bae8f93ac90b52a4fe5004f79caae7510..56d1514f17b449e8cb2a81759266ecef8fbe3c1c 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h -@@ -596,6 +596,7 @@ bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); +@@ -611,6 +611,7 @@ bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); bool Gecko_MediaFeatures_PrefersReducedTransparency( const mozilla::dom::Document*); bool Gecko_MediaFeatures_MacRTL(const mozilla::dom::Document*); @@ -1650,10 +1651,10 @@ index 05ffe79600949dbebf243b4b53e18580f17bb17c..1928bb27ca5ec542106ebde6785cbf31 const mozilla::dom::Document*); mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp -index e8c06e790a4e35316010464b9cf87b9e11cd9ecd..e76fa15fd63f0367759b17d74d8032f56f160fb2 100644 +index bcfd66022bf3cd26fc5c7bdba9fb1715240030d2..9c3d5ea64a9ff1cdf8580aeed26ea7eedbfbdcf4 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp -@@ -273,11 +273,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { +@@ -276,11 +276,7 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { } bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { @@ -1666,7 +1667,7 @@ index e8c06e790a4e35316010464b9cf87b9e11cd9ecd..e76fa15fd63f0367759b17d74d8032f5 } bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { -@@ -307,6 +303,20 @@ bool Gecko_MediaFeatures_MacRTL(const Document* aDocument) { +@@ -310,6 +306,20 @@ bool Gecko_MediaFeatures_MacRTL(const Document* aDocument) { // as a signal. StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( const Document* aDocument) { @@ -1687,8 +1688,35 @@ index e8c06e790a4e35316010464b9cf87b9e11cd9ecd..e76fa15fd63f0367759b17d74d8032f5 if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSPrefersContrast)) { return StylePrefersContrast::NoPreference; } +diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml +index 262eee800b3f2bf7b84809cd1f4a7aa2020eafb6..ebed6c29b9be37e6d85d8a30907331fb7af7b037 100644 +--- a/modules/libpref/init/StaticPrefList.yaml ++++ b/modules/libpref/init/StaticPrefList.yaml +@@ -12811,18 +12811,20 @@ + # Use the libwebrtc ScreenCaptureKit desktop capture backend on Mac by default. + # When disabled, or on a host where not supported (< macOS 14), the older + # CoreGraphics backend is used instead. ++# PLAYWRIGHT: disable this preference to avoid this kicking during screencast. + - name: media.getdisplaymedia.screencapturekit.enabled + type: bool +- value: true ++ value: false + mirror: once + + # Use SCContentSharingPicker for source picking when the libwebrtc + # ScreenCaptureKit desktop capture backend is used. When this is true and the + # backend supports SCContentSharingPicker, this takes precendence over the + # enumeration pref below. ++# PLAYWRIGHT: disable this preference to avoid this kicking during screencast. + - name: media.getdisplaymedia.screencapturekit.picker.enabled + type: bool +- value: true ++ value: false + mirror: once + + # Use the libwebrtc ScreenCaptureKit desktop capture backend on Mac for screen diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp -index a963941c152da364181ecfb7261593f59ab244f5..0b09db5fd942cd8bff8abfa777073342a1c69cd4 100644 +index fa7db176b1dfe023c9aaccdb2324696f9d226542..6ac5774da83a1249f42e2b2e1b5d4ef71ecd23fa 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -750,7 +750,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) @@ -1701,7 +1729,7 @@ index a963941c152da364181ecfb7261593f59ab244f5..0b09db5fd942cd8bff8abfa777073342 } LoadInfo::LoadInfo( -@@ -2096,4 +2097,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { +@@ -2104,4 +2105,16 @@ void LoadInfo::UpdateParentAddressSpaceInfo() { } } @@ -1719,10 +1747,10 @@ index a963941c152da364181ecfb7261593f59ab244f5..0b09db5fd942cd8bff8abfa777073342 + } // namespace mozilla::net diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h -index 2b4593ad7b88a71b29ed5a5ec7343c95cc960f2d..deb87ecc3e585764939cbc90dd47f037ca14eceb 100644 +index 6d8ce05b11257cdbc90e327ffc1638ba9c60a4a9..ee10457b694e810edb35e4162c83f7a37aa9ba58 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h -@@ -541,6 +541,8 @@ class LoadInfo final : public nsILoadInfo { +@@ -550,6 +550,8 @@ class LoadInfo final : public nsILoadInfo { dom::UserNavigationInvolvement::None; bool mSkipHTTPSUpgrade = false; @@ -1784,22 +1812,22 @@ index 7f91d2df6f8bb4020c75c132dc8f6bf26625fa1e..aaa5541a17039d6b13ad83ab176fdaaf * Set the status and reason for the forthcoming synthesized response. * Multiple calls overwrite existing values. diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp -index 634865583e6fefdae7a23e3ff63c3ea68a6ee609..91585bddb7de091b3324ebe2cc10e2f8e183d012 100644 +index 81eeeb14ffe5eb40f57a18cd3d4bd714ad59454c..6d1f4acb69f1028300be5925a0d85649f616f4e8 100644 --- a/netwerk/ipc/DocumentLoadListener.cpp +++ b/netwerk/ipc/DocumentLoadListener.cpp -@@ -190,6 +190,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, - loadInfo->SetTextDirectiveUserActivation( - aLoadState->GetTextDirectiveUserActivation()); +@@ -198,6 +198,7 @@ static auto CreateDocumentLoadInfo(CanonicalBrowsingContext* aBrowsingContext, + aLoadState->GetTextDirectiveUserActivation() || + aLoadState->HasLoadFlags(nsIWebNavigation::LOAD_FLAGS_FROM_EXTERNAL)); loadInfo->SetIsMetaRefresh(aLoadState->IsMetaRefresh()); + loadInfo->SetJugglerLoadIdentifier(aLoadState->GetLoadIdentifier()); return loadInfo.forget(); } diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index 9442c40a3d3e9f0f46978e96f08e492bf3d6b766..3ced65b2737587512cda08a90181e0412e1825d6 100644 +index d79401c3cbd38a297dc2d25e713422eaa8784018..2f5e2229ad881b0621b654b33ecd1d4bb4555893 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.cpp +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -724,10 +724,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) +@@ -722,10 +722,33 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) } // anonymous namespace @@ -1833,7 +1861,7 @@ index 9442c40a3d3e9f0f46978e96f08e492bf3d6b766..3ced65b2737587512cda08a90181e041 if (mCanceled) { return mStatus; } -@@ -1142,11 +1165,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { +@@ -1139,11 +1162,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { GetCallback(mProgressSink); } @@ -1853,10 +1881,10 @@ index 9442c40a3d3e9f0f46978e96f08e492bf3d6b766..3ced65b2737587512cda08a90181e041 if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this)); diff --git a/netwerk/protocol/http/InterceptedHttpChannel.h b/netwerk/protocol/http/InterceptedHttpChannel.h -index 7a2a4f2910d74ded7f585c4d0a4c347bb9e03642..a416e1357aebbaab9d9a40ef6f0c2a0306913e2e 100644 +index eb287a6fc9f782c1e0232c298a3759d3e639d29a..fdd5acedb69d6ba3df2aa337c6817b3c5f2f8344 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.h +++ b/netwerk/protocol/http/InterceptedHttpChannel.h -@@ -90,6 +90,11 @@ class InterceptedHttpChannel final +@@ -91,6 +91,11 @@ class InterceptedHttpChannel final Atomic<bool> mCallingStatusAndProgress; bool mInterceptionReset{false}; @@ -1869,10 +1897,10 @@ index 7a2a4f2910d74ded7f585c4d0a4c347bb9e03642..a416e1357aebbaab9d9a40ef6f0c2a03 * InterceptionTimeStamps is used to record the time stamps of the * interception. diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp -index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b781c4ce269 100644 +index 92fcaae7a12d9915abd865b079b5b4edcdef5a21..baa5b40d8ae796c245b4d673f42a9d65f5f6d7dd 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp -@@ -944,11 +944,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { +@@ -947,11 +947,9 @@ nsresult nsHttpChannel::OnBeforeConnect() { // SecurityInfo.sys.mjs mLoadInfo->SetHstsStatus(isSecureURI); @@ -1885,7 +1913,7 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { return NS_ERROR_OFFLINE; } -@@ -1061,9 +1059,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, +@@ -1064,9 +1062,7 @@ nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade, return aStatus; } @@ -1896,7 +1924,7 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC() || forceOffline) { -@@ -1540,15 +1536,14 @@ nsresult nsHttpChannel::ContinueConnect() { +@@ -1543,15 +1539,14 @@ nsresult nsHttpChannel::ContinueConnect() { "CORS preflight must have been finished by the time we " "do the rest of ContinueConnect"); @@ -1914,7 +1942,7 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())) { return NS_ERROR_OFFLINE; } -@@ -1590,7 +1585,7 @@ nsresult nsHttpChannel::ContinueConnect() { +@@ -1593,7 +1588,7 @@ nsresult nsHttpChannel::ContinueConnect() { } // We're about to hit the network. Don't if we're forced offline. @@ -1923,7 +1951,7 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 return NS_ERROR_OFFLINE; } -@@ -1698,12 +1693,9 @@ void nsHttpChannel::SpeculativeConnect() { +@@ -1701,12 +1696,9 @@ void nsHttpChannel::SpeculativeConnect() { // don't speculate if we are offline, when doing http upgrade (i.e. // websockets bootstrap), or if we can't do keep-alive (because then we // couldn't reuse the speculative connection anyhow). @@ -1937,7 +1965,7 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 return; } -@@ -4785,9 +4777,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { +@@ -4947,9 +4939,6 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { uint32_t cacheEntryOpenFlags; bool offline = gIOService->IsOffline(); @@ -1947,7 +1975,7 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 bool maybeRCWN = false; nsAutoCString cacheControlRequestHeader; -@@ -4798,7 +4787,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { +@@ -4960,7 +4949,7 @@ nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) { return NS_OK; } @@ -1956,7 +1984,7 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 if (offline || (mLoadFlags & INHIBIT_CACHING) || forceOffline) { if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass()) && !offline && !forceOffline) { -@@ -8097,6 +8086,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { +@@ -8274,6 +8263,20 @@ void nsHttpChannel::MaybeStartDNSPrefetch() { } } @@ -1978,10 +2006,10 @@ index f8197fdfdeb835757c7cd30554c0df75c1d622de..59f81b246fa3ace1879b8a8eec7a0b78 nsHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) { if (mCacheEntry && !LoadCacheEntryIsWriteOnly()) { diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h -index 53d4b75298d13751b5a588601b705a0528a50e65..051d7ae8ae2dd9a5f374d0bd3d85a96330cc891e 100644 +index ec9960bbacab75e07f6f67dac6bee9a725d756c6..02e92938551cfe4a19717be81ee57cffcc535e1e 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h -@@ -312,6 +312,10 @@ class nsHttpChannel final : public HttpBaseChannel, +@@ -314,6 +314,10 @@ class nsHttpChannel final : public HttpBaseChannel, void MaybeResolveProxyAndBeginConnect(); void MaybeStartDNSPrefetch(); @@ -1993,10 +2021,10 @@ index 53d4b75298d13751b5a588601b705a0528a50e65..051d7ae8ae2dd9a5f374d0bd3d85a963 // end server host name. ProxyDNSStrategy GetProxyDNSStrategy(); diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index 72523ca8c1cfe099561efc0af5fb1574048a4615..465aac80a7a486e0e2bf5ee33b97a2bf83ebb85a 100644 +index aa6b6c81f0eeba728a6c9c76f038d5f46ba1c5f3..7e97f7f023ec46e184a598b78020a437a7645cc0 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1367,6 +1367,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( +@@ -1377,6 +1377,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -2021,19 +2049,19 @@ index 9d262dbf33be49f64dbfc7ff4c87db05344ecdc5..495afbbe2b830218cf6e8332cc871ab7 nsCOMPtr<nsIMarionette> marionette = do_GetService(NS_MARIONETTE_CONTRACTID); if (marionette) { diff --git a/services/settings/Utils.sys.mjs b/services/settings/Utils.sys.mjs -index b6b61710c0c5f1e19ebc492fe52a1c8e36c647f3..6fcfa8ced1fe0b1789afd5bf4cf1895675273858 100644 +index da12049e14b38adcbf074f87ecc5a5745cd9a2eb..24621137e2c8c8fac881ce4320266441b253ab3d 100644 --- a/services/settings/Utils.sys.mjs +++ b/services/settings/Utils.sys.mjs -@@ -97,7 +97,7 @@ const _cdnURLs = {}; +@@ -99,7 +99,7 @@ const _cdnURLs = {}; export var Utils = { get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -@@ -110,6 +110,9 @@ export var Utils = { +- return lazy.allowServerURL ++ return true || lazy.allowServerURL + ? // eslint-disable-next-line mozilla/valid-lazy + lazy.gServerURL + : AppConstants.REMOTE_SETTINGS_SERVER_URLS[0]; +@@ -113,6 +113,9 @@ export var Utils = { log, get shouldSkipRemoteActivityDueToTests() { @@ -2044,21 +2072,21 @@ index b6b61710c0c5f1e19ebc492fe52a1c8e36c647f3..6fcfa8ced1fe0b1789afd5bf4cf18956 (lazy.isRunningTests || Cu.isInAutomation) && this.SERVER_URL == "data:,#remote-settings-dummy/v1" diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 75555352b8a15a50e4a21e34fc8ede4e9246c7cc..72855a404effa42b6c55cd0c2fcb8bdd6c2b3f9f 100644 +index e2b69d51df97f5bb22eba0a4b9ead3f47256dfb6..2168b1381616ef747875e1137d748c8fcd2b8ec3 100644 --- a/toolkit/components/browser/nsIWebBrowserChrome.idl +++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -74,6 +74,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 1 << 21; +@@ -88,6 +88,9 @@ interface nsIWebBrowserChrome : nsISupports + // Whether this is a Document Picture-in-Picture window + const unsigned long CHROME_DOCUMENT_PIP = 1 << 22; + // Whether this window has "width" or "height" defined in features -+ const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 0x00400000; ++ const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 1 << 23; + // Prevents new window animations on MacOS and Windows. Currently // ignored for Linux. const unsigned long CHROME_SUPPRESS_ANIMATION = 1 << 24; diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs -index bb451a279599da49412da3c287e57d4b06a9c4dc..cf5ae514662d951102876efc00f58c3eb3387a3d 100644 +index fff3c6b3e433678e01ce87a2a5253ce77f9cc2e1..4643e246bb4c506d98778dc3ea0b8b10f2c813b8 100644 --- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs +++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs @@ -106,7 +106,9 @@ EnterprisePoliciesManager.prototype = { @@ -2093,7 +2121,7 @@ index bb451a279599da49412da3c287e57d4b06a9c4dc..cf5ae514662d951102876efc00f58c3e constructor() { this._policies = null; diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index 5175a8a3ef0b99d8bde75f397579e5ef6db53f6b..4c6b3137f788b90e2d68b1f0dfb6834c63127c17 100644 +index c5eddf7f3f91ec617fd65840a1a2482cf0ed32c1..43e2d7c71b0b95946d1a69d94b674f56224d0730 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -360,7 +360,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { @@ -2121,10 +2149,10 @@ index 36fe2d427ee8e6c52e32930367cbddfa22e0444b..593795dfb21d215895521a1cfb998339 int32_t aMaxSelfProgress, int32_t aCurTotalProgress, diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -index 942cb7c4003098527623a1cdf09e560cc64dba1b..864cf804b6d8a1a079c41c787995bac117ed8a72 100644 +index af0e6b01844fc52b1ee771eb80f414024545493a..f563ee4a69f33f463be59a7eeb55230c790bcfad 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1880,7 +1880,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( +@@ -1918,7 +1918,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( // Open a minimal popup. *aIsPopupRequested = true; @@ -2138,10 +2166,10 @@ index 942cb7c4003098527623a1cdf09e560cc64dba1b..864cf804b6d8a1a079c41c787995bac1 /** diff --git a/toolkit/mozapps/update/UpdateService.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs -index c5b1a1f52daf9e4b6eac755e4f71beb8e2556925..1d58a9cd3d34fae4945396d03d0e9acd64242049 100644 +index 2a02e586524384ea45d31f084f9a10ef47cc60b6..d8ae08c71a068bb93254d9e5fa8793c2b9237d46 100644 --- a/toolkit/mozapps/update/UpdateService.sys.mjs +++ b/toolkit/mozapps/update/UpdateService.sys.mjs -@@ -4021,6 +4021,8 @@ export class UpdateService { +@@ -4026,6 +4026,8 @@ export class UpdateService { } get disabledForTesting() { @@ -2198,10 +2226,10 @@ index b7c376eadc1460b0f4e378ca3047eb82a079c19c..44385776349e13f7452d7c1b382cf738 // 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 ef95040ffc1b598f4e91570c64908fd461b928c3..f62a103de62031f05a4f568acf1f0c4d0a4424b0 100644 +index 25b07226295c1aa3a35468fd6a86d92ac1d10d12..911380185f6377e8c9435c1baa0ac037e33519ad 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp -@@ -897,6 +897,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, +@@ -885,6 +885,12 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, mIsLoadingJavascriptURI ? "javascript URI" : "document.open")); @@ -2215,10 +2243,10 @@ index ef95040ffc1b598f4e91570c64908fd461b928c3..f62a103de62031f05a4f568acf1f0c4d // 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 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc20a644f01 100644 +index 45919614755ee5ebbdd27df065808f699168c4bc..cfce3eac34664e2eaf778db1a169ef84d37d7109 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -111,6 +111,7 @@ +@@ -112,6 +112,7 @@ #include "mozilla/Components.h" #include "mozilla/ClearOnShutdown.h" @@ -2226,7 +2254,7 @@ index 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc2 #include "mozilla/Preferences.h" #include "mozilla/ipc/URIUtils.h" -@@ -866,6 +867,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( +@@ -867,6 +868,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( return NS_OK; } @@ -2239,7 +2267,7 @@ index 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc2 nsresult nsExternalHelperAppService::GetFileTokenForPath( const char16_t* aPlatformAppPath, nsIFile** aFile) { nsDependentString platformAppPath(aPlatformAppPath); -@@ -1497,7 +1504,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { +@@ -1498,7 +1505,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { // Strip off the ".part" from mTempLeafName mTempLeafName.Truncate(mTempLeafName.Length() - std::size(".part") + 1); @@ -2252,7 +2280,7 @@ index 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc2 mSaver = do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); -@@ -1681,7 +1693,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1682,7 +1694,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { return NS_OK; } @@ -2290,7 +2318,7 @@ index 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc2 if (NS_FAILED(rv)) { nsresult transferError = rv; -@@ -1742,6 +1783,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1743,6 +1784,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { bool alwaysAsk = true; mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); @@ -2300,7 +2328,7 @@ index 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc2 if (alwaysAsk) { // But we *don't* ask if this mimeInfo didn't come from // our user configuration datastore and the user has said -@@ -2258,6 +2302,15 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, +@@ -2259,6 +2303,15 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, NotifyTransfer(aStatus); } @@ -2316,7 +2344,7 @@ index 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc2 return NS_OK; } -@@ -2741,6 +2794,14 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { +@@ -2742,6 +2795,14 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { } } @@ -2332,7 +2360,7 @@ index 04c46fda68b158ba7ea61b1764f22bab8d8e2565..a0292f3a3c1771abdeb319d91406ecc2 // OnStartRequest) mDialog = nullptr; diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h -index f2e7d379f3e22ada8693d88070e2d2645ed06be4..a5932f2986b29d7b448847b175015c1901ecd95a 100644 +index 968d7ab01fabcb03cbf2dd1d1ea085556a4c617f..b58b60ae6c2269b85c07a0d7ef9e8c698334e340 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -270,6 +270,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, @@ -2638,7 +2666,7 @@ index facd2bc65afab8ec1aa322faa20a67464964dfb9..3c5751ad1b7f042bc7cd9a63895cebcd } // namespace widget diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index eb2b51e3396b0eb40f985e077db745f0e225e126..38f744ce584b1a891dc838fd2a72b0e17f54acc9 100644 +index d47d8992b767403459a75334ff027d609567a2f7..0e76476a68b6e5ab166c084861e82ee343e5b86f 100644 --- a/widget/headless/HeadlessWidget.cpp +++ b/widget/headless/HeadlessWidget.cpp @@ -113,6 +113,8 @@ void HeadlessWidget::Destroy() { diff --git a/browser_patches/webkit/UPSTREAM_CONFIG.sh b/browser_patches/webkit/UPSTREAM_CONFIG.sh index e48e0850f7d3e..71d26bd405a6e 100644 --- a/browser_patches/webkit/UPSTREAM_CONFIG.sh +++ b/browser_patches/webkit/UPSTREAM_CONFIG.sh @@ -1,3 +1,3 @@ REMOTE_URL="https://github.com/WebKit/WebKit.git" BASE_BRANCH="main" -BASE_REVISION="6b34ac51510516bd6a3ec2f5edc97413758d3ab1" +BASE_REVISION="d8fa5ad85d476be6d60c96ace769a2c9293bc2a8" diff --git a/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m b/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m index 05f37a98d0584..9c468dc95e5bf 100644 --- a/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m +++ b/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m @@ -211,8 +211,6 @@ - (void)awakeFromNib | _WKRenderingProgressEventFirstLayoutAfterSuppressedIncrementalRendering | _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering; - _webView.customUserAgent = @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15"; - _webView._usePlatformFindUI = NO; _textFinder = [[PlaywrightNSTextFinder alloc] init]; @@ -576,6 +574,10 @@ - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfigurat { // WebView lifecycle will control the BrowserWindowController life times. BrowserWindowController *controller = [[BrowserWindowController alloc] initWithConfiguration:configuration]; + if (!controller) + return nil; + NSWindow *window = controller.window; + [window setIsVisible:YES]; return controller->_webView; } diff --git a/browser_patches/webkit/patches/bootstrap.diff b/browser_patches/webkit/patches/bootstrap.diff index 2347ee8733aa5..66a1066e5be2a 100644 --- a/browser_patches/webkit/patches/bootstrap.diff +++ b/browser_patches/webkit/patches/bootstrap.diff @@ -1,8 +1,8 @@ diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt -index 346c8703fb8fa72385056f027b99818d0051e387..ac90d424170ef7659a0058431fb16c706b42dc65 100644 +index c257f6a5a523ce12f67857e0d344aadffea6601a..f8c46e22eb4fa79c6b9f56846828391c3bf4de21 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt -@@ -1593,21 +1593,26 @@ set(JavaScriptCore_INSPECTOR_DOMAINS +@@ -1615,21 +1615,26 @@ set(JavaScriptCore_INSPECTOR_DOMAINS ${JAVASCRIPTCORE_DIR}/inspector/protocol/CSS.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Canvas.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Console.json @@ -30,10 +30,10 @@ index 346c8703fb8fa72385056f027b99818d0051e387..ac90d424170ef7659a0058431fb16c70 ${JAVASCRIPTCORE_DIR}/inspector/protocol/ServiceWorker.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Target.json diff --git a/Source/JavaScriptCore/DerivedSources-input.xcfilelist b/Source/JavaScriptCore/DerivedSources-input.xcfilelist -index 76fad0e5facc2040128eb1971f69d230418f34c7..7cf1d220f6ff2bdc15076522baced8d31f4f6371 100644 +index 55eacb0d378fddea15ece56db612655ac5d64061..cb6cfa7c542e82671f68984ff9373e1bf58da2b8 100644 --- a/Source/JavaScriptCore/DerivedSources-input.xcfilelist +++ b/Source/JavaScriptCore/DerivedSources-input.xcfilelist -@@ -102,20 +102,25 @@ $(PROJECT_DIR)/inspector/protocol/CPUProfiler.json +@@ -101,20 +101,25 @@ $(PROJECT_DIR)/inspector/protocol/CPUProfiler.json $(PROJECT_DIR)/inspector/protocol/CSS.json $(PROJECT_DIR)/inspector/protocol/Canvas.json $(PROJECT_DIR)/inspector/protocol/Console.json @@ -60,10 +60,10 @@ index 76fad0e5facc2040128eb1971f69d230418f34c7..7cf1d220f6ff2bdc15076522baced8d3 $(PROJECT_DIR)/inspector/protocol/Security.json $(PROJECT_DIR)/inspector/protocol/ServiceWorker.json diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make -index 40706dcca1ed7c555d36f7e651dbc4af29c21c3d..cdd9d4e746548d1b56fc918c1fff78d0c20feea9 100644 +index 7eb4f1c1e0cd3abdf61203d33cd2f53d77d4264d..01adf210b42055612dc02aba0ed52e6f6ed1d10f 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make -@@ -300,21 +300,26 @@ INSPECTOR_DOMAINS := \ +@@ -298,21 +298,26 @@ INSPECTOR_DOMAINS := \ $(JavaScriptCore)/inspector/protocol/CSS.json \ $(JavaScriptCore)/inspector/protocol/Canvas.json \ $(JavaScriptCore)/inspector/protocol/Console.json \ @@ -130,7 +130,7 @@ index e145f18eff043f6d718f38d14159415327a0b43b..747c06864110ef4488d8e4b0f6fd74a1 JS_EXPORT_PRIVATE static String requestId(unsigned long identifier); }; diff --git a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp -index f71488e1292102e0a6e5bfc0cb9a3ddaf572dc80..3e8381c00ac82d186484da22f1e2c3b2c8b28835 100644 +index 4d9152423abf35dfbdf338435b567a822b2f6904..4e6b551494e1d124655c8cc54f121ac4843c3298 100644 --- a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp +++ b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp @@ -85,7 +85,10 @@ static RefPtr<JSON::Value> jsToInspectorValue(JSC::JSGlobalObject* globalObject, @@ -169,7 +169,7 @@ index 449ff9c805107a41f783eaf72b9901d0df6a3e72..a56a086892caa03e171616bd90db8cbf // We could be called re-entrantly from a nested run loop, so restore the previous id. SetForScope scopedRequestId(m_currentRequestId, requestId); diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h -index b7bb400886ba7911bcedbefefe4933d42ffc2f5b..eb628f59aed910a7cb0ec35cea5a5c1b8e89b4be 100644 +index ed0cb419967759a258d3d250fd42d2b86ca32561..0788de297278f875d18dd9da22df53a72f34d52b 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h @@ -97,8 +97,11 @@ public: @@ -220,7 +220,7 @@ index b68a7eb5e8d26ea7631b451f629734c886896684..92dba414b7e9c3587ae40c4cb7bb6e4f } diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h -index 36ab8686085b18e43602f857c23a969335fb2bf3..df94e7f5edb3a17e51aa3151c79b33edbbe3f4ed 100644 +index 421d62c0071a43b7fb111a4e2b120e28c5ba96af..de764f8519c3df6a9325d3eb87e7fe907c5b5b6a 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.h +++ b/Source/JavaScriptCore/inspector/InspectorTarget.h @@ -61,8 +61,12 @@ public: @@ -256,7 +256,7 @@ index ddd58da62382291979c72d62700c61c137f5b965..ab114ba249ec6901c78da7703b5e8140 { auto message = makeString(method, " is currently ignored in JavaScript context inspection."_s); diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h -index 56ca0ba36ff4f65bc1328cc707d48118782af5d5..fed316cf8302b415d821e807fac7b0712d51c0f6 100644 +index ed7dbb3ee1de5183f1c1868310b332f52d2e8cd6..90dd8331ba5cf87a32407a01cfe9d218b4822f1c 100644 --- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h +++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h @@ -68,6 +68,7 @@ private: @@ -268,21 +268,10 @@ index 56ca0ba36ff4f65bc1328cc707d48118782af5d5..fed316cf8302b415d821e807fac7b071 void warnUnimplemented(const String& method); void internalAddMessage(MessageType, MessageLevel, JSC::JSGlobalObject*, Ref<ScriptArguments>&&); diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp -index a48b3dcd1ce11c1164860ebfa36951ce58a43091..e6b7ccdb960d64f339adf2d4f0045a0d9eb1cd6a 100644 +index bd5258cf60b70750c52277007f657fbfaeaeec68..8ad812f65d8f2f6112d2456789a82520e215633b 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp -@@ -194,9 +194,8 @@ void InspectorRuntimeAgent::callFunctionOn(const Protocol::Runtime::RemoteObject - void InspectorRuntimeAgent::callFunctionOn(InjectedScript& injectedScript, const Protocol::Runtime::RemoteObjectId& objectId, const String& functionDeclaration, RefPtr<JSON::Array>&& arguments, std::optional<bool>&& doNotPauseOnExceptionsAndMuteConsole, std::optional<bool>&& returnByValue, std::optional<bool>&& generatePreview, std::optional<bool>&& /* emulateUserGesture */, std::optional<bool>&& awaitPromise, Ref<CallFunctionOnCallback>&& callback) - { - ASSERT(!injectedScript.hasNoValue()); -- - JSC::Debugger::TemporarilyDisableExceptionBreakpoints temporarilyDisableExceptionBreakpoints(m_debugger); -- -+ - bool pauseAndMute = doNotPauseOnExceptionsAndMuteConsole.value_or(false); - if (pauseAndMute) { - temporarilyDisableExceptionBreakpoints.replace(); -@@ -215,6 +214,11 @@ void InspectorRuntimeAgent::callFunctionOn(InjectedScript& injectedScript, const +@@ -219,6 +219,11 @@ void InspectorRuntimeAgent::callFunctionOn(InjectedScript& injectedScript, const unmuteConsole(); } @@ -295,7 +284,7 @@ index a48b3dcd1ce11c1164860ebfa36951ce58a43091..e6b7ccdb960d64f339adf2d4f0045a0d { Protocol::ErrorString errorString; diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h -index 241790f97d1f59dfcbfa89b32a42145d11afe358..19adfb3bee0602e112af6734b6bc732d3d6ab8c4 100644 +index f7ed41f0b3aaa9bb0eb388c4edbef2645e9b1dd4..511ff1799f7480c85fb46beda36fb52f3d489099 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h @@ -65,6 +65,7 @@ public: @@ -307,7 +296,7 @@ index 241790f97d1f59dfcbfa89b32a42145d11afe358..19adfb3bee0602e112af6734b6bc732d Protocol::ErrorStringOr<Ref<Protocol::Runtime::ObjectPreview>> getPreview(const Protocol::Runtime::RemoteObjectId&) final; Protocol::ErrorStringOr<std::tuple<Ref<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>, RefPtr<JSON::ArrayOf<Protocol::Runtime::InternalPropertyDescriptor>>>> getProperties(const Protocol::Runtime::RemoteObjectId&, std::optional<bool>&& ownProperties, std::optional<int>&& fetchStart, std::optional<int>&& fetchCount, std::optional<bool>&& generatePreview) final; diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp -index ff3a990394674c30274a320863d8bcd63aa3ffa6..9213eed13d8503120350157f8c6604a6467a7ffc 100644 +index 38d8aa7a256deab40470631c8f2231d9d34613e1..6c7f776c0b7f2ab7a1a3870ebaa42a3da5ad794c 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp @@ -90,6 +90,34 @@ Protocol::ErrorStringOr<void> InspectorTargetAgent::sendMessageToTarget(const St @@ -344,8 +333,8 @@ index ff3a990394674c30274a320863d8bcd63aa3ffa6..9213eed13d8503120350157f8c6604a6 + void InspectorTargetAgent::sendMessageFromTargetToFrontend(const String& targetId, const String& message) { - ASSERT_WITH_MESSAGE(m_targets.get(targetId), "Sending a message from an untracked target to the frontend."); -@@ -149,7 +177,17 @@ void InspectorTargetAgent::targetDestroyed(InspectorTarget& target) + m_frontendDispatcher->dispatchMessageFromTarget(targetId, message); +@@ -147,7 +175,17 @@ void InspectorTargetAgent::targetDestroyed(InspectorTarget& target) if (!m_isConnected) return; @@ -848,10 +837,10 @@ index 0000000000000000000000000000000000000000..1c43b476603325fa412bcfded9163e7a + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Network.json b/Source/JavaScriptCore/inspector/protocol/Network.json -index ddf769378ef2e15ca2fd90384e5ac01a2a5136b2..314f92e5377816f5115a85aac7255b713c1ffa8c 100644 +index 29a3ef3294dcdf9e9559b665e9f1bb9a5727cf4b..b6b90f356dd6b7de7752ab4296069c8f07b4de38 100644 --- a/Source/JavaScriptCore/inspector/protocol/Network.json +++ b/Source/JavaScriptCore/inspector/protocol/Network.json -@@ -352,6 +352,13 @@ +@@ -360,6 +360,13 @@ "parameters": [ { "name": "bytesPerSecondLimit", "type": "integer", "optional": true, "description": "Limits the bytes per second of requests if positive. Removes any limits if zero or not provided." } ] @@ -1458,7 +1447,7 @@ index 0000000000000000000000000000000000000000..ade3e257b614f210ba5dcc024df81642 + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json -index 293f11b5a1a82c5e0f67cbdcb5d8b36789c2b148..213000a8dfe9c6a8a7f85e294e15e8ae6f137903 100644 +index b8c2c5b7c4a4411affc4d928521f809bc468673c..b0134b3d794df05a6386ed012715bb47519248f2 100644 --- a/Source/JavaScriptCore/inspector/protocol/Runtime.json +++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json @@ -272,6 +272,13 @@ @@ -1603,7 +1592,7 @@ index 6af957ee69490bad4443e90161adc2230c329105..1270e77b913578ba8965fdd30c4bd446 private: enum class ArgumentRequirement { No, Yes }; diff --git a/Source/ThirdParty/skia/CMakeLists.txt b/Source/ThirdParty/skia/CMakeLists.txt -index de02afc8c3d658aa558de21e0e07da90f128638b..76659fec1e8cc1e0ea769de7ca492c6dd4d111a4 100644 +index 607a4b0f761b0aadd3ca8b83e080519ad6f97715..609f5b23e6ebd2629a1313673d9d8ea5d6fc57b7 100644 --- a/Source/ThirdParty/skia/CMakeLists.txt +++ b/Source/ThirdParty/skia/CMakeLists.txt @@ -10,6 +10,8 @@ if (USE_SKIA_ENCODERS) @@ -1615,7 +1604,7 @@ index de02afc8c3d658aa558de21e0e07da90f128638b..76659fec1e8cc1e0ea769de7ca492c6d if (ANDROID) find_package(EXPAT REQUIRED) endif () -@@ -965,6 +967,7 @@ endif () +@@ -970,6 +972,7 @@ endif () target_link_libraries(Skia PRIVATE JPEG::JPEG PNG::PNG @@ -1624,10 +1613,10 @@ index de02afc8c3d658aa558de21e0e07da90f128638b..76659fec1e8cc1e0ea769de7ca492c6d WEBKIT_ADD_TARGET_CXX_FLAGS(Skia diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml -index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837702c2d8d 100644 +index 991cbe56d742a6cdd31d5a142754675272d4abd8..ce7e004a533d87765976b46e1d538799d2226af5 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml -@@ -599,6 +599,7 @@ ApplePayEnabled: +@@ -605,6 +605,7 @@ ApplePayEnabled: richJavaScript: true # FIXME: This is on by default in WebKit2 PLATFORM(COCOA). Perhaps we should consider turning it on for WebKitLegacy as well. @@ -1635,7 +1624,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 AsyncClipboardAPIEnabled: type: bool status: mature -@@ -609,7 +610,7 @@ AsyncClipboardAPIEnabled: +@@ -615,7 +616,7 @@ AsyncClipboardAPIEnabled: default: false WebKit: "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)" : true @@ -1644,7 +1633,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 WebCore: default: false -@@ -865,13 +866,10 @@ BlobFileAccessEnforcementEnabled: +@@ -871,13 +872,10 @@ BlobFileAccessEnforcementEnabled: sharedPreferenceForWebProcess: true defaultValue: WebKitLegacy: @@ -1657,8 +1646,8 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 - "PLATFORM(COCOA)": true default: false - BlockFontServiceInWebContentSandbox: -@@ -2077,6 +2075,7 @@ CrossOriginEmbedderPolicyEnabled: + BlockIOKitInWebContentSandbox: +@@ -2073,6 +2071,7 @@ CrossOriginEmbedderPolicyEnabled: WebCore: default: false @@ -1666,7 +1655,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 CrossOriginOpenerPolicyEnabled: type: bool status: stable -@@ -2150,6 +2149,7 @@ DOMAudioSessionFullEnabled: +@@ -2146,6 +2145,7 @@ DOMAudioSessionFullEnabled: WebCore: default: false @@ -1674,7 +1663,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 DOMPasteAccessRequestsEnabled: type: bool status: internal -@@ -2161,7 +2161,7 @@ DOMPasteAccessRequestsEnabled: +@@ -2157,7 +2157,7 @@ DOMPasteAccessRequestsEnabled: default: false WebKit: "PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(VISION)": true @@ -1683,7 +1672,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 WebCore: default: false -@@ -2227,10 +2227,10 @@ DataListElementEnabled: +@@ -2223,10 +2223,10 @@ DataListElementEnabled: WebKitLegacy: default: false WebKit: @@ -1696,7 +1685,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false sharedPreferenceForWebProcess: true -@@ -2243,7 +2243,7 @@ DataTransferItemsEnabled: +@@ -2239,7 +2239,7 @@ DataTransferItemsEnabled: WebKitLegacy: default: true WebKit: @@ -1705,7 +1694,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false WebCore: default: false -@@ -2486,7 +2486,7 @@ DirectoryUploadEnabled: +@@ -2482,7 +2482,7 @@ DirectoryUploadEnabled: WebKitLegacy: default: false WebKit: @@ -1714,7 +1703,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false WebCore: default: false -@@ -3184,10 +3184,10 @@ FullScreenEnabled: +@@ -3188,10 +3188,10 @@ FullScreenEnabled: WebKitLegacy: default: false WebKit: @@ -1727,7 +1716,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false sharedPreferenceForWebProcess: true -@@ -3484,7 +3484,7 @@ HardwareAccelerationEnabled: +@@ -3503,7 +3503,7 @@ HardwareAccelerationEnabled: status: internal humanReadableName: "Hardware acceleration" humanReadableDescription: "Enable hardware acceleration" @@ -1736,7 +1725,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 defaultValue: WebKitLegacy: default: true -@@ -3862,7 +3862,7 @@ InputTypeColorEnabled: +@@ -3910,7 +3910,7 @@ InputTypeColorEnabled: WebKitLegacy: default: false WebKit: @@ -1745,7 +1734,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false WebCore: default: false -@@ -3895,7 +3895,7 @@ InputTypeDateEnabled: +@@ -3943,7 +3943,7 @@ InputTypeDateEnabled: "PLATFORM(IOS_FAMILY)": true default: false WebKit: @@ -1754,7 +1743,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false WebCore: default: false -@@ -3911,7 +3911,7 @@ InputTypeDateTimeLocalEnabled: +@@ -3959,7 +3959,7 @@ InputTypeDateTimeLocalEnabled: "PLATFORM(IOS_FAMILY)": true default: false WebKit: @@ -1763,7 +1752,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false WebCore: default: false -@@ -3943,7 +3943,7 @@ InputTypeTimeEnabled: +@@ -3991,7 +3991,7 @@ InputTypeTimeEnabled: "PLATFORM(IOS_FAMILY)": true default: false WebKit: @@ -1772,7 +1761,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false WebCore: default: false -@@ -4004,6 +4004,7 @@ InspectorMaximumResourcesContentSize: +@@ -4052,6 +4052,7 @@ InspectorMaximumResourcesContentSize: "PLATFORM(WPE)": 50 default: 200 @@ -1780,7 +1769,7 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 InspectorStartsAttached: type: bool status: embedder -@@ -4011,7 +4012,7 @@ InspectorStartsAttached: +@@ -4059,7 +4060,7 @@ InspectorStartsAttached: exposed: [ WebKit ] defaultValue: WebKit: @@ -1789,16 +1778,16 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 InspectorSupportsShowingCertificate: type: bool -@@ -6212,7 +6213,7 @@ PointerLockEnabled: +@@ -6266,7 +6267,7 @@ PointerLockEnabled: "PLATFORM(IOS_FAMILY)": false default: true WebCore: - default: false + default: true - PointerLockOptionsEnabled: + PopoverAttributeEnabled: type: bool -@@ -6856,7 +6857,7 @@ ScreenOrientationAPIEnabled: +@@ -6896,7 +6897,7 @@ ScreenOrientationAPIEnabled: WebKitLegacy: default: false WebKit: @@ -1808,10 +1797,10 @@ index 317f374d175d692544bc37b3c42c13c2fbea30c2..3392e32a9a506f099854329600a67837 default: false sharedPreferenceForWebProcess: true diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h -index 2ee5a8359e668737ca4552a41bfe7458668a20af..a656b2c9048e069c91b5eaf0ed8c33eed480f1f5 100644 +index 7219e25002712fb773a8dd1c7c601e60b63c5d14..3d3054fbce6dda47761e0a1c1533a51764bf79ba 100644 --- a/Source/WTF/wtf/PlatformEnable.h +++ b/Source/WTF/wtf/PlatformEnable.h -@@ -465,7 +465,7 @@ +@@ -455,7 +455,7 @@ // ORIENTATION_EVENTS should never get enabled on Desktop, only Mobile. #if !defined(ENABLE_ORIENTATION_EVENTS) @@ -1820,7 +1809,7 @@ index 2ee5a8359e668737ca4552a41bfe7458668a20af..a656b2c9048e069c91b5eaf0ed8c33ee #endif #if OS(WINDOWS) -@@ -578,7 +578,7 @@ +@@ -568,7 +568,7 @@ #endif #if !defined(ENABLE_TOUCH_EVENTS) @@ -1828,12 +1817,12 @@ index 2ee5a8359e668737ca4552a41bfe7458668a20af..a656b2c9048e069c91b5eaf0ed8c33ee +#define ENABLE_TOUCH_EVENTS 1 #endif - #if !defined(ENABLE_TOUCH_ACTION_REGIONS) + #if !defined(ENABLE_CSS_TAP_HIGHLIGHT_COLOR) && ENABLE(TOUCH_EVENTS) diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h -index b03fc81380461a7a006b1cbcdf9cd5284cd4c7b6..f645ddd0efdd6a0f121a5fcaa3746fbee07e399b 100644 +index cfa2003ccb9464bbf804c4aa37a283110ac0fbfd..3db834d1a46023ed7a3cdffd64b012ab882aa8c9 100644 --- a/Source/WTF/wtf/PlatformEnableCocoa.h +++ b/Source/WTF/wtf/PlatformEnableCocoa.h -@@ -860,7 +860,7 @@ +@@ -822,7 +822,7 @@ #endif #if !defined(ENABLE_SEC_ITEM_SHIM) @@ -1842,25 +1831,11 @@ index b03fc81380461a7a006b1cbcdf9cd5284cd4c7b6..f645ddd0efdd6a0f121a5fcaa3746fbe #endif #if !defined(ENABLE_SERVER_PRECONNECT) -diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h -index 55a140deb990434a92049455cb42f1738b4b4717..77b550990f041d0f87abc2f3ded715a7f02c8fa5 100644 ---- a/Source/WTF/wtf/PlatformHave.h -+++ b/Source/WTF/wtf/PlatformHave.h -@@ -1063,7 +1063,8 @@ - #endif - - #if PLATFORM(MAC) --#define HAVE_GPU_AVAILABILITY_CHECK 1 -+// Playwright: disable the check to make WebGL always work. -+#define HAVE_GPU_AVAILABILITY_CHECK 0 - #endif - - #if !defined(HAVE_LOCKDOWN_MODE_PDF_ADDITIONS) && \ diff --git a/Source/WTF/wtf/StdLibExtras.h b/Source/WTF/wtf/StdLibExtras.h -index cc82d99e5976a98540940ab2537be9357ea5880f..6117cf11197d3ffb95eeee2ea66b025283244868 100644 +index ebdcb2707223f582f378d83ccbf31aa115724047..cc2d26b056618c847d6e184f73fff1701d5b921d 100644 --- a/Source/WTF/wtf/StdLibExtras.h +++ b/Source/WTF/wtf/StdLibExtras.h -@@ -1579,6 +1579,39 @@ template<typename T, typename U> constexpr auto forward_like(U&& value) -> detai +@@ -1607,6 +1607,39 @@ template<typename T, typename U> constexpr auto forward_like(U&& value) -> detai template<typename T, typename U> constexpr auto forward_like_preserving_const(U&& value) -> detail::forward_like_preserving_const_impl<T, U> { return static_cast<detail::forward_like_preserving_const_impl<T, U>>(value); } } // namespace WTF @@ -1901,7 +1876,7 @@ index cc82d99e5976a98540940ab2537be9357ea5880f..6117cf11197d3ffb95eeee2ea66b0252 using WTF::KB; using WTF::MB; diff --git a/Source/WTF/wtf/unicode/UTF8Conversion.h b/Source/WTF/wtf/unicode/UTF8Conversion.h -index aa4092454a9595d10976022434500fa0c927dd16..44a046daf08f84edc777114340a730487a66ee07 100644 +index 8f551b2abcca06a623c432ac52db75de16849e8e..92bbd90bd032b9a9290ec741e7b38f9e9438f97e 100644 --- a/Source/WTF/wtf/unicode/UTF8Conversion.h +++ b/Source/WTF/wtf/unicode/UTF8Conversion.h @@ -30,6 +30,11 @@ @@ -1917,10 +1892,10 @@ index aa4092454a9595d10976022434500fa0c927dd16..44a046daf08f84edc777114340a73048 namespace Unicode { diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make -index fd78d0bc1b9e046b9c01e78e935c1ea13d75cea7..b241dbb9a5f782a173a02348014d7d8b8050dbdc 100644 +index e98fccbdefe93270040e91cb9fef8e28879c7dec..5187df2924731e17a779a23e5fd51eafadd8bb0e 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make -@@ -1253,6 +1253,10 @@ JS_BINDING_IDLS := \ +@@ -1257,6 +1257,10 @@ JS_BINDING_IDLS := \ $(WebCore)/dom/SubscriberCallback.idl \ $(WebCore)/dom/SubscriptionObserver.idl \ $(WebCore)/dom/SubscriptionObserverCallback.idl \ @@ -1931,7 +1906,7 @@ index fd78d0bc1b9e046b9c01e78e935c1ea13d75cea7..b241dbb9a5f782a173a02348014d7d8b $(WebCore)/dom/Text.idl \ $(WebCore)/dom/TextDecoder.idl \ $(WebCore)/dom/TextDecoderStream.idl \ -@@ -1877,9 +1881,6 @@ JS_BINDING_IDLS := \ +@@ -1881,9 +1885,6 @@ JS_BINDING_IDLS := \ ADDITIONAL_BINDING_IDLS = \ DocumentTouch.idl \ GestureEvent.idl \ @@ -1942,10 +1917,10 @@ index fd78d0bc1b9e046b9c01e78e935c1ea13d75cea7..b241dbb9a5f782a173a02348014d7d8b vpath %.in $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) diff --git a/Source/WebCore/Modules/geolocation/Geolocation.cpp b/Source/WebCore/Modules/geolocation/Geolocation.cpp -index 85d022853bdb80865537886accb4762fb1ea665f..5f8c788998285c85e5e08565bfc6abd95a904e42 100644 +index f468a12c6cae3ecc22fd9d7eacccb55c199f4dab..7fdb15208f24e4c91267c7d9fb776b774e5dfdda 100644 --- a/Source/WebCore/Modules/geolocation/Geolocation.cpp +++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp -@@ -369,8 +369,9 @@ bool Geolocation::shouldBlockGeolocationRequests() +@@ -365,8 +365,9 @@ bool Geolocation::shouldBlockGeolocationRequests() bool isSecure = SecurityOrigin::isSecure(document->url()) || document->isSecureContext(); bool isLocalOrigin = securityOrigin()->isLocal(); @@ -1957,10 +1932,10 @@ index 85d022853bdb80865537886accb4762fb1ea665f..5f8c788998285c85e5e08565bfc6abd9 } diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm -index 74d5031133478642f7b9dcf44286c388a7705783..00af313757c9c19514dbd9de1492bdf04d7f2482 100644 +index de8ce576a7e7156460680e5ea11f10a84cda83ec..3b502fa4663dc528cb892d28e5217c4ec8bb7ea4 100644 --- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm +++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm -@@ -197,6 +197,7 @@ - (void)sendEndIfNeeded +@@ -198,6 +198,7 @@ - (void)sendEndIfNeeded - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available { @@ -1968,7 +1943,7 @@ index 74d5031133478642f7b9dcf44286c388a7705783..00af313757c9c19514dbd9de1492bdf0 ASSERT(isMainThread()); if (available || !_task) -@@ -210,6 +211,7 @@ - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidC +@@ -211,6 +212,7 @@ - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidC - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription { @@ -1976,7 +1951,7 @@ index 74d5031133478642f7b9dcf44286c388a7705783..00af313757c9c19514dbd9de1492bdf0 ASSERT(isMainThread()); [self sendSpeechStartIfNeeded]; -@@ -218,6 +220,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTran +@@ -219,6 +221,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTran - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult { @@ -1984,7 +1959,7 @@ index 74d5031133478642f7b9dcf44286c388a7705783..00af313757c9c19514dbd9de1492bdf0 ASSERT(isMainThread()); if (task.state == SFSpeechRecognitionTaskStateCanceling || (!_doMultipleRecognitions && task.state == SFSpeechRecognitionTaskStateCompleted)) -@@ -231,6 +234,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecogniti +@@ -232,6 +235,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecogniti - (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task { @@ -2005,10 +1980,10 @@ index 72b2846f2c82818fc9a64fd90b7cba0c0601e15f..22277ab6c3233f040852d9daf9becf7b elseif (USE_SKIA) list(APPEND WebCore_SOURCES diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt -index 52f75feefac6b03d677e78b66aeba5216008b974..9d24ae4e4d561f5d7104e1a4117c46d32517771b 100644 +index 0630227f46780e9af2a5442c8f6807f2e889b011..acb032704a3b778b9c184afb02f7cb70450de1b0 100644 --- a/Source/WebCore/SourcesCocoa.txt +++ b/Source/WebCore/SourcesCocoa.txt -@@ -744,3 +744,9 @@ testing/cocoa/WebViewVisualIdentificationOverlay.mm @nonARC +@@ -746,3 +746,9 @@ testing/cocoa/WebViewVisualIdentificationOverlay.mm @nonARC platform/graphics/angle/GraphicsContextGLANGLE.cpp @no-unify platform/graphics/cocoa/GraphicsContextGLCocoa.mm @nonARC @no-unify platform/graphics/cv/GraphicsContextGLCVCocoa.mm @nonARC @no-unify @@ -2047,11 +2022,11 @@ index eb48da502311408b4772385e51b4143da28fc5d0..0cbc5941fa1c659f5a76f77cc4b22ee5 +JSSpeechSynthesisErrorEventInit.cpp +JSSpeechSynthesisEventInit.cpp diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj -index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a0f07a12d 100644 +index 308d7803e73db4277cd404ddb1314d29d3dba836..9526210649e3d9f55ec524547be40f3087aaa9dd 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj -@@ -6915,6 +6915,13 @@ - EE62BD9D2DE12C1B006C9A05 /* ResolvedScopedName.h in Headers */ = {isa = PBXBuildFile; fileRef = EE62BD9B2DE12BD4006C9A05 /* ResolvedScopedName.h */; settings = {ATTRIBUTES = (Private, ); }; }; +@@ -6992,6 +6992,13 @@ + EE6C530F2F8831FF00C7B706 /* RenderTreeOrder.h in Headers */ = {isa = PBXBuildFile; fileRef = EE6C530D2F8830BD00C7B706 /* RenderTreeOrder.h */; settings = {ATTRIBUTES = (Private, ); }; }; EEE349082DE0061C00A7D4BB /* StyleScopeIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = EEE349072DE005FC00A7D4BB /* StyleScopeIdentifier.h */; settings = {ATTRIBUTES = (Private, ); }; }; EFCC6C8F20FE914400A2321B /* CanvasActivityRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F050E16823AC9C080011CE47 /* PlatformTouchEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -2064,7 +2039,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a F12171F616A8CF0B000053CA /* WebVTTElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F12171F416A8BC63000053CA /* WebVTTElement.h */; }; F30EE46B2E721BA800935B60 /* FrameInspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = F30EE46A2E721B9D00935B60 /* FrameInspectorController.h */; settings = {ATTRIBUTES = (Private, ); }; }; F32BDCD92363AACA0073B6AE /* UserGestureEmulationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = F32BDCD72363AACA0073B6AE /* UserGestureEmulationScope.h */; }; -@@ -22451,6 +22458,14 @@ +@@ -22710,6 +22717,14 @@ EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasActivityRecord.h; sourceTree = "<group>"; }; F088343F2E721B29001B2348 /* AXLocalFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AXLocalFrame.h; sourceTree = "<group>"; }; F08834402E721B33001B2348 /* AXLocalFrame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AXLocalFrame.cpp; sourceTree = "<group>"; }; @@ -2079,7 +2054,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a F12171F316A8BC63000053CA /* WebVTTElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebVTTElement.cpp; sourceTree = "<group>"; }; F12171F416A8BC63000053CA /* WebVTTElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTElement.h; sourceTree = "<group>"; }; F30EE46A2E721B9D00935B60 /* FrameInspectorController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameInspectorController.h; sourceTree = "<group>"; }; -@@ -30487,6 +30502,11 @@ +@@ -30743,6 +30758,11 @@ BC4A5324256055590028C592 /* TextDirectionSubmenuInclusionBehavior.h */, 2D4F96F11A1ECC240098BF88 /* TextIndicator.cpp */, 2D4F96F21A1ECC240098BF88 /* TextIndicator.h */, @@ -2091,7 +2066,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a F48570A42644C76D00C05F71 /* TranslationContextMenuInfo.h */, D640B24C2E3058C800EB6C49 /* UADataValues.h */, D640B24E2E3058C800EB6C49 /* UADataValues.idl */, -@@ -38364,6 +38384,8 @@ +@@ -38753,6 +38773,8 @@ 29E4D8DF16B0940F00C84704 /* PlatformSpeechSynthesizer.h */, 1AD8F81A11CAB9E900E93E54 /* PlatformStrategies.cpp */, 1AD8F81911CAB9E900E93E54 /* PlatformStrategies.h */, @@ -2100,7 +2075,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a FE3DC9932D0C063C0021B6FC /* PlatformTZoneImpls.cpp */, 0FD7C21D23CE41E30096D102 /* PlatformWheelEvent.cpp */, 935C476A09AC4D4F00A6AAB4 /* PlatformWheelEvent.h */, -@@ -41317,6 +41339,7 @@ +@@ -41766,6 +41788,7 @@ AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */, 6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */, 6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */, @@ -2108,7 +2083,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a 7CE7FA5B1EF882300060C9D6 /* DocumentTouch.cpp */, 7CE7FA591EF882300060C9D6 /* DocumentTouch.h */, A8185F3209765765005826D9 /* DocumentType.cpp */, -@@ -46446,6 +46469,8 @@ +@@ -46955,6 +46978,8 @@ F4E90A3C2B52038E002DA469 /* PlatformTextAlternatives.h in Headers */, 0F7D07331884C56C00B4AF86 /* PlatformTextTrack.h in Headers */, 074E82BB18A69F0E007EF54C /* PlatformTimeRanges.h in Headers */, @@ -2117,7 +2092,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a CDD08ABD277E542600EA3755 /* PlatformTrackConfiguration.h in Headers */, CD1F9B022700323D00617EB6 /* PlatformVideoColorPrimaries.h in Headers */, CD1F9B01270020B700617EB6 /* PlatformVideoColorSpace.h in Headers */, -@@ -48101,6 +48126,7 @@ +@@ -48629,6 +48654,7 @@ 0F54DD081881D5F5003EEDBB /* Touch.h in Headers */, 71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */, 0F54DD091881D5F5003EEDBB /* TouchEvent.h in Headers */, @@ -2125,7 +2100,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a 0F54DD0A1881D5F5003EEDBB /* TouchList.h in Headers */, 070334D71459FFD5008D8D45 /* TrackBase.h in Headers */, 513C7B6E2E7C2E7A00079881 /* TrackInfo.h in Headers */, -@@ -49367,7 +49393,9 @@ +@@ -49903,7 +49929,9 @@ 2D22830323A8470700364B7E /* CursorMac.mm in Sources */, 5CBD59592280E926002B22AA /* CustomHeaderFields.cpp in Sources */, 07E4BDBF2A3A5FAB000D5509 /* DictationCaretAnimator.cpp in Sources */, @@ -2135,7 +2110,7 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a 7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */, 4667EA3E2968D9DA00BAB1E2 /* GameControllerHapticEffect.mm in Sources */, 46FE73D32968E52000B8064C /* GameControllerHapticEngines.mm in Sources */, -@@ -49464,6 +49492,9 @@ +@@ -50000,6 +50028,9 @@ 072F696F2E755BFA00281FC5 /* TextListParser.cpp in Sources */, BE39137129B267F500FA5D4F /* TextTransformCocoa.cpp in Sources */, 51DF6D800B92A18E00C2DC85 /* ThreadCheck.mm in Sources */, @@ -2146,10 +2121,10 @@ index 73e3cfee23dbf823aab021499b6d9e709670665d..7617b70b8d751a42be9c4ac1bc03fd8a 538EC8031F96AF81004D22A8 /* UnifiedSource1-nonARC.mm in Sources */, 538EC8021F96AF81004D22A8 /* UnifiedSource1.cpp in Sources */, diff --git a/Source/WebCore/css/query/MediaQueryFeatures.cpp b/Source/WebCore/css/query/MediaQueryFeatures.cpp -index 2d24dfbbd311fcda83f1a467bcf6df424d4f2f4f..5e30a87979658868f927f2a6e001bee41ef55522 100644 +index ab1b8b7d0e7baff7d7564609736a6145472c2e3a..00921097a9f2b5d96937785e62f5a3533afafe55 100644 --- a/Source/WebCore/css/query/MediaQueryFeatures.cpp +++ b/Source/WebCore/css/query/MediaQueryFeatures.cpp -@@ -403,7 +403,11 @@ static const IdentifierSchema& forcedColorsFeatureSchema() +@@ -404,7 +404,11 @@ static const IdentifierSchema& forcedColorsFeatureSchema() "forced-colors"_s, FixedVector { CSSValueNone, CSSValueActive }, OptionSet<MediaQueryDynamicDependency>(), @@ -2162,7 +2137,7 @@ index 2d24dfbbd311fcda83f1a467bcf6df424d4f2f4f..5e30a87979658868f927f2a6e001bee4 return MatchingIdentifiers { CSSValueNone }; } }; -@@ -591,6 +595,9 @@ static const IdentifierSchema& prefersReducedMotionFeatureSchema() +@@ -592,6 +596,9 @@ static const IdentifierSchema& prefersReducedMotionFeatureSchema() [](auto& context) { bool userPrefersReducedMotion = [&] { Ref frame = *context.document->frame(); @@ -2173,7 +2148,7 @@ index 2d24dfbbd311fcda83f1a467bcf6df424d4f2f4f..5e30a87979658868f927f2a6e001bee4 case ForcedAccessibilityValue::On: return true; diff --git a/Source/WebCore/dom/DataTransfer.cpp b/Source/WebCore/dom/DataTransfer.cpp -index 5f765a55524e409e527d1b69d777adb2a1870756..f11df9bb37680c6daa0fcdc49ea8946cd1059c4f 100644 +index 6fac2c209afa640cf7a305c9c322791c0cce2435..a609e0272959a42dec0e44cfd943ab6a8d78865a 100644 --- a/Source/WebCore/dom/DataTransfer.cpp +++ b/Source/WebCore/dom/DataTransfer.cpp @@ -531,6 +531,14 @@ Ref<DataTransfer> DataTransfer::createForDrag(const Document& document) @@ -2192,7 +2167,7 @@ index 5f765a55524e409e527d1b69d777adb2a1870756..f11df9bb37680c6daa0fcdc49ea8946c { auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique<StaticPasteboard>(), Type::DragAndDropData)); diff --git a/Source/WebCore/dom/DataTransfer.h b/Source/WebCore/dom/DataTransfer.h -index d798a1982a6e5809a5d299f78a57ca4aff411093..a0c968644264f85d57a9856e61bd7254c291d5a7 100644 +index 64a53ff58bf7bcd9e56ccc8b74cea8c9c75bf89e..10d52432373f02622328f32d3f665ed0fdd8bc24 100644 --- a/Source/WebCore/dom/DataTransfer.h +++ b/Source/WebCore/dom/DataTransfer.h @@ -92,6 +92,9 @@ public: @@ -2237,7 +2212,7 @@ index 2feeeac677ee3f36cb13c2bac1afbc57fbe70e12..6ed92e45b7659c48b3bb1e24f7f00751 SecureContext ] interface DeviceOrientationEvent : Event { diff --git a/Source/WebCore/dom/PointerEvent.cpp b/Source/WebCore/dom/PointerEvent.cpp -index d2b50320eac0f2fe77b72779aaec7278a958a520..dbcb8d574a9daf2df9120cd70d6f7623e9ec31ac 100644 +index dd8c59fe17c70a72f03df3c884b5a92f8f655e61..9c2b847b15f4361ad8199729c2b808a0253b77c2 100644 --- a/Source/WebCore/dom/PointerEvent.cpp +++ b/Source/WebCore/dom/PointerEvent.cpp @@ -20,7 +20,7 @@ @@ -2259,7 +2234,7 @@ index d2b50320eac0f2fe77b72779aaec7278a958a520..dbcb8d574a9daf2df9120cd70d6f7623 #include "PointerEventTypeNames.h" #include <numbers> #include <wtf/TZoneMallocInlines.h> -@@ -331,4 +333,59 @@ double PointerEvent::offsetY() +@@ -380,4 +382,59 @@ double PointerEvent::offsetY() return adjustedCoordinateForType(offsetLocation().y()); } @@ -2304,7 +2279,7 @@ index d2b50320eac0f2fe77b72779aaec7278a958a520..dbcb8d574a9daf2df9120cd70d6f7623 + +PointerEvent::PointerEvent(const AtomString& type, const PlatformTouchEvent& event, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, CanBubble canBubble, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&& view, const DoublePoint& touchDelta) + : MouseEvent(EventInterfaceType::PointerEvent, type, canBubble, isCancelable, typeIsComposed(type), event.timestamp().approximateMonotonicTime(), WTF::move(view), 0, -+ event.touchPoints().at(touchIndex).pos(), event.touchPoints().at(touchIndex).pos(), touchDelta.x(), touchDelta.y(), event.modifiers(), buttonForType(type), buttonsForType(type), nullptr, 0, SyntheticClickType::NoTap, { }, { }, IsSimulated::No, IsTrusted::Yes) ++ event.touchPoints().at(touchIndex).pos(), event.touchPoints().at(touchIndex).pos(), touchDelta.x(), touchDelta.y(), event.modifiers(), buttonForType(type), buttonsForType(type), nullptr, 0, SyntheticClickType::NoTap, { }, { }, std::nullopt, IsSimulated::No, IsTrusted::Yes) + , m_pointerId(event.touchPoints().at(touchIndex).id()) + , m_width(2 * event.touchPoints().at(touchIndex).radius().width()) + , m_height(2 * event.touchPoints().at(touchIndex).radius().height()) @@ -2320,7 +2295,7 @@ index d2b50320eac0f2fe77b72779aaec7278a958a520..dbcb8d574a9daf2df9120cd70d6f7623 + } // namespace WebCore diff --git a/Source/WebCore/dom/PointerEvent.h b/Source/WebCore/dom/PointerEvent.h -index 0edeb2e3c8b0122d2e33b552bba39afe819ca25f..681a30414072db49de8d58c3e381674d2f6b9a4c 100644 +index a9ad0f77eedb629a360c8ec77257e84e59418dbf..3486cfaa73edb83300e597ab3fc8ab115e96ee54 100644 --- a/Source/WebCore/dom/PointerEvent.h +++ b/Source/WebCore/dom/PointerEvent.h @@ -41,8 +41,8 @@ @@ -2334,7 +2309,7 @@ index 0edeb2e3c8b0122d2e33b552bba39afe819ca25f..681a30414072db49de8d58c3e381674d #endif namespace WebCore { -@@ -99,7 +99,7 @@ public: +@@ -99,14 +99,18 @@ public: static Ref<PointerEvent> create(const AtomString& type, MouseButton, const MouseEvent&, PointerID, const String& pointerType, CanBubble, IsCancelable); static Ref<PointerEvent> create(const AtomString& type, PointerID, const String& pointerType, IsPrimary = IsPrimary::No); @@ -2343,7 +2318,19 @@ index 0edeb2e3c8b0122d2e33b552bba39afe819ca25f..681a30414072db49de8d58c3e381674d static Ref<PointerEvent> create(const PlatformTouchEvent&, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&, const DoublePoint& touchDelta = { }); static Ref<PointerEvent> create(const PlatformTouchEvent&, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, CanBubble, IsCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&& view, const DoublePoint& touchDelta = { }); static Ref<PointerEvent> create(const AtomString& type, const PlatformTouchEvent&, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&, const DoublePoint& touchDelta = { }); -@@ -190,7 +190,7 @@ private: + #endif + +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(WPE) || PLATFORM(GTK)) ++#if ENABLE(TOUCH_EVENTS) ++#if PLATFORM(WPE) || PLATFORM(GTK) + static unsigned pointerIdForTouchPoint(const PlatformTouchPoint&); ++#elif !ENABLE(IOS_TOUCH_EVENTS) ++ static unsigned pointerIdForTouchPoint(const PlatformTouchPoint& point) { return point.id(); } ++#endif + #endif + + virtual ~PointerEvent(); +@@ -194,7 +198,7 @@ private: PointerEvent(); PointerEvent(const AtomString&, Init&&, IsTrusted); PointerEvent(const AtomString& type, PointerID, const String& pointerType, IsPrimary); @@ -2395,10 +2382,10 @@ index d0a3d5c048647b07772e1581c76c4eb60ecf41b0..bec324636991079264e620c0dfdaf984 #endif // USE(LIBWPE) diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp -index 7a2de0702571fa37739a155e48a82b6dc4f2c069..cad655f443a1e6b1eb91c4af8287e468bf1fb934 100644 +index 70293a7486130c23eda9198e399f4fc7a998c2b3..1ff1dc564dbe7f2ed2d35000d82bac6e2fb2cad0 100644 --- a/Source/WebCore/html/FileInputType.cpp +++ b/Source/WebCore/html/FileInputType.cpp -@@ -38,6 +38,7 @@ +@@ -39,6 +39,7 @@ #include "HTMLNames.h" #include "Icon.h" #include "InputTypeNames.h" @@ -2406,8 +2393,8 @@ index 7a2de0702571fa37739a155e48a82b6dc4f2c069..cad655f443a1e6b1eb91c4af8287e468 #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MIMETypeRegistry.h" -@@ -161,6 +162,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) - if (protect(element())->isDisabledFormControl()) +@@ -162,6 +163,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) + if (element()->isDisabledFormControl()) return; + bool intercept = false; @@ -2419,10 +2406,10 @@ index 7a2de0702571fa37739a155e48a82b6dc4f2c069..cad655f443a1e6b1eb91c4af8287e468 return; diff --git a/Source/WebCore/inspector/FrameInspectorController.cpp b/Source/WebCore/inspector/FrameInspectorController.cpp -index a02cfbc44a72e4e6dcfdc9a3e4882c5f03c78532..fca59770988d2dd270881102ac0758273adaa43a 100644 +index 12650ec508ee1acef286c9b862e37a73f652409f..5721af8def5099347a80e7ad31c7551dbc0be0d5 100644 --- a/Source/WebCore/inspector/FrameInspectorController.cpp +++ b/Source/WebCore/inspector/FrameInspectorController.cpp -@@ -115,6 +115,12 @@ void FrameInspectorController::connectFrontend(Inspector::FrontendChannel& front +@@ -170,6 +170,12 @@ void FrameInspectorController::connectFrontend(Inspector::FrontendChannel& front UNUSED_PARAM(isAutomaticInspection); UNUSED_PARAM(immediatelyPause); @@ -2432,10 +2419,10 @@ index a02cfbc44a72e4e6dcfdc9a3e4882c5f03c78532..fca59770988d2dd270881102ac075827 + return; + // Playwright end + - if (RefPtr page = m_frame->page()) + if (auto* page = m_frame->page()) page->settings().setDeveloperExtrasEnabled(true); -@@ -129,6 +135,19 @@ void FrameInspectorController::connectFrontend(Inspector::FrontendChannel& front +@@ -184,6 +190,19 @@ void FrameInspectorController::connectFrontend(Inspector::FrontendChannel& front m_injectedScriptManager->addClient(); m_agents.didCreateFrontendAndBackend(); } @@ -2455,11 +2442,70 @@ index a02cfbc44a72e4e6dcfdc9a3e4882c5f03c78532..fca59770988d2dd270881102ac075827 } void FrameInspectorController::disconnectFrontend(Inspector::FrontendChannel& frontendChannel) +diff --git a/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp b/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp +index 1585d249dafdc13f4258ff1dde95268eeb329f93..24d21908c7a79e744aadf37a6d8ba0918f2dd7b7 100644 +--- a/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp ++++ b/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp +@@ -48,20 +48,22 @@ Protocol::Network::FrameId LegacyIdentifierRegistry::frameId(const WebCore::Fram + { + if (!frame) + return emptyString(); +- return m_frameToIdentifier.ensure(*frame, [this, frame] { +- auto identifier = IdentifiersFactory::createIdentifier(); +- m_identifierToFrame.set(identifier, frame); +- return identifier; +- }).iterator->value; ++ ++ auto identifier = String::number(frame->frameID().toUInt64()); ++ m_identifierToFrame.set(identifier, frame); ++ return identifier; + } + + Protocol::Network::LoaderId LegacyIdentifierRegistry::loaderId(WebCore::DocumentLoader* loader) + { + if (!loader) + return emptyString(); +- return m_loaderToIdentifier.ensure(loader, [] { +- return IdentifiersFactory::createIdentifier(); +- }).iterator->value; ++ ++ auto navigationID = loader->navigationID(); ++ if (!navigationID) ++ return emptyString(); ++ ++ return String::number(navigationID->toUInt64()); + } + + WebCore::LocalFrame* LegacyIdentifierRegistry::assertFrame(Protocol::ErrorString& errorString, const Protocol::Network::FrameId& frameId) +@@ -74,15 +76,19 @@ WebCore::LocalFrame* LegacyIdentifierRegistry::assertFrame(Protocol::ErrorString + + Protocol::Network::FrameId LegacyIdentifierRegistry::takeFrame(const WebCore::Frame& frame) + { +- auto identifier = m_frameToIdentifier.take(frame); +- if (!identifier.isNull()) +- m_identifierToFrame.remove(identifier); ++ auto identifier = String::number(frame.frameID().toUInt64()); ++ if (!m_identifierToFrame.take(identifier)) ++ return {}; + return identifier; + } + + Protocol::Network::LoaderId LegacyIdentifierRegistry::takeLoader(WebCore::DocumentLoader& loader) + { +- return m_loaderToIdentifier.take(&loader); ++ auto navigationID = loader.navigationID(); ++ if (!navigationID) ++ return {}; ++ ++ return String::number(navigationID->toUInt64()); + } + + } // namespace Inspector diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp -index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6ab4424094 100644 +index 68b5996d7ae96ce0c3f5eda869e353b448823da7..5227faf95b488a3f67e2e63e30089ba9b9cd0d5c 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp -@@ -600,6 +600,12 @@ void InspectorInstrumentation::applyUserAgentOverrideImpl(InstrumentingAgents& i +@@ -617,6 +617,12 @@ void InspectorInstrumentation::applyUserAgentOverrideImpl(InstrumentingAgents& i pageAgent->applyUserAgentOverride(userAgent); } @@ -2471,8 +2517,8 @@ index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6a + void InspectorInstrumentation::applyEmulatedMediaImpl(InstrumentingAgents& instrumentingAgents, AtomString& media) { - if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) -@@ -683,6 +689,12 @@ void InspectorInstrumentation::didFailLoadingImpl(InstrumentingAgents& instrumen + if (CheckedPtr pageAgent = instrumentingAgents.enabledPageAgent()) +@@ -700,6 +706,12 @@ void InspectorInstrumentation::didFailLoadingImpl(InstrumentingAgents& instrumen consoleAgent->didFailLoading(identifier, error); // This should come AFTER resource notification, front-end relies on this. } @@ -2485,14 +2531,14 @@ index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6a void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents) { if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) -@@ -715,20 +727,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& +@@ -732,20 +744,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { - if (!frame.isMainFrame()) - return; - - if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) + if (CheckedPtr pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->domContentEventFired(); + pageAgent->domContentEventFired(frame); } @@ -2503,26 +2549,26 @@ index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6a + if (!frame) return; - if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) + if (CheckedPtr pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->loadEventFired(); + pageAgent->loadEventFired(*frame); } void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) -@@ -808,12 +817,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins +@@ -825,12 +834,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins pageDOMDebuggerAgent->frameDocumentUpdated(frame); } -void InspectorInstrumentation::loaderDetachedFromFrameImpl(InstrumentingAgents& instrumentingAgents, DocumentLoader& loader) -{ -- if (auto* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) +- if (CheckedPtr inspectorPageAgent = instrumentingAgents.enabledPageAgent()) - inspectorPageAgent->loaderDetachedFromFrame(loader); -} - void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { if (frame.isMainFrame()) { -@@ -844,6 +847,12 @@ void InspectorInstrumentation::accessibilitySettingsDidChangeImpl(InstrumentingA +@@ -861,6 +864,12 @@ void InspectorInstrumentation::accessibilitySettingsDidChangeImpl(InstrumentingA inspectorPageAgent->accessibilitySettingsDidChange(); } @@ -2535,7 +2581,7 @@ index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6a #if ENABLE(DARK_MODE_CSS) void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents) { -@@ -896,6 +905,12 @@ void InspectorInstrumentation::interceptResponseImpl(InstrumentingAgents& instru +@@ -913,6 +922,12 @@ void InspectorInstrumentation::interceptResponseImpl(InstrumentingAgents& instru networkAgent->interceptResponse(response, identifier, WTF::move(handler)); } @@ -2546,9 +2592,9 @@ index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6a +} + // JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes. - static bool isConsoleAssertMessage(MessageSource source, MessageType type) + static bool NODELETE isConsoleAssertMessage(MessageSource source, MessageType type) { -@@ -1033,6 +1048,12 @@ void InspectorInstrumentation::consoleStopRecordingCanvasImpl(InstrumentingAgent +@@ -1050,6 +1065,12 @@ void InspectorInstrumentation::consoleStopRecordingCanvasImpl(InstrumentingAgent canvasAgent->consoleStopRecordingCanvas(context); } @@ -2561,7 +2607,7 @@ index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6a void InspectorInstrumentation::didDispatchDOMStorageEventImpl(InstrumentingAgents& instrumentingAgents, const String& key, const String& oldValue, const String& newValue, StorageType storageType, const SecurityOrigin& securityOrigin) { if (auto* domStorageAgent = instrumentingAgents.enabledDOMStorageAgent()) -@@ -1330,6 +1351,36 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins +@@ -1347,6 +1368,36 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins layerTreeAgent->renderLayerDestroyed(renderLayer); } @@ -2599,7 +2645,7 @@ index c7c92ebd20a4ba15d98fa257f474ead61dad907f..1d9d08320fdcd755ac8a0bc96ec21e6a { return globalScope.inspectorController().m_instrumentingAgents; diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h -index a2caf79633711dea4147106e10c43af87b244446..bd20bb948eede5f6521e1ff088befd84edabca42 100644 +index d3c1a73fd1eaa95dad8e582f8e52ed894a53a8be..24791c5f62638513dd507ff0886ae4d593523919 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -45,6 +45,7 @@ @@ -2731,9 +2777,9 @@ index a2caf79633711dea4147106e10c43af87b244446..bd20bb948eede5f6521e1ff088befd84 + static void willCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&); + static void didCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&, bool cancel); + - static InstrumentingAgents& instrumentingAgents(Page&); - static InstrumentingAgents& instrumentingAgents(const LocalFrame&); - static InstrumentingAgents& instrumentingAgents(const LocalFrameView&); + static InstrumentingAgents& NODELETE instrumentingAgents(Page&); + static InstrumentingAgents& NODELETE instrumentingAgents(const LocalFrame&); + static InstrumentingAgents& NODELETE instrumentingAgents(const LocalFrameView&); @@ -1078,6 +1100,12 @@ inline void InspectorInstrumentation::applyUserAgentOverride(LocalFrame& frame, applyUserAgentOverrideImpl(instrumentingAgents(frame), userAgent); } @@ -2905,10 +2951,10 @@ index 01ad196099f09a89717830cd70dded3b495cf5f5..c9d2e97c6f5f5e6b0a8f70c31af947ef + } diff --git a/Source/WebCore/inspector/PageInspectorController.cpp b/Source/WebCore/inspector/PageInspectorController.cpp -index daaffe5cbbf4350ed327834437d81c8e9ceb7c39..cbdc7ec8b58aff3893e456ebef38ad03802c7605 100644 +index 4fa92ae7d7c2f6e501eecb90691c3dca65e4482e..21dbf683927dec650570a540f0fcd5be6538afa5 100644 --- a/Source/WebCore/inspector/PageInspectorController.cpp +++ b/Source/WebCore/inspector/PageInspectorController.cpp -@@ -285,6 +285,8 @@ void PageInspectorController::disconnectFrontend(FrontendChannel& frontendChanne +@@ -291,6 +291,8 @@ void PageInspectorController::disconnectFrontend(FrontendChannel& frontendChanne // Unplug all instrumentations since they aren't needed now. InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get()); @@ -2917,7 +2963,7 @@ index daaffe5cbbf4350ed327834437d81c8e9ceb7c39..cbdc7ec8b58aff3893e456ebef38ad03 } m_inspectorBackendClient->frontendCountChanged(m_frontendRouter->frontendCount()); -@@ -299,6 +301,8 @@ void PageInspectorController::disconnectAllFrontends() +@@ -305,6 +307,8 @@ void PageInspectorController::disconnectAllFrontends() // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow(). ASSERT(!m_inspectorFrontendClient); @@ -2926,7 +2972,7 @@ index daaffe5cbbf4350ed327834437d81c8e9ceb7c39..cbdc7ec8b58aff3893e456ebef38ad03 if (!m_frontendRouter->hasFrontends()) return; -@@ -378,8 +382,8 @@ void PageInspectorController::inspect(Node* node) +@@ -384,8 +388,8 @@ void PageInspectorController::inspect(Node* node) if (!enabled()) return; @@ -2937,7 +2983,7 @@ index daaffe5cbbf4350ed327834437d81c8e9ceb7c39..cbdc7ec8b58aff3893e456ebef38ad03 CheckedRef { ensureDOMAgent() }->inspect(node); } -@@ -517,4 +521,34 @@ void PageInspectorController::didComposite(LocalFrame& frame) +@@ -523,4 +527,34 @@ void PageInspectorController::didComposite(LocalFrame& frame) InspectorInstrumentation::didComposite(frame); } @@ -2973,10 +3019,10 @@ index daaffe5cbbf4350ed327834437d81c8e9ceb7c39..cbdc7ec8b58aff3893e456ebef38ad03 + } // namespace WebCore diff --git a/Source/WebCore/inspector/PageInspectorController.h b/Source/WebCore/inspector/PageInspectorController.h -index b7f0987dd62369d944a2cc17c6cb1c530952f348..0899fb9da82500948ceedda517839a11ecc08108 100644 +index 1418886b19d5310d76deef334ae994ff8afd0562..6217b778b6c0bd73d7da6f9b8ef1454dda156806 100644 --- a/Source/WebCore/inspector/PageInspectorController.h +++ b/Source/WebCore/inspector/PageInspectorController.h -@@ -115,6 +115,12 @@ public: +@@ -117,6 +117,12 @@ public: WEBCORE_EXPORT void willComposite(LocalFrame&); WEBCORE_EXPORT void didComposite(LocalFrame&); @@ -2989,7 +3035,7 @@ index b7f0987dd62369d944a2cc17c6cb1c530952f348..0899fb9da82500948ceedda517839a11 // Testing support. bool isUnderTest() const { return m_isUnderTest; } void setIsUnderTest(bool isUnderTest) { m_isUnderTest = isUnderTest; } -@@ -149,6 +155,7 @@ private: +@@ -153,6 +159,7 @@ private: PageAgentContext pageAgentContext(); void createLazyAgents(); @@ -2997,7 +3043,7 @@ index b7f0987dd62369d944a2cc17c6cb1c530952f348..0899fb9da82500948ceedda517839a11 WeakRef<Page> m_page; const Ref<InstrumentingAgents> m_instrumentingAgents; -@@ -172,6 +179,7 @@ private: +@@ -177,6 +184,7 @@ private: bool m_isAutomaticInspection { false }; bool m_pauseAfterInitialization = { false }; bool m_didCreateLazyAgents { false }; @@ -3006,7 +3052,7 @@ index b7f0987dd62369d944a2cc17c6cb1c530952f348..0899fb9da82500948ceedda517839a11 } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp -index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c2799567a 100644 +index aee336fcc014831222e12d1806ffc0052e0daed3..88d87a57acf14678214918c5c7a44063951f8b8f 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp @@ -54,6 +54,7 @@ @@ -3033,7 +3079,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "HTMLScriptElement.h" -@@ -105,12 +111,14 @@ +@@ -107,12 +113,14 @@ #include "Pasteboard.h" #include "PseudoElement.h" #include "RenderGrid.h" @@ -3048,7 +3094,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c #include "StaticNodeList.h" #include "StyleProperties.h" #include "StyleResolver.h" -@@ -153,7 +161,8 @@ using namespace HTMLNames; +@@ -156,7 +164,8 @@ using namespace HTMLNames; static const size_t maxTextSize = 10000; static const char16_t horizontalEllipsisUTF16[] = { horizontalEllipsis, 0 }; @@ -3058,7 +3104,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c { if (!colorObject) return std::nullopt; -@@ -172,7 +181,7 @@ static std::optional<Color> parseColor(RefPtr<JSON::Object>&& colorObject) +@@ -175,7 +184,7 @@ static std::optional<Color> parseColor(RefPtr<JSON::Object>&& colorObject) static std::optional<Color> parseRequiredConfigColor(const String& fieldName, JSON::Object& configObject) { @@ -3067,7 +3113,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c } static Color parseOptionalConfigColor(const String& fieldName, JSON::Object& configObject) -@@ -199,6 +208,20 @@ static bool parseQuad(Ref<JSON::Array>&& quadArray, FloatQuad* quad) +@@ -202,6 +211,20 @@ static bool parseQuad(Ref<JSON::Array>&& quadArray, FloatQuad* quad) return true; } @@ -3088,7 +3134,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c class RevalidateStyleAttributeTask final : public CanMakeCheckedPtr<RevalidateStyleAttributeTask> { WTF_MAKE_TZONE_ALLOCATED(RevalidateStyleAttributeTask); WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(RevalidateStyleAttributeTask); -@@ -484,6 +507,20 @@ Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorStrin +@@ -485,6 +508,20 @@ Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorStrin return node.unsafeGet(); } @@ -3109,7 +3155,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c Document* InspectorDOMAgent::assertDocument(Inspector::Protocol::ErrorString& errorString, Inspector::Protocol::DOM::NodeId nodeId) { RefPtr node = assertNode(errorString, nodeId); -@@ -1606,15 +1643,7 @@ Inspector::Protocol::ErrorStringOr<void> InspectorDOMAgent::highlightNode(std::o +@@ -1602,15 +1639,7 @@ Inspector::Protocol::ErrorStringOr<void> InspectorDOMAgent::highlightNode(std::o { Inspector::Protocol::ErrorString errorString; @@ -3126,7 +3172,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c if (!node) return makeUnexpected(errorString); -@@ -1870,15 +1899,159 @@ Inspector::Protocol::ErrorStringOr<void> InspectorDOMAgent::setInspectedNode(Ins +@@ -1861,15 +1890,159 @@ Inspector::Protocol::ErrorStringOr<void> InspectorDOMAgent::setInspectedNode(Ins return { }; } @@ -3289,7 +3335,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c if (!object) return makeUnexpected("Missing injected script for given nodeId"_s); -@@ -3147,7 +3320,7 @@ Inspector::Protocol::ErrorStringOr<Inspector::Protocol::DOM::NodeId> InspectorDO +@@ -3133,7 +3306,7 @@ Inspector::Protocol::ErrorStringOr<Inspector::Protocol::DOM::NodeId> InspectorDO return makeUnexpected("Missing node for given path"_s); } @@ -3298,7 +3344,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c { RefPtr document = &node->document(); if (auto* templateHost = document->templateDocumentHost()) -@@ -3156,12 +3329,18 @@ RefPtr<Inspector::Protocol::Runtime::RemoteObject> InspectorDOMAgent::resolveNod +@@ -3142,12 +3315,18 @@ RefPtr<Inspector::Protocol::Runtime::RemoteObject> InspectorDOMAgent::resolveNod if (!frame) return nullptr; @@ -3320,7 +3366,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c } Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value) -@@ -3315,4 +3494,53 @@ Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::DOM::MediaStats>> In +@@ -3301,4 +3480,53 @@ Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::DOM::MediaStats>> In #endif } @@ -3337,7 +3383,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c + return; + } + -+ if (node->nodeType() != Node::ELEMENT_NODE || node->nodeName() != "INPUT"_s) { ++ if (node->nodeType() != NodeType::Element || node->nodeName() != "INPUT"_s) { + callback->sendFailure("Not an input node"_s); + return; + } @@ -3375,7 +3421,7 @@ index 89bee1d256b8b3641ada8496066c9a66fa6f2d6f..bccaa466012d55fe6fb540c79481375c + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h -index 95f3f66244b5350e9457268ba054a5d9100eea87..71c5726fefdb5dfc1257adf6cc3aa63347bd2332 100644 +index 8f83cc5eaca550bbcea167c98b944f704d9a9cb1..2f655b6534f1428a23907e1cada99c244a9a2c98 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h @@ -62,6 +62,7 @@ namespace WebCore { @@ -3448,7 +3494,7 @@ index 95f3f66244b5350e9457268ba054a5d9100eea87..71c5726fefdb5dfc1257adf6cc3aa633 void discardBindings(); diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp -index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c9c8ccf56 100644 +index dd164a0c7161396ee21bc3e1e4f7889f5ddbb770..58a528c6ac0efea4b383688d5369606013282075 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp @@ -62,6 +62,7 @@ @@ -3479,7 +3525,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c if (resourceLoader) { auto* metrics = response.deprecatedNetworkLoadMetricsOrNull(); responseObject->setTiming(buildObjectForTiming(metrics ? *metrics : NetworkLoadMetrics::emptyMetrics(), *resourceLoader)); -@@ -519,7 +522,7 @@ void InspectorNetworkAgent::didReceiveResponse(ResourceLoaderIdentifier identifi +@@ -522,7 +525,7 @@ void InspectorNetworkAgent::didReceiveResponse(ResourceLoaderIdentifier identifi // 'Raw' is used for loading worker scripts, and those should stay as 'Script' and not change to 'XHR' type. if (type != newType && newType != ResourceType::XHR && newType != ResourceType::Other) type = newType; @@ -3488,7 +3534,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c // FIXME: <webkit.org/b/216125> 304 Not Modified responses for XHR/Fetch do not have all their information from the cache. if (isNotModified && (type == ResourceType::XHR || type == ResourceType::Fetch) && (!cachedResource || !cachedResource->encodedSize())) { if (auto previousResourceData = m_resourcesData->dataForURL(response.url().string())) { -@@ -530,12 +533,12 @@ void InspectorNetworkAgent::didReceiveResponse(ResourceLoaderIdentifier identifi +@@ -533,12 +536,12 @@ void InspectorNetworkAgent::didReceiveResponse(ResourceLoaderIdentifier identifi m_resourcesData->maybeAddResourceData(requestId, buffer); }); } @@ -3504,7 +3550,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c resourceResponse->setString("source"_s, Inspector::Protocol::Helpers::getEnumConstantValue(Inspector::Protocol::Network::Response::Source::DiskCache)); } } -@@ -614,6 +617,9 @@ void InspectorNetworkAgent::didFailLoading(ResourceLoaderIdentifier identifier, +@@ -617,6 +620,9 @@ void InspectorNetworkAgent::didFailLoading(ResourceLoaderIdentifier identifier, String requestId = IdentifiersFactory::requestId(identifier.toUInt64()); if (loader && m_resourcesData->resourceType(requestId) == ResourceType::Document) { @@ -3514,7 +3560,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c auto* frame = loader->frame(); if (frame && frame->loader().documentLoader() && frame->document()) { m_resourcesData->addResourceSharedBuffer(requestId, -@@ -843,6 +849,7 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::disable() +@@ -846,6 +852,7 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::disable() Ref { m_instrumentingAgents.get() }->setEnabledNetworkAgent(nullptr); m_resourcesData->clear(); m_extraRequestHeaders.clear(); @@ -3522,7 +3568,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c continuePendingRequests(); continuePendingResponses(); -@@ -901,6 +908,7 @@ void InspectorNetworkAgent::continuePendingResponses() +@@ -904,6 +911,7 @@ void InspectorNetworkAgent::continuePendingResponses() Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::setExtraHTTPHeaders(Ref<JSON::Object>&& headers) { @@ -3530,7 +3576,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c for (auto& entry : headers.get()) { auto stringValue = entry.value->asString(); if (!!stringValue) -@@ -1148,6 +1156,11 @@ void InspectorNetworkAgent::interceptResponse(const ResourceResponse& response, +@@ -1158,6 +1166,11 @@ void InspectorNetworkAgent::interceptResponse(const ResourceResponse& response, m_frontendDispatcher->responseIntercepted(requestId, resourceResponse.releaseNonNull()); } @@ -3542,7 +3588,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptContinue(const Inspector::Protocol::Network::RequestId& requestId, Inspector::Protocol::Network::NetworkStage networkStage) { switch (networkStage) { -@@ -1177,6 +1190,9 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptWithReq +@@ -1187,6 +1200,9 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptWithReq return makeUnexpected("Missing pending intercept request for given requestId"_s); auto& loader = *pendingRequest->m_loader; @@ -3552,7 +3598,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c ResourceRequest request = loader.request(); if (!!url) request.setURL(URL({ }, url)); -@@ -1272,13 +1288,22 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptRequest +@@ -1282,13 +1298,22 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptRequest response.setHTTPStatusCode(status); response.setHTTPStatusText(String { statusText }); HTTPHeaderMap explicitHeaders; @@ -3576,7 +3622,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c loader->didReceiveResponse(WTF::move(response), [loader, buffer = data.releaseNonNull()]() { if (loader->reachedTerminalState()) return; -@@ -1342,6 +1367,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::setEmulatedCondi +@@ -1352,6 +1377,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::setEmulatedCondi #endif // ENABLE(INSPECTOR_NETWORK_THROTTLING) @@ -3590,7 +3636,7 @@ index 695d96f2e3aa24c7212a3ca879776945988dca30..b87fad8fce6b51a50b8a32898689447c { auto searchResult = Inspector::Protocol::Page::SearchResult::create() diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h -index 74228bbedd0cd1a0f5a890be4e1bd3de6218d037..07122f0183516cb07c15f01e3d129832c12f16fc 100644 +index 5875ac43836d8cbd9b40e82ebf964a34eb65254f..175bd8649c496232fed546ccbb12102722d8608b 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h @@ -35,6 +35,8 @@ @@ -3602,15 +3648,15 @@ index 74228bbedd0cd1a0f5a890be4e1bd3de6218d037..07122f0183516cb07c15f01e3d129832 #include "WebSocket.h" #include <JavaScriptCore/ContentSearchUtilities.h> #include <JavaScriptCore/InspectorBackendDispatchers.h> -@@ -104,6 +106,7 @@ public: +@@ -105,6 +107,7 @@ public: #if ENABLE(INSPECTOR_NETWORK_THROTTLING) Inspector::Protocol::ErrorStringOr<void> setEmulatedConditions(std::optional<int>&& bytesPerSecondLimit) final; #endif + Inspector::Protocol::ErrorStringOr<void> setEmulateOfflineState(bool offline) final; // InspectorInstrumentation - void willRecalculateStyle(); -@@ -135,6 +138,7 @@ public: + void NODELETE willRecalculateStyle(); +@@ -136,6 +139,7 @@ public: bool shouldInterceptResponse(const ResourceResponse&); void interceptResponse(const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler<void(const ResourceResponse&, RefPtr<FragmentedSharedBuffer>)>&&); void interceptRequest(ResourceLoader&, Function<void(const ResourceRequest&)>&&); @@ -3618,19 +3664,19 @@ index 74228bbedd0cd1a0f5a890be4e1bd3de6218d037..07122f0183516cb07c15f01e3d129832 void searchOtherRequests(const JSC::Yarr::RegularExpression&, Ref<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>>&); void searchInRequest(Inspector::Protocol::ErrorString&, const Inspector::Protocol::Network::RequestId&, const String& query, bool caseSensitive, bool isRegex, RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>>&); -@@ -190,6 +194,7 @@ private: - bool m_enabled { false }; +@@ -192,6 +196,7 @@ private: bool m_loadingXHRSynchronously { false }; bool m_interceptionEnabled { false }; + bool m_clearResourceDataOnNavigate { true }; + bool m_stoppingLoadingDueToProcessSwap { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp -index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67bbc184c3f 100644 +index 6bb8dd192ae2fedac06e2b35bb9c6711950d5b23..5fb689a1a62b8fd687b73c590236ac11d5e1fb03 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp -@@ -32,21 +32,27 @@ +@@ -32,6 +32,7 @@ #include "config.h" #include "InspectorPageAgent.h" @@ -3638,8 +3684,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b #include "CachedResource.h" #include "Cookie.h" #include "CookieJar.h" -+#include "CustomHeaderFields.h" - #include "DOMWrapperWorld.h" +@@ -39,14 +40,17 @@ #include "DocumentLoader.h" #include "DocumentResourceLoader.h" #include "DocumentView.h" @@ -3651,14 +3696,13 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b #include "FrameInlines.h" #include "FrameLoadRequest.h" #include "FrameLoader.h" -+#include "FrameLoaderClient.h" #include "FrameSnapshotting.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" - #include "InspectorBackendClient.h" -@@ -55,29 +61,44 @@ + #include "ImageUtilities.h" +@@ -57,30 +61,38 @@ #include "InspectorOverlay.h" #include "InspectorResourceUtilities.h" #include "InstrumentingAgents.h" @@ -3668,12 +3712,10 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b #include "MIMETypeRegistry.h" #include "MemoryCache.h" #include "Page.h" -+#include "PageRuntimeAgent.h" + #include "PageInspectorController.h" +#include "PlatformScreen.h" #include "RenderObjectInlines.h" #include "RenderTheme.h" -+#include "DeprecatedGlobalSettings.h" -+#include "SimpleRange.h" #include "ScriptController.h" #include "ScriptSourceCode.h" +#include "ScrollingCoordinator.h" @@ -3682,9 +3724,8 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b #include "ShouldPartitionCookie.h" #include "StyleScope.h" #include "Theme.h" - #include <pal/text/TextEncoding.h> -+#include "TextIterator.h" +#include "TypingCommand.h" + #include <pal/text/TextEncoding.h> #include "UserGestureIndicator.h" #include <JavaScriptCore/ContentSearchUtilities.h> #include <JavaScriptCore/IdentifiersFactory.h> @@ -3693,9 +3734,6 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b +#include <wtf/DateMath.h> #include <wtf/ListHashSet.h> +#include <wtf/NeverDestroyed.h> -+#include <wtf/ObjectIdentifier.h> -+#include <wtf/Ref.h> -+#include <wtf/RefPtr.h> #include <wtf/Stopwatch.h> #include <wtf/TZoneMallocInlines.h> #include <wtf/text/Base64.h> @@ -3703,7 +3741,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b #include <wtf/text/StringBuilder.h> #if ENABLE(APPLICATION_MANIFEST) -@@ -99,6 +120,11 @@ using namespace Inspector; +@@ -102,6 +114,11 @@ using namespace Inspector; WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorPageAgent); @@ -3712,10 +3750,10 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b + return nameToWorld; +} + - Ref<InspectorOverlay> InspectorPageAgent::protectedOverlay() const + InspectorOverlay& InspectorPageAgent::overlay() const { return m_overlay.get(); -@@ -109,6 +135,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorBacke +@@ -112,6 +129,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorBacke , m_frontendDispatcher(makeUniqueRef<Inspector::PageFrontendDispatcher>(context.frontendRouter)) , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this)) , m_inspectedPage(context.inspectedPage) @@ -3723,7 +3761,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b , m_client(client) , m_overlay(overlay) { -@@ -139,12 +166,20 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::enable() +@@ -142,12 +160,20 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::enable() defaultUserPreferencesDidChange(); @@ -3744,7 +3782,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b std::ignore = setShowPaintRects(false); #if !PLATFORM(IOS_FAMILY) -@@ -197,6 +232,22 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::reload(std::optiona +@@ -200,6 +226,22 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::reload(std::optiona return { }; } @@ -3767,7 +3805,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideUserAgent(const String& value) { m_userAgentOverride = value; -@@ -204,6 +255,13 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideUserAgent(c +@@ -207,6 +249,13 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideUserAgent(c return { }; } @@ -3781,7 +3819,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Inspector::Protocol::Page::Setting setting, std::optional<bool>&& value) { auto& inspectedPageSettings = m_inspectedPage->settings(); -@@ -217,6 +275,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins +@@ -220,6 +269,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setAuthorAndUserStylesEnabledInspectorOverride(value); return { }; @@ -3794,7 +3832,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b case Inspector::Protocol::Page::Setting::ICECandidateFilteringEnabled: inspectedPageSettings.setICECandidateFilteringEnabledInspectorOverride(value); return { }; -@@ -243,6 +307,39 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins +@@ -246,6 +301,39 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins m_client->setDeveloperPreferenceOverride(InspectorBackendClient::DeveloperPreference::NeedsSiteSpecificQuirks, value); return { }; @@ -3834,7 +3872,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b case Inspector::Protocol::Page::Setting::ScriptEnabled: inspectedPageSettings.setScriptEnabledInspectorOverride(value); return { }; -@@ -255,6 +352,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins +@@ -258,6 +346,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setShowRepaintCounterInspectorOverride(value); return { }; @@ -3847,7 +3885,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b case Inspector::Protocol::Page::Setting::WebSecurityEnabled: inspectedPageSettings.setWebSecurityEnabledInspectorOverride(value); return { }; -@@ -664,15 +767,16 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setShowPaintRects(b +@@ -670,15 +764,16 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setShowPaintRects(b return { }; } @@ -3869,7 +3907,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b } void InspectorPageAgent::frameNavigated(LocalFrame& frame) -@@ -680,13 +784,29 @@ void InspectorPageAgent::frameNavigated(LocalFrame& frame) +@@ -686,6 +781,22 @@ void InspectorPageAgent::frameNavigated(LocalFrame& frame) m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame)); } @@ -3891,48 +3929,8 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b + void InspectorPageAgent::frameDetached(LocalFrame& frame) { -- auto identifier = m_frameToIdentifier.take(frame); -- if (identifier.isNull()) -+ String identifier = serializeFrameID(frame.frameID()); -+ if (!m_identifierToFrame.take(identifier)) - return; -+ - m_frontendDispatcher->frameDetached(identifier); -- m_identifierToFrame.remove(identifier); - } - - Frame* InspectorPageAgent::frameForId(const Inspector::Protocol::Network::FrameId& frameId) -@@ -698,20 +818,21 @@ String InspectorPageAgent::frameId(Frame* frame) - { - if (!frame) - return emptyString(); -- return m_frameToIdentifier.ensure(*frame, [this, frame] { -- auto identifier = IdentifiersFactory::createIdentifier(); -- m_identifierToFrame.set(identifier, frame); -- return identifier; -- }).iterator->value; -+ String identifier = serializeFrameID(frame->frameID()); -+ m_identifierToFrame.set(identifier, frame); -+ return identifier; - } - - String InspectorPageAgent::loaderId(DocumentLoader* loader) - { - if (!loader) - return emptyString(); -- return m_loaderToIdentifier.ensure(loader, [] { -- return IdentifiersFactory::createIdentifier(); -- }).iterator->value; -+ -+ auto navigationID = loader->navigationID(); -+ if (!navigationID) -+ return emptyString(); -+ -+ return String::number(navigationID->toUInt64()); - } - - LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& errorString, const Inspector::Protocol::Network::FrameId& frameId) -@@ -766,6 +887,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange() + auto identifier = m_inspectedPage->inspectorController().identifierRegistry().takeFrame(frame); +@@ -758,6 +869,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange() m_frontendDispatcher->defaultUserPreferencesDidChange(WTF::move(defaultUserPreferences)); } @@ -3945,7 +3943,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b #if ENABLE(DARK_MODE_CSS) void InspectorPageAgent::defaultAppearanceDidChange() { -@@ -779,6 +906,9 @@ void InspectorPageAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapp +@@ -771,6 +888,9 @@ void InspectorPageAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapp return; if (m_bootstrapScript.isEmpty()) @@ -3955,8 +3953,8 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b return; frame.script().evaluateIgnoringException(ScriptSourceCode(m_bootstrapScript, JSC::SourceTaintedOrigin::Untainted, URL { "web-inspector://bootstrap.js"_str })); -@@ -826,6 +956,51 @@ void InspectorPageAgent::didRecalculateStyle() - protectedOverlay()->update(); +@@ -818,6 +938,51 @@ void InspectorPageAgent::didRecalculateStyle() + protect(overlay())->update(); } +void InspectorPageAgent::runOpenPanel(HTMLInputElement* element, bool* intercept) @@ -4007,7 +4005,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b Ref<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(LocalFrame* frame) { ASSERT_ARG(frame, frame); -@@ -919,6 +1094,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent) +@@ -911,6 +1076,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent) userAgent = m_userAgentOverride; } @@ -4020,8 +4018,8 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b void InspectorPageAgent::applyEmulatedMedia(AtomString& media) { if (!m_emulatedMedia.isEmpty()) -@@ -934,7 +1115,7 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotNode(Insp - Node* node = domAgent->assertNode(errorString, nodeId); +@@ -926,7 +1097,7 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotNode(Insp + RefPtr node = domAgent->assertNode(errorString, nodeId); if (!node) return makeUnexpected(errorString); - @@ -4029,8 +4027,8 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b RefPtr localMainFrame = m_inspectedPage->localMainFrame(); if (!localMainFrame) return makeUnexpected("Main frame isn't local"_s); -@@ -946,11 +1127,13 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotNode(Insp - return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); +@@ -937,11 +1108,13 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotNode(Insp + return encodeDataURL(WTF::move(snapshot), "image/png"_s); } -Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem coordinateSystem) @@ -4044,8 +4042,8 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b IntRect rectangle(x, y, width, height); RefPtr localMainFrame = m_inspectedPage->localMainFrame(); -@@ -964,6 +1147,43 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotRect(int - return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); +@@ -954,6 +1127,43 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotRect(int + return encodeDataURL(WTF::move(snapshot), "image/png"_s); } +Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setForcedColors(std::optional<Inspector::Protocol::Page::ForcedColors>&& forcedColors) @@ -4088,7 +4086,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b #if ENABLE(WEB_ARCHIVE) && USE(CF) Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::archive() { -@@ -980,7 +1200,6 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::archive() +@@ -970,7 +1180,6 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::archive() } #endif @@ -4096,7 +4094,7 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setScreenSizeOverride(std::optional<int>&& width, std::optional<int>&& height) { if (width.has_value() != height.has_value()) -@@ -998,6 +1217,84 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setScreenSizeOverri +@@ -988,6 +1197,86 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setScreenSizeOverri localMainFrame->setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0))); return { }; } @@ -4155,6 +4153,8 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b +{ + for (Frame* frame = &m_inspectedPage->mainFrame(); frame; frame = frame->tree().traverseNext()) { + auto* localFrame = dynamicDowncast<LocalFrame>(frame); ++ if (!localFrame) ++ continue; + for (auto* world : worlds) + localFrame->windowProxy().jsWindowProxy(*world)->window(); + } @@ -4183,10 +4183,15 @@ index 736145be7718ac0c15480dbfe7bf3813fa254b9f..b16a37ec4de3400d19a8a706ba59d67b } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h -index d3b89895516a53d0aa2913687ba05e77aaa8c5b1..f71896e61c08cb67a22d00f094195ab49d0fb6e7 100644 +index 97c3cf09961f5c5ea7ede70d35755639fc66a3df..d5aabfbb3062f6037415bb3e136d3d7cebdfbbfd 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h -@@ -47,6 +47,7 @@ +@@ -43,10 +43,12 @@ + #include <wtf/Seconds.h> + #include <wtf/TZoneMalloc.h> + #include <wtf/WeakRef.h> ++#include <wtf/Vector.h> + #include <wtf/text/WTFString.h> namespace Inspector { enum class ResourceType; @@ -4194,15 +4199,15 @@ index d3b89895516a53d0aa2913687ba05e77aaa8c5b1..f71896e61c08cb67a22d00f094195ab4 } namespace WebCore { -@@ -54,6 +55,7 @@ namespace WebCore { +@@ -54,6 +56,7 @@ namespace WebCore { class DOMWrapperWorld; class DocumentLoader; class Frame; +class HTMLInputElement; - class InspectorBackendClient; class InspectorOverlay; class LocalFrame; -@@ -69,6 +71,9 @@ public: + class Page; +@@ -68,6 +71,9 @@ public: InspectorPageAgent(PageAgentContext&, InspectorBackendClient*, InspectorOverlay&); ~InspectorPageAgent(); @@ -4212,7 +4217,7 @@ index d3b89895516a53d0aa2913687ba05e77aaa8c5b1..f71896e61c08cb67a22d00f094195ab4 // InspectorAgentBase void didCreateFrontendAndBackend(); void willDestroyFrontendAndBackend(Inspector::DisconnectReason); -@@ -77,7 +82,10 @@ public: +@@ -76,7 +82,10 @@ public: Inspector::Protocol::ErrorStringOr<void> enable(); Inspector::Protocol::ErrorStringOr<void> disable(); Inspector::Protocol::ErrorStringOr<void> reload(std::optional<bool>&& ignoreCache, std::optional<bool>&& revalidateAllResources); @@ -4223,7 +4228,7 @@ index d3b89895516a53d0aa2913687ba05e77aaa8c5b1..f71896e61c08cb67a22d00f094195ab4 Inspector::Protocol::ErrorStringOr<void> overrideSetting(Inspector::Protocol::Page::Setting, std::optional<bool>&& value); Inspector::Protocol::ErrorStringOr<void> overrideUserPreference(Inspector::Protocol::Page::UserPreferenceName, std::optional<Inspector::Protocol::Page::UserPreferenceValue>&&); Inspector::Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Inspector::Protocol::Page::Cookie>>> getCookies(); -@@ -93,41 +101,60 @@ public: +@@ -92,41 +101,60 @@ public: #endif Inspector::Protocol::ErrorStringOr<void> setShowPaintRects(bool); Inspector::Protocol::ErrorStringOr<void> setEmulatedMedia(const String&); @@ -4287,9 +4292,9 @@ index d3b89895516a53d0aa2913687ba05e77aaa8c5b1..f71896e61c08cb67a22d00f094195ab4 double timestamp(); + void ensureUserWorldsExistInAllFrames(const Vector<DOMWrapperWorld*>&); - Ref<InspectorOverlay> protectedOverlay() const; + InspectorOverlay& NODELETE overlay() const; -@@ -142,17 +169,21 @@ private: +@@ -141,14 +169,19 @@ private: const Ref<Inspector::PageBackendDispatcher> m_backendDispatcher; WeakRef<Page> m_inspectedPage; @@ -4297,9 +4302,6 @@ index d3b89895516a53d0aa2913687ba05e77aaa8c5b1..f71896e61c08cb67a22d00f094195ab4 InspectorBackendClient* m_client { nullptr }; WeakRef<InspectorOverlay> m_overlay; -- WeakHashMap<Frame, String> m_frameToIdentifier; - MemoryCompactRobinHoodHashMap<String, WeakPtr<Frame>> m_identifierToFrame; - HashMap<DocumentLoader*, String> m_loaderToIdentifier; String m_userAgentOverride; + String m_platformOverride; AtomString m_emulatedMedia; @@ -4313,26 +4315,28 @@ index d3b89895516a53d0aa2913687ba05e77aaa8c5b1..f71896e61c08cb67a22d00f094195ab4 } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp -index 99c4b223a9bb34d7ef41fa7e5024c6893d61e57e..d6d17ab97b32ce5761f13e02dea21fe7150dba1b 100644 +index e93e93df33a77cf1995340ff1375488efee0a9df..002c160eec98597f97d547f6f2722b7edb58be72 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp -@@ -35,6 +35,7 @@ +@@ -35,7 +35,9 @@ #include "DOMWrapperWorld.h" #include "Document.h" #include "FrameConsoleClient.h" +#include "FrameLoader.h" - #include "InspectorPageAgent.h" + #include "InspectorIdentifierRegistry.h" ++#include "InspectorPageAgent.h" #include "InstrumentingAgents.h" #include "JSDOMWindowCustom.h" -@@ -42,6 +43,7 @@ - #include "LocalFrame.h" + #include "JSExecState.h" +@@ -43,6 +45,7 @@ #include "Page.h" + #include "PageInspectorController.h" #include "ScriptController.h" +#include "ScriptSourceCode.h" #include "SecurityOrigin.h" #include "UserGestureEmulationScope.h" #include <JavaScriptCore/InjectedScript.h> -@@ -90,13 +92,74 @@ Inspector::Protocol::ErrorStringOr<void> PageRuntimeAgent::disable() +@@ -90,13 +93,74 @@ Inspector::Protocol::ErrorStringOr<void> PageRuntimeAgent::disable() { Ref { m_instrumentingAgents.get() }->setEnabledPageRuntimeAgent(nullptr); @@ -4360,7 +4364,7 @@ index 99c4b223a9bb34d7ef41fa7e5024c6893d61e57e..d6d17ab97b32ce5761f13e02dea21fe7 + if (!callFrame->jsCallee()) + return result; + String bindingName; -+ if (auto* function = JSC::jsDynamicCast<JSC::JSFunction*>(callFrame->jsCallee())) ++ if (auto* function = dynamicDowncast<JSC::JSFunction>(callFrame->jsCallee())) + bindingName = function->name(globalObject->vm()); + auto client = globalObject->consoleClient(); + if (!client) @@ -4407,11 +4411,12 @@ index 99c4b223a9bb34d7ef41fa7e5024c6893d61e57e..d6d17ab97b32ce5761f13e02dea21fe7 } void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapperWorld& world) -@@ -105,7 +168,26 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper - if (!pageAgent) +@@ -105,7 +169,29 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper + if (frameId.isEmpty()) return; -+ if (pageAgent->ignoreDidClearWindowObject()) ++ auto* pageAgent = Ref { m_instrumentingAgents.get() }->enabledPageAgent(); ++ if (pageAgent && pageAgent->ignoreDidClearWindowObject()) + return; + + if (world.isNormal()) { @@ -4419,9 +4424,11 @@ index 99c4b223a9bb34d7ef41fa7e5024c6893d61e57e..d6d17ab97b32ce5761f13e02dea21fe7 + addBindingToFrame(frame, name); + } + -+ pageAgent->setIgnoreDidClearWindowObject(true); - notifyContextCreated(pageAgent->frameId(&frame), frame.script().globalObject(world), world); -+ pageAgent->setIgnoreDidClearWindowObject(false); ++ if (pageAgent) ++ pageAgent->setIgnoreDidClearWindowObject(true); + notifyContextCreated(frameId, frame.script().globalObject(world), world); ++ if (pageAgent) ++ pageAgent->setIgnoreDidClearWindowObject(false); +} + +void PageRuntimeAgent::didReceiveMainResourceError(LocalFrame& frame) @@ -4434,14 +4441,14 @@ index 99c4b223a9bb34d7ef41fa7e5024c6893d61e57e..d6d17ab97b32ce5761f13e02dea21fe7 } InjectedScript PageRuntimeAgent::injectedScriptForEval(Inspector::Protocol::ErrorString& errorString, std::optional<Inspector::Protocol::Runtime::ExecutionContextId>&& executionContextId) -@@ -144,9 +226,6 @@ void PageRuntimeAgent::reportExecutionContextCreation() - return; +@@ -142,9 +228,6 @@ void PageRuntimeAgent::reportExecutionContextCreation() + Ref identifierRegistry = m_inspectedPage->inspectorController().identifierRegistry(); m_inspectedPage->forEachLocalFrame([&](LocalFrame& frame) { - if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) - return; - - auto frameId = pageAgent->frameId(&frame); + auto frameId = identifierRegistry->frameId(&frame); // Always send the main world first. diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h @@ -4479,7 +4486,7 @@ index db4e1b7cd5ba1c46f962c07fa6e23cb13092832c..f7fb1503fc42b4b5fd21f76a893c8403 } // namespace WebCore diff --git a/Source/WebCore/loader/CookieJar.h b/Source/WebCore/loader/CookieJar.h -index ed8bec9c10c9d1bf659efab09f77ad7d8e439594..49bdaf8b08d157ecb7cd412ea847eb8ceedb8adf 100644 +index c2f9d5d90ff590154ef39132453194c162be0cc5..ff36e34f9e5963f1deaa41341174a7fd312ae25f 100644 --- a/Source/WebCore/loader/CookieJar.h +++ b/Source/WebCore/loader/CookieJar.h @@ -48,6 +48,7 @@ class NetworkStorageSession; @@ -4490,7 +4497,7 @@ index ed8bec9c10c9d1bf659efab09f77ad7d8e439594..49bdaf8b08d157ecb7cd412ea847eb8c class WEBCORE_EXPORT CookieJar : public RefCountedAndCanMakeWeakPtr<CookieJar> { public: -@@ -80,6 +81,9 @@ public: +@@ -82,6 +83,9 @@ public: virtual void clearCache() { } virtual void clearCacheForHost(const String&) { } @@ -4501,119 +4508,10 @@ index ed8bec9c10c9d1bf659efab09f77ad7d8e439594..49bdaf8b08d157ecb7cd412ea847eb8c protected: static SameSiteInfo sameSiteInfo(const Document&, IsForDOMCookieAccess = IsForDOMCookieAccess::No); diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp -index a0c561dd044d7037385d22b6d5f818e93af08a90..064bc1ab5248e128a167b8c9bd6ea0114962e7f2 100644 +index a060ef80b1c658b388324d5c3f724097fb5c3787..70a1c51d4e2b6e396afd5e5dbf9ad00cf88d42e8 100644 --- a/Source/WebCore/loader/DocumentLoader.cpp +++ b/Source/WebCore/loader/DocumentLoader.cpp -@@ -7,13 +7,13 @@ - * are met: - * - * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -+ * 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. -+ * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived -- * from this software without specific prior written permission. -+ * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -@@ -266,7 +266,7 @@ void DocumentLoader::setRequest(ResourceRequest&& req) - shouldNotifyAboutProvisionalURLChange = true; - - // We should never be getting a redirect callback after the data -- // source is committed, except in the unreachable URL case. It -+ // source is committed, except in the unreachable URL case. It - // would be a WebFoundation bug if it sent a redirect callback after commit. - ASSERT(!m_committed); - -@@ -324,8 +324,8 @@ void DocumentLoader::frameDestroyed() - } - - // Cancels the data source's pending loads. Conceptually, a data source only loads --// one document at a time, but one document may have many related resources. --// stopLoading will stop all loads initiated by the data source, -+// one document at a time, but one document may have many related resources. -+// stopLoading will stop all loads initiated by the data source, - // but not loads initiated by child frames' data sources -- that's the WebFrame's job. - void DocumentLoader::stopLoading() - { -@@ -355,7 +355,7 @@ void DocumentLoader::stopLoading() - callback(nullptr); - m_iconLoaders.clear(); - m_iconsPendingLoadDecision.clear(); -- -+ - #if ENABLE(APPLICATION_MANIFEST) - m_applicationManifestLoader = nullptr; - m_finishedLoadingApplicationManifest = false; -@@ -367,19 +367,19 @@ void DocumentLoader::stopLoading() - - if (RefPtr document = this->document()) - document->suspendFontLoading(); -- -+ - #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML) - clearArchiveResources(); - #endif - - if (!loading) { -- // If something above restarted loading we might run into mysterious crashes like -+ // If something above restarted loading we might run into mysterious crashes like - // https://bugs.webkit.org/show_bug.cgi?id=62764 and <rdar://problem/9328684> - ASSERT(!isLoading()); - return; - } - -- // We might run in to infinite recursion if we're stopping loading as the result of -+ // We might run in to infinite recursion if we're stopping loading as the result of - // detaching from the frame, so break out of that recursion here. - // See <rdar://problem/9673866> for more details. - if (m_isStopping) -@@ -409,10 +409,10 @@ void DocumentLoader::stopLoading() - // in unexpected side effects such as erroneous event dispatch. ( http://webkit.org/b/117112 ) - if (RefPtr document = this->document()) - document->cancelParsing(); -- -+ - stopLoadingSubresources(); - stopLoadingPlugIns(); -- -+ - m_isStopping = false; - } - -@@ -500,7 +500,7 @@ void DocumentLoader::finishedLoading() - maybeFinishLoadingMultipartContent(); - - timing().markEndTime(); -- -+ - commitIfReady(); - RefPtr frameLoader = this->frameLoader(); - if (!frameLoader) -@@ -640,7 +640,7 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc - { - // Note that there are no asserts here as there are for the other callbacks. This is due to the - // fact that this "callback" is sent when starting every load, and the state of callback -- // deferrals plays less of a part in this function in preventing the bad behavior deferring -+ // deferrals plays less of a part in this function in preventing the bad behavior deferring - // callbacks is meant to prevent. - ASSERT(!newRequest.isNull()); - -@@ -717,7 +717,7 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc - - RefPtr document = frame->document(); - ASSERT(document); -- -+ - // Update cookie policy base URL as URL changes, except for subframes, which use the - // URL of the main frame which doesn't change when we redirect. - if (frame->isMainFrame()) -@@ -769,8 +769,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc +@@ -787,8 +787,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc if (!didReceiveRedirectResponse) return completionHandler(WTF::move(newRequest)); @@ -4624,7 +4522,7 @@ index a0c561dd044d7037385d22b6d5f818e93af08a90..064bc1ab5248e128a167b8c9bd6ea011 switch (navigationPolicyDecision) { case NavigationPolicyDecision::IgnoreLoad: case NavigationPolicyDecision::LoadWillContinueInAnotherProcess: -@@ -1558,11 +1560,17 @@ void DocumentLoader::detachFromFrame(LoadWillContinueInAnotherProcess loadWillCo +@@ -1590,11 +1592,17 @@ void DocumentLoader::detachFromFrame(LoadWillContinueInAnotherProcess loadWillCo if (auto navigationID = std::exchange(m_navigationID, { })) frame->loader().client().documentLoaderDetached(*navigationID, loadWillContinueInAnotherProcess); @@ -4644,42 +4542,24 @@ index a0c561dd044d7037385d22b6d5f818e93af08a90..064bc1ab5248e128a167b8c9bd6ea011 void DocumentLoader::setNavigationID(NavigationIdentifier navigationID) { m_navigationID = navigationID; -@@ -1699,7 +1707,7 @@ bool DocumentLoader::maybeCreateArchive() - m_archive = archive.copyRef(); - if (!archive) - return false; -- -+ - addAllArchiveResources(*archive); - ASSERT(archive->mainResource()); - Ref mainResource = *archive->mainResource(); -@@ -1778,7 +1786,7 @@ RefPtr<ArchiveResource> DocumentLoader::subresource(const URL& url) const - { - if (!isCommitted()) - return nullptr; -- -+ - auto* resource = m_cachedResourceLoader->cachedResource(url); - if (!resource || !resource->isLoaded()) - return archiveResourceForURL(url); diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h -index de644ddbc38f74d3edee5c66b69c23fb97455c4b..1a74efb2c13dfefb505d67c188a39301dbd6e255 100644 +index ffebadc8882ffd9a519fdaec8d42ac2909c5fe65..145e7ee21440d14da048d59f7c177c8d334e0ee3 100644 --- a/Source/WebCore/loader/DocumentLoader.h +++ b/Source/WebCore/loader/DocumentLoader.h -@@ -213,6 +213,8 @@ public: +@@ -209,6 +209,8 @@ public: WEBCORE_EXPORT virtual void detachFromFrame(LoadWillContinueInAnotherProcess); + void replacedByFragmentNavigation(LocalFrame&); + - WEBCORE_EXPORT FrameLoader* frameLoader() const; - WEBCORE_EXPORT SubresourceLoader* mainResourceLoader() const; + WEBCORE_EXPORT FrameLoader* NODELETE frameLoader() const; + WEBCORE_EXPORT SubresourceLoader* NODELETE mainResourceLoader() const; WEBCORE_EXPORT RefPtr<FragmentedSharedBuffer> mainResourceData() const; diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp -index ae5f9ae95fd8c3d434e26e05b24e7e22825eaf7c..fbae9958f0c7ef3832609849c93a3d7c4940c44e 100644 +index 994f22fa6190e271f9f9927caa6a331c355cc43e..3f469ef6abebeea6f7df6b9406c8c0e9cd5fe386 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp -@@ -1354,6 +1354,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr<SerializedScriptValue> stat +@@ -1385,6 +1385,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr<SerializedScriptValue> stat } m_client->dispatchDidNavigateWithinPage(); @@ -4687,15 +4567,15 @@ index ae5f9ae95fd8c3d434e26e05b24e7e22825eaf7c..fbae9958f0c7ef3832609849c93a3d7c document->statePopped(stateObject ? stateObject.releaseNonNull() : SerializedScriptValue::nullValue()); m_client->dispatchDidPopStateWithinPage(); -@@ -1903,6 +1904,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t +@@ -1938,6 +1939,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t const String& httpMethod = loader->request().httpMethod(); - if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) { + if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL) && !loader->substituteData().isValid()) { + loader->replacedByFragmentNavigation(m_frame); RefPtr oldDocumentLoader = m_documentLoader; NavigationAction action { protect(frame->document()).releaseNonNull(), loader->request(), InitiatedByMainFrame::Unknown, loader->isRequestFromClientOrUserInput(), policyChecker().loadType(), isFormSubmission }; -@@ -1941,7 +1943,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t +@@ -1977,7 +1979,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t auto policyDecisionMode = loader->triggeringAction().isFromNavigationAPI() ? PolicyDecisionMode::Synchronous : PolicyDecisionMode::Asynchronous; RELEASE_ASSERT(!isBackForwardLoadType(policyChecker().loadType()) || history().provisionalItem()); @@ -4705,7 +4585,7 @@ index ae5f9ae95fd8c3d434e26e05b24e7e22825eaf7c..fbae9958f0c7ef3832609849c93a3d7c continueLoadAfterNavigationPolicy(request, RefPtr { weakFormSubmission.get() }.get(), navigationPolicyDecision, allowNavigationToInvalidURL); completionHandler(); }, policyDecisionMode, determineNavigationType(type, NavigationHistoryBehavior::Auto)); -@@ -3286,10 +3290,15 @@ String FrameLoader::userAgent(const URL& url) const +@@ -3324,10 +3328,15 @@ String FrameLoader::userAgent(const URL& url) const String FrameLoader::navigatorPlatform() const { @@ -4723,8 +4603,8 @@ index ae5f9ae95fd8c3d434e26e05b24e7e22825eaf7c..fbae9958f0c7ef3832609849c93a3d7c } void FrameLoader::dispatchOnloadEvents() -@@ -3741,6 +3750,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error, LoadWill - checkCompleted(); +@@ -3785,6 +3794,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error, LoadWill + } if (frame->page()) checkLoadComplete(loadWillContinueInAnotherProcess); + @@ -4732,7 +4612,7 @@ index ae5f9ae95fd8c3d434e26e05b24e7e22825eaf7c..fbae9958f0c7ef3832609849c93a3d7c } void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, const SecurityOrigin* requesterOrigin, bool shouldContinue, NavigationHistoryBehavior historyHandling) -@@ -4693,9 +4704,6 @@ String FrameLoader::referrer() const +@@ -4789,9 +4800,6 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() { @@ -4742,7 +4622,7 @@ index ae5f9ae95fd8c3d434e26e05b24e7e22825eaf7c..fbae9958f0c7ef3832609849c93a3d7c Vector<Ref<DOMWrapperWorld>> worlds; ScriptController::getAllWorlds(worlds); for (auto& world : worlds) -@@ -4705,13 +4713,12 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() +@@ -4801,13 +4809,12 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) { Ref frame = m_frame.get(); @@ -4775,7 +4655,7 @@ index 9a5561ea2fa43baab02c7f8d43d29cf4a5543411..4b1c8dfd6be705aa3560685bb2453dd4 virtual bool shouldPerformSecurityChecks() const { return false; } virtual bool havePerformedSecurityChecks(const ResourceResponse&) const { return false; } diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp -index 11161be2551c2a80ffc1d75c4454621a43576bd2..2549d584195355f2e4559ee7913e25d82da1ba26 100644 +index 3acb026789c46395be3f8cd6b837ebf207e215f7..a4e3c1e69fbbb108badd23f32e879423c0ec72e6 100644 --- a/Source/WebCore/loader/ProgressTracker.cpp +++ b/Source/WebCore/loader/ProgressTracker.cpp @@ -158,6 +158,8 @@ void ProgressTracker::progressCompleted(LocalFrame& frame) @@ -4797,10 +4677,10 @@ index 11161be2551c2a80ffc1d75c4454621a43576bd2..2549d584195355f2e4559ee7913e25d8 } diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp -index 08cd1cb04c8c8213b32effd331dab3466bdccac9..1b87e7801fcc1f1ba289ee2b37ee298266e1f022 100644 +index 01466dae0f43c53e7e50dad34c73731fbc8240d6..f37b4130add559d50a869ab494a3f7fb99b275d1 100644 --- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp +++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp -@@ -1132,8 +1132,11 @@ ResourceErrorOr<CachedResourceHandle<CachedResource>> CachedResourceLoader::requ +@@ -1159,8 +1159,11 @@ ResourceErrorOr<Ref<CachedResource>> CachedResourceLoader::requestResource(Cache request.updateReferrerPolicy(document ? document->referrerPolicy() : ReferrerPolicy::Default); @@ -4812,11 +4692,11 @@ index 08cd1cb04c8c8213b32effd331dab3466bdccac9..1b87e7801fcc1f1ba289ee2b37ee2982 + // request.setCachingPolicy(CachingPolicy::DisallowCaching); + } - if (RefPtr documentLoader = m_documentLoader.get()) { + if (RefPtr documentLoader = m_documentLoader) { bool madeHTTPS { request.resourceRequest().wasSchemeOptimisticallyUpgraded() }; -@@ -1786,8 +1789,9 @@ Vector<Ref<SVGImage>> CachedResourceLoader::allCachedSVGImages() const +@@ -1817,8 +1820,9 @@ Vector<Ref<SVGImage>> CachedResourceLoader::allCachedSVGImages() const - ResourceErrorOr<CachedResourceHandle<CachedResource>> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request) + ResourceErrorOr<Ref<CachedResource>> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request) { - if (InspectorInstrumentation::willIntercept(protect(frame()).get(), request.resourceRequest())) - return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s }); @@ -4824,13 +4704,13 @@ index 08cd1cb04c8c8213b32effd331dab3466bdccac9..1b87e7801fcc1f1ba289ee2b37ee2982 + // if (InspectorInstrumentation::willIntercept(protect(frame()).get(), request.resourceRequest())) + // return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s }); - RefPtr document = m_document.get(); + RefPtr document = m_document; ASSERT(document); diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h -index 2ca94f05a703d9d15f2c5453eed734c658ef1132..8ed2fce6feb37532b3a3b16dc4816b3406678cfb 100644 +index 1a4fae919b725be107c91cde64f8ccfa30b1e839..2687ebc237823715ebfa06440d54e9dd6dbddd8e 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h -@@ -403,7 +403,7 @@ public: +@@ -408,7 +408,7 @@ public: #endif #if ENABLE(ORIENTATION_EVENTS) @@ -4840,10 +4720,10 @@ index 2ca94f05a703d9d15f2c5453eed734c658ef1132..8ed2fce6feb37532b3a3b16dc4816b34 virtual RefPtr<ColorChooser> createColorChooser(ColorChooserClient&, const Color&) = 0; diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp -index e273214a726f85c3a898d0a76c76c7035edeb36c..c1c07dbe4481702e768db0696f2a413bc1075d57 100644 +index d425f52413eba85996fc0a1fae3a0af0974a1d5d..4fa3846cd38402a61676be5330e354ed7d96f92b 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp -@@ -4760,6 +4760,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr +@@ -4823,6 +4823,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr if (!document) return false; @@ -4856,7 +4736,7 @@ index e273214a726f85c3a898d0a76c76c7035edeb36c..c1c07dbe4481702e768db0696f2a413b dragState().dataTransfer = DataTransfer::createForDrag(*document); auto hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No; -@@ -5364,6 +5370,7 @@ static HitTestResult hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& +@@ -5427,6 +5433,7 @@ static HitTestResult hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& return result; } @@ -4864,43 +4744,16 @@ index e273214a726f85c3a898d0a76c76c7035edeb36c..c1c07dbe4481702e768db0696f2a413b Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(const PlatformTouchEvent& event) { Ref frame = m_frame.get(); -@@ -5437,7 +5444,7 @@ Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(co - - // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap. - unsigned touchPointTargetKey = point.id() + 1; --#if PLATFORM(WPE) -+#if !ENABLE(IOS_TOUCH_EVENTS) - bool pointerCancelled = false; - #endif - RefPtr<EventTarget> touchTarget; -@@ -5484,7 +5491,7 @@ Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(co - // we also remove it from the map. - touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey); - --#if PLATFORM(WPE) -+#if !ENABLE(IOS_TOUCH_EVENTS) - HitTestResult result = hitTestResultAtPoint(pagePoint, hitType | HitTestRequest::Type::AllowChildFrameContent); - pointerTarget = result.targetElement(); - pointerCancelled = (pointerTarget != touchTarget); -@@ -5509,7 +5516,7 @@ Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(co +@@ -5558,7 +5565,7 @@ Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(co if (!targetFrame) continue; --#if PLATFORM(WPE) -+#if !ENABLE(IOS_TOUCH_EVENTS) - // FIXME: WPE currently does not send touch stationary events, so create a naive TouchReleased PlatformTouchPoint - // on release if the hit test result changed since the previous TouchPressed or TouchMoved - if (pointState == PlatformTouchPoint::TouchReleased && pointerCancelled) { -@@ -5523,7 +5530,7 @@ Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(co - } - #endif - -#if PLATFORM(WPE) || PLATFORM(GTK) +#if !ENABLE(IOS_TOUCH_EVENTS) - // FIXME: Pass the touch delta for pointermove events by remembering the position per pointerID similar to - // Apple's m_touchLastGlobalPositionAndDeltaMap - protect(document->page())->pointerCaptureController().dispatchEventForTouchAtIndex( -@@ -5598,6 +5605,7 @@ Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(co + RefPtr<EventTarget> pointerTarget = touchTarget; + + if (pointState != PlatformTouchPoint::TouchPressed) { +@@ -5654,6 +5661,7 @@ Expected<bool, RemoteFrameGeometryTransformer> EventHandler::handleTouchEvent(co return swallowedEvent; } @@ -4909,10 +4762,10 @@ index e273214a726f85c3a898d0a76c76c7035edeb36c..c1c07dbe4481702e768db0696f2a413b #if ENABLE(TOUCH_EVENTS) diff --git a/Source/WebCore/page/FocusController.cpp b/Source/WebCore/page/FocusController.cpp -index c513e8afbce1f96d5bad3e86ee40f9c673026511..9cf4757d8b4a93f4f3a3b77e0055deefaa6c9a26 100644 +index 1862c8160a30a39f04c64819ab4be917fba219ca..b1877c40f4111f02d448ed9d5df2a2c5723f3a5b 100644 --- a/Source/WebCore/page/FocusController.cpp +++ b/Source/WebCore/page/FocusController.cpp -@@ -635,13 +635,14 @@ bool FocusController::relinquishFocusToChrome(FocusDirection direction) +@@ -708,13 +708,14 @@ bool FocusController::relinquishFocusToChrome(FocusDirection direction) return false; Ref page = m_page.get(); @@ -4930,10 +4783,10 @@ index c513e8afbce1f96d5bad3e86ee40f9c673026511..9cf4757d8b4a93f4f3a3b77e0055deef } diff --git a/Source/WebCore/page/FrameConsoleClient.cpp b/Source/WebCore/page/FrameConsoleClient.cpp -index b288e17d7ed9adebc63503f868ab99a83d65cdeb..b4fbb17112af2b3eed8056eb09c84920e92827cc 100644 +index 23e6d8380ec1e3488bc746887ea06be8eed79fb9..7a1b91c923530472bf1bd613a237dd5a8739b88f 100644 --- a/Source/WebCore/page/FrameConsoleClient.cpp +++ b/Source/WebCore/page/FrameConsoleClient.cpp -@@ -471,4 +471,12 @@ void FrameConsoleClient::screenshot(JSC::JSGlobalObject* lexicalGlobalObject, Re +@@ -478,4 +478,12 @@ void FrameConsoleClient::screenshot(JSC::JSGlobalObject* lexicalGlobalObject, Re addMessage(makeUnique<Inspector::ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Image, MessageLevel::Log, dataURL, ScriptArguments::create(lexicalGlobalObject, WTF::move(adjustedArguments)), lexicalGlobalObject, /* requestIdentifier */ 0, timestamp)); } @@ -4947,7 +4800,7 @@ index b288e17d7ed9adebc63503f868ab99a83d65cdeb..b4fbb17112af2b3eed8056eb09c84920 + } // namespace WebCore diff --git a/Source/WebCore/page/FrameConsoleClient.h b/Source/WebCore/page/FrameConsoleClient.h -index 1cb164735331abf30b1eae0b49b827d251dcc3c9..7d0ccff34bab67f4b4f3345e69dd0a0fb9578cc9 100644 +index 7a6671ff0da0bbec833318a1c37e6280ad9f4255..5a16fa04c515f0c3842d1187eeacc487a7491080 100644 --- a/Source/WebCore/page/FrameConsoleClient.h +++ b/Source/WebCore/page/FrameConsoleClient.h @@ -92,6 +92,7 @@ private: @@ -4959,10 +4812,10 @@ index 1cb164735331abf30b1eae0b49b827d251dcc3c9..7d0ccff34bab67f4b4f3345e69dd0a0f WeakRef<LocalFrame> m_frame; }; diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp -index 729093bd1ad56a1fcbea91f1f5df661d3a33ebaf..5780aa53bbaa26c5019109963fa8d1f647a11984 100644 +index dd21eb7cd8958c99a153769d26e03a8eb5bed0fb..a94d8b5d2eced11e03f963d3848159914d554ae3 100644 --- a/Source/WebCore/page/FrameSnapshotting.cpp +++ b/Source/WebCore/page/FrameSnapshotting.cpp -@@ -118,7 +118,7 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& +@@ -121,7 +121,7 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& // Other paint behaviors are set by paintContentsForSnapshot. frame.view()->setPaintBehavior(paintBehavior); @@ -4971,7 +4824,7 @@ index 729093bd1ad56a1fcbea91f1f5df661d3a33ebaf..5780aa53bbaa26c5019109963fa8d1f6 if (options.flags.contains(SnapshotFlags::PaintWith3xBaseScale)) scaleFactor = 3; -@@ -137,6 +137,8 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& +@@ -140,6 +140,8 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& return nullptr; buffer->context().translate(-imageRect.location()); @@ -4980,7 +4833,7 @@ index 729093bd1ad56a1fcbea91f1f5df661d3a33ebaf..5780aa53bbaa26c5019109963fa8d1f6 if (!clipRects.isEmpty()) { Path clipPath; -@@ -145,7 +147,10 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& +@@ -148,7 +150,10 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& buffer->context().clipPath(clipPath); } @@ -4993,30 +4846,30 @@ index 729093bd1ad56a1fcbea91f1f5df661d3a33ebaf..5780aa53bbaa26c5019109963fa8d1f6 } diff --git a/Source/WebCore/page/FrameSnapshotting.h b/Source/WebCore/page/FrameSnapshotting.h -index 4935bfd9a6e43d59a101c153fa89a8484fcb49e2..8384f5b5db8e405f86e1201d144d92d76a1a5ebd 100644 +index c34982712f798dff6c484e4a4b6b6a9b23905d4a..52da92d68344cd4d734db4565f174bbd05e26ad9 100644 --- a/Source/WebCore/page/FrameSnapshotting.h +++ b/Source/WebCore/page/FrameSnapshotting.h -@@ -59,6 +59,7 @@ enum class SnapshotFlags : uint16_t { - ExcludeText = 1 << 11, +@@ -60,6 +60,7 @@ enum class SnapshotFlags : uint16_t { FixedAndStickyLayersOnly = 1 << 12, DraggableElement = 1 << 13, -+ OmitDeviceScaleFactor = 1 << 14, + IncludeDocumentMarkers = 1 << 14, ++ OmitDeviceScaleFactor = 1 << 15, }; struct SnapshotOptions { diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp -index ee349890baf073f0432f590edbe326ec9f97115e..3022988b7d0b9b610cba13f8f429cd4c62404212 100644 +index 6cde8d25af42de8e96f6aa23dbeedb5abaa7feab..bef6092300de6f6d33c5a9e2a9354e00c200d9ef 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp -@@ -34,6 +34,7 @@ +@@ -35,6 +35,7 @@ #include "FrameLoader.h" #include "HistoryController.h" #include "HistoryItem.h" +#include "InspectorInstrumentation.h" #include "LocalFrame.h" + #include "LocalFrameInlines.h" #include "LocalFrameLoaderClient.h" - #include "Logging.h" -@@ -94,7 +95,7 @@ ExceptionOr<History::ScrollRestoration> History::scrollRestoration() const +@@ -97,7 +98,7 @@ ExceptionOr<History::ScrollRestoration> History::scrollRestoration() const RefPtr historyItem = frame->loader().history().currentItem(); if (!historyItem) return ScrollRestoration::Auto; @@ -5025,7 +4878,7 @@ index ee349890baf073f0432f590edbe326ec9f97115e..3022988b7d0b9b610cba13f8f429cd4c return historyItem->shouldRestoreScrollPosition() ? ScrollRestoration::Auto : ScrollRestoration::Manual; } -@@ -312,6 +313,8 @@ ExceptionOr<void> History::stateObjectAdded(RefPtr<SerializedScriptValue>&& data +@@ -315,6 +316,8 @@ ExceptionOr<void> History::stateObjectAdded(RefPtr<SerializedScriptValue>&& data } frame->loader().updateURLAndHistory(fullURL, WTF::move(data), historyBehavior); @@ -5035,7 +4888,7 @@ index ee349890baf073f0432f590edbe326ec9f97115e..3022988b7d0b9b610cba13f8f429cd4c } diff --git a/Source/WebCore/page/LocalFrame.cpp b/Source/WebCore/page/LocalFrame.cpp -index 1ce54cf2275bfd6253469e849ee8dbc5c0a64264..2905dc35d52ddafeb7e190144da59993dc8b3468 100644 +index 50342738fed8b72c737e834caa6517b3a642687f..3bf5c788d2a2091c521ae83a211de701d57bce4d 100644 --- a/Source/WebCore/page/LocalFrame.cpp +++ b/Source/WebCore/page/LocalFrame.cpp @@ -41,6 +41,7 @@ @@ -5046,15 +4899,15 @@ index 1ce54cf2275bfd6253469e849ee8dbc5c0a64264..2905dc35d52ddafeb7e190144da59993 #include "DiagnosticLoggingClient.h" #include "DiagnosticLoggingKeys.h" #include "DocumentLoader.h" -@@ -89,6 +90,7 @@ - #include "Logging.h" +@@ -92,6 +93,7 @@ + #include "MixedContentChecker.h" #include "Navigator.h" #include "NodeList.h" +#include "NodeRenderStyle.h" #include "NodeTraversal.h" #include "Page.h" #include "PaymentSession.h" -@@ -222,6 +224,7 @@ LocalFrame::LocalFrame(Page& page, ClientCreator&& clientCreator, FrameIdentifie +@@ -226,6 +228,7 @@ LocalFrame::LocalFrame(Page& page, ClientCreator&& clientCreator, FrameIdentifie void LocalFrame::init() { @@ -5062,7 +4915,7 @@ index 1ce54cf2275bfd6253469e849ee8dbc5c0a64264..2905dc35d52ddafeb7e190144da59993 loader().init(); } -@@ -452,7 +455,7 @@ void LocalFrame::orientationChanged() +@@ -462,7 +465,7 @@ void LocalFrame::orientationChanged() IntDegrees LocalFrame::orientation() const { if (RefPtr page = this->page()) @@ -5071,7 +4924,7 @@ index 1ce54cf2275bfd6253469e849ee8dbc5c0a64264..2905dc35d52ddafeb7e190144da59993 return 0; } #endif // ENABLE(ORIENTATION_EVENTS) -@@ -1696,7 +1699,6 @@ String LocalFrame::frameURLProtocol() const +@@ -1672,7 +1675,6 @@ String LocalFrame::frameURLProtocol() const return ""_s; } @@ -5079,7 +4932,16 @@ index 1ce54cf2275bfd6253469e849ee8dbc5c0a64264..2905dc35d52ddafeb7e190144da59993 static bool nodeIsMouseFocusable(Node& node) { -@@ -1946,7 +1948,6 @@ RefPtr<Node> LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& view +@@ -1908,7 +1910,7 @@ RefPtr<Node> LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& view + for (; node && node != terminationNode; node = node->parentInComposedTree()) { + if (!node->hasEventListeners(eventNames().dblclickEvent)) + continue; +-#if ENABLE(TOUCH_EVENTS) ++#if ENABLE(TWO_PHASE_CLICKS) + if (!node->allowsDoubleTapGesture()) + continue; + #endif +@@ -1922,7 +1924,6 @@ RefPtr<Node> LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& view return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTF::move(ancestorRespondingToDoubleClickEvent), ShouldApproximate::Yes); } @@ -5088,7 +4950,7 @@ index 1ce54cf2275bfd6253469e849ee8dbc5c0a64264..2905dc35d52ddafeb7e190144da59993 } // namespace WebCore diff --git a/Source/WebCore/page/LocalFrame.h b/Source/WebCore/page/LocalFrame.h -index c2ac6d0d1a599ac6947c5875d13aa389dcd591d4..00c457575f11c0c39c8913cd54f597688c35df28 100644 +index 8f81b0ea3fc343e6c214ad566ab4a6d9b95f5c3b..53ac6ea36a6fb13debd0f029f78c4dc4037d24f2 100644 --- a/Source/WebCore/page/LocalFrame.h +++ b/Source/WebCore/page/LocalFrame.h @@ -29,6 +29,7 @@ @@ -5109,35 +4971,35 @@ index c2ac6d0d1a599ac6947c5875d13aa389dcd591d4..00c457575f11c0c39c8913cd54f59768 class LocalFrame final : public Frame { public: -@@ -235,7 +234,6 @@ public: - WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults(); +@@ -232,7 +231,6 @@ public: + WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults() LIFETIME_BOUND; #endif -#if PLATFORM(COCOA) RefPtr<Node> betterApproximateNode(const IntPoint& testPoint, const NodeQualifier&, Node* best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect); WEBCORE_EXPORT RefPtr<Node> nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); -@@ -249,7 +247,6 @@ public: +@@ -246,7 +244,6 @@ public: WEBCORE_EXPORT RefPtr<Node> nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); static bool nodeWillRespondToMouseEvents(Node&); -#endif // PLATFORM(COCOA) #if PLATFORM(IOS_FAMILY) - const ViewportArguments& viewportArguments() const; -@@ -327,6 +324,7 @@ public: + const ViewportArguments& viewportArguments() const LIFETIME_BOUND; +@@ -324,6 +321,7 @@ public: WEBCORE_EXPORT FloatSize screenSize() const; void setOverrideScreenSize(FloatSize&&); + bool hasScreenSizeOverride() const { return !!m_overrideScreenSize; } - void selfOnlyRef(); + void NODELETE selfOnlyRef(); void selfOnlyDeref(); diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp -index 9ca90a896204491535d0656f8d7f90f5d2d6c014..0419fa1758253d1c1fff32276fcd317073a23d9b 100644 +index 52c005d8cf66917c42f05c5cd478b3d2e2b1cac3..13ba48bae2d135b620fd80a642c060a906e3b38c 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp -@@ -672,6 +672,44 @@ void Page::setOverrideViewportArguments(const std::optional<ViewportArguments>& +@@ -697,6 +697,44 @@ void Page::setOverrideViewportArguments(const std::optional<ViewportArguments>& localTopDocument->updateViewportArguments(); } @@ -5182,7 +5044,7 @@ index 9ca90a896204491535d0656f8d7f90f5d2d6c014..0419fa1758253d1c1fff32276fcd3170 ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { -@@ -4345,6 +4383,26 @@ void Page::setUseDarkAppearanceOverride(std::optional<bool> valueOverride) +@@ -4417,6 +4455,26 @@ void Page::setUseDarkAppearanceOverride(std::optional<bool> valueOverride) appearanceDidChange(); } @@ -5210,11 +5072,11 @@ index 9ca90a896204491535d0656f8d7f90f5d2d6c014..0419fa1758253d1c1fff32276fcd3170 { if (insets == m_fullscreenInsets) diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h -index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5dab99aef1 100644 +index 5bfae7e81b70cbd14f12e307bebd5b551f10c18b..ef95a268fd4aeb4ff5a325517386716ab17f257c 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h -@@ -408,6 +408,9 @@ public: - const ViewportArguments* overrideViewportArguments() const { return m_overrideViewportArguments.get(); } +@@ -413,6 +413,9 @@ public: + const ViewportArguments* overrideViewportArguments() const LIFETIME_BOUND { return m_overrideViewportArguments.get(); } WEBCORE_EXPORT void setOverrideViewportArguments(const std::optional<ViewportArguments>&); + WEBCORE_EXPORT FloatSize screenSize(); @@ -5222,11 +5084,11 @@ index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5d + static void refreshPlugins(bool reload); WEBCORE_EXPORT PluginData& pluginData(); - WEBCORE_EXPORT Ref<PluginData> protectedPluginData(); -@@ -493,6 +496,10 @@ public: + void clearPluginData(); +@@ -498,6 +501,10 @@ public: #if ENABLE(DRAG_SUPPORT) - DragController& dragController() { return m_dragController.get(); } - const DragController& dragController() const { return m_dragController.get(); } + DragController& dragController() LIFETIME_BOUND { return m_dragController.get(); } + const DragController& dragController() const LIFETIME_BOUND { return m_dragController.get(); } +#if PLATFORM(MAC) + void setDragPasteboardName(const String& pasteboardName) { m_overrideDragPasteboardName = pasteboardName; } + const String& overrideDragPasteboardName() { return m_overrideDragPasteboardName; } @@ -5234,7 +5096,7 @@ index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5d #endif FocusController& focusController() const { return m_focusController; } #if ENABLE(CONTEXT_MENUS) -@@ -679,6 +686,10 @@ public: +@@ -687,6 +694,10 @@ public: WEBCORE_EXPORT void setUseColorAppearance(bool useDarkAppearance, bool useElevatedUserInterfaceLevel); bool defaultUseDarkAppearance() const { return m_useDarkAppearance; } void setUseDarkAppearanceOverride(std::optional<bool>); @@ -5245,7 +5107,7 @@ index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5d #if ENABLE(TEXT_AUTOSIZING) float textAutosizingWidth() const { return m_textAutosizingWidth; } -@@ -1146,6 +1157,11 @@ public: +@@ -1150,6 +1161,11 @@ public: WEBCORE_EXPORT void setInteractionRegionsEnabled(bool); #endif @@ -5257,7 +5119,7 @@ index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5d #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) DeviceOrientationUpdateProvider* deviceOrientationUpdateProvider() const { return m_deviceOrientationUpdateProvider.get(); } #endif -@@ -1474,6 +1490,9 @@ private: +@@ -1484,6 +1500,9 @@ private: #if ENABLE(DRAG_SUPPORT) const UniqueRef<DragController> m_dragController; @@ -5267,7 +5129,7 @@ index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5d #endif const UniqueRef<FocusController> m_focusController; #if ENABLE(CONTEXT_MENUS) -@@ -1552,6 +1571,8 @@ private: +@@ -1562,6 +1581,8 @@ private: bool m_useElevatedUserInterfaceLevel { false }; bool m_useDarkAppearance { false }; std::optional<bool> m_useDarkAppearanceOverride; @@ -5276,7 +5138,7 @@ index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5d #if ENABLE(TEXT_AUTOSIZING) float m_textAutosizingWidth { 0 }; -@@ -1726,6 +1747,11 @@ private: +@@ -1739,6 +1760,11 @@ private: #endif std::unique_ptr<ViewportArguments> m_overrideViewportArguments; @@ -5289,10 +5151,10 @@ index 326a924ba84973e9b88c232b0cb498b27ca3d107..70ef6826e8d54d6dc207755eb72d8f5d #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) RefPtr<DeviceOrientationUpdateProvider> m_deviceOrientationUpdateProvider; diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp -index 1ac4d5c1571a4c20f29772ac56d9b75611a7cf10..5996222d95d103a67212eeb52cefa787e2840a23 100644 +index e9fa28ab43ecb4f3139791eca2bbb7bd82cfd6e0..8bbb8c76d913c37b60472972eb1647c58622c5a7 100644 --- a/Source/WebCore/page/PointerCaptureController.cpp +++ b/Source/WebCore/page/PointerCaptureController.cpp -@@ -209,7 +209,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi +@@ -213,7 +213,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi return capturingData && capturingData->preventsCompatibilityMouseEvents; } @@ -5301,7 +5163,7 @@ index 1ac4d5c1571a4c20f29772ac56d9b75611a7cf10..5996222d95d103a67212eeb52cefa787 static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName) { for (RefPtr<ContainerNode> currentNode = target; currentNode; currentNode = currentNode->parentInComposedTree()) { -@@ -565,7 +565,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint +@@ -574,7 +574,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint capturingData->pendingTargetOverride = nullptr; capturingData->state = CapturingData::State::Cancelled; @@ -5311,7 +5173,7 @@ index 1ac4d5c1571a4c20f29772ac56d9b75611a7cf10..5996222d95d103a67212eeb52cefa787 #endif diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h -index be1a0170215d1126ae4ea08de3f23192a7bc63b1..669495b8783ea5d26f9237009f85a3892104c139 100644 +index bafa2e9995a142e1bc07d506204ff5f14cbeab9c..d06922b691b02699ca89483c6e4e5c43bb49303c 100644 --- a/Source/WebCore/page/PointerCaptureController.h +++ b/Source/WebCore/page/PointerCaptureController.h @@ -63,7 +63,7 @@ public: @@ -5323,7 +5185,7 @@ index be1a0170215d1126ae4ea08de3f23192a7bc63b1..669495b8783ea5d26f9237009f85a389 void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&, const DoublePoint&); #endif -@@ -87,12 +87,12 @@ private: +@@ -91,12 +91,12 @@ private: WeakPtr<Document, WeakPtrImplWithEventTargetData> activeDocument; RefPtr<Element> pendingTargetOverride; RefPtr<Element> targetOverride; @@ -5383,10 +5245,10 @@ index cd1f3ce09ba0ab6e414bfcb12f38918404946700..f78cd1f89fb32ce4b9109c80f1f7c303 } diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp -index 9549a4197e46b09276b5e5b8950bbcab0d72f17e..9b73d730aa07d40f8712a62c8ff095e5bfda2f14 100644 +index cb4f081221a783cb05b6f65dba5cf338600148d5..88c4adcd84270f24bc4394125d44f34d7b2011c6 100644 --- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp -@@ -354,6 +354,8 @@ template<typename Predicate, typename... Args> +@@ -352,6 +352,8 @@ template<typename Predicate, typename... Args> bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, Predicate&& predicate, Args&&... args) const requires (!std::is_convertible_v<Predicate, ContentSecurityPolicy::ViolatedDirectiveCallback>) { @@ -5395,7 +5257,7 @@ index 9549a4197e46b09276b5e5b8950bbcab0d72f17e..9b73d730aa07d40f8712a62c8ff095e5 bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; for (auto& policy : m_policies) { if (policy->isReportOnly() != isReportOnly) -@@ -367,6 +369,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit +@@ -365,6 +367,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit template<typename Predicate, typename... Args> bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const { @@ -5404,7 +5266,7 @@ index 9549a4197e46b09276b5e5b8950bbcab0d72f17e..9b73d730aa07d40f8712a62c8ff095e5 bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; bool isAllowed = true; for (auto& policy : m_policies) { -@@ -383,6 +387,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit +@@ -381,6 +385,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit template<typename Predicate, typename... Args> bool ContentSecurityPolicy::allPoliciesAllow(NOESCAPE const ViolatedDirectiveCallback& callback, Predicate&& predicate, Args&&... args) const { @@ -5412,7 +5274,7 @@ index 9549a4197e46b09276b5e5b8950bbcab0d72f17e..9b73d730aa07d40f8712a62c8ff095e5 + return true; bool isAllowed = true; for (auto& policy : m_policies) { - if (const ContentSecurityPolicyDirective* violatedDirective = (policy.get()->*predicate)(std::forward<Args>(args)...)) { + if (const ContentSecurityPolicyDirective* violatedDirective = (policy.get()->*predicate)(args...)) { diff --git a/Source/WebCore/page/wpe/DragControllerWPE.cpp b/Source/WebCore/page/wpe/DragControllerWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bea08826a16de4774a55c81ccba0d81f7d72472 @@ -5502,7 +5364,7 @@ index 0000000000000000000000000000000000000000..7bea08826a16de4774a55c81ccba0d81 + +} diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h -index f20dc0d58d02e8e6207bd973950a6340477f5d57..40f8abd4c6975da4c203b7f153181b96c6850233 100644 +index 9e2964b6e5f27f3a9c9f39e95b37de574cd52b1b..20e211ebc0217e6f4e66118fd98a7eb42f0edc5d 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h @@ -93,8 +93,8 @@ public: @@ -5526,13 +5388,13 @@ index f20dc0d58d02e8e6207bd973950a6340477f5d57..40f8abd4c6975da4c203b7f153181b96 bool m_disallowFileAccess { false }; }; diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h -index 11cef75ac77ed181b76fac06229ba2eadd387e02..cc77e9aa4054e848f258526b41745363c903eeca 100644 +index 18569a97050f6711699829d52a3177a4a48e3cca..7e7c7d74edb2f7b9c5769ffd15bf7eb97a7cd396 100644 --- a/Source/WebCore/platform/Pasteboard.h +++ b/Source/WebCore/platform/Pasteboard.h @@ -322,6 +322,7 @@ public: COMPtr<IDataObject> dataObject() const { return m_dataObject; } WEBCORE_EXPORT void setExternalDataObject(IDataObject*); - const DragDataMap& dragDataMap() const { return m_dragDataMap; } + const DragDataMap& dragDataMap() const LIFETIME_BOUND { return m_dragDataMap; } + WEBCORE_EXPORT DragDataMap createDragDataMap(); void writeURLToWritableDataObject(const URL&, const String&); COMPtr<WCDataObject> writableDataObject() const { return m_writableDataObject; } @@ -5546,7 +5408,7 @@ index 11cef75ac77ed181b76fac06229ba2eadd387e02..cc77e9aa4054e848f258526b41745363 }; diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h -index 4e601893cc311bff51f91eff7dbf5479d7b4363a..432ec68c157460ad475f57ffaa7786cfe2436f47 100644 +index 071f9fa0e6cfaa84d9b077e39a64bec9361ead9a..fdd0ec667cc7e2f59bd2d21c5c381ae54dde06d9 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -134,6 +134,7 @@ namespace WebCore { @@ -5558,7 +5420,7 @@ index 4e601893cc311bff51f91eff7dbf5479d7b4363a..432ec68c157460ad475f57ffaa7786cf #endif diff --git a/Source/WebCore/platform/PlatformScreen.cpp b/Source/WebCore/platform/PlatformScreen.cpp -index ef0abc9a93e878897ffc9d2497a3da0fca5b37b7..abd96c6d1a6c3ab9e0121c1e78f2f75a5f805b32 100644 +index eac5bf40c150dba990c13775db0ae9e10f883574..563106c0d9fb259c2171aedd5d57efbf81049cc9 100644 --- a/Source/WebCore/platform/PlatformScreen.cpp +++ b/Source/WebCore/platform/PlatformScreen.cpp @@ -85,3 +85,24 @@ OptionSet<ContentsFormat> screenContentsFormatsForTesting() @@ -5587,10 +5449,10 @@ index ef0abc9a93e878897ffc9d2497a3da0fca5b37b7..abd96c6d1a6c3ab9e0121c1e78f2f75a +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/PlatformScreen.h b/Source/WebCore/platform/PlatformScreen.h -index 4566e5537a36331a9b5bd75f7235f94d0d9d60d4..195cfe90a57fafb57dc6ff0cabd1fa15b984b979 100644 +index 2a80049e6065880ac2e9d1a42784fc69659f889d..a804d1251cccef36547551344e9ebf838aec1e18 100644 --- a/Source/WebCore/platform/PlatformScreen.h +++ b/Source/WebCore/platform/PlatformScreen.h -@@ -164,10 +164,14 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); +@@ -162,10 +162,14 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); #endif #if ENABLE(TOUCH_EVENTS) @@ -5608,7 +5470,7 @@ index 4566e5537a36331a9b5bd75f7235f94d0d9d60d4..195cfe90a57fafb57dc6ff0cabd1fa15 #endif diff --git a/Source/WebCore/platform/PlatformTouchEvent.h b/Source/WebCore/platform/PlatformTouchEvent.h -index 23f011953c66f401553bedfaef3485af215ae083..6e6cfe1691b9684462c78d916ef4553f801c9991 100644 +index 8de9b7ed5c5c92eb9700105e5ae186755b13423a..91a007843f7539a2c61121217d393048877a8dc3 100644 --- a/Source/WebCore/platform/PlatformTouchEvent.h +++ b/Source/WebCore/platform/PlatformTouchEvent.h @@ -20,8 +20,8 @@ @@ -5624,37 +5486,15 @@ index 23f011953c66f401553bedfaef3485af215ae083..6e6cfe1691b9684462c78d916ef4553f #if ENABLE(TOUCH_EVENTS) @@ -42,7 +42,7 @@ public: - const Vector<PlatformTouchEvent>& predictedEvents() const { return m_predictedEvents; } + const Vector<PlatformTouchEvent>& predictedEvents() const LIFETIME_BOUND { return m_predictedEvents; } -#if PLATFORM(WPE) +#if !ENABLE(IOS_TOUCH_EVENTS) // FIXME: since WPE currently does not send touch stationary events, we need to be able to set // TouchCancelled touchPoints subsequently void setTouchPoints(Vector<PlatformTouchPoint>& touchPoints) { m_touchPoints = touchPoints; } -diff --git a/Source/WebCore/platform/PlatformTouchPoint.h b/Source/WebCore/platform/PlatformTouchPoint.h -index 1e04806dbf9cfb27dda3e5d2c3c61aa66efd8ae6..f319930cc2c6dba499e35b58c59fa5fe99199864 100644 ---- a/Source/WebCore/platform/PlatformTouchPoint.h -+++ b/Source/WebCore/platform/PlatformTouchPoint.h -@@ -20,7 +20,7 @@ - #ifndef PlatformTouchPoint_h - #define PlatformTouchPoint_h - --#include "DoublePoint.h" -+#include <WebCore/DoublePoint.h> - - #if ENABLE(TOUCH_EVENTS) - -@@ -47,7 +47,7 @@ public: - { - } - --#if PLATFORM(WPE) -+#if !ENABLE(IOS_TOUCH_EVENTS) - // FIXME: since WPE currently does not send touch stationary events, we need to be able to - // create a PlatformTouchPoint of type TouchCancelled artificially - PlatformTouchPoint(unsigned id, State state, DoublePoint screenPos, DoublePoint pos) diff --git a/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h b/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h -index 2a8741ef404e5453bd5cff096f41ff2d3aa7d06f..c2598bef2100170441c26b1a01ee4c7b35dc5b63 100644 +index a251b8f6a5e05997594a2962e7fcb3fab49a27b2..fd95b909650098869d44c8860a525051fc6996f8 100644 --- a/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h +++ b/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h @@ -36,7 +36,7 @@ class GraphicsContext; @@ -5666,19 +5506,19 @@ index 2a8741ef404e5453bd5cff096f41ff2d3aa7d06f..c2598bef2100170441c26b1a01ee4c7b static const unsigned scrollbarBorderSize = 1; static const unsigned thumbBorderSize = 1; static const unsigned overlayThumbSize = 3; -diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h -index 5b659c763b9754b025a63f89522954cc39915b9a..448b50a2b131361a75d3f816cdcbb6a102551280 100644 ---- a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h -+++ b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h -@@ -38,7 +38,7 @@ WEBCORE_EXPORT uint8_t verifyImageBufferIsBigEnough(std::span<const uint8_t> buf - +diff --git a/Source/WebCore/platform/graphics/ImageUtilities.h b/Source/WebCore/platform/graphics/ImageUtilities.h +index 2848aea78c6f4e7c75b2896428e4d5f6d32f4273..c1add6e2c65f702c056380a3744cc2af0ab05d7a 100644 +--- a/Source/WebCore/platform/graphics/ImageUtilities.h ++++ b/Source/WebCore/platform/graphics/ImageUtilities.h +@@ -81,7 +81,7 @@ WEBCORE_EXPORT void createBitmapsFromImageData(std::span<const uint8_t> data, st + WEBCORE_EXPORT RefPtr<SharedBuffer> createIconDataFromBitmaps(Vector<Ref<ShareableBitmap>>&&); + WEBCORE_EXPORT void decodeImageWithSize(std::span<const uint8_t> data, std::optional<FloatSize>, CompletionHandler<void(RefPtr<ShareableBitmap>&&)>&&); + +-Vector<uint8_t> encodeData(CGImageRef, const String& mimeType, std::optional<double> quality = std::nullopt); ++WEBCORE_EXPORT Vector<uint8_t> encodeData(CGImageRef, const String& mimeType, std::optional<double> quality = std::nullopt); + WEBCORE_EXPORT String encodeDataURL(CGImageRef, const String& mimeType, std::optional<double> quality = std::nullopt); + WEBCORE_EXPORT uint8_t NODELETE verifyImageBufferIsBigEnough(std::span<const uint8_t> buffer); RetainPtr<CFStringRef> utiFromImageBufferMIMEType(const String& mimeType); - CFStringRef jpegUTI(); --Vector<uint8_t> encodeData(CGImageRef, const String& mimeType, std::optional<double> quality); -+WEBCORE_EXPORT Vector<uint8_t> encodeData(CGImageRef, const String& mimeType, std::optional<double> quality); - Vector<uint8_t> encodeData(const PixelBuffer&, const String& mimeType, std::optional<double> quality); - Vector<uint8_t> encodeData(std::span<const uint8_t>, const String& mimeType, std::optional<double> quality); - diff --git a/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h b/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h index 515ddea3cd42796efa9f41ad74be07a7447c337e..36db42e2a0822d5609b39046191f05a1f8d2b54b 100644 --- a/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h @@ -5692,7 +5532,7 @@ index 515ddea3cd42796efa9f41ad74be07a7447c337e..36db42e2a0822d5609b39046191f05a1 namespace WebCore { diff --git a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp -index 04dceb079874694093b5d26a0dfb3c81cfbc3758..2ab74fc7611e01a14c8e233dd3e1ba4d6ab42341 100644 +index 775df102268b397e6c96e8b93296a7dbe6afcd26..cdbb7b79bde8ba30bc2b0f6bb579b44de72d7fc7 100644 --- a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp +++ b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp @@ -168,6 +168,33 @@ static Vector<unsigned> stringIndicesFromClusters(const Vector<WORD>& clusters, @@ -6123,13 +5963,13 @@ index e47f5bade7c0a27e8a27f8dc95b51174f025b4a6..016efe9bc0898bb648a33973e771b49e Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String&) const diff --git a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp -index aaabf3c17d676c14cfdc179ba90d042f9197318c..473313051009124d0043c57c551dbdce3dea2f02 100644 +index 6a5b3325d2aae3c4769332fa7488e2ca7dd55ef5..3065482616cb5fbc61913f71822262bcbbbd43cf 100644 --- a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp +++ b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp -@@ -41,6 +41,7 @@ +@@ -35,6 +35,7 @@ + #include <gst/video/video.h> #include <wtf/TZoneMallocInlines.h> #include <wtf/glib/GUniquePtr.h> - #include <wtf/glib/RunLoopSourcePriority.h> +#include <wtf/text/ASCIILiteral.h> #include <wtf/text/MakeString.h> #include <wtf/text/WTFString.h> @@ -6152,7 +5992,7 @@ index df27a094a0b2239892c96b4f5835826bcf8d7540..3bbea5c96110c0ae70d944b7f6fb018e m_commonHeaders.append(CommonHeader { name, value }); } diff --git a/Source/WebCore/platform/network/NetworkStorageSession.h b/Source/WebCore/platform/network/NetworkStorageSession.h -index 0708ea1a644e2dea797a284a2f7d46ec47620451..ff69e387c3dd246cd93e45c49e1d461dd0f3bbdb 100644 +index 0640345cf5f133b7f84d3e32b272871d9beff519..320dce768def18327ee25e889109cd6d75ba4cac 100644 --- a/Source/WebCore/platform/network/NetworkStorageSession.h +++ b/Source/WebCore/platform/network/NetworkStorageSession.h @@ -201,6 +201,7 @@ public: @@ -6164,7 +6004,7 @@ index 0708ea1a644e2dea797a284a2f7d46ec47620451..ff69e387c3dd246cd93e45c49e1d461d WEBCORE_EXPORT HTTPCookieAcceptPolicy cookieAcceptPolicy() const; WEBCORE_EXPORT void setCookie(const Cookie&); diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp -index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b5a2242c6 100644 +index e413db463376bcf31da4cd0f8e2f869f4b6a0a95..6d43a62553f3e82968964a89608a121a72bc3d74 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.cpp +++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp @@ -21,7 +21,7 @@ @@ -6176,7 +6016,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b */ #include "config.h" -@@ -79,6 +79,7 @@ ResourceResponseBase::ResourceResponseBase(std::optional<ResourceResponseData>&& +@@ -77,6 +77,7 @@ ResourceResponseBase::ResourceResponseBase(std::optional<ResourceResponseData>&& , m_httpStatusText(data ? WTF::move(data->httpStatusText) : String { }) , m_httpVersion(data ? WTF::move(data->httpVersion) : String { }) , m_httpHeaderFields(data ? WTF::move(data->httpHeaderFields) : HTTPHeaderMap { }) @@ -6184,7 +6024,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b , m_networkLoadMetrics(data && data->networkLoadMetrics ? Box<NetworkLoadMetrics>::create(WTF::move(*data->networkLoadMetrics)) : Box<NetworkLoadMetrics> { }) , m_certificateInfo(data ? WTF::move(data->certificateInfo) : std::nullopt) , m_httpStatusCode(data ? data->httpStatusCode : 0) -@@ -279,7 +280,7 @@ const String& ResourceResponseBase::mimeType() const +@@ -277,7 +278,7 @@ const String& ResourceResponseBase::mimeType() const { lazyInit(CommonFieldsOnly); @@ -6193,7 +6033,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b } void ResourceResponseBase::setMimeType(String&& mimeType) -@@ -293,7 +294,7 @@ void ResourceResponseBase::setMimeType(String&& mimeType) +@@ -291,7 +292,7 @@ void ResourceResponseBase::setMimeType(String&& mimeType) // FIXME: Should invalidate or update platform response if present. } @@ -6202,7 +6042,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b { lazyInit(CommonFieldsOnly); -@@ -306,7 +307,7 @@ void ResourceResponseBase::setExpectedContentLength(long long expectedContentLen +@@ -304,7 +305,7 @@ void ResourceResponseBase::setExpectedContentLength(long long expectedContentLen m_isNull = false; // FIXME: Content length is determined by HTTP Content-Length header. We should update the header, so that it doesn't disagree with m_expectedContentLength. @@ -6211,7 +6051,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b // FIXME: Should invalidate or update platform response if present. } -@@ -397,7 +398,7 @@ const String& ResourceResponseBase::httpStatusText() const +@@ -395,7 +396,7 @@ const String& ResourceResponseBase::httpStatusText() const { lazyInit(AllFields); @@ -6220,7 +6060,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b } void ResourceResponseBase::setHTTPStatusText(String&& statusText) -@@ -412,16 +413,16 @@ void ResourceResponseBase::setHTTPStatusText(String&& statusText) +@@ -410,16 +411,16 @@ void ResourceResponseBase::setHTTPStatusText(String&& statusText) const String& ResourceResponseBase::httpVersion() const { lazyInit(AllFields); @@ -6240,7 +6080,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b // FIXME: Should invalidate or update platform response if present. } -@@ -559,12 +560,12 @@ String ResourceResponseBase::httpHeaderField(StringView name) const +@@ -557,12 +558,12 @@ String ResourceResponseBase::httpHeaderField(StringView name) const // If we already have the header, just return it instead of consuming memory by grabing all headers. String value = m_httpHeaderFields.get(name); @@ -6255,7 +6095,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b } String ResourceResponseBase::httpHeaderField(HTTPHeaderName name) const -@@ -578,7 +579,7 @@ String ResourceResponseBase::httpHeaderField(HTTPHeaderName name) const +@@ -576,7 +577,7 @@ String ResourceResponseBase::httpHeaderField(HTTPHeaderName name) const lazyInit(AllFields); @@ -6264,7 +6104,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b } void ResourceResponseBase::updateHeaderParsedState(HTTPHeaderName name) -@@ -688,7 +689,7 @@ void ResourceResponseBase::parseCacheControlDirectives() const +@@ -686,7 +687,7 @@ void ResourceResponseBase::parseCacheControlDirectives() const m_cacheControlDirectives = WebCore::parseCacheControlDirectives(m_httpHeaderFields); m_haveParsedCacheControlHeader = true; } @@ -6273,7 +6113,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b bool ResourceResponseBase::cacheControlContainsNoCache() const { if (!m_haveParsedCacheControlHeader) -@@ -709,7 +710,7 @@ bool ResourceResponseBase::cacheControlContainsMustRevalidate() const +@@ -707,7 +708,7 @@ bool ResourceResponseBase::cacheControlContainsMustRevalidate() const parseCacheControlDirectives(); return m_cacheControlDirectives.mustRevalidate; } @@ -6282,7 +6122,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b bool ResourceResponseBase::cacheControlContainsImmutable() const { if (!m_haveParsedCacheControlHeader) -@@ -864,7 +865,7 @@ void ResourceResponseBase::lazyInit(InitLevel initLevel) const +@@ -862,7 +863,7 @@ void ResourceResponseBase::lazyInit(InitLevel initLevel) const bool ResourceResponseBase::equalForWebKitLegacyChallengeComparison(const ResourceResponse& a, const ResourceResponse& b) { if (a.isNull() != b.isNull()) @@ -6291,7 +6131,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b if (a.url() != b.url()) return false; if (a.mimeType() != b.mimeType()) -@@ -898,7 +899,7 @@ std::optional<ResourceResponseData> ResourceResponseBase::getResponseData() cons +@@ -896,7 +897,7 @@ std::optional<ResourceResponseData> ResourceResponseBase::getResponseData() cons if (m_isNull) return std::nullopt; lazyInit(AllFields); @@ -6300,7 +6140,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b return { ResourceResponseData { URL { m_url }, String { m_mimeType }, -@@ -908,6 +909,7 @@ std::optional<ResourceResponseData> ResourceResponseBase::getResponseData() cons +@@ -906,6 +907,7 @@ std::optional<ResourceResponseData> ResourceResponseBase::getResponseData() cons String { m_httpStatusText }, String { m_httpVersion }, HTTPHeaderMap { m_httpHeaderFields }, @@ -6308,7 +6148,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b m_networkLoadMetrics ? std::optional(*m_networkLoadMetrics) : std::nullopt, m_source, m_type, -@@ -984,6 +986,11 @@ std::optional<WebCore::ResourceResponseData> Coder<WebCore::ResourceResponseData +@@ -982,6 +984,11 @@ std::optional<WebCore::ResourceResponseData> Coder<WebCore::ResourceResponseData if (!httpHeaderFields) return std::nullopt; @@ -6320,7 +6160,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b std::optional<short> httpStatusCode; decoder >> httpStatusCode; if (!httpStatusCode) -@@ -1043,6 +1050,7 @@ std::optional<WebCore::ResourceResponseData> Coder<WebCore::ResourceResponseData +@@ -1041,6 +1048,7 @@ std::optional<WebCore::ResourceResponseData> Coder<WebCore::ResourceResponseData WTF::move(*httpStatusText), WTF::move(*httpVersion), WTF::move(*httpHeaderFields), @@ -6329,7 +6169,7 @@ index 59226d34782375aaacbd6e2bd500ccefe5887de4..8b2561d9196fd7796495eb6ec87c3e0b *source, *type, diff --git a/Source/WebCore/platform/network/ResourceResponseBase.h b/Source/WebCore/platform/network/ResourceResponseBase.h -index 82fb074cbf598b56598b3557828583248290c155..e4a77c696945dbf410698b725ac0256fe4ff58ba 100644 +index ef0c552143191b48c1a52a0702c7596da349eff4..b69149fef86c536d95dd01c39da64f719b86e89d 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.h +++ b/Source/WebCore/platform/network/ResourceResponseBase.h @@ -21,7 +21,7 @@ @@ -6391,10 +6231,10 @@ index 82fb074cbf598b56598b3557828583248290c155..e4a77c696945dbf410698b725ac0256f ResourceResponseBase::Source source; ResourceResponseBase::Type type; diff --git a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm -index fc53db15a4730cbb4f06ad6c29f694faed1a79a4..3dc6bb08bc413144f04d612e13ca0de5a84688df 100644 +index 3ed98966972014b88f2a4ca24ea615717a9a812c..7b75b20a84474ac8f227666d2d8305a60c1923f5 100644 --- a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm +++ b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm -@@ -587,6 +587,27 @@ bool NetworkStorageSession::setCookieFromDOM(const URL& firstParty, const SameSi +@@ -582,6 +582,27 @@ bool NetworkStorageSession::setCookieFromDOM(const URL& firstParty, const SameSi return false; } @@ -6436,7 +6276,7 @@ index 96e0a63b347c170c963bc7e851f383b91665c5c8..2f0afc26bcc87e9440e201728778892b bool m_detectedDatabaseCorruption { false }; diff --git a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp -index 565d89cd623fb332cc11883d962371e50f4d45b2..5224d88a87aa7f82a41ad96616b57a24ded9d1a8 100644 +index 5a78d6c775542cd62d3b192dc60972fdbea92270..5dab0edfef83cc1672012d94bcb4d6390b91bc97 100644 --- a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp +++ b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp @@ -136,6 +136,12 @@ void NetworkStorageSession::setCookieAcceptPolicy(CookieAcceptPolicy policy) con @@ -6453,7 +6293,7 @@ index 565d89cd623fb332cc11883d962371e50f4d45b2..5224d88a87aa7f82a41ad96616b57a24 { switch (cookieDatabase().acceptPolicy()) { diff --git a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp -index 9e6bbc08a5364904e3204e02a6959fbd739208b0..ebc9a4b734b01240a802629bef338e9fbca1944c 100644 +index f3c07eb9e056bf031d37b1d2d30a2ebcbe4ba42e..c6b732f75b4e3e823d8c3ebc0b825e389e1d175a 100644 --- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp +++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp @@ -531,6 +531,26 @@ void NetworkStorageSession::replaceCookies(const Vector<Cookie>& cookies) @@ -6483,6 +6323,18 @@ index 9e6bbc08a5364904e3204e02a6959fbd739208b0..ebc9a4b734b01240a802629bef338e9f void NetworkStorageSession::deleteCookie(const Cookie& cookie, CompletionHandler<void()>&& completionHandler) { GUniquePtr<SoupCookie> targetCookie(cookie.toSoupCookie()); +diff --git a/Source/WebCore/platform/text/LocaleICU.cpp b/Source/WebCore/platform/text/LocaleICU.cpp +index 2eaf11c3c0739754768810694c0016d7a21a7951..f25e84fe43e2590829146a1d134776ec549de810 100644 +--- a/Source/WebCore/platform/text/LocaleICU.cpp ++++ b/Source/WebCore/platform/text/LocaleICU.cpp +@@ -41,6 +41,7 @@ + #include <wtf/TZoneMallocInlines.h> + #include <wtf/text/StringBuffer.h> + #include <wtf/text/StringBuilder.h> ++#include <wtf/TZoneMallocInlines.h> + #include <wtf/unicode/icu/ICUHelpers.h> + + #if USE(HARFBUZZ) diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp index 8e6023c5f1200884723bd0871bf602ba4a37ad04..582365cfb1c9a109308d0133922ee4d2bc0ae7db 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -6572,10 +6424,10 @@ index f6c0cc49e9c39686bb5a5b36c29762173f2b4d1f..f396b564ee4aa7203d1728ff84608373 OptionSet<PlatformEvent::Modifier> PlatformKeyboardEvent::currentStateOfModifierKeys() diff --git a/Source/WebCore/platform/win/PasteboardWin.cpp b/Source/WebCore/platform/win/PasteboardWin.cpp -index 74b13efd7217257e8e63b5bd25951cde74d1735e..6d86d767bbabe071d341eaba3f074ef6b3557fca 100644 +index 89eb26e07f1bc8174ed50f088a1a9e61e227c627..5949b188bf03caa7c35af1966b3879465f2a92f6 100644 --- a/Source/WebCore/platform/win/PasteboardWin.cpp +++ b/Source/WebCore/platform/win/PasteboardWin.cpp -@@ -1144,7 +1144,21 @@ void Pasteboard::writeCustomData(const Vector<PasteboardCustomData>& data) +@@ -1145,7 +1145,21 @@ void Pasteboard::writeCustomData(const Vector<PasteboardCustomData>& data) } clear(); @@ -6597,7 +6449,7 @@ index 74b13efd7217257e8e63b5bd25951cde74d1735e..6d86d767bbabe071d341eaba3f074ef6 if (::OpenClipboard(m_owner)) { const auto& customData = data.first(); customData.forEachPlatformStringOrBuffer([](auto& type, auto& stringOrBuffer) { -@@ -1183,4 +1197,25 @@ void Pasteboard::write(const Color&) +@@ -1184,4 +1198,25 @@ void Pasteboard::write(const Color&) { } @@ -6624,10 +6476,10 @@ index 74b13efd7217257e8e63b5bd25951cde74d1735e..6d86d767bbabe071d341eaba3f074ef6 + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp -index 14cb9f8091065e5875734d5cb53bea88945e4fb4..a9412b97ac7c78e931b9f21acbdbb97ee7ebcb3a 100644 +index 7cf7bbc03d7824b38b097427587367b50978c2c0..00f87e2b8155d18385cd2aae8461c442266634ef 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp -@@ -1083,8 +1083,10 @@ bool RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update +@@ -1065,8 +1065,10 @@ bool RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update return false; } @@ -6639,7 +6491,7 @@ index 14cb9f8091065e5875734d5cb53bea88945e4fb4..a9412b97ac7c78e931b9f21acbdbb97e bool isPageScroll = !updateRootArg || updateRootArg == &rootRenderLayer(); CheckedPtr updateRoot = &rootRenderLayer(); diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp -index 0c806a55ba312f10fae97c7e395b67747cbf8327..50f29e994d3450b9796283040c6c20b432fc868d 100644 +index 7b1911e2444250e1b87bb9fd9b2d6e1e56fa43f0..fdbb83e5ac55b35390f2bf5f383cff5f7bbcf0ae 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -244,13 +244,13 @@ void RenderTextControl::layoutExcludedChildren(RelayoutChildren relayoutChildren @@ -6658,12 +6510,12 @@ index 0c806a55ba312f10fae97c7e395b67747cbf8327..50f29e994d3450b9796283040c6c20b4 { if (auto innerTextElement = this->innerTextElement(); innerTextElement && innerTextElement->renderer()) diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h -index 2dd4c506974fc81bbc8d64a9638f08acf5de5a31..c7aaccb73e924dbff4ac9f9ee5f82fac8e98477f 100644 +index 00011d61c20cf7509b03407ecbcc29ce2da0ccca..d939e62c37573487cf4df7a16cf6201b5400cf0c 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -38,8 +38,8 @@ public: - WEBCORE_EXPORT HTMLTextFormControlElement& textFormControlElement() const; + WEBCORE_EXPORT HTMLTextFormControlElement& NODELETE textFormControlElement() const; -#if PLATFORM(IOS_FAMILY) bool canScroll() const; @@ -6672,18 +6524,18 @@ index 2dd4c506974fc81bbc8d64a9638f08acf5de5a31..c7aaccb73e924dbff4ac9f9ee5f82fac #endif diff --git a/Source/WebCore/workers/WorkerConsoleClient.cpp b/Source/WebCore/workers/WorkerConsoleClient.cpp -index 826c1e53ac8f5ba3343ac992e217c5e20dce09b8..ac1a86b9ced5f0133f04073604047e2e72b413ff 100644 +index fe03d2c8d0625725e07a2aa0eef3a0d9127cf211..9c661ee5f91766bb6d903cfd25f3c7a43d9f3538 100644 --- a/Source/WebCore/workers/WorkerConsoleClient.cpp +++ b/Source/WebCore/workers/WorkerConsoleClient.cpp -@@ -253,4 +253,6 @@ Ref<WorkerOrWorkletGlobalScope> WorkerConsoleClient::protectedGlobalScope() - return m_globalScope.get(); +@@ -257,4 +257,6 @@ void WorkerConsoleClient::screenshot(JSC::JSGlobalObject* lexicalGlobalObject, R + InspectorInstrumentation::addMessageToConsole(protect(globalScope()), makeUnique<Inspector::ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Image, MessageLevel::Log, dataURL, ScriptArguments::create(lexicalGlobalObject, WTF::move(adjustedArguments)), lexicalGlobalObject, /* requestIdentifier */ 0, timestamp)); } +void WorkerConsoleClient::bindingCalled(JSC::JSGlobalObject*, const String&, const String&) { } + } // namespace WebCore diff --git a/Source/WebCore/workers/WorkerConsoleClient.h b/Source/WebCore/workers/WorkerConsoleClient.h -index a1ae48a654d89c7ee36611884f9ea64367523824..cc43f238783da61f1487f22473988e327e15f478 100644 +index 60e744703647b7593426c59814975bf12dc4ebaa..d5156a30396fb2ad7e73c5c5429a07d56df0c928 100644 --- a/Source/WebCore/workers/WorkerConsoleClient.h +++ b/Source/WebCore/workers/WorkerConsoleClient.h @@ -59,6 +59,7 @@ private: @@ -6692,22 +6544,48 @@ index a1ae48a654d89c7ee36611884f9ea64367523824..cc43f238783da61f1487f22473988e32 void screenshot(JSC::JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) override; + void bindingCalled(JSC::JSGlobalObject*, const String& name, const String& arg) override; - Ref<WorkerOrWorkletGlobalScope> protectedGlobalScope(); + WorkerOrWorkletGlobalScope& globalScope() { return m_globalScope; } + +diff --git a/Source/WebGPU/WGSL/UniformityAnalysis.cpp b/Source/WebGPU/WGSL/UniformityAnalysis.cpp +index 85806067d986a7f9047708500e1c510fd0df1834..39e066e5882c4fbe8f7b31bfa5d62e3188761709 100644 +--- a/Source/WebGPU/WGSL/UniformityAnalysis.cpp ++++ b/Source/WebGPU/WGSL/UniformityAnalysis.cpp +@@ -118,8 +118,10 @@ struct FunctionInfo { + { + switch (severity) { + case SeverityControl::Error: return requiredToBeUniform[0]; ++IGNORE_CLANG_WARNINGS_BEGIN("unsafe-buffer-usage") + case SeverityControl::Warning: return requiredToBeUniform[1]; + case SeverityControl::Info: return requiredToBeUniform[2]; ++IGNORE_CLANG_WARNINGS_END + case SeverityControl::Off: return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); +@@ -311,8 +313,10 @@ std::optional<Error> UniformityGraph::processFunction(AST::Function& function) + m_currentFunction = &info; + + info.requiredToBeUniform[0] = info.createNode(); ++IGNORE_CLANG_WARNINGS_BEGIN("unsafe-buffer-usage") + info.requiredToBeUniform[1] = info.createNode(); + info.requiredToBeUniform[2] = info.createNode(); ++IGNORE_CLANG_WARNINGS_END + info.mayBeNonUniform = info.createNode(); + info.cfStart = info.createNode(); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp -index 2309bc596ce634b7bf5e1c1e1fbd14403c1854b0..8e369ecbdc276a927f07c7fea612f4db29e79bd0 100644 +index dfc334dff3edea4f775d8f59ba3dd303af861735..de87609382fb0de678b10e8ea77a8c5a6f3acbe9 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp -@@ -98,6 +98,8 @@ +@@ -99,6 +99,8 @@ #if PLATFORM(COCOA) - #include <wtf/OSObjectPtr.h> + #include <wtf/FileSystem.h> +#include "NetworkDataTaskCocoa.h" +#include "NetworkSessionCocoa.h" + #include <wtf/OSObjectPtr.h> + #include <wtf/spi/darwin/SandboxSPI.h> #endif - - #if ENABLE(APPLE_PAY_REMOTE_UI) -@@ -1287,6 +1289,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) +@@ -1318,6 +1320,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) storageSession->clearPageSpecificDataForResourceLoadStatistics(pageID); } @@ -6723,10 +6601,10 @@ index 2309bc596ce634b7bf5e1c1e1fbd14403c1854b0..8e369ecbdc276a927f07c7fea612f4db { if (CheckedPtr storageSession = m_networkProcess->storageSession(m_sessionID)) diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h -index a908a09e7584aed9417c76e20f6e3da2b92eccbb..2b9ebe07dc4309919bc180434ba312d78808fa32 100644 +index 5d24c2e36dcdbee25a0bb005bf0a20963d442a31..aff9bb1a0a64d689e15f7be57bed9e5bec80be6a 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h -@@ -397,6 +397,8 @@ private: +@@ -399,6 +399,8 @@ private: void clearPageSpecificData(WebCore::PageIdentifier); @@ -6749,7 +6627,7 @@ index 6f43a9c68ee5c247184e327bdda83ce65df444f5..b34971ca9e296106dda574f165c4f28d LogUserInteraction(WebCore::RegistrableDomain domain) ResourceLoadStatisticsUpdated(Vector<WebCore::ResourceLoadStatistics> statistics) -> () diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm -index 0e5e0a6a203675f45e107ed487a3ed120c70ee4f..91f26663519d0cea2b868c48c618613a94008582 100644 +index 446f6d91016132ceb2a28122990e844e4576ed4c..0886e0642ac2353de9184b12b8a0d23d6f0f0fd3 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm @@ -894,6 +894,14 @@ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)data @@ -6799,10 +6677,10 @@ index 38aee06c97b6c7d20e0569295bde4192999d9c6e..eb7159615e69a275fe0b52790311209e ;; Except deny access to new-style iOS Keychain folders which are UUIDs. (deny file-read* file-write* diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp -index 9ebef44bdd6458e145f3dbdf9c5733020b378f10..29722291ef1391809c931aa7e0e5417d84d20f23 100644 +index f7edb09dfd0bcee4b60f4bf8ce16f8cbeea937f8..1c10fb6ea21b897015a5c0092fc8f6cd4fb34c0c 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp -@@ -396,6 +396,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr<GInputStream>&& inputStream) +@@ -427,6 +427,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr<GInputStream>&& inputStream) else m_inputStream = WTF::move(inputStream); @@ -6812,10 +6690,10 @@ index 9ebef44bdd6458e145f3dbdf9c5733020b378f10..29722291ef1391809c931aa7e0e5417d } diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake -index e0e3a8185373f3e51937955343fae379cd435fca..9d936f5e3c0d7fac37d5eb914310fd7fe7565bae 100644 +index f98ae19e9c5fa4b0601572de46b1e0a1c62e92d8..747157cb6b47441ed2c1ca89465c81a89acc7f2a 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake -@@ -228,6 +228,7 @@ set(WPE_API_HEADER_TEMPLATES +@@ -227,6 +227,7 @@ set(WPE_API_HEADER_TEMPLATES ${WEBKIT_DIR}/UIProcess/API/glib/WebKitWebsitePolicies.h.in ${WEBKIT_DIR}/UIProcess/API/glib/WebKitXRPermissionRequest.h.in ${WEBKIT_DIR}/UIProcess/API/glib/webkit.h.in @@ -6824,7 +6702,7 @@ index e0e3a8185373f3e51937955343fae379cd435fca..9d936f5e3c0d7fac37d5eb914310fd7f if (ENABLE_2022_GLIB_API) diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake -index 86a1febedca9fcbe7203db8cec94e8db1ef25a43..bda8ea972400bc6f3b28ef5fd40463d5a50e3a9c 100644 +index 86a1febedca9fcbe7203db8cec94e8db1ef25a43..efdc87688149706c783906b643489fbe695d61d2 100644 --- a/Source/WebKit/PlatformWin.cmake +++ b/Source/WebKit/PlatformWin.cmake @@ -54,8 +54,13 @@ list(APPEND WebKit_SOURCES @@ -6832,9 +6710,9 @@ index 86a1febedca9fcbe7203db8cec94e8db1ef25a43..bda8ea972400bc6f3b28ef5fd40463d5 UIProcess/win/AutomationClientWin.cpp UIProcess/win/AutomationSessionClientWin.cpp + -+ UIProcess/win/WebPageInspectorTargetProxyWin.cpp + UIProcess/win/InspectorPlaywrightAgentClientWin.cpp UIProcess/win/PageClientImpl.cpp ++ UIProcess/win/PageInspectorTargetProxyWin.cpp UIProcess/win/WebContextMenuProxyWin.cpp + UIProcess/win/WebPageInspectorEmulationAgentWin.cpp + UIProcess/win/WebPageInspectorInputAgentWin.cpp @@ -6850,10 +6728,10 @@ index 86a1febedca9fcbe7203db8cec94e8db1ef25a43..bda8ea972400bc6f3b28ef5fd40463d5 WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp diff --git a/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h b/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h -index 3e3718b9be38ecb2115030a13c71e226d4b14f64..408b6706a324078f6d1e575863a8581c7b021560 100644 +index 5c7a6999176357ad21ca673db75363f27cf33790..faa9a55d561a185a659519bcaa5a1026fa3b1921 100644 --- a/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h +++ b/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h -@@ -44,6 +44,7 @@ +@@ -45,6 +45,7 @@ #import <WebKit/WKWebViewPrivate.h> #import <WebKit/_WKActivatedElementInfo.h> #import <WebKit/_WKAttachment.h> @@ -6862,7 +6740,7 @@ index 3e3718b9be38ecb2115030a13c71e226d4b14f64..408b6706a324078f6d1e575863a8581c #import <WebKit/_WKContentWorldConfiguration.h> #import <WebKit/_WKElementAction.h> diff --git a/Source/WebKit/Shared/AuxiliaryProcess.h b/Source/WebKit/Shared/AuxiliaryProcess.h -index 97d887311d7dabc0902587072b234cfbfb0c8264..3950ae8702e3288e18e98a2b167564ab6ec9f7e1 100644 +index 04ffbae16bdfe24465e635afce7f5042073158a0..9c87adff05fcdc47fb15cc4bcac86c26882c6e3e 100644 --- a/Source/WebKit/Shared/AuxiliaryProcess.h +++ b/Source/WebKit/Shared/AuxiliaryProcess.h @@ -216,6 +216,11 @@ struct AuxiliaryProcessInitializationParameters { @@ -6878,7 +6756,7 @@ index 97d887311d7dabc0902587072b234cfbfb0c8264..3950ae8702e3288e18e98a2b167564ab } // namespace WebKit diff --git a/Source/WebKit/Shared/NativeWebKeyboardEvent.h b/Source/WebKit/Shared/NativeWebKeyboardEvent.h -index 02d7072a9124bdc6ae3abb395c6e1451a18916db..aa5d78c48f7cb1b9213725ef2d87c75c1af038b2 100644 +index 63cfe7fc9385af4f17293ad0e43997e688401cd8..e22b7ee6001ee06a731f01c4ca3ab2d3e2e525a8 100644 --- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h +++ b/Source/WebKit/Shared/NativeWebKeyboardEvent.h @@ -33,6 +33,7 @@ @@ -6932,7 +6810,7 @@ index 02d7072a9124bdc6ae3abb395c6e1451a18916db..aa5d78c48f7cb1b9213725ef2d87c75c #if USE(APPKIT) diff --git a/Source/WebKit/Shared/NativeWebMouseEvent.h b/Source/WebKit/Shared/NativeWebMouseEvent.h -index fc425c3817e9b43bca3afe6b650bd091797f2448..30c4096aaee42cc822ad79098be0d75919d5cec3 100644 +index 3f1087581732873bef9aab9de8010804a337e3e5..feb044c070a3042b3c4bf2e81078e52d5c8f7382 100644 --- a/Source/WebKit/Shared/NativeWebMouseEvent.h +++ b/Source/WebKit/Shared/NativeWebMouseEvent.h @@ -91,6 +91,11 @@ public: @@ -6941,14 +6819,14 @@ index fc425c3817e9b43bca3afe6b650bd091797f2448..30c4096aaee42cc822ad79098be0d759 +#if PLATFORM(GTK) || USE(LIBWPE) || PLATFORM(WIN) + NativeWebMouseEvent(WebEventType type, WebMouseEventButton button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet<WebEventModifier> modifiers, MonotonicTime timestamp) -+ : WebMouseEvent({type, modifiers, timestamp}, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount, 0, WebMouseEventInputSource::Hardware) { } ++ : WebMouseEvent({type, modifiers, timestamp}, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount, 0, WebEventInputSource::UserDriven) { } +#endif + #if USE(APPKIT) NSEvent* nativeEvent() const { return m_nativeEvent.get(); } #elif PLATFORM(GTK) diff --git a/Source/WebKit/Shared/NativeWebWheelEvent.h b/Source/WebKit/Shared/NativeWebWheelEvent.h -index 58c90822b9bda82b1bdba018ddc1e20378a52461..71c59771e2cc2db98f699cc43b624fc3c0e13127 100644 +index b5361fedd7d921f512956d20819c49d425221080..3628908eeaba9dda7c19ded41b6da6e5c148d382 100644 --- a/Source/WebKit/Shared/NativeWebWheelEvent.h +++ b/Source/WebKit/Shared/NativeWebWheelEvent.h @@ -79,6 +79,11 @@ public: @@ -6964,10 +6842,10 @@ index 58c90822b9bda82b1bdba018ddc1e20378a52461..71c59771e2cc2db98f699cc43b624fc3 NSEvent* nativeEvent() const { return m_nativeEvent.get(); } #elif PLATFORM(GTK) diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in -index 28284f8b63d59d4ae21223cce2012e78e7829f56..41aaae3573cb952d517e73607361a6476f325e63 100644 +index 597e611a1b621f049fa034d7934cb7918cad8f87..5829c63b669d57903b73d7078a41ebfe9006fc89 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in -@@ -2717,6 +2717,9 @@ class WebCore::AuthenticationChallenge { +@@ -2728,6 +2728,9 @@ class WebCore::AuthenticationChallenge { class WebCore::DragData { #if PLATFORM(COCOA) String pasteboardName(); @@ -6977,7 +6855,7 @@ index 28284f8b63d59d4ae21223cce2012e78e7829f56..41aaae3573cb952d517e73607361a647 #endif WebCore::IntPoint clientPosition(); WebCore::IntPoint globalPosition(); -@@ -3503,6 +3506,7 @@ enum class WebCore::WasPrivateRelayed : bool; +@@ -3160,6 +3163,7 @@ enum class WebCore::WasPrivateRelayed : bool; String httpStatusText; String httpVersion; WebCore::HTTPHeaderMap httpHeaderFields; @@ -6986,7 +6864,7 @@ index 28284f8b63d59d4ae21223cce2012e78e7829f56..41aaae3573cb952d517e73607361a647 WebCore::ResourceResponseBase::Source source; WebCore::ResourceResponseBase::Type type; diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp -index b81260e021336831e0a8a45279edf1ebc1d1da22..ad3601d874eb87da17ac6975271f9fde266549c7 100644 +index fcadde7e024c363ebdf53d1c20436af5d2512e1a..67cd6dce8d6c1bf66e429c29d9ed0a396718cb80 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.cpp +++ b/Source/WebKit/Shared/WebKeyboardEvent.cpp @@ -51,6 +51,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S @@ -7064,11 +6942,11 @@ index b81260e021336831e0a8a45279edf1ebc1d1da22..ad3601d874eb87da17ac6975271f9fde + +#endif + - WebKeyboardEvent::~WebKeyboardEvent() - { - } + WebKeyboardEvent::~WebKeyboardEvent() = default; + + bool WebKeyboardEvent::isKeyboardEventType(WebEventType type) diff --git a/Source/WebKit/Shared/WebKeyboardEvent.h b/Source/WebKit/Shared/WebKeyboardEvent.h -index b0fa2a97f017bfaae88204fd737d411f2ec8ed44..7c805dd37431c1adf6a21e6843f347828fe5391e 100644 +index 8915f44919a131e5e12344362907396b3821e13e..62846c5c837a584c4180d6c5d069fc39c8b58980 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.h +++ b/Source/WebKit/Shared/WebKeyboardEvent.h @@ -42,14 +42,18 @@ public: @@ -7089,7 +6967,7 @@ index b0fa2a97f017bfaae88204fd737d411f2ec8ed44..7c805dd37431c1adf6a21e6843f34782 + WebKeyboardEvent(WebEventType, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier>, MonotonicTime timestamp); #endif - const String& text() const { return m_text; } + const String& text() const LIFETIME_BOUND { return m_text; } @@ -93,6 +97,7 @@ public: static String keyCodeStringForGdkKeycode(unsigned); static String keyIdentifierForGdkKeyval(unsigned); @@ -7099,22 +6977,22 @@ index b0fa2a97f017bfaae88204fd737d411f2ec8ed44..7c805dd37431c1adf6a21e6843f34782 #endif diff --git a/Source/WebKit/Shared/WebMouseEvent.h b/Source/WebKit/Shared/WebMouseEvent.h -index bb4add3d11084126cee36228b6f3ff7d54d7a6f5..c0601efc42769db53cdd24788e3ddca34f311911 100644 +index 3accf5c66062f746029665e4a9ef970418784df2..e16205860562432eedeb017d354cd0c948b0e036 100644 --- a/Source/WebKit/Shared/WebMouseEvent.h +++ b/Source/WebKit/Shared/WebMouseEvent.h -@@ -74,6 +74,7 @@ public: +@@ -72,6 +72,7 @@ public: WebMouseEventButton button() const { return m_button; } unsigned short buttons() const { return m_buttons; } + void playwrightSetButtons(unsigned short buttons) { m_buttons = buttons; } const WebCore::DoublePoint& position() const { return m_position; } // Relative to the view. void setPosition(const WebCore::DoublePoint& position) { m_position = position; } - const WebCore::DoublePoint& globalPosition() const { return m_globalPosition; } + const WebCore::DoublePoint& globalPosition() const LIFETIME_BOUND { return m_globalPosition; } diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h -index 89788953d745be3ba7362eddd81c5d30414f1b3b..b9012215e881ecad2b97265b03fb49152db256ae 100644 +index d0e04502450eedf0dc1e6104f10fe122edee992e..aaa5dfced49e1f20cbd02da81364dbf0285a04d9 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.h +++ b/Source/WebKit/Shared/WebPageCreationParameters.h -@@ -313,6 +313,9 @@ struct WebPageCreationParameters { +@@ -317,6 +317,9 @@ struct WebPageCreationParameters { WebCore::ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking { WebCore::ShouldRelaxThirdPartyCookieBlocking::No }; bool httpsUpgradeEnabled { true }; @@ -7125,10 +7003,10 @@ index 89788953d745be3ba7362eddd81c5d30414f1b3b..b9012215e881ecad2b97265b03fb4915 #if ENABLE(APP_HIGHLIGHTS) WebCore::HighlightVisibility appHighlightsVisible { WebCore::HighlightVisibility::Hidden }; diff --git a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in -index 4ca6fc620263b984a12b4d1b53ebe85481686202..cccb74fa82f11b661916d211bccc028cae9fff90 100644 +index 707a31d075afd590890fb3e0054f256b4a567ac1..55ac3de3488b82b77888101d6677fb76c1b1c00c 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in +++ b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in -@@ -229,6 +229,9 @@ enum class WebCore::UserInterfaceLayoutDirection : bool; +@@ -233,6 +233,9 @@ enum class WebCore::UserInterfaceLayoutDirection : bool; bool httpsUpgradeEnabled; @@ -7139,7 +7017,7 @@ index 4ca6fc620263b984a12b4d1b53ebe85481686202..cccb74fa82f11b661916d211bccc028c WebCore::HighlightVisibility appHighlightsVisible; #endif diff --git a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp -index b41816f4ba670a7058014f078ef02441c3ab0abf..983d8679574a2555b348ab0df7699253b7d4a9fe 100644 +index 64bcde96dfe76998f6ed6297be892c6548123049..be05d2e4f6749ef60a13e2c8cf77e3fa6ffd41f7 100644 --- a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp +++ b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp @@ -32,7 +32,7 @@ @@ -7153,13 +7031,13 @@ index b41816f4ba670a7058014f078ef02441c3ab0abf..983d8679574a2555b348ab0df7699253 CString executablePath = FileSystem::currentExecutablePath(); @@ -44,7 +44,7 @@ static String getExecutablePath() - static String findWebKitProcess(const char* processName) + static String findWebKitProcess(const ASCIILiteral processName) { -#if ENABLE(DEVELOPER_MODE) +#if TRUE static const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH"); if (execDirectory) { - String processPath = FileSystem::pathByAppendingComponent(FileSystem::stringFromFileSystemRepresentation(execDirectory), StringView::fromLatin1(processName)); + String processPath = FileSystem::pathByAppendingComponent(FileSystem::stringFromFileSystemRepresentation(execDirectory), processName); diff --git a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp index 6091f843195ae84a25e955304170d84df8ec012e..6c8ce488b96ffeee50371925df704accf03e154c 100644 --- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp @@ -7423,10 +7301,10 @@ index 092d3c2f493aa18e09f43db2d153d5aa6822e000..65d577e344637c99885b373500d353c1 + } // namespace WebKit diff --git a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp -index dc348e105065fd3c5494aa827cd69690f593dc2e..ee883b24d9c62784890b2638014c9427f6ad43ae 100644 +index 7d054a56b04d1b19f12e6463077bccb67adcad25..bab6718c22da62179df92dcead696c7610cb4a9d 100644 --- a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp +++ b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp -@@ -40,6 +40,15 @@ +@@ -51,6 +51,15 @@ __attribute__((weak)) extern "C" int __llvm_profile_dump(void); namespace WebKit { @@ -7442,7 +7320,7 @@ index dc348e105065fd3c5494aa827cd69690f593dc2e..ee883b24d9c62784890b2638014c9427 AuxiliaryProcessMainCommon::AuxiliaryProcessMainCommon() { #if ENABLE(BREAKPAD) -@@ -81,6 +90,10 @@ WTF_ALLOW_UNSAFE_BUFFER_USAGE_END +@@ -91,6 +100,10 @@ bool AuxiliaryProcessMainCommon::parseCommandLine(int argc, char** argv) } #endif @@ -7454,7 +7332,7 @@ index dc348e105065fd3c5494aa827cd69690f593dc2e..ee883b24d9c62784890b2638014c9427 } diff --git a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp -index 053e9336017d8818b3cbea79ce7c145fd5c46274..5632498d6ef875df80fc68ec206a9d08e5d05a6f 100644 +index b321d93d23d0d1862385b022569dc65323e8691c..ba3bcc9bc20b9512b9288cb2d7e5a3d8b90a0e37 100644 --- a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp +++ b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp @@ -47,6 +47,10 @@ bool AuxiliaryProcessMainCommon::parseCommandLine(int argc, char** argv) @@ -7469,7 +7347,7 @@ index 053e9336017d8818b3cbea79ce7c145fd5c46274..5632498d6ef875df80fc68ec206a9d08 JSC::Config::configureForTesting(); else if (!strcmp(argv[i], "-disable-jit")) diff --git a/Source/WebKit/Sources.txt b/Source/WebKit/Sources.txt -index 2ff64a35be0d18321b1086c2c24387c063b8b83f..8f50c9cff94223f4e90adb4cd2d659e178c65d55 100644 +index 382ea8985d8781d7d49f12a90bf0ecc65232985f..ebe6f275fed47f09490052f0548641b1dec4b8f4 100644 --- a/Source/WebKit/Sources.txt +++ b/Source/WebKit/Sources.txt @@ -403,6 +403,7 @@ UIProcess/AboutSchemeHandler.cpp @@ -7480,7 +7358,7 @@ index 2ff64a35be0d18321b1086c2c24387c063b8b83f..8f50c9cff94223f4e90adb4cd2d659e1 UIProcess/DeviceIdHashSaltStorage.cpp UIProcess/DisplayLink.cpp UIProcess/DisplayLinkProcessProxyClient.cpp -@@ -414,6 +415,8 @@ UIProcess/FrameLoadState.cpp +@@ -414,17 +415,21 @@ UIProcess/FrameLoadState.cpp UIProcess/FrameProcess.cpp UIProcess/GeolocationPermissionRequestManagerProxy.cpp UIProcess/GeolocationPermissionRequestProxy.cpp @@ -7489,11 +7367,11 @@ index 2ff64a35be0d18321b1086c2c24387c063b8b83f..8f50c9cff94223f4e90adb4cd2d659e1 UIProcess/LegacyGlobalSettings.cpp UIProcess/MediaKeySystemPermissionRequestManagerProxy.cpp UIProcess/MediaKeySystemPermissionRequestProxy.cpp -@@ -421,10 +424,12 @@ UIProcess/ModelElementController.cpp UIProcess/OverrideLanguages.cpp UIProcess/PageClient.cpp UIProcess/PageLoadState.cpp +UIProcess/PlaywrightFullScreenManagerProxyClient.cpp + UIProcess/ProcessActivityGroup.cpp UIProcess/ProcessAssertion.cpp UIProcess/ProcessThrottler.cpp UIProcess/ProvisionalFrameProxy.cpp @@ -7511,8 +7389,8 @@ index 2ff64a35be0d18321b1086c2c24387c063b8b83f..8f50c9cff94223f4e90adb4cd2d659e1 UIProcess/WebPageProxy.cpp UIProcess/WebPageProxyMessageReceiverRegistration.cpp UIProcess/WebPageProxyTesting.cpp -@@ -640,6 +647,7 @@ UIProcess/Inspector/WebPageInspectorController.cpp - UIProcess/Inspector/WebPageInspectorTargetProxy.cpp +@@ -641,6 +648,7 @@ UIProcess/Inspector/WebPageDebuggable.cpp + UIProcess/Inspector/WebPageInspectorController.cpp UIProcess/Inspector/Agents/InspectorBrowserAgent.cpp +UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp @@ -7520,10 +7398,10 @@ index 2ff64a35be0d18321b1086c2c24387c063b8b83f..8f50c9cff94223f4e90adb4cd2d659e1 UIProcess/Media/AudioSessionRoutingArbitratorProxy.cpp UIProcess/Media/MediaUsageManager.cpp diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt -index 6c8674c676b3f869db7dd78f976d16f239372ecc..2c70d8c7dcd8179d7c10d9ad6e186f3c5195dda6 100644 +index 8f5e05d7905c09452701a390277d8528d3c53170..3ac17db7930b41d33d7e0f6ee9564b997967a8a6 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt -@@ -283,6 +283,7 @@ UIProcess/API/Cocoa/_WKArchiveExclusionRule.mm @nonARC +@@ -286,6 +286,7 @@ UIProcess/API/Cocoa/_WKArchiveExclusionRule.mm @nonARC UIProcess/API/Cocoa/_WKAttachment.mm @nonARC UIProcess/API/Cocoa/_WKAutomationSession.mm @nonARC UIProcess/API/Cocoa/_WKAutomationSessionConfiguration.mm @nonARC @@ -7532,7 +7410,7 @@ index 6c8674c676b3f869db7dd78f976d16f239372ecc..2c70d8c7dcd8179d7c10d9ad6e186f3c UIProcess/API/Cocoa/_WKContextMenuElementInfo.mm @nonARC UIProcess/API/Cocoa/_WKCustomHeaderFields.mm @nonARC @no-unify diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt -index 2327e9e6ae538686f92ff71aa644f87b74c921cc..fe3318e5bc94db3cb442803137a00d14d5d9cc9b 100644 +index 4b68f079d9d43d1b0bef8e3b31cd0d6f3a730ae9..3799718e6e5791791335171a8adb0365231501bf 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -134,6 +134,7 @@ UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify @@ -7559,30 +7437,32 @@ index 2327e9e6ae538686f92ff71aa644f87b74c921cc..fe3318e5bc94db3cb442803137a00d14 UIProcess/glib/ScreenManager.cpp UIProcess/glib/SystemSettingsManagerProxy.cpp UIProcess/glib/WebPageProxyGLib.cpp -@@ -287,7 +290,6 @@ UIProcess/gtk/DisplayX11.cpp @no-unify +@@ -287,9 +290,9 @@ UIProcess/gtk/DisplayX11.cpp @no-unify UIProcess/gtk/DisplayWayland.cpp @no-unify UIProcess/gtk/GRefPtrGtk.cpp @no-unify UIProcess/gtk/GtkUtilities.cpp @no-unify -UIProcess/gtk/WebDateTimePickerGtk.cpp UIProcess/gtk/HardwareAccelerationManager.cpp UIProcess/gtk/KeyBindingTranslator.cpp ++UIProcess/gtk/PageInspectorTargetProxyGtk.cpp UIProcess/gtk/PointerLockManager.cpp @no-unify -@@ -303,6 +305,10 @@ UIProcess/gtk/ViewGestureControllerGtk.cpp + UIProcess/gtk/PointerLockManagerWayland.cpp @no-unify + UIProcess/gtk/PointerLockManagerX11.cpp @no-unify +@@ -303,6 +306,9 @@ UIProcess/gtk/ViewGestureControllerGtk.cpp UIProcess/gtk/WebColorPickerGtk.cpp UIProcess/gtk/WebContextMenuProxyGtk.cpp UIProcess/gtk/WebDataListSuggestionsDropdownGtk.cpp +UIProcess/gtk/WebDateTimePickerGtk.cpp +UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp +UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp -+UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp UIProcess/gtk/WebPageProxyGtk.cpp @no-unify UIProcess/gtk/WebPasteboardProxyGtk.cpp UIProcess/gtk/WebPopupMenuProxyGtk.cpp diff --git a/Source/WebKit/SourcesWPE.txt b/Source/WebKit/SourcesWPE.txt -index d1cfdba673d22324a7e9188cc40070bf30eea360..7bce1f94bbcfdd78ed10ffdee1c7ce5d13dc0c9e 100644 +index 3d1ed6156127f02614905e30835fa4c6334ae914..fb362b66d00c2081d6eb5380fb2bd7967223f489 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt -@@ -137,6 +137,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify +@@ -138,6 +138,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify @@ -7590,7 +7470,7 @@ index d1cfdba673d22324a7e9188cc40070bf30eea360..7bce1f94bbcfdd78ed10ffdee1c7ce5d UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify UIProcess/API/glib/WebKitCookieManager.cpp @no-unify UIProcess/API/glib/WebKitCredential.cpp @no-unify -@@ -171,6 +172,7 @@ UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify +@@ -174,6 +175,7 @@ UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify UIProcess/API/glib/WebKitOptionMenuItem.cpp @no-unify UIProcess/API/glib/WebKitPermissionRequest.cpp @no-unify UIProcess/API/glib/WebKitPermissionStateQuery.cpp @no-unify @@ -7598,7 +7478,7 @@ index d1cfdba673d22324a7e9188cc40070bf30eea360..7bce1f94bbcfdd78ed10ffdee1c7ce5d UIProcess/API/glib/WebKitPolicyDecision.cpp @no-unify UIProcess/API/glib/WebKitPrivate.cpp @no-unify UIProcess/API/glib/WebKitProtocolHandler.cpp @no-unify -@@ -239,6 +241,7 @@ UIProcess/Gamepad/wpe/PlatformGamepadWPE.cpp +@@ -242,6 +244,7 @@ UIProcess/Gamepad/wpe/PlatformGamepadWPE.cpp UIProcess/geoclue/GeoclueGeolocationProvider.cpp @@ -7606,7 +7486,7 @@ index d1cfdba673d22324a7e9188cc40070bf30eea360..7bce1f94bbcfdd78ed10ffdee1c7ce5d UIProcess/glib/DRMMainDevice.cpp @no-unify UIProcess/glib/DisplayLinkGLib.cpp UIProcess/glib/DisplayVBlankMonitor.cpp -@@ -246,6 +249,7 @@ UIProcess/glib/DisplayVBlankMonitorDRM.cpp +@@ -249,6 +252,7 @@ UIProcess/glib/DisplayVBlankMonitorDRM.cpp UIProcess/glib/DisplayVBlankMonitorThreaded.cpp UIProcess/glib/DisplayVBlankMonitorTimer.cpp UIProcess/glib/FenceMonitor.cpp @@ -7614,7 +7494,11 @@ index d1cfdba673d22324a7e9188cc40070bf30eea360..7bce1f94bbcfdd78ed10ffdee1c7ce5d UIProcess/glib/ScreenManager.cpp UIProcess/glib/SystemSettingsManagerProxy.cpp UIProcess/glib/WebPageProxyGLib.cpp -@@ -284,6 +288,12 @@ UIProcess/wpe/DisplayVBlankMonitorWPE.cpp +@@ -284,9 +288,15 @@ UIProcess/soup/WebProcessPoolSoup.cpp + + UIProcess/wpe/AcceleratedBackingStore.cpp + UIProcess/wpe/DisplayVBlankMonitorWPE.cpp ++UIProcess/wpe/PageInspectorTargetProxyWPE.cpp UIProcess/wpe/ScreenManagerWPE.cpp UIProcess/wpe/SystemSettingsManagerProxyWPE.cpp UIProcess/wpe/WPEUtilities.cpp @@ -7623,12 +7507,11 @@ index d1cfdba673d22324a7e9188cc40070bf30eea360..7bce1f94bbcfdd78ed10ffdee1c7ce5d +UIProcess/wpe/WebDateTimePickerWPE.cpp +UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp +UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp -+UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp UIProcess/wpe/WebPageProxyWPE.cpp UIProcess/wpe/WebPasteboardProxyWPE.cpp UIProcess/wpe/WebPreferencesWPE.cpp diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp -index be65e4df37f9cabe694a5dc3c3489fb0d4ecef8c..eaa76aba0cf70222ce85e1277830ef596ea099ce 100644 +index 367ad615c527a09f3c3d3d86bf7eca87afbc13ed..9ef85591e159555c93e5b7a9635d5e289c22a243 100644 --- a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp @@ -261,6 +261,11 @@ BrowsingContextGroup* PageConfiguration::preferredBrowsingContextGroup() const @@ -7644,51 +7527,33 @@ index be65e4df37f9cabe694a5dc3c3489fb0d4ecef8c..eaa76aba0cf70222ce85e1277830ef59 { return m_data.pageToCloneSessionStorageFrom.get(); diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.h b/Source/WebKit/UIProcess/API/APIPageConfiguration.h -index d57d51192f786dabd007b8128a0a69fc9ddaaa3d..7e9caa2ed2ce23fe942ebae95fda7a392d335924 100644 +index b2227e338dcd10bfdaaf1a4c4d632003cf9e6f73..3afcd9c4f12d7cf755f9b849da7dfb98812afdf7 100644 --- a/Source/WebKit/UIProcess/API/APIPageConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.h -@@ -170,6 +170,10 @@ public: - WebKit::WebPageProxy* relatedPage() const; +@@ -173,6 +173,10 @@ public: + WebKit::WebPageProxy* NODELETE relatedPage() const; void setRelatedPage(WeakPtr<WebKit::WebPageProxy>&& relatedPage) { m_data.relatedPage = WTF::move(relatedPage); } + // This is similar to relatedPage(), but it is also set for noopener links. + WebKit::WebPageProxy* openerPageForInspector() const; + void setOpenerPageForInspector(WeakPtr<WebKit::WebPageProxy>&& openerPageForInspector) { m_data.openerPageForInspector = WTF::move(openerPageForInspector); } + - WebKit::WebPageProxy* pageToCloneSessionStorageFrom() const; - void setPageToCloneSessionStorageFrom(WeakPtr<WebKit::WebPageProxy>&&); - -@@ -297,7 +301,7 @@ public: - #if ENABLE(APP_BOUND_DOMAINS) - bool ignoresAppBoundDomains() const { return m_data.ignoresAppBoundDomains; } - void setIgnoresAppBoundDomains(bool shouldIgnore) { m_data.ignoresAppBoundDomains = shouldIgnore; } -- -+ - bool limitsNavigationsToAppBoundDomains() const { return m_data.limitsNavigationsToAppBoundDomains; } - void setLimitsNavigationsToAppBoundDomains(bool limits) { m_data.limitsNavigationsToAppBoundDomains = limits; } - #endif -@@ -442,7 +446,7 @@ public: - - bool isLockdownModeExplicitlySet() const; - bool lockdownModeEnabled() const; -- -+ - bool isEnhancedSecurityEnabled() const; + WebKit::WebPageProxy* NODELETE pageToCloneSessionStorageFrom() const; + void NODELETE setPageToCloneSessionStorageFrom(WeakPtr<WebKit::WebPageProxy>&&); - void setAllowTestOnlyIPC(bool enabled) { m_data.allowTestOnlyIPC = enabled; } -@@ -531,6 +535,7 @@ private: +@@ -540,6 +544,7 @@ private: #endif RefPtr<WebKit::WebPageGroup> pageGroup; WeakPtr<WebKit::WebPageProxy> relatedPage; + WeakPtr<WebKit::WebPageProxy> openerPageForInspector; Box<std::optional<OpenerInfo>> openerInfo; WebCore::Site openedSite; - WTF::String openedMainFrameName; + bool processInheritedFromOpener { false }; diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp -index b909437495735fa6bb662d63f9a1f08552e012f2..2e21776b6adeb2ae8ef8cfc668e3d67c9120f5f2 100644 +index 182dacc96abaab8d5fc9be0658dd1683f48af4db..80d6939f779a5d9a46e1a916cafef718faab9326 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp -@@ -52,6 +52,10 @@ Ref<ProcessPoolConfiguration> ProcessPoolConfiguration::copy() +@@ -56,6 +56,10 @@ Ref<ProcessPoolConfiguration> ProcessPoolConfiguration::copy() copy->m_ignoreSynchronousMessagingTimeoutsForTesting = this->m_ignoreSynchronousMessagingTimeoutsForTesting; copy->m_attrStyleEnabled = this->m_attrStyleEnabled; copy->m_shouldThrowExceptionForGlobalConstantRedeclaration = this->m_shouldThrowExceptionForGlobalConstantRedeclaration; @@ -7700,7 +7565,7 @@ index b909437495735fa6bb662d63f9a1f08552e012f2..2e21776b6adeb2ae8ef8cfc668e3d67c copy->m_shouldTakeUIBackgroundAssertion = this->m_shouldTakeUIBackgroundAssertion; copy->m_shouldCaptureDisplayInUIProcess = this->m_shouldCaptureDisplayInUIProcess; diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h -index 637b5c677a806040d62d2796cff59a7f1505a8fd..f02e0b487fb1550f8093e8a5306b26f0b2267564 100644 +index 2b0e5565fd123126f1c6db65059975a344f152df..99b237e2736cd1b5c0e93dfcef5c81ab29ea74c1 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h @@ -49,7 +49,7 @@ public: @@ -7712,7 +7577,7 @@ index 637b5c677a806040d62d2796cff59a7f1505a8fd..f02e0b487fb1550f8093e8a5306b26f0 Ref<ProcessPoolConfiguration> copy(); bool usesSingleWebProcess() const { return m_usesSingleWebProcess; } -@@ -92,10 +92,20 @@ public: +@@ -93,10 +93,20 @@ public: bool attrStyleEnabled() const { return m_attrStyleEnabled; } void setAttrStyleEnabled(bool enabled) { m_attrStyleEnabled = enabled; } @@ -7735,7 +7600,7 @@ index 637b5c677a806040d62d2796cff59a7f1505a8fd..f02e0b487fb1550f8093e8a5306b26f0 bool alwaysRunsAtBackgroundPriority() const { return m_alwaysRunsAtBackgroundPriority; } void setAlwaysRunsAtBackgroundPriority(bool alwaysRunsAtBackgroundPriority) { m_alwaysRunsAtBackgroundPriority = alwaysRunsAtBackgroundPriority; } -@@ -176,6 +186,10 @@ private: +@@ -177,6 +187,10 @@ private: bool m_ignoreSynchronousMessagingTimeoutsForTesting { false }; bool m_attrStyleEnabled { false }; bool m_shouldThrowExceptionForGlobalConstantRedeclaration { true }; @@ -7759,7 +7624,7 @@ index d9f80360027a2e0c9dd5a3594189dddfde53966d..c6862db4346514707fb84427123fb4ce virtual void setStatusText(WebKit::WebPageProxy*, const WTF::String&) { } virtual void mouseDidMoveOverElement(WebKit::WebPageProxy&, const WebKit::WebHitTestResultData&, OptionSet<WebKit::WebEventModifier>) { } diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.cpp b/Source/WebKit/UIProcess/API/C/WKInspector.cpp -index 5c80a1fbd3be779d7d99d04e7f803cbc9de739b0..9d2b7166e4e12ab43a23f5cb9d12b8c0b825ef56 100644 +index 5ae69462a4c5a61e098e4df7def6dec3c842e167..e04134e2d91bfc5b1832a7a641614483c748513a 100644 --- a/Source/WebKit/UIProcess/API/C/WKInspector.cpp +++ b/Source/WebKit/UIProcess/API/C/WKInspector.cpp @@ -28,6 +28,11 @@ @@ -7775,7 +7640,7 @@ index 5c80a1fbd3be779d7d99d04e7f803cbc9de739b0..9d2b7166e4e12ab43a23f5cb9d12b8c0 #include "WebFrameProxy.h" #include "WebInspectorUIProxy.h" @@ -131,4 +136,11 @@ void WKInspectorToggleElementSelection(WKInspectorRef inspectorRef) - toProtectedImpl(inspectorRef)->toggleElementSelection(); + protect(toImpl(inspectorRef))->toggleElementSelection(); } +void WKInspectorInitializeRemoteInspectorPipe(ConfigureDataStoreCallback configureDataStore, CreatePageCallback createPage, QuitCallback quit) @@ -7802,10 +7667,10 @@ index 026121d114c5fcad84c1396be8d692625beaa3bd..edd6e5cae033124c589959a42522fde0 } #endif diff --git a/Source/WebKit/UIProcess/API/C/WKPage.cpp b/Source/WebKit/UIProcess/API/C/WKPage.cpp -index d0fa40efed0a6c61d903058464bcdced85276d6c..0d99584472bebf4a95d0e34df63e6ea6b8abe251 100644 +index 3ceafb8efa81d2ea5d6d5db862564e5d9549fd50..5aad4b41ff5975d2e4b499e407a41e3fe1983b90 100644 --- a/Source/WebKit/UIProcess/API/C/WKPage.cpp +++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp -@@ -1912,6 +1912,13 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient +@@ -1913,6 +1913,13 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient m_client.addMessageToConsole(toAPI(&page), toAPI(message.impl()), m_client.base.clientInfo); } @@ -7819,7 +7684,7 @@ index d0fa40efed0a6c61d903058464bcdced85276d6c..0d99584472bebf4a95d0e34df63e6ea6 void setStatusText(WebPageProxy* page, const String& text) final { if (!m_client.setStatusText) -@@ -1949,6 +1956,8 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient +@@ -1950,6 +1957,8 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient { if (!m_client.didNotHandleKeyEvent) return; @@ -7906,11 +7771,11 @@ index acaeaef1be6d64f16d56d966db12cf9bb1f0507e..bb81783b20e33f69ceef2d00785a2e9c /*! @abstract A delegate to request permission for microphone audio and camera video access. @param webView The web view invoking the delegate method. diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h -index 47b1b5ed21a65035d9bef05a991845480cfa1e93..17bd5eeafa50f94062b6f2a1b178efbfd23722fc 100644 +index dcab0400bfdd58f9d16726aba6ce66492f7be34b..a1337cc7ab9f04fea3f51a3003fdb946ce3d34e5 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h -@@ -138,6 +138,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) - #endif +@@ -132,6 +132,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) + @property (nullable, nonatomic, copy) NSArray *proxyConfigurations NS_REFINED_FOR_SWIFT API_AVAILABLE(macos(14.0), ios(17.0)); #endif +- (uint64_t)sessionID; @@ -7919,10 +7784,10 @@ index 47b1b5ed21a65035d9bef05a991845480cfa1e93..17bd5eeafa50f94062b6f2a1b178efbf NS_ASSUME_NONNULL_END diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm -index 083bb2ee778bfc04e66bfe261f81e0dfcb8496fb..c2138b162edc34a44163137745e9526447d24841 100644 +index 632bf6f982628fe174eac150b36a10c1d7677b09..09f3075420aa9aa84a93c40533d3eea7acbdc587 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm -@@ -56,6 +56,7 @@ +@@ -57,6 +57,7 @@ #import "_WKWebPushActionInternal.h" #import "_WKWebsiteDataStoreConfigurationInternal.h" #import "_WKWebsiteDataStoreDelegate.h" @@ -7930,7 +7795,7 @@ index 083bb2ee778bfc04e66bfe261f81e0dfcb8496fb..c2138b162edc34a44163137745e95264 #import <WebCore/Credential.h> #import <WebCore/RegistrableDomain.h> #import <WebCore/ResourceResponse.h> -@@ -517,6 +518,11 @@ - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date comple +@@ -532,6 +533,11 @@ - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date comple }); } @@ -8073,7 +7938,7 @@ index 0000000000000000000000000000000000000000..69eb9c6aa30beb8ea21a0ef647e46304 +} +@end diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h -index da15690a3d5a783a96aa5557676abeb7c349061d..cf3c06c2f1e9def8fa342019770f03d3673f41d8 100644 +index bcfc045d528aff77f639f53b9ebbbc4487050e39..08e1ec9a39e54fff521dbc65822f6c352087b0c0 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h @@ -67,6 +67,7 @@ WK_EXTERN WK_API_DEPRECATED("Creating and using multiple instances of WKProcessP @@ -8085,10 +7950,10 @@ index da15690a3d5a783a96aa5557676abeb7c349061d..cf3c06c2f1e9def8fa342019770f03d3 @property (nonatomic) BOOL processSwapsOnNavigationWithinSameNonHTTPFamilyProtocol WK_API_AVAILABLE(macos(12.0), ios(15.0)); @property (nonatomic) BOOL prewarmsProcessesAutomatically WK_API_AVAILABLE(macos(10.14.4), ios(12.2)); diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm -index 450fd8f758f9b21abc0a29b628f6042b42281a8e..be99131c2427c18d2d29e86debdbf094afb839f6 100644 +index 63e3701355c7e47568b4506cdced95a46ff375af..014081a828011fa403676839c27f8514b3b73741 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm -@@ -250,6 +250,16 @@ - (BOOL)processSwapsOnNavigation +@@ -244,6 +244,16 @@ - (BOOL)processSwapsOnNavigation return _processPoolConfiguration->processSwapsOnNavigation(); } @@ -8118,7 +7983,7 @@ index 4974e14214e2bb3e982325b885bab33e54f83998..cacdf8c71fab248d38d2faf03f7affdc typedef NS_ENUM(NSInteger, _WKUserStyleLevel) { _WKUserStyleUserLevel, diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm -index 289e0dd591b20396fd3a1fd6a29fe8a7096bd703..e39ccf4f27a747e1f0ad07aad7b65e0bae98f485 100644 +index 4e688f53f9b1022b423e6ae171f042ddfcb858e0..611cd57e8ce91f64bc379b7be952f0e2ceb3e828 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm @@ -28,6 +28,9 @@ @@ -8349,7 +8214,7 @@ index 0000000000000000000000000000000000000000..e0b1da48465c850f541532ed961d1b77 +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext*); +void webkitBrowserInspectorQuitApplication(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp b/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp -index ecbe5c804188309e51f606fa03fddd593674bc4d..0e71df3670f44be57c5b31aafa291dbfe60cfdd8 100644 +index c816d0248895d9aa670e2226798237c696451b45..4d317eb4aaa630a97c03d70e7b15b05460354b01 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp @@ -160,51 +160,7 @@ static bool canvasAccelerationEnabled(WebKitURISchemeRequest* request) @@ -8592,10 +8457,10 @@ index e94ec4aae750773fdb635e2b302735f6821ae3ef..eb8547be6916f5f95dc3be86c35292b4 bool canRunBeforeUnloadConfirmPanel() const final { return true; } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp -index abf5d3f7cfa46b4e2552c8e3229ac4fea68489b8..ca4d7f72baba1af3c3b3340fb23690326471b9a3 100644 +index e1e5687811e65ce1f4cbeb082febffef479a279e..352135e3c98948921b5b135805ecc86043bb336a 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp -@@ -425,10 +425,19 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa +@@ -426,10 +426,19 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa } } @@ -8615,7 +8480,7 @@ index abf5d3f7cfa46b4e2552c8e3229ac4fea68489b8..ca4d7f72baba1af3c3b3340fb2369032 GUniquePtr<char> bundleFilename(g_build_filename(injectedBundleDirectory(), INJECTED_BUNDLE_FILENAME, nullptr)); WebKitWebContext* webContext = WEBKIT_WEB_CONTEXT(object); -@@ -484,6 +493,8 @@ static void webkitWebContextConstructed(GObject* object) +@@ -485,6 +494,8 @@ static void webkitWebContextConstructed(GObject* object) static void webkitWebContextDispose(GObject* object) { @@ -8624,7 +8489,7 @@ index abf5d3f7cfa46b4e2552c8e3229ac4fea68489b8..ca4d7f72baba1af3c3b3340fb2369032 WebKitWebContextPrivate* priv = WEBKIT_WEB_CONTEXT(object)->priv; if (!priv->clientsDetached) { priv->clientsDetached = true; -@@ -945,6 +956,11 @@ WebKitNetworkSession* webkit_web_context_get_network_session_for_automation(WebK +@@ -946,6 +957,11 @@ WebKitNetworkSession* webkit_web_context_get_network_session_for_automation(WebK return nullptr; #endif } @@ -8661,7 +8526,7 @@ index c1945fbe717a42afc1f51d64a80c7de3fa9009ba..ab63fe19b00ecbd64c9421e6eecad3e2 #endif +int webkitWebContextExistingCount(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp -index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7d7318fea 100644 +index 3ed130d4fb0345c7309a240d3a412991e15f9904..10c9c0c89e4a9caf68d8075cde195bbf805e6887 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -40,6 +40,7 @@ @@ -8672,7 +8537,7 @@ index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7 #include "WebKitAuthenticationRequestPrivate.h" #include "WebKitBackForwardListPrivate.h" #include "WebKitContextMenuClient.h" -@@ -157,6 +158,7 @@ enum { +@@ -160,6 +161,7 @@ enum { CLOSE, SCRIPT_DIALOG, @@ -8680,7 +8545,7 @@ index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7 DECIDE_POLICY, PERMISSION_REQUEST, -@@ -535,6 +537,13 @@ GRefPtr<WebKitOptionMenu> WebKitWebViewClient::showOptionMenu(WebKitPopupMenu& p +@@ -546,6 +548,13 @@ GRefPtr<WebKitOptionMenu> WebKitWebViewClient::showOptionMenu(WebKitPopupMenu& p void WebKitWebViewClient::frameDisplayed(WKWPE::View&) { @@ -8694,7 +8559,7 @@ index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7 { SetForScope inFrameDisplayedGuard(m_webView->priv->inFrameDisplayed, true); for (const auto& callback : m_webView->priv->frameDisplayedCallbacks) { -@@ -642,7 +651,7 @@ static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* +@@ -653,7 +662,7 @@ static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request) { @@ -8703,7 +8568,7 @@ index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7 if (WEBKIT_IS_POINTER_LOCK_PERMISSION_REQUEST(request)) { webkit_permission_request_allow(request); return TRUE; -@@ -977,6 +986,10 @@ static void webkitWebViewConstructed(GObject* object) +@@ -1001,6 +1010,10 @@ static void webkitWebViewConstructed(GObject* object) priv->websitePolicies = adoptGRef(webkit_website_policies_new()); Ref configuration = priv->relatedView && priv->relatedView->priv->configurationForNextRelatedView ? priv->relatedView->priv->configurationForNextRelatedView.releaseNonNull() : webkitWebViewCreatePageConfiguration(webView); @@ -8714,7 +8579,7 @@ index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7 webkitWebViewCreatePage(webView, WTF::move(configuration)); webkitWebContextWebViewCreated(priv->context.get(), webView); -@@ -2068,6 +2081,15 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) +@@ -2114,6 +2127,15 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_SCRIPT_DIALOG); @@ -8730,7 +8595,7 @@ index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7 /** * WebKitWebView::decide-policy: * @web_view: the #WebKitWebView on which the signal is emitted -@@ -2858,6 +2880,23 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const +@@ -2948,6 +2970,23 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const webkit_script_dialog_unref(webView->priv->currentScriptDialog); } @@ -8755,10 +8620,10 @@ index d232384bfd442590c8617d713cdc8d3a9c6bd5fe..71778e8188ea307580ac7a89c242c5c7 { if (!webView->priv->currentScriptDialog) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h -index 4e16a2a088f6e48f43362850cc047da7de3c88ef..5ca5ae9572d2ed962d80a5dd67f8f379cd9e8117 100644 +index 8bff6235bb227ed9e53017f45ce6469dede379fb..34a4c07514c1661ea7e333de5ea674123b809b2f 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h -@@ -64,6 +64,7 @@ void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString& message, Fun +@@ -67,6 +67,7 @@ void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString& message, Fun void webkitWebViewRunJavaScriptConfirm(WebKitWebView*, const CString& message, Function<void(bool)>&& completionHandler); void webkitWebViewRunJavaScriptPrompt(WebKitWebView*, const CString& message, const CString& defaultText, Function<void(const String&)>&& completionHandler); void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView*, const CString& message, Function<void(bool)>&& completionHandler); @@ -8767,7 +8632,7 @@ index 4e16a2a088f6e48f43362850cc047da7de3c88ef..5ca5ae9572d2ed962d80a5dd67f8f379 bool webkitWebViewIsScriptDialogRunning(WebKitWebView*, WebKitScriptDialog*); String webkitWebViewGetCurrentScriptDialogMessage(WebKitWebView*); diff --git a/Source/WebKit/UIProcess/API/glib/webkit.h.in b/Source/WebKit/UIProcess/API/glib/webkit.h.in -index 9d13feb910ba0556e13e2b065531e285909c97a3..4a42710d90bdc43504da4e94b1527b88470cd202 100644 +index d48845217e514f1fb9dc84917cd8ba7b26046dee..0402761230371a6f9e9e78caaaf2f207fa3c760c 100644 --- a/Source/WebKit/UIProcess/API/glib/webkit.h.in +++ b/Source/WebKit/UIProcess/API/glib/webkit.h.in @@ -45,6 +45,7 @@ @@ -8779,7 +8644,7 @@ index 9d13feb910ba0556e13e2b065531e285909c97a3..4a42710d90bdc43504da4e94b1527b88 #include <@API_INCLUDE_PREFIX@/WebKitClipboardPermissionRequest.h> #include <@API_INCLUDE_PREFIX@/WebKitColorChooserRequest.h> diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp -index 09776daa9a925ccd5e8015d8e9af4de9c9a2f62a..6e4bb294b8c8e1c03b628bc2d662e0fa4cfb1c3c 100644 +index a33310d9ef8795338756c5d38da9fdc18fd65d6d..363988712345502a202f9feea21f2ca365ed41c0 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp @@ -246,7 +246,7 @@ WebCore::IntPoint PageClientImpl::accessibilityScreenToRootView(const WebCore::I @@ -8813,7 +8678,7 @@ index 09776daa9a925ccd5e8015d8e9af4de9c9a2f62a..6e4bb294b8c8e1c03b628bc2d662e0fa void PageClientImpl::didChangeContentSize(const IntSize& size) diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h -index d78e37c1be9e07c2ec95ae95e8693018d822a4e3..b531b97a991603b0888e2659f8bd63d26d2120e3 100644 +index 0dae577227eaac423bdc97d9c859fe5afc2d06c1..8edbe1cb3e7d0f818290122861635c063595c632 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h @@ -104,7 +104,7 @@ private: @@ -8931,7 +8796,7 @@ index 496079da90993ac37689b060b69ecd4a67c2b6a8..af30181ca922f16c0f6e245c70e5ce7d G_BEGIN_DECLS diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp -index 631ce852083435f7cd4f4a9464586df94511aecc..0a6c195381d12a98643bca74587bd56d58c4be41 100644 +index d5bb72f0ffbf99eddebc9819cb3f24fdaffdf468..d248c201e0ee9db63a117b8cde34661595a594fa 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp @@ -2879,6 +2879,11 @@ void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase) @@ -9015,7 +8880,7 @@ index 9091ae5198e765c2cfe0584d121afe4f88df3c0e..b0efedec419673ef2bfd0fd79406774e virtual void didChangePageID(WKWPE::View&) { } virtual void didReceiveUserMessage(WKWPE::View&, WebKit::UserMessage&&, CompletionHandler<void(WebKit::UserMessage&&)>&& completionHandler) { completionHandler(WebKit::UserMessage()); } diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp -index 1c346654cfcdcb3138a63af2f0ca5ad1748cd733..db8bcf38c093ece4b6078b58c856c280847b6fbd 100644 +index 44bec4dfe534281e791339bc6eebc3795d65b2c9..4d7cd002b8420382e3628886a7fc4c6229db2702 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp @@ -36,9 +36,12 @@ @@ -9057,11 +8922,11 @@ index 1c346654cfcdcb3138a63af2f0ca5ad1748cd733..db8bcf38c093ece4b6078b58c856c280 } #endif --RefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy&, const WebCore::Color& intialColor, const WebCore::IntRect&, ColorControlSupportsAlpha supportsAlpha, Vector<WebCore::Color>&&) -+RefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy& page, const WebCore::Color& intialColor, const WebCore::IntRect& rect, ColorControlSupportsAlpha supportsAlpha, Vector<WebCore::Color>&&) +-RefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy&, const WebCore::Color& intialColor, const WebCore::IntRect&, ColorControlSupportsAlpha supportsAlpha, Vector<WebCore::Color>&&, std::optional<WebCore::FrameIdentifier>) ++RefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy& page, const WebCore::Color& intialColor, const WebCore::IntRect& rect, ColorControlSupportsAlpha supportsAlpha, Vector<WebCore::Color>&&, std::optional<WebCore::FrameIdentifier> frameID) { - return nullptr; -+ return WebColorPickerWPE::create(page, intialColor, rect); ++ return WebColorPickerWPE::create(page, intialColor, rect, frameID); } -RefPtr<WebDataListSuggestionsDropdown> PageClientImpl::createDataListSuggestionsDropdown(WebPageProxy&) @@ -9099,7 +8964,7 @@ index 1c346654cfcdcb3138a63af2f0ca5ad1748cd733..db8bcf38c093ece4b6078b58c856c280 + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h -index 5566ef5b4432632366679149f411659c7331ad9e..24c551315008d1a1c788144c149281ce27b45c10 100644 +index a1f18769eb2398cb467067f7f2d6ad864d1ed0ee..842bc438edd93ad09ddc1012898856e4ac686f00 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h @@ -193,7 +193,11 @@ private: @@ -9116,10 +8981,10 @@ index 5566ef5b4432632366679149f411659c7331ad9e..24c551315008d1a1c788144c149281ce WKWPE::View& m_view; DefaultUndoController m_undoController; diff --git a/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp b/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp -index d2cb304f89e2a93d452dd69eb3fb72aa49b27af7..413078a5b0fd8aab3054881192f357e366158f5a 100644 +index 32b91bcbf205dfbd36c9275a6167877cf561a172..ce45bcc6e7fdd92efa31d974a8230253fbf3294e 100644 --- a/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp -@@ -637,9 +637,9 @@ void ViewPlatform::callAfterNextPresentationUpdate(CompletionHandler<void()>&& c +@@ -645,9 +645,9 @@ void ViewPlatform::callAfterNextPresentationUpdate(CompletionHandler<void()>&& c } } @@ -9237,7 +9102,7 @@ index 0000000000000000000000000000000000000000..22baa003f1220a87d5c1012cd485a6fe + +#endif diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp -index 1e562cfa11689020bd927e57ada5f775bc92122c..0e61d0e1fae3b485686e79a9a7d3eba26391641f 100644 +index 96170b6fd5f7dfc9ae97019f1dae74ee686f3a89..731d1aa724878543872a604c55da6b0affca45b6 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp @@ -56,6 +56,7 @@ struct _WebKitWebViewBackend { @@ -9308,10 +9173,10 @@ index 21131a4d26ba115f3249b227d3e1dabd42398c80..7b1a6e98f3c1fb5ef5d54f416c49ba3e + +PlatformImage webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend*); diff --git a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h -index cf391118d8ced9ab6d377183e754b3e886873f96..28e571afa5a241ec59f940cf806d4be3d137623a 100644 +index c38751ae3064aa6a42a3ed8fdb902f70473a8e08..f6bf1a674402bc08f69bccc97058954981ad4ebc 100644 --- a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h +++ b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h -@@ -310,6 +310,8 @@ public: +@@ -318,6 +318,8 @@ public: void didDestroyFrame(WebCore::FrameIdentifier); @@ -9320,7 +9185,7 @@ index cf391118d8ced9ab6d377183e754b3e886873f96..28e571afa5a241ec59f940cf806d4be3 RefPtr<WebPageProxy> webPageProxyForHandle(const String&); String effectiveHandleForWebFrameProxy(const WebFrameProxy&); String handleForWebFrameID(std::optional<WebCore::FrameIdentifier>); -@@ -369,7 +371,6 @@ private: +@@ -385,7 +387,6 @@ private: // Get base64-encoded PNG data from a bitmap. static std::optional<String> platformGetBase64EncodedPNGData(WebCore::ShareableBitmap::Handle&&); @@ -9329,10 +9194,10 @@ index cf391118d8ced9ab6d377183e754b3e886873f96..28e571afa5a241ec59f940cf806d4be3 // Save base64-encoded file contents to a local file path and return the path. // This reuses the basename of the remote file path so that the filename exposed to DOM API remains the same. diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp -index 3817cf179bda9613b9e1686becb4edf136a0d878..777a168267d119e3f0d48d171ee8a407714908fd 100644 +index d2e4f4cf05d2c7ce330319b4116c816c237df2dd..04e2e8d6125daf90a8c0c7aaa69e626f95b044d9 100644 --- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp +++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp -@@ -175,7 +175,11 @@ void AuxiliaryProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& lau +@@ -176,7 +176,11 @@ void AuxiliaryProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& lau launchOptions.processCmdPrefix = String::fromUTF8(processCmdPrefix); #endif // ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE)) @@ -9345,7 +9210,7 @@ index 3817cf179bda9613b9e1686becb4edf136a0d878..777a168267d119e3f0d48d171ee8a407 platformGetLaunchOptions(launchOptions); } diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h -index 63ee6bf6200ef0de13beb434ffe4ffcce97a2760..7d3b0bb489753f2421575b76fb932f590ffb97d4 100644 +index 0241fd8531d53a1f773e7c4a2c871e1903816eba..f199f4096d254ce0242c569db600554efac8c226 100644 --- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h +++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h @@ -296,13 +296,16 @@ protected: @@ -9367,7 +9232,7 @@ index 63ee6bf6200ef0de13beb434ffe4ffcce97a2760..7d3b0bb489753f2421575b76fb932f59 // Connection::Client diff --git a/Source/WebKit/UIProcess/BackingStore.h b/Source/WebKit/UIProcess/BackingStore.h -index ed08cad66cd9f9726d4282eda40b7aa6f2d96c07..c71ace8ea14d50d1aa714eb9d6ab735a33e74aa3 100644 +index 15f1d5ff3973e173c1a3ee3eeb3bdf5e1ec4cd87..6516a47bc4aa788b1b1c09d21254ea9482190f6c 100644 --- a/Source/WebKit/UIProcess/BackingStore.h +++ b/Source/WebKit/UIProcess/BackingStore.h @@ -67,6 +67,11 @@ public: @@ -9493,15 +9358,15 @@ index 0000000000000000000000000000000000000000..cd66887de171cda7d15a8e4dc6dbff63 +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) -diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SubFrameSOAuthorizationSession.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SubFrameSOAuthorizationSession.h -index d6458617d8c06283d0efc9a0432f0ed01c7716b9..22f56ace3b3e4e6799a4a742e8e77e6116111bc2 100644 ---- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SubFrameSOAuthorizationSession.h -+++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/SubFrameSOAuthorizationSession.h +diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h +index 45abb108899e19cfe0cecd6716083afbff03d73c..11ced1bb2d03c949cb31435eeeee2a196928a2de 100644 +--- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h ++++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h @@ -31,6 +31,7 @@ - #include "NavigationSOAuthorizationSession.h" - #include <WebCore/FrameIdentifier.h> - #include <wtf/Deque.h> -+#include <wtf/Markable.h> + #include "WebViewDidMoveToWindowObserver.h" + #include <wtf/CompletionHandler.h> + #include <wtf/text/WTFString.h> ++#include <wtf/URL.h> namespace WebKit { @@ -9518,7 +9383,7 @@ index 89d125f7742f81ead8c50f218ecb1771b8000636..baa6cf58ad502c6c033ee6293a6cc8d4 namespace WebKit { diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h -index ef6fc3f7a8799ed657f81857ddae6dd764e1e630..5784fbd83cb53e4369590e901c02e98bd903de91 100644 +index 1c037ebba6c9cf3713e0936d4f2327d0d46a626e..e0f463694dea3aae9d8d01376ac62e75e9b0e826 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h @@ -105,6 +105,7 @@ private: @@ -9538,7 +9403,7 @@ index ef6fc3f7a8799ed657f81857ddae6dd764e1e630..5784fbd83cb53e4369590e901c02e98b bool webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler : 1; bool webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm -index 6194164ab08094d2f1892b88acb7aa1813be65f6..0052a5a2bdc396ad458fae32aa6c239a302f85c4 100644 +index c660d8204b89997bb25637ed24198acf5028e280..6d7c9102b1bc57fd179ba742cf703b1bf3eaf5af 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm @@ -136,6 +136,7 @@ void UIDelegate::setDelegate(id<WKUIDelegate> delegate) @@ -9549,7 +9414,7 @@ index 6194164ab08094d2f1892b88acb7aa1813be65f6..0052a5a2bdc396ad458fae32aa6c239a m_delegateMethods.webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:completionHandler:)]; m_delegateMethods.webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:forQuirkDomains:completionHandler:)]; m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; -@@ -504,6 +505,15 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy& page, const WTF::St +@@ -502,6 +503,15 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy& page, const WTF::St }).get()]; } @@ -9566,7 +9431,7 @@ index 6194164ab08094d2f1892b88acb7aa1813be65f6..0052a5a2bdc396ad458fae32aa6c239a { RefPtr uiDelegate = m_uiDelegate.get(); diff --git a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm -index 8e48b5769f273384949ebc258555b82b43a52917..84009743aad7161ddb0edb30846dddc8d9ca7a44 100644 +index 177ac869fe4128bb459d2577d90f6b208e8395a2..e6ade97d800a2119d4abd9e241186915c432fd9c 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm @@ -45,7 +45,9 @@ @@ -9579,9 +9444,9 @@ index 8e48b5769f273384949ebc258555b82b43a52917..84009743aad7161ddb0edb30846dddc8 #import "PlatformXRSystem.h" #import "PlaybackSessionManagerProxy.h" #import "RemoteLayerTreeCommitBundle.h" -@@ -443,11 +445,85 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting() +@@ -446,11 +448,85 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting() - void WebPageProxy::startDrag(const DragItem& dragItem, ShareableBitmap::Handle&& dragImageHandle, const std::optional<NodeIdentifier>& nodeID) + void WebPageProxy::startDrag(const DragItem& dragItem, ShareableBitmap::Handle&& dragImageHandle, const std::optional<NodeIdentifier>& nodeID, const std::optional<FrameIdentifier>& frameID) { + if (m_interceptDrags) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName: m_overrideDragPasteboardName.createNSString().get()]; @@ -9614,7 +9479,7 @@ index 8e48b5769f273384949ebc258555b82b43a52917..84009743aad7161ddb0edb30846dddc8 + } + if (RefPtr pageClient = this->pageClient()) - pageClient->startDrag(dragItem, WTF::move(dragImageHandle), nodeID); + pageClient->startDrag(dragItem, WTF::move(dragImageHandle), nodeID, frameID); } -#endif @@ -9667,10 +9532,10 @@ index 8e48b5769f273384949ebc258555b82b43a52917..84009743aad7161ddb0edb30846dddc8 #if ENABLE(ATTACHMENT_ELEMENT) diff --git a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm -index 2fd431350646269a959b8f58ab73aa2f619fa0b6..27522c586432885cf6a8c6805d872f57c15cde4f 100644 +index 4b43164f215ca8e72a68252f36862e25b2742ea8..0804791f8ef0174b905cb18851962f04b43151e4 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm -@@ -453,7 +453,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END +@@ -451,7 +451,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END auto screenProperties = WebCore::collectScreenProperties(); parameters.screenProperties = WTF::move(screenProperties); #if PLATFORM(MAC) @@ -9679,7 +9544,7 @@ index 2fd431350646269a959b8f58ab73aa2f619fa0b6..27522c586432885cf6a8c6805d872f57 #endif #if PLATFORM(VISION) -@@ -866,8 +866,8 @@ void WebProcessPool::registerNotificationObservers() +@@ -864,8 +864,8 @@ void WebProcessPool::registerNotificationObservers() }]; m_scrollerStyleNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { @@ -9799,7 +9664,7 @@ index be40fa0e3e3e8698c29f70a2b8dac324225aba97..4e6cc206ed0a25914d8df604f6174656 #if !PLATFORM(WPE) && !PLATFORM(GTK) diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h -index a77e650fb857ffe42b2d199c4788310100778cd5..8a9126c359e81e17f415f2f488eccae4dc240868 100644 +index 99a1c243ee534edf127f6f932e4d05cb65676528..d880229ef91bfd33e37b5065976fbe3c7f6dc443 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h @@ -29,6 +29,7 @@ @@ -9813,7 +9678,7 @@ index a77e650fb857ffe42b2d199c4788310100778cd5..8a9126c359e81e17f415f2f488eccae4 @@ -60,6 +61,10 @@ public: bool isInAcceleratedCompositingMode() const { return !m_layerTreeContext.isEmpty(); } - const LayerTreeContext& layerTreeContext() const { return m_layerTreeContext; } + const LayerTreeContext& layerTreeContext() const LIFETIME_BOUND { return m_layerTreeContext; } + void waitForSizeUpdate(Function<void (const DrawingAreaProxyCoordinatedGraphics&)>&&); +#if !PLATFORM(WPE) + void captureFrame(); @@ -9830,7 +9695,7 @@ index a77e650fb857ffe42b2d199c4788310100778cd5..8a9126c359e81e17f415f2f488eccae4 #if !PLATFORM(WPE) && !PLATFORM(GTK) bool m_isBackingStoreDiscardable { true }; diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp -index ce2813559a25f93b355cca6e4106515bc4c52d89..313a44ad3b2e2fdd876641b2a0500c1f7d8f11e6 100644 +index 6537111d8f973509b072b3ec0da911d9c1d24f1d..206023b88f3bb0f7b14bcc7600679bce11a9053a 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp @@ -41,8 +41,10 @@ @@ -9872,9 +9737,9 @@ index ce2813559a25f93b355cca6e4106515bc4c52d89..313a44ad3b2e2fdd876641b2a0500c1f if (RefPtr downloadProxyMap = protectedThis->m_downloadProxyMap.get()) downloadProxyMap->downloadFinished(*protectedThis); }); -@@ -163,6 +171,33 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour - suggestedFilename = m_suggestedFilename; - suggestedFilename = MIMETypeRegistry::appendFileExtensionIfNecessary(suggestedFilename, response.mimeType()); +@@ -182,6 +190,35 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour + else + suggestedFilename = MIMETypeRegistry::appendFileExtensionIfNecessary(suggestedFilename, response.mimeType()); + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFilenameSuggested(m_uuid, suggestedFilename); @@ -9883,7 +9748,9 @@ index ce2813559a25f93b355cca6e4106515bc4c52d89..313a44ad3b2e2fdd876641b2a0500c1f + SandboxExtension::Handle sandboxExtensionHandle; + String destination; + if (*m_dataStore->allowDownloadForAutomation()) { -+ destination = FileSystem::pathByAppendingComponent(m_dataStore->downloadPathForAutomation(), m_uuid); ++ auto downloadPath = m_dataStore->downloadPathForAutomation(); ++ FileSystem::makeAllDirectories(downloadPath); ++ destination = FileSystem::pathByAppendingComponent(downloadPath, m_uuid); + if (auto handle = SandboxExtension::createHandle(destination, SandboxExtension::Type::ReadWrite)) + sandboxExtensionHandle = WTF::move(*handle); + } @@ -9906,7 +9773,7 @@ index ce2813559a25f93b355cca6e4106515bc4c52d89..313a44ad3b2e2fdd876641b2a0500c1f protect(client())->decideDestinationWithSuggestedFilename(*this, response, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), [this, protectedThis = Ref { *this }, completionHandler = WTF::move(completionHandler)] (AllowOverwrite allowOverwrite, String destination) mutable { SandboxExtension::Handle sandboxExtensionHandle; if (!destination.isNull()) { -@@ -227,6 +262,8 @@ void DownloadProxy::didFinish() +@@ -246,6 +283,8 @@ void DownloadProxy::didFinish() protect(client())->didFinish(*this); if (m_downloadIsCancelled) return; @@ -9915,7 +9782,7 @@ index ce2813559a25f93b355cca6e4106515bc4c52d89..313a44ad3b2e2fdd876641b2a0500c1f // This can cause the DownloadProxy object to be deleted. if (RefPtr downloadProxyMap = m_downloadProxyMap.get()) -@@ -241,6 +278,8 @@ void DownloadProxy::didFail(const ResourceError& error, std::span<const uint8_t> +@@ -260,6 +299,8 @@ void DownloadProxy::didFail(const ResourceError& error, std::span<const uint8_t> m_legacyResumeData = createData(resumeData); protect(client())->didFail(*this, error, m_legacyResumeData.get()); @@ -9925,7 +9792,7 @@ index ce2813559a25f93b355cca6e4106515bc4c52d89..313a44ad3b2e2fdd876641b2a0500c1f // This can cause the DownloadProxy object to be deleted. if (RefPtr downloadProxyMap = m_downloadProxyMap.get()) diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h -index 2bb0d331b873d198227e896b18b1764dac69ab84..51b8a5cdca4e5dfb43b5ca8ee8800a3f1ebae7a2 100644 +index be567b89bb406f0ee0df005c83b186cb956025ae..16342e90dcbf94325b8fac5f4c877c5fd372f673 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h @@ -168,6 +168,7 @@ private: @@ -9937,12 +9804,12 @@ index 2bb0d331b873d198227e896b18b1764dac69ab84..51b8a5cdca4e5dfb43b5ca8ee8800a3f } // namespace WebKit diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.h b/Source/WebKit/UIProcess/DrawingAreaProxy.h -index f3aab33d3bce0fcf2574eaad58d9795b2de5a579..d8c78700ad256f3c6eea5bb303d9f28fd295741e 100644 +index 546c51f13212c98bf9a26bf1ee804c74d75f241e..e681ec646dd033ade64bae6eabdc472e9e0b8c6a 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.h +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.h @@ -96,6 +96,7 @@ public: - const WebCore::IntSize& size() const { return m_size; } + const WebCore::IntSize& size() const LIFETIME_BOUND { return m_size; } bool setSize(const WebCore::IntSize&, const WebCore::IntSize& scrollOffset = { }); + void waitForSizeUpdate(Function<void ()>&&); @@ -9950,10 +9817,10 @@ index f3aab33d3bce0fcf2574eaad58d9795b2de5a579..d8c78700ad256f3c6eea5bb303d9f28f virtual void sizeToContentAutoSizeMaximumSizeDidChange() { } diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..7f957949228527a2d647f9498e4131fdc721aa02 +index 0000000000000000000000000000000000000000..6a89043bb0b8f6a22ee9af2b271de34989e6a5c1 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp -@@ -0,0 +1,287 @@ +@@ -0,0 +1,294 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * @@ -10007,7 +9874,7 @@ index 0000000000000000000000000000000000000000..7f957949228527a2d647f9498e4131fd +#endif + +#if PLATFORM(MAC) -+#include <WebCore/ImageBufferUtilitiesCG.h> ++#include <WebCore/ImageUtilities.h> +#endif + +#if PLATFORM(WIN) @@ -10071,7 +9938,7 @@ index 0000000000000000000000000000000000000000..7f957949228527a2d647f9498e4131fd + } + // Do not send the same frame over and over. + size_t len = pixmap.computeByteSize(); -+ auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_1); ++ auto cryptoDigest = PAL::Crypto::CryptoDigest::create(PAL::Crypto::CryptoDigest::Algorithm::SHA_1); + cryptoDigest->addBytes(std::span(reinterpret_cast<const unsigned char*>(pixmap.addr()), len)); + auto digest = cryptoDigest->computeHash(); + if (m_lastFrameDigest == digest) @@ -10114,12 +9981,12 @@ index 0000000000000000000000000000000000000000..7f957949228527a2d647f9498e4131fd +{ + if (m_screencast) + return makeUnexpected("Already screencasting"_s); ++ + m_screencast = true; + m_screencastWidth = width; + m_screencastHeight = height; + m_screencastQuality = quality; + m_screencastToolbarHeight = toolbarHeight; -+ m_screencastFramesInFlight = 0; + ++m_screencastGeneration; + kickFramesStarted(); + return m_screencastGeneration; @@ -10127,8 +9994,12 @@ index 0000000000000000000000000000000000000000..7f957949228527a2d647f9498e4131fd + +Inspector::Protocol::ErrorStringOr<void> InspectorScreencastAgent::screencastFrameAck(int generation) +{ ++ if (!m_screencast) ++ return makeUnexpected("Not screencasting"_s); ++ + if (m_screencastGeneration != generation) + return { }; ++ + --m_screencastFramesInFlight; + return { }; +} @@ -10137,8 +10008,11 @@ index 0000000000000000000000000000000000000000..7f957949228527a2d647f9498e4131fd +{ + if (!m_screencast) + return makeUnexpected("Not screencasting"_s); ++ + m_screencast = false; + m_framesAreGoing = false; ++ m_screencastFramesInFlight = 0; ++ m_lastFrameDigest.clear(); + return { }; +} + @@ -10203,7 +10077,7 @@ index 0000000000000000000000000000000000000000..7f957949228527a2d647f9498e4131fd + auto data = WebCore::encodeData(imagePtr, "image/jpeg"_s, m_screencastQuality * 0.1); + + // Do not send the same frame over and over. -+ auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_1); ++ auto cryptoDigest = PAL::Crypto::CryptoDigest::create(PAL::Crypto::CryptoDigest::Algorithm::SHA_1); + cryptoDigest->addBytes(std::span(data.mutableSpan().data(), data.size())); + auto digest = cryptoDigest->computeHash(); + if (m_lastFrameDigest != digest) { @@ -10347,56 +10221,143 @@ index 0000000000000000000000000000000000000000..afadd2371dffab9d4b92e4245f562282 +}; + +} // namespace WebKit -diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp -index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537008bbee6 100644 ---- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp -+++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp -@@ -26,17 +26,26 @@ - #include "config.h" - #include "WebPageInspectorController.h" - -+#include "APINavigation.h" -+#include "APIPageConfiguration.h" - #include "APIUIClient.h" - #include "InspectorBrowserAgent.h" -+#include "InspectorDialogAgent.h" -+#include "InspectorScreencastAgent.h" - #include "ProvisionalPageProxy.h" -+#include "WebFrameInspectorTarget.h" - #include "WebFrameInspectorTargetProxy.h" - #include "WebFrameProxy.h" - #include "WebPageInspectorAgentBase.h" -+#include "WebPageInspectorEmulationAgent.h" -+#include "WebPageInspectorInputAgent.h" - #include "WebPageInspectorTarget.h" - #include "WebPageInspectorTargetProxy.h" - #include "WebPageProxy.h" - #include "WebProcess/Inspector/WebFrameInspectorTarget.h" - #include "WebsiteDataStore.h" -+#include <WebCore/ResourceError.h> -+#include <WebCore/WindowFeatures.h> - #include <JavaScriptCore/InspectorAgentBase.h> - #include <JavaScriptCore/InspectorBackendDispatcher.h> - #include <JavaScriptCore/InspectorBackendDispatchers.h> -@@ -56,6 +65,17 @@ static String getTargetID(const ProvisionalPageProxy& provisionalPage) - - WTF_MAKE_TZONE_ALLOCATED_IMPL(WebPageInspectorController); +diff --git a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp +index 66e1ddd0ad468d7e9d262442ad0efdbcf7989ea1..28c0a0f7b7edaaf7f30c677594365a436344512d 100644 +--- a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp ++++ b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp +@@ -59,6 +59,11 @@ std::unique_ptr<PageInspectorTargetProxy> PageInspectorTargetProxy::create(Provi + return target; + } -+WebPageInspectorControllerObserver* WebPageInspectorController::s_observer = nullptr; -+ -+void WebPageInspectorController::setObserver(WebPageInspectorControllerObserver* observer) ++std::unique_ptr<PageInspectorTargetProxy> PageInspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId) +{ -+ s_observer = observer; -+} -+ -+WebPageInspectorControllerObserver* WebPageInspectorController::observer() { -+ return s_observer; ++ return PageInspectorTargetProxy::create(provisionalPage, targetId, Inspector::InspectorTargetType::Page); +} + - WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPage) - : m_frontendRouter(FrontendRouter::create()) - , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) -@@ -69,16 +89,92 @@ WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPa + PageInspectorTargetProxy::PageInspectorTargetProxy(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) + : InspectorTargetProxy(targetId, type) + , m_page(page) +@@ -109,6 +114,31 @@ void PageInspectorTargetProxy::didCommitProvisionalTarget() + m_provisionalPage = nullptr; + } + ++void PageInspectorTargetProxy::willResume() ++{ ++ if (m_page->hasRunningProcess()) ++ m_page->legacyMainFrameProcess().send(Messages::WebPage::ResumeInspectorIfPausedInNewWindow(), m_page->webPageIDInMainFrameProcess()); ++} ++ ++void PageInspectorTargetProxy::activate(String& error) ++{ ++ if (type() != Inspector::InspectorTargetType::Page) ++ return InspectorTarget::activate(error); ++ ++ platformActivate(error); ++} ++ ++void PageInspectorTargetProxy::close(String& error, bool runBeforeUnload) ++{ ++ if (type() != Inspector::InspectorTargetType::Page) ++ return InspectorTarget::close(error, runBeforeUnload); ++ ++ if (runBeforeUnload) ++ m_page->tryClose(); ++ else ++ m_page->closePage(); ++} ++ + bool PageInspectorTargetProxy::isProvisional() const + { + return !!m_provisionalPage; +diff --git a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h +index 88fe6b2104c5e26cee4a975a552e8a2c78f44129..96631d61f1a043d09769098849c4d91ad2cf6b21 100644 +--- a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h ++++ b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h +@@ -44,6 +44,7 @@ class PageInspectorTargetProxy final : public InspectorTargetProxy { + public: + static std::unique_ptr<PageInspectorTargetProxy> create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); + static std::unique_ptr<PageInspectorTargetProxy> create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType); ++ static std::unique_ptr<PageInspectorTargetProxy> create(ProvisionalPageProxy&, const String& targetId); + PageInspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); + + void didCommitProvisionalTarget() override; +@@ -52,8 +53,13 @@ public: + void connect(Inspector::FrontendChannel::ConnectionType) override; + void disconnect() override; + void sendMessageToTargetBackend(const String&) override; ++ void activate(String& error) override; ++ void close(String& error, bool runBeforeUnload) override; + + private: ++ void willResume() override; ++ void platformActivate(String& error) const; ++ + WeakRef<WebPageProxy> m_page; + WeakPtr<ProvisionalPageProxy> m_provisionalPage; + }; +diff --git a/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp b/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp +index 232b5dc1c574e4d4231307fee144aff59b519758..651fc7fe63d80cf093192e4eec1576c7621201e1 100644 +--- a/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp ++++ b/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp +@@ -28,6 +28,7 @@ + + #if ENABLE(WEBASSEMBLY_DEBUGGER) && ENABLE(REMOTE_INSPECTOR) + ++#include "WebPageProxy.h" + #include "WebProcessProxy.h" + #include "WebProcessProxyMessages.h" + #include <JavaScriptCore/InspectorFrontendChannel.h> +diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp +index 13da6142d0889583d399b4ee9ead9a6850b700b2..626f87341d5eb3d7192d4c80621e84bf9181940f 100644 +--- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp ++++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp +@@ -26,19 +26,27 @@ + #include "config.h" + #include "WebPageInspectorController.h" + ++#include "APINavigation.h" ++#include "APIPageConfiguration.h" + #include "APIUIClient.h" + #include "FrameInspectorTarget.h" + #include "FrameInspectorTargetProxy.h" + #include "InspectorBrowserAgent.h" ++#include "InspectorDialogAgent.h" ++#include "InspectorScreencastAgent.h" + #include "PageInspectorTarget.h" + #include "PageInspectorTargetProxy.h" + #include "ProvisionalFrameProxy.h" + #include "ProvisionalPageProxy.h" + #include "WebFrameProxy.h" + #include "WebPageInspectorAgentBase.h" ++#include "WebPageInspectorEmulationAgent.h" ++#include "WebPageInspectorInputAgent.h" + #include "WebPageProxy.h" + #include "WebProcessProxy.h" + #include "WebsiteDataStore.h" ++#include <WebCore/ResourceError.h> ++#include <WebCore/WindowFeatures.h> + #include <JavaScriptCore/InspectorAgentBase.h> + #include <JavaScriptCore/InspectorBackendDispatcher.h> + #include <JavaScriptCore/InspectorBackendDispatchers.h> +@@ -69,6 +77,17 @@ static String getTargetID(const ProvisionalFrameProxy& provisionalFrame) + + WTF_MAKE_TZONE_ALLOCATED_IMPL(WebPageInspectorController); + ++WebPageInspectorControllerObserver* WebPageInspectorController::s_observer = nullptr; ++ ++void WebPageInspectorController::setObserver(WebPageInspectorControllerObserver* observer) ++{ ++ s_observer = observer; ++} ++ ++WebPageInspectorControllerObserver* WebPageInspectorController::observer() { ++ return s_observer; ++} ++ + WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPage) + : m_frontendRouter(FrontendRouter::create()) + , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) +@@ -82,16 +101,92 @@ WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPa WebPageInspectorController::~WebPageInspectorController() = default; void WebPageInspectorController::init() @@ -10420,19 +10381,19 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 + +void WebPageInspectorController::didInitializeWebPage() { - String pageTargetId = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + String pageTargetId = PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + // Create target only after attaching to a Web Process first time. Before that + // we cannot event establish frontend connection. + if (m_targets.contains(pageTargetId)) + return; - addTarget(WebPageInspectorTargetProxy::create(protect(m_inspectedPage), pageTargetId, Inspector::InspectorTargetType::Page)); + addTarget(PageInspectorTargetProxy::create(protect(m_inspectedPage), pageTargetId, Inspector::InspectorTargetType::Page)); + if (m_inspectedPage->mainFrame()) + didCreateFrame(*m_inspectedPage->mainFrame()); } void WebPageInspectorController::pageClosed() { -+ String pageTargetId = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); ++ String pageTargetId = PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + removeTarget(pageTargetId); + + @@ -10448,7 +10409,7 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 +{ + if (reason != ProcessTerminationReason::Crash) + return false; -+ String targetId = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); ++ String targetId = PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + auto it = m_targets.find(targetId); + if (it == m_targets.end()) + return false; @@ -10489,7 +10450,7 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 } bool WebPageInspectorController::hasLocalFrontend() const -@@ -92,6 +188,14 @@ void WebPageInspectorController::connectFrontend(Inspector::FrontendChannel& fro +@@ -105,6 +200,14 @@ void WebPageInspectorController::connectFrontend(Inspector::FrontendChannel& fro bool connectingFirstFrontend = !m_frontendRouter->hasFrontends(); @@ -10504,7 +10465,7 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 m_frontendRouter->connectFrontend(frontendChannel); if (connectingFirstFrontend) -@@ -111,8 +215,10 @@ void WebPageInspectorController::disconnectFrontend(FrontendChannel& frontendCha +@@ -124,8 +227,10 @@ void WebPageInspectorController::disconnectFrontend(FrontendChannel& frontendCha m_frontendRouter->disconnectFrontend(frontendChannel); bool disconnectingLastFrontend = !m_frontendRouter->hasFrontends(); @@ -10516,7 +10477,7 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 Ref inspectedPage = m_inspectedPage.get(); inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); -@@ -136,6 +242,8 @@ void WebPageInspectorController::disconnectAllFrontends() +@@ -149,6 +254,8 @@ void WebPageInspectorController::disconnectAllFrontends() // Disconnect any remaining remote frontends. m_frontendRouter->disconnectAllFrontends(); @@ -10525,7 +10486,7 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 Ref inspectedPage = m_inspectedPage.get(); inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); -@@ -164,11 +272,117 @@ void WebPageInspectorController::setIndicating(bool indicating) +@@ -177,6 +284,66 @@ void WebPageInspectorController::setIndicating(bool indicating) } #endif @@ -10591,6 +10552,8 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 + void WebPageInspectorController::sendMessageToInspectorFrontend(const String& targetId, const String& message) { + if (!m_targets.contains(targetId)) { +@@ -191,6 +358,52 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta protect(m_targetAgent)->sendMessageFromTargetToFrontend(targetId, message); } @@ -10608,7 +10571,7 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 + if (!m_inspectedPage->isPageOpenedByDOMShowingInitialEmptyDocument()) + return false; + -+ auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); ++ auto* target = m_targets.get(PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); + // The method is expeted to be called only when the WebPage has already been + // initilized, so the target must exist. + ASSERT(target); @@ -10635,7 +10598,7 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 + +void WebPageInspectorController::setContinueLoadingCallback(WTF::Function<void()>&& callback) +{ -+ auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); ++ auto* target = m_targets.get(PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); + ASSERT(target); + target->setResumeCallback(WTF::move(callback)); +} @@ -10643,22 +10606,20 @@ index 9816fe2f54d4f34ab6abe1ca7ac6062924693d31..30f3bb138d2c422d0f5efb2993a3f537 bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const { if (!m_frontendRouter->hasFrontends()) -@@ -188,7 +402,9 @@ void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPag +@@ -210,7 +423,7 @@ void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPag - void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage) + void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage, WebCore::FrameIdentifier mainFrameID, WebProcessProxy& mainFrameProcess) { -- addTarget(WebPageInspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page)); -+ addTarget(WebPageInspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage))); -+ if (provisionalPage.mainFrame()) -+ didCreateFrame(*provisionalPage.mainFrame()); - } +- addTarget(PageInspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page)); ++ addTarget(PageInspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage))); - void WebPageInspectorController::willDestroyProvisionalPage(const ProvisionalPageProxy& provisionalPage) + if (shouldManageFrameTargets()) { + constexpr bool isProvisional = true; diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h -index 009322b020c98cd1b3dd82c2ea144878f4ca6c30..d113975dcb1908a96fbd9a939be475a703570be5 100644 +index f670f9007a9386bf9933e59c32463f697dbb6597..17fa5c0f2860c9423de3e167616d46fa5d857125 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h -@@ -28,20 +28,40 @@ +@@ -28,9 +28,11 @@ #include "InspectorTargetProxy.h" #include "ProvisionalPageProxy.h" #include "UIProcess/WebFrameProxy.h" @@ -10668,8 +10629,9 @@ index 009322b020c98cd1b3dd82c2ea144878f4ca6c30..d113975dcb1908a96fbd9a939be475a7 #include <WebCore/FrameIdentifier.h> +#include <WebCore/NavigationIdentifier.h> #include <WebCore/PageIdentifier.h> + #include <WebCore/ProcessIdentifier.h> #include <wtf/CheckedRef.h> - #include <wtf/Forward.h> +@@ -38,11 +40,29 @@ #include <wtf/Noncopyable.h> #include <wtf/TZoneMalloc.h> #include <wtf/text/WTFString.h> @@ -10699,7 +10661,7 @@ index 009322b020c98cd1b3dd82c2ea144878f4ca6c30..d113975dcb1908a96fbd9a939be475a7 } namespace WebKit { -@@ -50,6 +70,22 @@ class InspectorBrowserAgent; +@@ -51,6 +71,22 @@ class InspectorBrowserAgent; class ProvisionalPageProxy; struct WebPageAgentContext; @@ -10722,7 +10684,7 @@ index 009322b020c98cd1b3dd82c2ea144878f4ca6c30..d113975dcb1908a96fbd9a939be475a7 class WebPageInspectorController { WTF_MAKE_TZONE_ALLOCATED(WebPageInspectorController); WTF_MAKE_NONCOPYABLE(WebPageInspectorController); -@@ -58,7 +94,21 @@ public: +@@ -59,7 +95,21 @@ public: ~WebPageInspectorController(); void init(); @@ -10744,7 +10706,7 @@ index 009322b020c98cd1b3dd82c2ea144878f4ca6c30..d113975dcb1908a96fbd9a939be475a7 bool hasLocalFrontend() const; -@@ -71,9 +121,25 @@ public: +@@ -72,9 +122,25 @@ public: #if ENABLE(REMOTE_INSPECTOR) void setIndicating(bool); #endif @@ -10770,7 +10732,7 @@ index 009322b020c98cd1b3dd82c2ea144878f4ca6c30..d113975dcb1908a96fbd9a939be475a7 bool shouldPauseLoading(const ProvisionalPageProxy&) const; void setContinueLoadingCallback(const ProvisionalPageProxy&, WTF::Function<void()>&&); -@@ -105,9 +171,16 @@ private: +@@ -111,9 +177,16 @@ private: CheckedPtr<Inspector::InspectorTargetAgent> m_targetAgent; HashMap<String, std::unique_ptr<InspectorTargetProxy>> m_targets; @@ -10787,80 +10749,6 @@ index 009322b020c98cd1b3dd82c2ea144878f4ca6c30..d113975dcb1908a96fbd9a939be475a7 }; } // namespace WebKit -diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.cpp -index 87072046c40465cfd162f9d87f7040d865fdafa4..4925473a5bd83438fa36e964810ac61fd6ea81d5 100644 ---- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.cpp -+++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.cpp -@@ -59,6 +59,11 @@ std::unique_ptr<WebPageInspectorTargetProxy> WebPageInspectorTargetProxy::create - return target; - } - -+std::unique_ptr<WebPageInspectorTargetProxy> WebPageInspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId) -+{ -+ return WebPageInspectorTargetProxy::create(provisionalPage, targetId, Inspector::InspectorTargetType::Page); -+} -+ - WebPageInspectorTargetProxy::WebPageInspectorTargetProxy(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) - : InspectorTargetProxy(targetId, type) - , m_page(page) -@@ -109,6 +114,31 @@ void WebPageInspectorTargetProxy::didCommitProvisionalTarget() - m_provisionalPage = nullptr; - } - -+void WebPageInspectorTargetProxy::willResume() -+{ -+ if (m_page->hasRunningProcess()) -+ m_page->legacyMainFrameProcess().send(Messages::WebPage::ResumeInspectorIfPausedInNewWindow(), m_page->webPageIDInMainFrameProcess()); -+} -+ -+void WebPageInspectorTargetProxy::activate(String& error) -+{ -+ if (type() != Inspector::InspectorTargetType::Page) -+ return InspectorTarget::activate(error); -+ -+ platformActivate(error); -+} -+ -+void WebPageInspectorTargetProxy::close(String& error, bool runBeforeUnload) -+{ -+ if (type() != Inspector::InspectorTargetType::Page) -+ return InspectorTarget::close(error, runBeforeUnload); -+ -+ if (runBeforeUnload) -+ m_page->tryClose(); -+ else -+ m_page->closePage(); -+} -+ - bool WebPageInspectorTargetProxy::isProvisional() const - { - return !!m_provisionalPage; -diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.h -index 619c7e0ed8c3d36120e9c2c5f7d55be0d9b2906b..a36aa3a97fe484e7ecca78d3e88a21a4f82f6923 100644 ---- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.h -+++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorTargetProxy.h -@@ -44,6 +44,7 @@ class WebPageInspectorTargetProxy final : public InspectorTargetProxy { - public: - static std::unique_ptr<WebPageInspectorTargetProxy> create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); - static std::unique_ptr<WebPageInspectorTargetProxy> create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType); -+ static std::unique_ptr<WebPageInspectorTargetProxy> create(ProvisionalPageProxy&, const String& targetId); - WebPageInspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); - - void didCommitProvisionalTarget() override; -@@ -52,8 +53,13 @@ public: - void connect(Inspector::FrontendChannel::ConnectionType) override; - void disconnect() override; - void sendMessageToTargetBackend(const String&) override; -+ void activate(String& error) override; -+ void close(String& error, bool runBeforeUnload) override; - - private: -+ void willResume() override; -+ void platformActivate(String& error) const; -+ - WeakRef<WebPageProxy> m_page; - WeakPtr<ProvisionalPageProxy> m_provisionalPage; - }; diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.cpp b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53bf0625a4e6af2f4387b9a516604d5e6219cfef @@ -11035,7 +10923,7 @@ index 0000000000000000000000000000000000000000..26775d9cfe30d220b14c1b2355a9baf9 +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..f2bc9c6bbdf5ff20f8617070e62e247ec437f22a +index 0000000000000000000000000000000000000000..635da5eda9d9bbe21c5fa35936656b02c4b3ab46 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp @@ -0,0 +1,1033 @@ @@ -11078,6 +10966,7 @@ index 0000000000000000000000000000000000000000..f2bc9c6bbdf5ff20f8617070e62e247e +#include "NetworkProcessMessages.h" +#include "NetworkProcessProxy.h" +#include "PageClient.h" ++#include "PageInspectorTarget.h" +#include "PlaywrightFullScreenManagerProxyClient.h" +#include "SandboxExtension.h" +#include "StorageNamespaceIdentifier.h" @@ -11088,7 +10977,6 @@ index 0000000000000000000000000000000000000000..f2bc9c6bbdf5ff20f8617070e62e247e +#include "WebInspectorUtilities.h" +#include "WebPageGroup.h" +#include "WebPageInspectorController.h" -+#include "WebPageInspectorTarget.h" +#include "WebPageMessages.h" +#include "WebPageProxy.h" +#include "WebPreferences.h" @@ -12299,10 +12187,10 @@ index 0000000000000000000000000000000000000000..af71e4077eb0c6f95396de7bfef89a3e + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp -index de3aaa8c032a92a2afa52ec033ee51027c3c1d23..9fa579c2602f31726ff9ba0ba58cfdc316be6427 100644 +index 9e0f05585ae96f4ec9ab2390cb015b5307fe85e6..048dfad9f9221fc5389de5d7874a0a67ec61499a 100644 --- a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp +++ b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp -@@ -164,6 +164,13 @@ void ProcessLauncher::launchProcess() +@@ -160,6 +160,13 @@ void ProcessLauncher::launchProcess() nargs++; } #endif @@ -12314,9 +12202,9 @@ index de3aaa8c032a92a2afa52ec033ee51027c3c1d23..9fa579c2602f31726ff9ba0ba58cfdc3 + } +// Playwright end - WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN // GTK/WPE port - -@@ -181,6 +188,10 @@ void ProcessLauncher::launchProcess() + Vector<char*> argv(nargs); + unsigned i = 0; +@@ -175,6 +182,10 @@ void ProcessLauncher::launchProcess() if (configureJSCForTesting) argv[i++] = const_cast<char*>("--configure-jsc-for-testing"); #endif @@ -12326,7 +12214,7 @@ index de3aaa8c032a92a2afa52ec033ee51027c3c1d23..9fa579c2602f31726ff9ba0ba58cfdc3 +// Playwright end argv[i++] = nullptr; - WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + // Warning: we want GIO to be able to spawn with posix_spawn() rather than fork()/exec(), in diff --git a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp index 6723ee0d9943be07bc8ad09d2b678838aca968df..0d7fb3c7b1a4c877a2ff2f2189d12c7d00eb8f7b 100644 --- a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp @@ -12355,11 +12243,11 @@ index 6723ee0d9943be07bc8ad09d2b678838aca968df..0d7fb3c7b1a4c877a2ff2f2189d12c7d BOOL result = ::CreateProcess(0, commandLine.mutableSpan().data(), 0, 0, true, 0, 0, 0, &startupInfo, &processInformation); diff --git a/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp b/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp -index 08425c2e4cb83c19430a5253e6ed0d0cf42e5b7a..573231a61d48a0cc5c16bce0b4dbc0611db0ae69 100644 +index e9bf93632655ddfe5104808d67cb1e550e965098..a62ab1cb298654ea69cc8131f275d2cc7fe75602 100644 --- a/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp +++ b/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp -@@ -30,6 +30,7 @@ - +@@ -31,6 +31,7 @@ + #include "MessageSenderInlines.h" #include "RemoteMediaSessionClientProxy.h" #include "RemoteMediaSessionManagerMessages.h" +#include "RemoteMediaSessionManager.h" @@ -12367,7 +12255,7 @@ index 08425c2e4cb83c19430a5253e6ed0d0cf42e5b7a..573231a61d48a0cc5c16bce0b4dbc061 #include "RemoteMediaSessionProxy.h" #include "RemoteMediaSessionState.h" diff --git a/Source/WebKit/UIProcess/PageClient.h b/Source/WebKit/UIProcess/PageClient.h -index 02627105c3825bcab2753dd73f33e600b3585876..8a1bde61436904b12acc00cf1705214221ebcabd 100644 +index ec8a8accd195844f2ceb5fea0d73bc0ab50ce733..164e60cbc7fbd520d4d43a99021891c770f1fe3e 100644 --- a/Source/WebKit/UIProcess/PageClient.h +++ b/Source/WebKit/UIProcess/PageClient.h @@ -77,6 +77,11 @@ @@ -12382,7 +12270,7 @@ index 02627105c3825bcab2753dd73f33e600b3585876..8a1bde61436904b12acc00cf17052142 OBJC_CLASS AVPlayerViewController; OBJC_CLASS CALayer; OBJC_CLASS NSFileWrapper; -@@ -398,7 +403,15 @@ public: +@@ -400,7 +405,15 @@ public: virtual void selectionDidChange() = 0; #endif @@ -12532,7 +12420,7 @@ index 0000000000000000000000000000000000000000..f855bb5ff6e91cc3383fb9a96d32392f + +#endif // ENABLE(FULLSCREEN_API) diff --git a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp -index 67b2f5cb03c1af0da00b92e8eae5ad038167009a..6fe8fe64135d6722f56a07810f9891eb292585f5 100644 +index 0e8f21982c6499e6886f5db6c193afc43663f29c..43ed4c8837479744a98ef76ceb2911c0e49d3f2b 100644 --- a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp +++ b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp @@ -25,6 +25,7 @@ @@ -12544,7 +12432,7 @@ index 67b2f5cb03c1af0da00b92e8eae5ad038167009a..6fe8fe64135d6722f56a07810f9891eb #include "FrameProcess.h" #include "ProvisionalFrameCreationParameters.h" diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.h b/Source/WebKit/UIProcess/ProvisionalPageProxy.h -index ab1cd48c4b3e821a1582241afd6d7b64dac7494d..a6e61edca183d7b88af6ef737fbd70822addaf92 100644 +index 90b6b6b10906e9bf9f4229dc413421380be8a01a..0620c78e35e40e5b4997ab3813cac98cfdef7372 100644 --- a/Source/WebKit/UIProcess/ProvisionalPageProxy.h +++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.h @@ -32,8 +32,10 @@ @@ -12885,7 +12773,7 @@ index 7ef986965d3fda34b4f09279c62bdad40712ab12..5e0bc508f72bbbd0bcb4bb1254782028 namespace WebKit { diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm b/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm -index df8b4f48b760487aa2e4bbb611b824002a8d8231..0fdf9c69df946a0215f7b3de58d2f5aac8e71c1b 100644 +index 07e7aec9d5f53dd4adfb83b6626f469621362663..18d049adb49ab565f60e9e1dded55da1a6aaaf3a 100644 --- a/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm +++ b/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm @@ -46,6 +46,7 @@ @@ -12914,7 +12802,7 @@ index 3f6cd845733e2e8f5e25c318e7ab54f77032d4cf..e4399bfd734a28ef5df5ec855b7c78b4 class RemotePagePlaybackSessionManagerProxy : public IPC::MessageReceiver, public RefCounted<RemotePagePlaybackSessionManagerProxy> { diff --git a/Source/WebKit/UIProcess/RemotePageProxy.cpp b/Source/WebKit/UIProcess/RemotePageProxy.cpp -index 1a8feec76715cf4210de81b36bc70213a3b44669..f48336d489711583cb5f9ecea8f0b22a7cf4a1f6 100644 +index f7a0ee83fa8ee37d1c6d927f167b6e6bb647d817..919494d9b459a94d17617a0b514552e21cd21a29 100644 --- a/Source/WebKit/UIProcess/RemotePageProxy.cpp +++ b/Source/WebKit/UIProcess/RemotePageProxy.cpp @@ -37,6 +37,7 @@ @@ -12933,8 +12821,27 @@ index 1a8feec76715cf4210de81b36bc70213a3b44669..f48336d489711583cb5f9ecea8f0b22a #if ENABLE(FULLSCREEN_API) #include "WebFullScreenManagerProxy.h" #endif +diff --git a/Source/WebKit/UIProcess/TextExtractionAssertionScope.h b/Source/WebKit/UIProcess/TextExtractionAssertionScope.h +index 986c0812fedd2be938675ef5de41041e9fc76a0b..69da96c1e1ccb3b6d6b142ccb3b337f0bcb14957 100644 +--- a/Source/WebKit/UIProcess/TextExtractionAssertionScope.h ++++ b/Source/WebKit/UIProcess/TextExtractionAssertionScope.h +@@ -25,13 +25,12 @@ + + #pragma once + ++#include "WebPageProxy.h" + #include <wtf/FastMalloc.h> + #include <wtf/WeakPtr.h> + + namespace WebKit { + +-class WebPageProxy; +- + class TextExtractionAssertionScope { + WTF_MAKE_TZONE_ALLOCATED(TextExtractionAssertionScope); + WTF_MAKE_NONCOPYABLE(TextExtractionAssertionScope); diff --git a/Source/WebKit/UIProcess/WebContextMenuProxy.h b/Source/WebKit/UIProcess/WebContextMenuProxy.h -index e3dac51d347635bd88d486a6fda9123df5f80150..f9fa5a7c64ca30ed2db8f09fb0186f85a5eeec4d 100644 +index 364666d82ffd69aef6cb4f8d63b61ae13e163d87..a491699c43502e6feae3b3df73b3558a79bb73e3 100644 --- a/Source/WebKit/UIProcess/WebContextMenuProxy.h +++ b/Source/WebKit/UIProcess/WebContextMenuProxy.h @@ -51,6 +51,7 @@ public: @@ -12944,28 +12851,7 @@ index e3dac51d347635bd88d486a6fda9123df5f80150..f9fa5a7c64ca30ed2db8f09fb0186f85 + virtual void hide() {} WebPageProxy* page() const { return m_page.get(); } - const FrameInfoData& frameInfo() const { return m_frameInfo; } -diff --git a/Source/WebKit/UIProcess/WebFrameProxy.cpp b/Source/WebKit/UIProcess/WebFrameProxy.cpp -index 231a519e2b2bf7f4a38aac0958f0d49840ab8a86..8232f6f5b0e348dddc09ae54e1b927cef337c69a 100644 ---- a/Source/WebKit/UIProcess/WebFrameProxy.cpp -+++ b/Source/WebKit/UIProcess/WebFrameProxy.cpp -@@ -127,7 +127,6 @@ WebFrameProxy::WebFrameProxy(WebPageProxy& page, FrameProcess& process, FrameIde - allFrames().set(frameID, *this); - WebProcessPool::statistics().wkFrameCount++; - -- page.inspectorController().didCreateFrame(*this); - - protect(m_frameProcess)->incrementFrameCount(); - } -@@ -513,6 +512,8 @@ void WebFrameProxy::didCreateSubframe(WebCore::FrameIdentifier frameID, String&& - if (RefPtr session = page->activeAutomationSession()) - session->didCreateFrame(child); - #endif -+ -+ page->inspectorController().didCreateFrame(*this); - } - - void WebFrameProxy::prepareForProvisionalLoadInProcess(WebProcessProxy& process, API::Navigation& navigation, BrowsingContextGroup& group, std::optional<SecurityOriginData> effectiveOrigin, CompletionHandler<void(WebCore::PageIdentifier)>&& completionHandler) + const FrameInfoData& frameInfo() const LIFETIME_BOUND { return m_frameInfo; } diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc495bff7d10aeb071ba30002d292b82e26d51b7 @@ -13217,10 +13103,10 @@ index 0000000000000000000000000000000000000000..8c772fb1b67ec7d83cbe2394d8ab0478 +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..c52e077d89c8531adf8bc184cd237cb5d2bc0bc3 +index 0000000000000000000000000000000000000000..a29ae94cda78928fab928bbdd250f8cd1c8b4cc5 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp -@@ -0,0 +1,396 @@ +@@ -0,0 +1,397 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * @@ -13254,6 +13140,7 @@ index 0000000000000000000000000000000000000000..c52e077d89c8531adf8bc184cd237cb5 +#include "NativeWebMouseEvent.h" +#include "NativeWebWheelEvent.h" +#include "WebPageProxy.h" ++#include "WebProcessProxy.h" +#include "WebTouchEvent.h" +#include "WebWheelEvent.h" +#include <wtf/MathExtras.h> @@ -13349,7 +13236,7 @@ index 0000000000000000000000000000000000000000..c52e077d89c8531adf8bc184cd237cb5 +static String keyIdentifierForKey(const String& key) +{ + if (key.length() == 1) -+ return makeString("U+"_s, hex(toASCIIUpper(key.characterAt(0)), 4)); ++ return makeString("U+"_s, hex(toASCIIUpper(key.codeUnitAt(0)), 4)); + if (key == "Delete"_s) + return "U+007F"_s; + if (key == "Backspace"_s) @@ -13711,10 +13598,10 @@ index 0000000000000000000000000000000000000000..fb0cd51d362dfd8af2370f43ecb8835c + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp -index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1bac51d3a85 100644 +index b51fd21469a35bea05d91465215e463dd9be078d..87789a4c6edfd8b48bcb3f083cc8b4edb3c5a498 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp -@@ -218,6 +218,7 @@ +@@ -219,6 +219,7 @@ #include <WebCore/CaptureDeviceManager.h> #include <WebCore/CaptureDeviceWithCapabilities.h> #include <WebCore/ChromeClient.h> @@ -13722,7 +13609,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #include <WebCore/CompositionHighlight.h> #include <WebCore/CrossSiteNavigationDataTransfer.h> #include <WebCore/CryptoKey.h> -@@ -230,6 +231,7 @@ +@@ -232,6 +233,7 @@ #include <WebCore/DigitalCredentialsProtocols.h> #include <WebCore/DigitalCredentialsRequestData.h> #include <WebCore/DigitalCredentialsResponseData.h> @@ -13730,7 +13617,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #include <WebCore/DragController.h> #include <WebCore/DragData.h> #include <WebCore/DragEventTargetData.h> -@@ -257,6 +259,7 @@ +@@ -260,6 +262,7 @@ #include <WebCore/ModalContainerTypes.h> #include <WebCore/NotImplemented.h> #include <WebCore/OrganizationStorageAccessPromptQuirk.h> @@ -13738,7 +13625,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #include <WebCore/PerformanceLoggingClient.h> #include <WebCore/PermissionDescriptor.h> #include <WebCore/PermissionState.h> -@@ -266,10 +269,12 @@ +@@ -269,10 +272,12 @@ #include <WebCore/Quirks.h> #include <WebCore/RealtimeMediaSourceCenter.h> #include <WebCore/ReferrerPolicy.h> @@ -13751,7 +13638,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #include <WebCore/SecurityOrigin.h> #include <WebCore/SecurityOriginData.h> #include <WebCore/SerializedCryptoKeyWrap.h> -@@ -363,7 +368,7 @@ +@@ -366,7 +371,7 @@ #include "ViewSnapshotStore.h" #endif @@ -13760,7 +13647,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #include <WebCore/SelectionData.h> #endif -@@ -495,6 +500,17 @@ static constexpr Seconds tryCloseTimeoutDelay = 50_ms; +@@ -496,6 +501,17 @@ static constexpr Seconds tryCloseTimeoutDelay = 50_ms; static constexpr Seconds audibleActivityClearDelay = 10_s; #endif @@ -13778,7 +13665,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #if PLATFORM(COCOA) static WorkQueue& sharedFileQueueSingleton() { -@@ -1071,6 +1087,10 @@ WebPageProxy::~WebPageProxy() +@@ -1105,6 +1121,10 @@ WebPageProxy::~WebPageProxy() ASSERT(webPageProxyMap().get(m_identifier) == this); webPageProxyMap().remove(m_identifier); @@ -13789,7 +13676,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba } void WebPageProxy::addAllMessageReceivers() -@@ -1625,7 +1645,7 @@ void WebPageProxy::didAttachToRunningProcess() +@@ -1678,7 +1698,7 @@ void WebPageProxy::didAttachToRunningProcess() #if ENABLE(FULLSCREEN_API) ASSERT(!m_fullScreenManager); @@ -13798,7 +13685,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #endif #if ENABLE(VIDEO_PRESENTATION_MODE) ASSERT(!m_playbackSessionManager); -@@ -1664,7 +1684,7 @@ void WebPageProxy::didAttachToRunningProcess() +@@ -1710,7 +1730,7 @@ void WebPageProxy::didAttachToRunningProcess() #endif #if !PLATFORM(IOS_FAMILY) @@ -13807,7 +13694,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #else auto currentOrientation = toScreenOrientationType(m_deviceOrientation); #endif -@@ -1797,6 +1817,7 @@ void WebPageProxy::initializeWebPage(const Site& site, WebCore::SandboxFlags eff +@@ -1850,6 +1870,7 @@ void WebPageProxy::initializeWebPage(const Site& site, WebCore::SandboxFlags eff if (preferences->siteIsolationEnabled()) browsingContextGroup->addPage(*this); process->send(Messages::WebProcess::CreateWebPage(m_webPageID, creationParameters(process, *protect(drawingArea()), m_mainFrame->frameID(), std::nullopt)), 0); @@ -13815,8 +13702,8 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #if ENABLE(WINDOW_PROXY_PROPERTY_ACCESS_NOTIFICATION) internals().frameLoadStateObserver = WebPageProxyFrameLoadStateObserver::create(); -@@ -2123,6 +2144,21 @@ Ref<WebProcessProxy> WebPageProxy::ensureProtectedRunningProcess() - return ensureRunningProcess(); +@@ -2171,6 +2192,21 @@ WebProcessProxy& WebPageProxy::ensureRunningProcess() + return m_legacyMainFrameProcess; } +RefPtr<API::Navigation> WebPageProxy::loadRequestForInspector(WebCore::ResourceRequest&& request, WebFrameProxy* frame) @@ -13837,7 +13724,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba RefPtr<API::Navigation> WebPageProxy::loadRequest(WebCore::ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, NavigationUpgradeToHTTPSBehavior navigationUpgradeToHTTPSBehavior, std::unique_ptr<NavigationActionData>&& lastNavigationAction, API::Object* userData, bool isRequestFromClientOrUserInput) { if (m_isClosed) -@@ -2246,11 +2282,29 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& proces +@@ -2296,11 +2332,29 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& proces navigation->setIsLoadedWithNavigationShared(true); protectedProcess->markProcessAsRecentlyUsed(); @@ -13871,7 +13758,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba }); } -@@ -2798,6 +2852,53 @@ RefPtr<WebAutomationSession> WebPageProxy::activeAutomationSession() const +@@ -2896,6 +2950,53 @@ RefPtr<WebAutomationSession> WebPageProxy::activeAutomationSession() const return m_configuration->processPool().automationSession(); } @@ -13925,7 +13812,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message) { m_inspectorController->sendMessageToInspectorFrontend(targetId, message); -@@ -3075,6 +3176,24 @@ void WebPageProxy::updateActivityState(OptionSet<ActivityState> flagsToUpdate) +@@ -3199,6 +3300,24 @@ void WebPageProxy::updateActivityState(OptionSet<ActivityState> flagsToUpdate) bool wasVisible = isViewVisible(); RefPtr pageClient = this->pageClient(); internals().activityState.remove(flagsToUpdate); @@ -13950,7 +13837,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba if (flagsToUpdate & ActivityState::IsFocused && pageClient->isViewFocused()) internals().activityState.add(ActivityState::IsFocused); if (flagsToUpdate & ActivityState::WindowIsActive && pageClient->isViewWindowActive()) -@@ -3863,7 +3982,7 @@ void WebPageProxy::performDragOperation(DragData& dragData, const String& dragSt +@@ -3988,7 +4107,7 @@ void WebPageProxy::performDragOperation(DragData& dragData, const String& dragSt if (!hasRunningProcess()) return; @@ -13959,7 +13846,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba URL url { dragData.asURL() }; if (url.protocolIsFile()) protect(legacyMainFrameProcess())->assumeReadAccessToBaseURL(*this, url.string(), [] { }); -@@ -3906,6 +4025,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag +@@ -4031,6 +4150,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag if (!hasRunningProcess()) return; @@ -13968,7 +13855,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba auto completionHandler = [this, protectedThis = Ref { *this }, action, dragData] (std::optional<WebCore::DragOperation> dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect, std::optional<WebCore::RemoteUserInputEventData> remoteUserInputEventData) mutable { if (!m_pageClient) return; -@@ -3917,7 +4038,7 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag +@@ -4042,7 +4163,7 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag dragData.setClientPosition(roundedIntPoint(remoteUserInputEventData->transformedPoint)); performDragControllerAction(action, dragData, remoteUserInputEventData->targetFrameID); }; @@ -13977,7 +13864,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba ASSERT(dragData.platformData()); sendWithAsyncReplyToProcessContainingFrame(frameID, Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), *dragData.platformData(), dragData.flags()), WTF::move(completionHandler)); #else -@@ -3952,17 +4073,36 @@ void WebPageProxy::didPerformDragControllerAction(std::optional<WebCore::DragOpe +@@ -4077,17 +4198,36 @@ void WebPageProxy::didPerformDragControllerAction(std::optional<WebCore::DragOpe setDragCaretRect(insertionRect); if (RefPtr pageClient = this->pageClient()) pageClient->didPerformDragControllerAction(); @@ -14017,7 +13904,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba didStartDrag(); } #endif -@@ -3983,6 +4123,24 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo +@@ -4108,6 +4248,24 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo setDragCaretRect({ }); } @@ -14039,14 +13926,13 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba +} +#endif + - void WebPageProxy::didStartDrag() + void WebPageProxy::didStartDrag(const std::optional<FrameIdentifier>& targetFrameID) { if (!hasRunningProcess()) -@@ -3990,6 +4148,26 @@ void WebPageProxy::didStartDrag() - +@@ -4116,6 +4274,25 @@ void WebPageProxy::didStartDrag(const std::optional<FrameIdentifier>& targetFram discardQueuedMouseEvents(); - send(Messages::WebPage::DidStartDrag()); -+ + + sendToProcessContainingFrame(targetFrameID, Messages::WebPage::DidStartDrag(targetFrameID)); + if (m_interceptDrags) { + { +#if PLATFORM(WIN) || PLATFORM(COCOA) @@ -14069,7 +13955,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba } void WebPageProxy::dragCancelled() -@@ -4170,26 +4348,47 @@ void WebPageProxy::processNextQueuedMouseEvent() +@@ -4300,26 +4477,47 @@ void WebPageProxy::processNextQueuedMouseEvent() auto eventType = event->type(); startResponsivenessTimerForMouseEvent(*targetFrame, eventType); @@ -14129,7 +14015,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba } #if ENABLE(MAC_GESTURE_EVENTS) -@@ -4413,6 +4612,8 @@ void WebPageProxy::wheelEventHandlingCompleted(bool wasHandled) +@@ -4586,6 +4784,8 @@ void WebPageProxy::wheelEventHandlingCompleted(bool wasHandled) if (RefPtr automationSession = m_configuration->processPool().automationSession()) automationSession->wheelEventsFlushedForPage(*this); @@ -14138,7 +14024,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba } void WebPageProxy::cacheWheelEventScrollingAccelerationCurve(const NativeWebWheelEvent& nativeWheelEvent) -@@ -4556,7 +4757,7 @@ static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b) +@@ -4729,7 +4929,7 @@ static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b) void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent) { @@ -14147,7 +14033,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba for (auto& touchPoint : touchStartEvent.touchPoints()) { auto location = touchPoint.locationInRootView(); auto update = [this, location](TrackingType& trackingType, EventTrackingRegions::EventType eventType) { -@@ -5377,6 +5578,7 @@ Ref<WebPageProxy> WebPageProxy::navigationOriginatingPage(const FrameInfoData& f +@@ -5571,6 +5771,7 @@ Ref<WebPageProxy> WebPageProxy::navigationOriginatingPage(const FrameInfoData& f void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, std::optional<std::pair<Ref<API::WebsitePolicies>, Ref<WebProcessProxy>>>&& websitePoliciesAndProcess, Ref<API::NavigationAction>&& navigationAction, WillContinueLoadInNewProcess willContinueLoadInNewProcess, std::optional<SandboxExtension::Handle> sandboxExtensionHandle, std::optional<PolicyDecisionConsoleMessage>&& consoleMessage, CompletionHandler<void(PolicyDecision&&)>&& completionHandler) { @@ -14155,7 +14041,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba if (!hasRunningProcess()) return completionHandler(PolicyDecision { }); -@@ -6416,6 +6618,7 @@ void WebPageProxy::viewScaleFactorDidChange(IPC::Connection& connection, double +@@ -6671,6 +6872,7 @@ void WebPageProxy::viewScaleFactorDidChange(IPC::Connection& connection, double MESSAGE_CHECK_BASE(scaleFactorIsValid(scaleFactor), connection); if (!legacyMainFrameProcess().hasConnection(connection)) return; @@ -14163,7 +14049,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba forEachWebContentProcess([&] (auto& process, auto pageID) { if (&process == &legacyMainFrameProcess()) -@@ -7200,6 +7403,7 @@ void WebPageProxy::didDestroyNavigationShared(Ref<WebProcessProxy>&& process, We +@@ -7524,6 +7726,7 @@ void WebPageProxy::didDestroyNavigationShared(Ref<WebProcessProxy>&& process, We RefPtr protectedPageClient { pageClient() }; m_navigationState->didDestroyNavigation(process->coreProcessIdentifier(), navigationID); @@ -14171,16 +14057,16 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba } void WebPageProxy::didStartProvisionalLoadForFrame(IPC::Connection& connection, FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, std::optional<WebCore::NavigationIdentifier> navigationID, URL&& url, URL&& unreachableURL, const UserData& userData, WallTime timestamp) -@@ -7569,6 +7773,8 @@ void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& p - +@@ -7918,6 +8121,8 @@ void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& p m_failingProvisionalLoadURL = { }; + m_allowsLoadingAlternateHTMLForFailingProvisionalLoadURL = true; + m_inspectorController->didFailProvisionalLoadForFrame(*navigationID, error); + // If the provisional page's load fails then we destroy the provisional page. - if (m_provisionalPage && m_provisionalPage->mainFrame() == &frame && (willContinueLoading == WillContinueLoading::No || protect(preferences())->siteIsolationEnabled())) + if (m_provisionalPage && m_provisionalPage->mainFrame() == &frame && (willContinueLoading == WillContinueLoading::No)) m_provisionalPage = nullptr; -@@ -9269,6 +9475,8 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w +@@ -9687,6 +9892,8 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w if (RefPtr page = originatingFrameInfo->page()) openerAppInitiatedState = page->lastNavigationWasAppInitiated(); @@ -14189,7 +14075,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba auto completionHandler = [ this, protectedThis = Ref { *this }, -@@ -9356,6 +9564,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w +@@ -9774,6 +9981,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w configuration->setInitialReferrerPolicy(effectiveReferrerPolicy); configuration->setWindowFeatures(WTF::move(windowFeatures)); configuration->setOpenedMainFrameName(openedMainFrameName); @@ -14197,7 +14083,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba if (RefPtr openerFrame = WebFrameProxy::webFrame(originatingFrameInfoData.frameID); navigationActionData.hasOpener && openerFrame) { configuration->setRelatedPage(*this); -@@ -9391,6 +9600,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w +@@ -9809,6 +10017,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w void WebPageProxy::showPage() { m_uiClient->showPage(this); @@ -14205,7 +14091,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba } bool WebPageProxy::hasOpenedPage() const -@@ -9534,6 +9744,10 @@ void WebPageProxy::closePage() +@@ -9952,6 +10161,10 @@ void WebPageProxy::closePage() if (isClosed()) return; @@ -14216,7 +14102,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba WEBPAGEPROXY_RELEASE_LOG(Process, "closePage:"); if (RefPtr pageClient = this->pageClient()) pageClient->clearAllEditCommands(); -@@ -9573,6 +9787,8 @@ void WebPageProxy::runJavaScriptAlert(IPC::Connection& connection, FrameIdentifi +@@ -9991,6 +10204,8 @@ void WebPageProxy::runJavaScriptAlert(IPC::Connection& connection, FrameIdentifi auto showModal = [protectedThis = Ref { *this }](RefPtr<WebFrameProxy>&& frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler<void()>&& reply) mutable { protectedThis->runModalJavaScriptDialog(WTF::move(frame), WTF::move(frameInfo), WTF::move(message), [reply = WTF::move(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler<void()>&& completion) mutable { @@ -14225,7 +14111,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba page.m_uiClient->runJavaScriptAlert(page, WTF::move(message), frame, WTF::move(frameInfo), [reply = WTF::move(reply), completion = WTF::move(completion)]() mutable { reply(); completion(); -@@ -9606,6 +9822,8 @@ void WebPageProxy::runJavaScriptConfirm(IPC::Connection& connection, FrameIdenti +@@ -10024,6 +10239,8 @@ void WebPageProxy::runJavaScriptConfirm(IPC::Connection& connection, FrameIdenti if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this, message, std::nullopt); } @@ -14234,7 +14120,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba auto showModal = [protectedThis = Ref { *this }](RefPtr<WebFrameProxy>&& frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler<void(bool)>&& reply) mutable { protectedThis->runModalJavaScriptDialog(WTF::move(frame), WTF::move(frameInfo), WTF::move(message), [reply = WTF::move(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler<void()>&& completion) mutable { -@@ -9642,6 +9860,8 @@ void WebPageProxy::runJavaScriptPrompt(IPC::Connection& connection, FrameIdentif +@@ -10060,6 +10277,8 @@ void WebPageProxy::runJavaScriptPrompt(IPC::Connection& connection, FrameIdentif if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this, message, defaultValue); } @@ -14243,7 +14129,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba auto showModal = [protectedThis = Ref { *this }](RefPtr<WebFrameProxy>&& frame, FrameInfoData&& frameInfo, String&& message, String&& defaultValue, CompletionHandler<void(const String&)>&& reply) mutable { protectedThis->runModalJavaScriptDialog(WTF::move(frame), WTF::move(frameInfo), WTF::move(message), [reply = WTF::move(reply), defaultValue = WTF::move(defaultValue)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler<void()>&& completion) mutable { -@@ -9766,6 +9986,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(IPC::Connection& connection, Fram +@@ -10274,6 +10493,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(IPC::Connection& connection, Fram return; } } @@ -14252,7 +14138,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer and the tryClose timer. webProcess->stopResponsivenessTimer(); -@@ -10425,6 +10647,11 @@ void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, +@@ -10963,6 +11184,11 @@ void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, } #if ENABLE(FULLSCREEN_API) @@ -14264,7 +14150,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba WebFullScreenManagerProxy* WebPageProxy::fullScreenManager() { return m_fullScreenManager.get(); -@@ -10557,6 +10784,17 @@ void WebPageProxy::requestDOMPasteAccess(IPC::Connection& connection, DOMPasteAc +@@ -11092,6 +11318,17 @@ void WebPageProxy::requestDOMPasteAccess(IPC::Connection& connection, DOMPasteAc } } @@ -14282,7 +14168,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba protect(pageClient())->requestDOMPasteAccess(pasteAccessCategory, requiresInteraction, elementRect, originIdentifier, WTF::move(completionHandler)); } -@@ -11527,6 +11765,8 @@ void WebPageProxy::mouseEventHandlingCompleted(std::optional<WebEventType> event +@@ -12074,6 +12311,8 @@ void WebPageProxy::mouseEventHandlingCompleted(std::optional<WebEventType> event if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->mouseEventsFlushedForPage(*this); didFinishProcessingAllPendingMouseEvents(); @@ -14291,15 +14177,15 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba } } -@@ -11584,6 +11824,7 @@ void WebPageProxy::keyEventHandlingCompleted(std::optional<WebEventType> eventTy - if (!canProcessMoreKeyEvents) { +@@ -12132,6 +12371,7 @@ void WebPageProxy::keyEventHandlingCompleted(std::optional<WebEventType> eventTy if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->keyboardEventsFlushedForPage(*this); + didFinishProcessingAllPendingKeyEvents(); + m_inspectorController->didProcessAllPendingKeyboardEvents(); } } -@@ -12028,7 +12269,10 @@ void WebPageProxy::dispatchProcessDidTerminate(WebProcessProxy& process, Process +@@ -12576,7 +12816,10 @@ void WebPageProxy::dispatchProcessDidTerminate(WebProcessProxy& process, Process protect(browsingContextGroup())->processDidTerminate(*this, process); } @@ -14311,7 +14197,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba if (m_loaderClient) handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this); else -@@ -12692,6 +12936,9 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc +@@ -13251,6 +13494,9 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc parameters.allowPostingLegacySynchronousMessages = m_configuration->allowPostingLegacySynchronousMessages(); parameters.backgroundTextExtractionEnabled = m_configuration->backgroundTextExtractionEnabled(); @@ -14321,7 +14207,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba #if ENABLE(APP_HIGHLIGHTS) parameters.appHighlightsVisible = appHighlightsVisibility() ? HighlightVisibility::Visible : HighlightVisibility::Hidden; #endif -@@ -12867,8 +13114,47 @@ void WebPageProxy::allowGamepadAccess() +@@ -13429,8 +13675,47 @@ void WebPageProxy::allowGamepadAccess() #endif // ENABLE(GAMEPAD) @@ -14369,7 +14255,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes) { m_navigationClient->shouldAllowLegacyTLS(*this, authenticationChallenge.get(), [this, protectedThis = Ref { *this }, authenticationChallenge] (bool shouldAllowLegacyTLS) { if (shouldAllowLegacyTLS) -@@ -12964,6 +13250,12 @@ void WebPageProxy::requestGeolocationPermissionForFrame(IPC::Connection& connect +@@ -13526,6 +13811,12 @@ void WebPageProxy::requestGeolocationPermissionForFrame(IPC::Connection& connect request->deny(); }; @@ -14382,7 +14268,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba // FIXME: Once iOS migrates to the new WKUIDelegate SPI, clean this up // and make it one UIClient call that calls the completionHandler with false // if there is no delegate instead of returning the completionHandler -@@ -13072,6 +13364,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi +@@ -13634,6 +13925,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi shouldChangeDeniedToPrompt = false; if (sessionID().isEphemeral()) { @@ -14395,7 +14281,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied); return; } -@@ -13086,6 +13384,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi +@@ -13648,6 +13945,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi return; } @@ -14409,7 +14295,7 @@ index 688b610a5776d8854c30924b1fb03940754e2d72..1386f07187519b3612b5219d209ac1ba completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied); return; diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h -index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d570b0b886 100644 +index c304883cbac2d21900bd09c7d7bc6e9701597e15..7083a7d4aba95ae552cbeb2b20440448a740ddca 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -28,6 +28,7 @@ @@ -14420,7 +14306,7 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 #include "MessageReceiver.h" #include <wtf/ApproximateTime.h> #include <wtf/CheckedRef.h> -@@ -41,6 +42,20 @@ +@@ -40,6 +41,20 @@ #include <wtf/SwiftBridging.h> #include <wtf/UniqueRef.h> #include <wtf/WeakHashSet.h> @@ -14441,7 +14327,7 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 #if USE(COORDINATED_GRAPHICS) && HAVE(DISPLAY_LINK) #include "DisplayLinkObserverID.h" -@@ -128,6 +143,7 @@ class DragData; +@@ -127,6 +142,7 @@ class DragData; class Exception; class FloatPoint; class FloatQuad; @@ -14449,24 +14335,24 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 class FloatRect; class FloatSize; class FontAttributeChanges; -@@ -816,6 +832,8 @@ public: +@@ -839,6 +855,8 @@ public: + RefPtr<WebAutomationSession> activeAutomationSession() const; - WebPageInspectorController& inspectorController() { return m_inspectorController.get(); } + InspectorDialogAgent* inspectorDialogAgent() { return m_inspectorDialogAgent; } + void setInspectorDialogAgent(InspectorDialogAgent * dialogAgent) { m_inspectorDialogAgent = dialogAgent; } + WebPageInspectorController& inspectorController() LIFETIME_BOUND { return m_inspectorController.get(); } #if PLATFORM(IOS_FAMILY) - void showInspectorIndication(); -@@ -848,6 +866,7 @@ public: - bool hasSleepDisabler() const; +@@ -872,6 +890,7 @@ public: + bool NODELETE hasSleepDisabler() const; #if ENABLE(FULLSCREEN_API) + void setFullScreenManagerClientOverride(std::unique_ptr<WebFullScreenManagerProxyClient>&&); - WebFullScreenManagerProxy* fullScreenManager(); + WebFullScreenManagerProxy* NODELETE fullScreenManager(); void setFullScreenClientForTesting(std::unique_ptr<WebKit::WebFullScreenManagerProxyClient>&&); -@@ -951,6 +970,12 @@ public: +@@ -940,6 +959,12 @@ public: void setPageLoadStateObserver(RefPtr<PageLoadStateObserverBase>&&); @@ -14479,7 +14365,7 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 void initializeWebPage(const WebCore::Site&, WebCore::SandboxFlags, WebCore::ReferrerPolicy); void setDrawingArea(RefPtr<DrawingAreaProxy>&&); -@@ -982,6 +1007,8 @@ public: +@@ -971,6 +996,8 @@ public: RefPtr<API::Navigation> loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::NavigationUpgradeToHTTPSBehavior); RefPtr<API::Navigation> loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::NavigationUpgradeToHTTPSBehavior, std::unique_ptr<NavigationActionData>&&, API::Object* userData = nullptr, bool isRequestFromClientOrUserInput = true); @@ -14488,30 +14374,30 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 RefPtr<API::Navigation> loadFile(const String& fileURL, const String& resourceDirectoryURL, bool isAppInitiated = true, API::Object* userData = nullptr); RefPtr<API::Navigation> loadData(Ref<WebCore::SharedBuffer>&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData = nullptr); RefPtr<API::Navigation> loadData(Ref<WebCore::SharedBuffer>&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldOpenExternalURLsPolicy); -@@ -1077,6 +1104,7 @@ public: +@@ -1072,6 +1099,7 @@ public: void restoreSelectionInFocusedEditableElement(); - PageClient* pageClient() const; + PageClient* NODELETE pageClient() const; + bool hasPageClient() const { return !!m_pageClient; } void setViewNeedsDisplay(const WebCore::Region&); void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin, WebCore::ScrollIsAnimated, WebCore::InterruptScrollAnimation); -@@ -1749,11 +1777,14 @@ public: - void didStartDrag(); +@@ -1755,11 +1783,14 @@ public: + void didStartDrag(const std::optional<WebCore::FrameIdentifier>& = std::nullopt); void dragCancelled(); void setDragCaretRect(const WebCore::IntRect&); + void setInterceptDrags(bool shouldIntercept); + bool cancelDragIfNeeded(); #if PLATFORM(COCOA) void propagateDragAndDrop(DragEventForwardingData&&, const String&, WebCore::DragData&&); - void startDrag(const WebCore::DragItem&, WebCore::ShareableBitmapHandle&& dragImageHandle, const std::optional<WebCore::NodeIdentifier>&); + void startDrag(const WebCore::DragItem&, WebCore::ShareableBitmapHandle&& dragImageHandle, const std::optional<WebCore::NodeIdentifier>&, const std::optional<WebCore::FrameIdentifier>& = std::nullopt); void setPromisedDataForImage(IPC::Connection&, const String& pasteboardName, WebCore::SharedMemoryHandle&& imageHandle, const String& filename, const String& extension, const String& title, const String& url, const String& visibleURL, WebCore::SharedMemoryHandle&& archiveHandle, const String& originIdentifier); + void releaseInspectorDragPasteboard(); #endif #if PLATFORM(GTK) || PLATFORM(WPE) void startDrag(WebCore::SelectionData&&, OptionSet<WebCore::DragOperation>, std::optional<WebCore::ShareableBitmapHandle>&& dragImage, WebCore::IntPoint&& dragImageHotspot); -@@ -1761,6 +1792,9 @@ public: +@@ -1767,6 +1798,9 @@ public: #if ENABLE(MODEL_PROCESS) void modelDragEnded(const WebCore::NodeIdentifier); #endif @@ -14521,15 +14407,15 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 #endif void processDidBecomeUnresponsive(WebProcessProxy&); -@@ -2007,6 +2041,7 @@ public: +@@ -2030,6 +2064,7 @@ public: void setViewportSizeForCSSViewportUnits(const WebCore::FloatSize&); - WebCore::FloatSize viewportSizeForCSSViewportUnits() const; + WebCore::FloatSize NODELETE viewportSizeForCSSViewportUnits() const; + bool shouldSendAutomationCredentialsForProtectionSpace(const WebProtectionSpace&); void didReceiveAuthenticationChallengeProxy(Ref<AuthenticationChallengeProxy>&&, NegotiatedLegacyTLS); void negotiatedLegacyTLS(); void didNegotiateModernTLS(const URL&); -@@ -2040,6 +2075,8 @@ public: +@@ -2063,6 +2098,8 @@ public: // TODO Replace RefPtr with Expected for error reporting https://webkit.org/b/300271 RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&); RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&, ForceSoftwareCapturingViewportSnapshot); @@ -14538,15 +14424,15 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 #endif void serializeAndWrapCryptoKey(IPC::Connection&, WebCore::CryptoKeyData&&, CompletionHandler<void(std::optional<Vector<uint8_t>>&&)>&&); -@@ -3136,6 +3173,7 @@ private: +@@ -3202,6 +3239,7 @@ private: RefPtr<API::Navigation> launchProcessForReload(); void requestNotificationPermission(const String& originString, CompletionHandler<void(bool allowed)>&&); + std::optional<bool> permissionForAutomation(const String& origin, const String& permission) const; #if ENABLE(WEB_ARCHIVE) - bool shouldAlwaysPromptForPermission(WebCore::PermissionName) const; -@@ -3669,11 +3707,13 @@ private: + bool NODELETE shouldAlwaysPromptForPermission(WebCore::PermissionName) const; +@@ -3752,11 +3790,13 @@ private: String m_openedMainFrameName; RefPtr<WebInspectorUIProxy> m_inspector; @@ -14560,7 +14446,7 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 RefPtr<WebFullScreenManagerProxy> m_fullScreenManager; std::unique_ptr<API::FullscreenClient> m_fullscreenClient; #endif -@@ -3875,6 +3915,22 @@ private: +@@ -3962,6 +4002,22 @@ private: std::optional<WebCore::DragOperation> m_currentDragOperation; bool m_currentDragIsOverFileInput { false }; unsigned m_currentDragNumberOfFilesToBeAccepted { 0 }; @@ -14583,7 +14469,7 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 #endif bool m_mainFrameHasHorizontalScrollbar { false }; -@@ -4045,6 +4101,11 @@ private: +@@ -4132,6 +4188,11 @@ private: RefPtr<API::Object> messageBody; }; Vector<InjectedBundleMessage> m_pendingInjectedBundleMessages; @@ -14596,7 +14482,7 @@ index 7a8a7b2bb8582944cf13dfb090419806ff8a9cb5..d781bf1304aefc891f669fe2159d42d5 #if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION) RefPtr<WebDeviceOrientationUpdateProviderProxy> m_webDeviceOrientationUpdateProviderProxy; diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in -index 70c42df56c678ae01f366f3d5ac3012d7b92a760..a3cf4f8fe954a44c7b06fa5e7f57ffe8df9a6ceb 100644 +index 155543cbd71b814586ab391daaa2efa2d11c22ea..b39e2260133f4aa7fe9580496bd4237b3fd52629 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.messages.in +++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in @@ -35,6 +35,7 @@ messages -> WebPageProxy { @@ -14607,7 +14493,7 @@ index 70c42df56c678ae01f366f3d5ac3012d7b92a760..a3cf4f8fe954a44c7b06fa5e7f57ffe8 DidReceiveEventIPC(enum:uint32_t WebKit::WebEventType eventType, bool handled, struct std::optional<WebCore::RemoteUserInputEventData> remoteUserInputEventData) SetCursor(WebCore::Cursor cursor) -@@ -343,6 +344,10 @@ messages -> WebPageProxy { +@@ -365,6 +366,10 @@ messages -> WebPageProxy { StartDrag(WebCore::SelectionData selectionData, OptionSet<WebCore::DragOperation> dragOperationMask, std::optional<WebCore::ShareableBitmapHandle> dragImage, WebCore::IntPoint dragImageHotspot) #endif @@ -14619,10 +14505,10 @@ index 70c42df56c678ae01f366f3d5ac3012d7b92a760..a3cf4f8fe954a44c7b06fa5e7f57ffe8 WillReceiveEditDragSnapshot() DidReceiveEditDragSnapshot(RefPtr<WebCore::TextIndicator> textIndicator) diff --git a/Source/WebKit/UIProcess/WebProcessCache.cpp b/Source/WebKit/UIProcess/WebProcessCache.cpp -index 302e7346a5607d06ef0467fae67f38a116144184..568eaa02fdb313a2c4f25be9f61e695d33ed87ba 100644 +index 1593c4e060fb5fbf399c7d53cb7a81896b945556..c10a4b847f118012380a8d8f35984c81c841d697 100644 --- a/Source/WebKit/UIProcess/WebProcessCache.cpp +++ b/Source/WebKit/UIProcess/WebProcessCache.cpp -@@ -120,6 +120,10 @@ bool WebProcessCache::canCacheProcess(WebProcessProxy& process) const +@@ -125,6 +125,10 @@ bool WebProcessCache::canCacheProcess(WebProcessProxy& process) const return false; } @@ -14634,10 +14520,10 @@ index 302e7346a5607d06ef0467fae67f38a116144184..568eaa02fdb313a2c4f25be9f61e695d } diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp -index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4129f12d4 100644 +index c9e5f1f1a7dfed59616429838f635538c34124f9..af87d3e1c00f0513658180c5fb397621c1b5505a 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.cpp +++ b/Source/WebKit/UIProcess/WebProcessPool.cpp -@@ -431,10 +431,10 @@ void WebProcessPool::setAutomationClient(std::unique_ptr<API::AutomationClient>& +@@ -423,10 +423,10 @@ void WebProcessPool::setAutomationClient(std::unique_ptr<API::AutomationClient>& void WebProcessPool::setOverrideLanguages(Vector<String>&& languages) { @@ -14650,7 +14536,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 #if ENABLE(GPU_PROCESS) if (RefPtr gpuProcess = GPUProcessProxy::singletonIfCreated()) -@@ -442,9 +442,10 @@ void WebProcessPool::setOverrideLanguages(Vector<String>&& languages) +@@ -434,9 +434,10 @@ void WebProcessPool::setOverrideLanguages(Vector<String>&& languages) #endif #if USE(SOUP) for (Ref networkProcess : NetworkProcessProxy::allNetworkProcesses()) @@ -14662,7 +14548,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 void WebProcessPool::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled) { -@@ -1011,7 +1012,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa +@@ -977,7 +978,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa #endif parameters.cacheModel = LegacyGlobalSettings::singleton().cacheModel(); @@ -14671,7 +14557,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 LOG_WITH_STREAM(Language, stream << "WebProcessPool is initializing a new web process with overrideLanguages: " << parameters.overrideLanguages); parameters.urlSchemesRegisteredAsSecure = copyToVector(LegacyGlobalSettings::singleton().schemesToRegisterAsSecure()); -@@ -1084,7 +1085,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa +@@ -1056,7 +1057,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa if (!injectedBundleInitializationUserData) injectedBundleInitializationUserData = m_injectedBundleInitializationUserData; parameters.initializationUserData = UserData(process.transformObjectsToHandles(injectedBundleInitializationUserData.get())); @@ -14680,7 +14566,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 if (websiteDataStore) parameters.websiteDataStoreParameters = webProcessDataStoreParameters(process, *websiteDataStore); -@@ -1178,14 +1179,14 @@ void WebProcessPool::processDidFinishLaunching(WebProcessProxy& process) +@@ -1150,14 +1151,14 @@ void WebProcessPool::processDidFinishLaunching(WebProcessProxy& process) // Sometimes the memorySampler gets initialized after process initialization has happened but before the process has finished launching // so check if it needs to be started here if (m_memorySamplerEnabled) { @@ -14697,7 +14583,20 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 process.send(Messages::WebProcess::StartMemorySampler(WTF::move(sampleLogSandboxHandle), sampleLogFilePath, m_memorySamplerInterval), 0); } -@@ -1380,9 +1381,9 @@ Ref<WebPageProxy> WebProcessPool::createWebPage(PageClient& pageClient, Ref<API: +@@ -1327,6 +1328,12 @@ Ref<WebPageProxy> WebProcessPool::createWebPage(PageClient& pageClient, Ref<API: + auto enhancedSecurity = (protect(pageConfiguration->preferences())->forceEnhancedSecurity() || pageConfiguration->isEnhancedSecurityEnabled() || useEnhancedSecurityFallback) ? EnhancedSecurity::EnabledPolicy : EnhancedSecurity::Disabled; + + RefPtr relatedPage = pageConfiguration->relatedPage(); ++ ++ // Fix WPE/GTK crashes after 310806@main. upstream-status (pending). See issue https://github.com/microsoft/playwright-browsers/issues/2171 ++ // Ensure popups inherit the StorageBlockingPolicy of the parent so they stay compatible for same-process popup creation. ++ if (relatedPage) ++ pageConfiguration->preferences().setStorageBlockingPolicy(relatedPage->preferences().storageBlockingPolicy()); ++ + bool siteIsolationEnabled = protect(pageConfiguration->preferences())->siteIsolationEnabled(); + if (siteIsolationEnabled) + protect(pageConfiguration->preferences())->setUseUIProcessForBackForwardItemLoading(true); +@@ -1358,9 +1365,9 @@ Ref<WebPageProxy> WebProcessPool::createWebPage(PageClient& pageClient, Ref<API: } Ref userContentController = pageConfiguration->userContentController(); @@ -14709,7 +14608,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 process->setAllowTestOnlyIPC(pageConfiguration->allowTestOnlyIPC()); auto page = process->createWebPage(pageClient, WTF::move(pageConfiguration)); -@@ -1767,18 +1768,18 @@ void WebProcessPool::setEnhancedAccessibility(bool flag) +@@ -1745,18 +1752,18 @@ void WebProcessPool::setEnhancedAccessibility(bool flag) { sendToAllProcesses(Messages::WebProcess::SetEnhancedAccessibility(flag)); } @@ -14732,7 +14631,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 for (auto& process : m_processes) { if (!process->canSendMessage()) continue; -@@ -1797,10 +1798,10 @@ void WebProcessPool::startMemorySampler(const double interval) +@@ -1775,10 +1782,10 @@ void WebProcessPool::startMemorySampler(const double interval) } void WebProcessPool::stopMemorySampler() @@ -14745,7 +14644,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 // For UIProcess #if ENABLE(MEMORY_SAMPLER) WebMemorySampler::singleton()->stop(); -@@ -1852,7 +1853,7 @@ void WebProcessPool::setAutomationSession(RefPtr<WebAutomationSession>&& automat +@@ -1830,7 +1837,7 @@ void WebProcessPool::setAutomationSession(RefPtr<WebAutomationSession>&& automat { if (RefPtr previousSession = m_automationSession) previousSession->setProcessPool(nullptr); @@ -14754,7 +14653,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 m_automationSession = WTF::move(automationSession); #if ENABLE(REMOTE_INSPECTOR) -@@ -2415,7 +2416,7 @@ std::tuple<Ref<WebProcessProxy>, RefPtr<SuspendedPageProxy>, ASCIILiteral> WebPr +@@ -2403,7 +2410,7 @@ std::tuple<Ref<WebProcessProxy>, RefPtr<SuspendedPageProxy>, ASCIILiteral> WebPr } auto reason = "Navigation is cross-site"_s; @@ -14763,7 +14662,7 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 if (m_configuration->alwaysKeepAndReuseSwappedProcesses()) { LOG(ProcessSwapping, "(ProcessSwapping) Considering re-use of a previously cached process for domain %s", targetSite.domain().string().utf8().data()); -@@ -2520,7 +2521,7 @@ void WebProcessPool::setDomainsWithUserInteraction(HashSet<WebCore::RegistrableD +@@ -2508,7 +2515,7 @@ void WebProcessPool::setDomainsWithUserInteraction(HashSet<WebCore::RegistrableD } void WebProcessPool::setDomainsWithCrossPageStorageAccess(HashMap<TopFrameDomain, Vector<SubResourceDomain>>&& domains, CompletionHandler<void()>&& completionHandler) @@ -14771,9 +14670,9 @@ index fee48b818c8c467c76d7a2969f50f59b91251166..28c0e7d660aaa3b54d3970e2b34db4f4 +{ Ref callbackAggregator = CallbackAggregator::create(WTF::move(completionHandler)); - for (Ref process : processes()) + for (Ref process : borrow(this->processes()).get()) diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp -index e29052953675da1ad140f2dd485f7f41c8b5a1d1..8f422f122082809ab716bba4d8deab04eb47a49f 100644 +index 1f2073d6c2900da0994e09c3edaee6c67298fade..b7a2870799a36988a051efe48c62f1d975156751 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.cpp +++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp @@ -215,6 +215,11 @@ Vector<Ref<WebProcessProxy>> WebProcessProxy::allProcesses() @@ -14788,8 +14687,8 @@ index e29052953675da1ad140f2dd485f7f41c8b5a1d1..8f422f122082809ab716bba4d8deab04 RefPtr<WebProcessProxy> WebProcessProxy::processForIdentifier(ProcessIdentifier identifier) { return allProcessMap().get(identifier); -@@ -564,6 +569,26 @@ void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt - if (WebKit::isInspectorProcessPool(protect(processPool()))) +@@ -583,6 +588,26 @@ void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt + if (WebKit::isInspectorProcessPool(processPool())) launchOptions.extraInitializationData.add<HashTranslatorASCIILiteral>("inspector-process"_s, "1"_s); + /* playwright revert fb205fb, 50f8fee */ @@ -14816,7 +14715,7 @@ index e29052953675da1ad140f2dd485f7f41c8b5a1d1..8f422f122082809ab716bba4d8deab04 if (isPrewarmed()) diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h -index 1b7181721762e1a28ab0d0688c5a35dfd4fb9ee3..49b5e50f3932a9fa2c57585e70cd9e4065079480 100644 +index 2bf85bf9e81bcca1c2c0830004a3cb6ef67708d0..4284c4b480346514dd3ba1ad4c01802ff151753b 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.h +++ b/Source/WebKit/UIProcess/WebProcessProxy.h @@ -208,6 +208,7 @@ public: @@ -14827,23 +14726,11 @@ index 1b7181721762e1a28ab0d0688c5a35dfd4fb9ee3..49b5e50f3932a9fa2c57585e70cd9e40 void initializeWebProcess(WebProcessCreationParameters&&); -diff --git a/Source/WebKit/UIProcess/WebURLSchemeTask.cpp b/Source/WebKit/UIProcess/WebURLSchemeTask.cpp -index 39ea73a0da8bf68156f3e17ab4b575d25b4962a5..4b3567e34f588104f6dd76cb38fcd0ba158cd9c2 100644 ---- a/Source/WebKit/UIProcess/WebURLSchemeTask.cpp -+++ b/Source/WebKit/UIProcess/WebURLSchemeTask.cpp -@@ -33,6 +33,7 @@ - #include "WebErrors.h" - #include "WebPageMessages.h" - #include "WebPageProxy.h" -+#include "WebProcessProxy.h" - #include "WebURLSchemeHandler.h" - #include "WebURLSchemeHandlerIdentifier.h" - #include <WebCore/ResourceLoaderIdentifier.h> diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp -index c9c6418e3b4c9fea5c21dae27d21300986bfdbce..1f0ad46549bacd791b83d3ab98a6bae17b72b1c6 100644 +index 200b1f02601242c6e2240ab6bbb7d2b7e093e5b4..a95b9dfb1939a1fb2ae271e34a00d7201dfe06aa 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp -@@ -314,15 +314,10 @@ SOAuthorizationCoordinator& WebsiteDataStore::soAuthorizationCoordinator(const W +@@ -315,15 +315,10 @@ SOAuthorizationCoordinator& WebsiteDataStore::soAuthorizationCoordinator(const W static Ref<NetworkProcessProxy> networkProcessForSession(PAL::SessionID sessionID) { @@ -14862,7 +14749,7 @@ index c9c6418e3b4c9fea5c21dae27d21300986bfdbce..1f0ad46549bacd791b83d3ab98a6bae1 #else UNUSED_PARAM(sessionID); return NetworkProcessProxy::ensureDefaultNetworkProcess(); -@@ -2116,6 +2111,15 @@ void WebsiteDataStore::setCacheModelSynchronouslyForTesting(CacheModel cacheMode +@@ -2100,6 +2095,15 @@ void WebsiteDataStore::setCacheModelSynchronouslyForTesting(CacheModel cacheMode processPool->setCacheModelSynchronouslyForTesting(cacheModel); } @@ -14878,8 +14765,8 @@ index c9c6418e3b4c9fea5c21dae27d21300986bfdbce..1f0ad46549bacd791b83d3ab98a6bae1 Vector<WebsiteDataStoreParameters> WebsiteDataStore::parametersFromEachWebsiteDataStore() { return WTF::map(allDataStores(), [](auto& entry) { -@@ -2535,6 +2539,12 @@ void WebsiteDataStore::originDirectoryForTesting(WebCore::ClientOrigin&& origin, - protect(networkProcess())->websiteDataOriginDirectoryForTesting(m_sessionID, WTF::move(origin), type, WTF::move(completionHandler)); +@@ -2524,6 +2528,12 @@ void WebsiteDataStore::lastPageLoadNetworkActivityCompletionCodeForTesting(WebCo + protect(networkProcess())->lastPageLoadNetworkActivityCompletionCodeForTesting(m_sessionID, pageID, WTF::move(completionHandler)); } +void WebsiteDataStore::setDownloadForAutomation(std::optional<bool> allow, const String& downloadPath) @@ -14892,10 +14779,10 @@ index c9c6418e3b4c9fea5c21dae27d21300986bfdbce..1f0ad46549bacd791b83d3ab98a6bae1 void WebsiteDataStore::hasAppBoundSession(CompletionHandler<void(bool)>&& completionHandler) const { diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h -index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb8355103d 100644 +index 8de753cfce229075cbfa2bc7a81eab3d2fe1fb03..f78922cea6147503e3bcbcf8869ebda2518ef62c 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h -@@ -102,6 +102,7 @@ class DeviceIdHashSaltStorage; +@@ -103,6 +103,7 @@ class DeviceIdHashSaltStorage; class DownloadProxy; class NetworkProcessProxy; class SOAuthorizationCoordinator; @@ -14903,7 +14790,7 @@ index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb class VirtualAuthenticatorManager; class WebPageProxy; class WebProcessPool; -@@ -117,6 +118,7 @@ enum class UnifiedOriginStorageLevel : uint8_t; +@@ -118,6 +119,7 @@ enum class UnifiedOriginStorageLevel : uint8_t; enum class WebsiteDataFetchOption : uint8_t; enum class WebsiteDataType : uint32_t; @@ -14911,7 +14798,7 @@ index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb struct ITPThirdPartyData; struct NetworkProcessConnectionInfo; struct WebPushMessage; -@@ -126,6 +128,14 @@ struct WebsiteDataStoreParameters; +@@ -127,6 +129,14 @@ struct WebsiteDataStoreParameters; enum RemoveDataTaskCounterType { }; using RemoveDataTaskCounter = RefCounter<RemoveDataTaskCounterType>; @@ -14926,7 +14813,7 @@ index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb class WebsiteDataStore : public API::ObjectImpl<API::Object::Type::WebsiteDataStore>, public CanMakeWeakPtr<WebsiteDataStore> { public: static WebsiteDataStore& defaultDataStore(); -@@ -331,8 +341,10 @@ public: +@@ -330,8 +340,10 @@ public: #if USE(SOUP) void setPersistentCredentialStorageEnabled(bool); bool persistentCredentialStorageEnabled() const { return m_persistentCredentialStorageEnabled && isPersistent(); } @@ -14935,9 +14822,9 @@ index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb bool ignoreTLSErrors() const { return m_ignoreTLSErrors; } +#if USE(SOUP) void setNetworkProxySettings(WebCore::SoupNetworkProxySettings&&); - const WebCore::SoupNetworkProxySettings& networkProxySettings() const { return m_networkProxySettings; } + const WebCore::SoupNetworkProxySettings& networkProxySettings() const LIFETIME_BOUND { return m_networkProxySettings; } void setCookiePersistentStorage(const String&, SoupCookiePersistentStorageType); -@@ -425,6 +437,12 @@ public: +@@ -422,6 +434,12 @@ public: static const String& defaultBaseDataDirectory(); #endif @@ -14950,7 +14837,7 @@ index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb void resetQuota(CompletionHandler<void()>&&); void resetStoragePersistedState(CompletionHandler<void()>&&); #if PLATFORM(IOS_FAMILY) -@@ -641,7 +659,9 @@ private: +@@ -642,7 +660,9 @@ private: #if USE(SOUP) bool m_persistentCredentialStorageEnabled { true }; @@ -14961,7 +14848,7 @@ index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb WebCore::SoupNetworkProxySettings m_networkProxySettings; String m_cookiePersistentStoragePath; SoupCookiePersistentStorageType m_cookiePersistentStorageType { SoupCookiePersistentStorageType::SQLite }; -@@ -668,6 +688,10 @@ private: +@@ -669,6 +689,10 @@ private: const RefPtr<API::HTTPCookieStore> m_cookieStore; RefPtr<NetworkProcessProxy> m_networkProcess; @@ -14973,7 +14860,7 @@ index 865a19833f9b6e849fa3c38578a1ae52d723499a..c7e3aacb258241b85be1405a58bf07cb const std::unique_ptr<SOAuthorizationCoordinator> m_soAuthorizationCoordinator; #endif diff --git a/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp b/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp -index b7a4f8afd5c88971efa47613d5a2ade8fc7acf60..eab188385a65f42378b0a294ca18c05b9e6166d6 100644 +index ad30e3705de228f71b2206a9da314451bbb2ca00..e46d97003021b06d17f66dd60f7ffcf2c69049cb 100644 --- a/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp +++ b/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp @@ -31,6 +31,7 @@ @@ -15488,7 +15375,7 @@ index 0000000000000000000000000000000000000000..68bc7b610703bfcd3eff0d1c032092f6 + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp b/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp -index 250f6c755a363c4755bcfbb29c5bf5f37913a752..486052a0943c71207557b99544f6173f0925ade7 100644 +index e69e33b4359e24075e9054f014f5e5ab488b78c7..f395398acf790cc4fa80122dd4f59381ee03f5ac 100644 --- a/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp +++ b/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp @@ -127,6 +127,8 @@ static OptionSet<AvailableInputDevices> availableInputDevices() @@ -15501,10 +15388,10 @@ index 250f6c755a363c4755bcfbb29c5bf5f37913a752..486052a0943c71207557b99544f6173f return AvailableInputDevices::Touchscreen; #else diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp -index cf23273b830c15058fe057ff205e9bfc5b6fa146..dd5778518cacc50877bd3d1aa389d7093a7eb4c3 100644 +index 3dd2a77a24c59cb7fb1f01d3a74d75267a0f36bf..a020ccc929af8c9130ecca0125e5229ee8670e54 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp -@@ -822,4 +822,30 @@ RefPtr<NativeImage> AcceleratedBackingStore::bufferAsNativeImageForTesting() con +@@ -864,4 +864,30 @@ RefPtr<NativeImage> AcceleratedBackingStore::bufferAsNativeImageForTesting() con return m_committedBuffer->asNativeImageForTesting(); } @@ -15536,18 +15423,18 @@ index cf23273b830c15058fe057ff205e9bfc5b6fa146..dd5778518cacc50877bd3d1aa389d709 + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h -index 1ade1dec8e7865d1c782c3704d02c12ff1c386ff..74519f7efae955e7ec1ffa824ab9c1589ec9808f 100644 +index 2a15a005441f41bcc3a44ce666dabeab7ab671f2..cc802e0634696b9455cd650527886c35a14a3ea3 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h -@@ -41,6 +41,7 @@ +@@ -42,6 +42,7 @@ #include <wtf/unix/UnixFileDescriptor.h> typedef void *EGLImage; +typedef struct _cairo_surface cairo_surface_t; #if USE(GBM) - struct gbm_bo; -@@ -84,6 +85,7 @@ public: + #include <WebCore/DMABufBuffer.h> +@@ -86,6 +87,7 @@ public: void unrealize(); RendererBufferDescription bufferDescription() const; RefPtr<WebCore::NativeImage> bufferAsNativeImageForTesting() const; @@ -15555,7 +15442,7 @@ index 1ade1dec8e7865d1c782c3704d02c12ff1c386ff..74519f7efae955e7ec1ffa824ab9c158 private: explicit AcceleratedBackingStore(WebPageProxy&); -@@ -250,6 +252,10 @@ private: +@@ -268,6 +270,10 @@ private: RefPtr<Buffer> m_committedBuffer; Rects m_pendingDamageRects; HashMap<uint64_t, RefPtr<Buffer>> m_buffers; @@ -15616,8 +15503,58 @@ index 0000000000000000000000000000000000000000..8f661f8c62dc091670f9474db037e7ee +} + +} // namespace WebKit +diff --git a/Source/WebKit/UIProcess/gtk/PageInspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/PageInspectorTargetProxyGtk.cpp +new file mode 100644 +index 0000000000000000000000000000000000000000..4412881043189ba16e7803eeab98bce574ab9267 +--- /dev/null ++++ b/Source/WebKit/UIProcess/gtk/PageInspectorTargetProxyGtk.cpp +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (C) 2019 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. ++ */ ++ ++#include "config.h" ++#include "PageInspectorTargetProxy.h" ++ ++#include "WebPageProxy.h" ++#include "GtkUtilities.h" ++#include <gtk/gtk.h> ++ ++namespace WebKit { ++ ++void PageInspectorTargetProxy::platformActivate(String& error) const ++{ ++ GtkWidget* parent = GTK_WIDGET(gtk_widget_get_root(m_page->viewWidget())); ++ if (widgetIsOnscreenToplevelWindow(parent)) ++ gtk_window_present(GTK_WINDOW(parent)); ++ else ++ error = "The view is not on screen"_s; ++} ++ ++} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp -index 31ebf8480d842db47e17bdb4639a3cd5e934ea49..bdffaeb1b97fe54f58086a62e7b641ebc6bc0196 100644 +index ed7f7adafd75f27ce458324b50144b28fb225565..3864cd324b918f97283a7d99dad753c84e3cb748 100644 --- a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp +++ b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp @@ -128,6 +128,8 @@ int SystemSettingsManagerProxy::xftDPI() const @@ -15825,56 +15762,6 @@ index 0000000000000000000000000000000000000000..40355b2c69d7a94e924451b5fe1c0b96 +} + +} // namespace WebKit -diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp -new file mode 100644 -index 0000000000000000000000000000000000000000..4c30302b5bd7d7f989da63375f1b4eb9c0b15b50 ---- /dev/null -+++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp -@@ -0,0 +1,44 @@ -+/* -+ * Copyright (C) 2019 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. -+ */ -+ -+#include "config.h" -+#include "WebPageInspectorTargetProxy.h" -+ -+#include "WebPageProxy.h" -+#include "GtkUtilities.h" -+#include <gtk/gtk.h> -+ -+namespace WebKit { -+ -+void WebPageInspectorTargetProxy::platformActivate(String& error) const -+{ -+ GtkWidget* parent = GTK_WIDGET(gtk_widget_get_root(m_page->viewWidget())); -+ if (widgetIsOnscreenToplevelWindow(parent)) -+ gtk_window_present(GTK_WINDOW(parent)); -+ else -+ error = "The view is not on screen"_s; -+} -+ -+} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp index baeb21c5cee36343d37fdf552cc36b26b2d5213e..d9efcdf56227966efafe53ba82c98673a47a9959 100644 --- a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp @@ -15970,7 +15857,7 @@ index 0000000000000000000000000000000000000000..edb4581e8f1f484976a9081d37cb61e5 +} // namespace API diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm new file mode 100644 -index 0000000000000000000000000000000000000000..d8dbc62b3ec8cd0588e8c22b9e4cf2fda0c9d03f +index 0000000000000000000000000000000000000000..409444cd94c22ff0662d786c95b04688ce2ea7b3 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm @@ -0,0 +1,96 @@ @@ -16011,7 +15898,7 @@ index 0000000000000000000000000000000000000000..d8dbc62b3ec8cd0588e8c22b9e4cf2fd +#import "WKWebsiteDataStoreInternal.h" +#import "WKWebView.h" +#import "WKWebViewInternal.h" -+#import <WebCore/ImageBufferUtilitiesCG.h> ++#import <WebCore/ImageUtilities.h> +#import <wtf/RefPtr.h> +#import <wtf/text/WTFString.h> + @@ -16065,7 +15952,7 @@ index 0000000000000000000000000000000000000000..d8dbc62b3ec8cd0588e8c22b9e4cf2fd + + clipRect.move(0, toolbarHeight); + RetainPtr<CGImageRef> transformedImageRef = adoptCF(CGImageCreateWithImageInRect(imageRef.get(), clipRect)); -+ completionHandler(emptyString(), WebCore::dataURL(transformedImageRef.get(), "image/png"_s, std::nullopt)); ++ completionHandler(emptyString(), WebCore::encodeDataURL(transformedImageRef.get(), "image/png"_s, std::nullopt)); + }); +} + @@ -16119,7 +16006,7 @@ index 0000000000000000000000000000000000000000..8adbd51bfecad2a273117588bf50f8f7 + +#endif diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.h b/Source/WebKit/UIProcess/mac/PageClientImplMac.h -index 50915547582917bb455e037a702f3d5c5ab2e34b..f1f8670b0c86e3f356c90d3802a7e16ad309f81c 100644 +index a621f334b3f1a1d2ea1c4bba63d73fa0757fe2bd..3d6b14a3a2a8a6f42f8da31b535e76715b6fe20a 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.h +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.h @@ -31,9 +31,11 @@ @@ -16153,7 +16040,7 @@ index 50915547582917bb455e037a702f3d5c5ab2e34b..f1f8670b0c86e3f356c90d3802a7e16a RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&) override; RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&, ForceSoftwareCapturingViewportSnapshot) override; void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) override; -@@ -228,6 +235,10 @@ private: +@@ -233,6 +240,10 @@ private: void beganExitFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame, CompletionHandler<void()>&&) override; #endif @@ -16165,10 +16052,10 @@ index 50915547582917bb455e037a702f3d5c5ab2e34b..f1f8670b0c86e3f356c90d3802a7e16a void navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem&) override; void navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem&) override; diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm -index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a83a09b22 100644 +index 23ae9a262af01284fadc90a18436b77af5752c24..730af4dee8db0f9a5dcf34623d499f4619e0d83d 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm -@@ -112,6 +112,13 @@ using namespace WebCore; +@@ -113,6 +113,13 @@ using namespace WebCore; WTF_MAKE_TZONE_ALLOCATED_IMPL(PageClientImpl); @@ -16182,7 +16069,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a PageClientImpl::PageClientImpl(NSView *view, WKWebView *webView) : PageClientImplCocoa(webView) , m_view(view) -@@ -171,6 +178,9 @@ NSWindow *PageClientImpl::activeWindow() const +@@ -172,6 +179,9 @@ NSWindow *PageClientImpl::activeWindow() const bool PageClientImpl::isViewWindowActive() { @@ -16192,7 +16079,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer)); RetainPtr activeViewWindow = activeWindow(); return activeViewWindow.get().isKeyWindow || (activeViewWindow && [NSApp keyWindow] == activeViewWindow.get()); -@@ -178,6 +188,9 @@ bool PageClientImpl::isViewWindowActive() +@@ -179,6 +189,9 @@ bool PageClientImpl::isViewWindowActive() bool PageClientImpl::isViewFocused() { @@ -16202,9 +16089,9 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a // FIXME: This is called from the WebPageProxy constructor before we have a WebViewImpl. // Once WebViewImpl and PageClient merge, this won't be a problem. if (CheckedPtr impl = m_impl.get()) -@@ -201,6 +214,9 @@ void PageClientImpl::makeFirstResponder() +@@ -202,6 +215,9 @@ void PageClientImpl::makeFirstResponder() - bool PageClientImpl::isViewVisible(NSView *view, NSWindow *viewWindow) + bool PageClientImpl::isViewVisible(NSView *view, NSWindow *viewWindow) const { + if (_headless) + return true; @@ -16212,7 +16099,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a auto windowIsOccluded = [&]()->bool { return m_impl && m_impl->windowOcclusionDetectionEnabled() && (viewWindow.occlusionState & NSWindowOcclusionStateVisible) != NSWindowOcclusionStateVisible; }; -@@ -299,7 +315,8 @@ void PageClientImpl::didRelaunchProcess() +@@ -300,7 +316,8 @@ void PageClientImpl::didRelaunchProcess() void PageClientImpl::preferencesDidChange() { @@ -16222,7 +16109,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a } void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip) -@@ -523,6 +540,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) +@@ -533,6 +550,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { @@ -16231,7 +16118,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a protect(m_impl)->doneWithKeyEvent(RetainPtr { event.nativeEvent() }.get(), eventWasHandled); } -@@ -542,6 +561,8 @@ void PageClientImpl::computeHasVisualSearchResults(const URL& imageURL, Shareabl +@@ -552,6 +571,8 @@ void PageClientImpl::computeHasVisualSearchResults(const URL& imageURL, Shareabl RefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy& page) { @@ -16240,7 +16127,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a return WebPopupMenuProxyMac::create(m_view.get().get(), protect(page.popupMenuClient())); } -@@ -667,6 +688,12 @@ CALayer *PageClientImpl::footerBannerLayer() const +@@ -677,6 +698,12 @@ CALayer *PageClientImpl::footerBannerLayer() const return m_impl->footerBannerLayer(); } @@ -16253,7 +16140,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a RefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot(std::optional<WebCore::IntRect>&&) { return protect(m_impl)->takeViewSnapshot(); -@@ -884,6 +911,13 @@ void PageClientImpl::beganExitFullScreen(const IntRect& initialFrame, const IntR +@@ -898,6 +925,13 @@ void PageClientImpl::beganExitFullScreen(const IntRect& initialFrame, const IntR #endif // ENABLE(FULLSCREEN_API) @@ -16267,7 +16154,7 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a void PageClientImpl::navigationGestureDidBegin() { protect(m_impl)->dismissContentRelativeChildWindowsWithAnimation(true); -@@ -1064,6 +1098,9 @@ void PageClientImpl::requestScrollToRect(const WebCore::FloatRect& targetRect, c +@@ -1078,6 +1112,9 @@ void PageClientImpl::requestScrollToRect(const WebCore::FloatRect& targetRect, c bool PageClientImpl::windowIsFrontWindowUnderMouse(const NativeWebMouseEvent& event) { @@ -16277,6 +16164,54 @@ index 1ed5dcc1b743cdc5013f6ace7d61dfcf33301d06..33f31f4e18aad7617c506cf2d4d5bf7a return protect(m_impl)->windowIsFrontWindowUnderMouse(RetainPtr { event.nativeEvent() }.get()); } +diff --git a/Source/WebKit/UIProcess/mac/PageInspectorTargetProxyMac.mm b/Source/WebKit/UIProcess/mac/PageInspectorTargetProxyMac.mm +new file mode 100644 +index 0000000000000000000000000000000000000000..cdeaad88feeb7c0d0d6ec485c73928030741904a +--- /dev/null ++++ b/Source/WebKit/UIProcess/mac/PageInspectorTargetProxyMac.mm +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2019 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. ++ */ ++ ++#import "config.h" ++#import "PageInspectorTargetProxy.h" ++#import "WebPageProxy.h" ++ ++#if PLATFORM(MAC) ++ ++namespace WebKit { ++ ++void PageInspectorTargetProxy::platformActivate(String& error) const ++{ ++ NSWindow* window = m_page->platformWindow(); ++ [window makeKeyAndOrderFront:nil]; ++} ++ ++} // namespace WebKit ++ ++#endif diff --git a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in b/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in index f46895285dbc84c624537a194814c18f771a0c08..29ef9e5afa13b8d2b47b7f2dd4ce37846b61c35f 100644 --- a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in @@ -16313,10 +16248,10 @@ index 6cfc616d5492bd12f7516ff2d6a67e77705f42b0..fd2e2a98b1db2c469a7f18fb2b7cbfbd @interface WKTextAnimationTypeEffectData : NSObject diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h -index 0aacf596ab1b3a080661bbdb3581893f4cd2d311..25e26ea53096bf13ec8dd8c0796c1ec3adfb700a 100644 +index d063c571127353548110ca306fabf076cae2c966..015f0932a0b9da6888365eb072f7c6d5d048b9bb 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h -@@ -86,6 +86,7 @@ private: +@@ -87,6 +87,7 @@ private: void show() override; void showContextMenuWithItems(Vector<Ref<WebContextMenuItem>>&&) override; void useContextMenuItems(Vector<Ref<WebContextMenuItem>>&&) override; @@ -16325,10 +16260,10 @@ index 0aacf596ab1b3a080661bbdb3581893f4cd2d311..25e26ea53096bf13ec8dd8c0796c1ec3 bool showAfterPostProcessingContextData(); diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm -index 90afb16340db0c2f3946dd8ad720d180af5b472c..9ff4b816525f39c43c72c297a726e5b0a66b65c3 100644 +index 960f2529fe031dd6799c5d0d16ebf899089620e6..0a9e4684a6a149cffc4addc64b3b79bffc07211b 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm -@@ -534,6 +534,12 @@ RetainPtr<NSMenuItem> WebContextMenuProxyMac::createShareMenuItem(ShareMenuItemT +@@ -543,6 +543,12 @@ RetainPtr<NSMenuItem> WebContextMenuProxyMac::createShareMenuItem(ShareMenuItemT } #endif @@ -16393,7 +16328,7 @@ index 0000000000000000000000000000000000000000..6113f4cd60a5d72b8ead61176cb43200 +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm new file mode 100644 -index 0000000000000000000000000000000000000000..e49fbb17708b557074f1df851717adaef1e9e916 +index 0000000000000000000000000000000000000000..e6d3a8764ef084790a4ca4e9891b09ddcbb70781 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm @@ -0,0 +1,141 @@ @@ -16502,7 +16437,7 @@ index 0000000000000000000000000000000000000000..e49fbb17708b557074f1df851717adae + event = [NSEvent eventWithCGEvent:cgEvent]; + } + -+ NativeWebMouseEvent nativeEvent(event, nil, [window contentView], WebKit::WebMouseEventInputSource::Hardware); ++ NativeWebMouseEvent nativeEvent(event, nil, [window contentView], WebKit::WebEventInputSource::UserDriven); + nativeEvent.playwrightSetButtons(buttons); + m_page.handleMouseEvent(nativeEvent); +} @@ -16538,56 +16473,8 @@ index 0000000000000000000000000000000000000000..e49fbb17708b557074f1df851717adae +} + +} // namespace WebKit -diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorTargetProxyMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorTargetProxyMac.mm -new file mode 100644 -index 0000000000000000000000000000000000000000..c58e17e9095c73eb9670ca55e5465b0d3afd6223 ---- /dev/null -+++ b/Source/WebKit/UIProcess/mac/WebPageInspectorTargetProxyMac.mm -@@ -0,0 +1,42 @@ -+/* -+ * Copyright (C) 2019 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. -+ */ -+ -+#import "config.h" -+#import "WebPageInspectorTargetProxy.h" -+#import "WebPageProxy.h" -+ -+#if PLATFORM(MAC) -+ -+namespace WebKit { -+ -+void WebPageInspectorTargetProxy::platformActivate(String& error) const -+{ -+ NSWindow* window = m_page->platformWindow(); -+ [window makeKeyAndOrderFront:nil]; -+} -+ -+} // namespace WebKit -+ -+#endif diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.h b/Source/WebKit/UIProcess/mac/WebViewImpl.h -index d126a49ff1409f870e4af4fc389d5a191177d112..8497af03a2cc32e9d76827dab1115dfda6fbb606 100644 +index 00f01a73b212bdc22a7da18c3ce1441735cec72f..ec0714a8b65d0323de74d09d039373059708f528 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.h +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.h @@ -39,6 +39,7 @@ @@ -16595,10 +16482,10 @@ index d126a49ff1409f870e4af4fc389d5a191177d112..8497af03a2cc32e9d76827dab1115dfd #include "WebMouseEvent.h" #include <WebCore/DOMPasteAccess.h> +#include <WebCore/FrameIdentifier.h> + #include <WebCore/DigitalCredentialsRequestData.h> #include <WebCore/FocusDirection.h> #include <WebCore/HTMLMediaElementIdentifier.h> - #include <WebCore/KeypressCommand.h> -@@ -606,6 +607,9 @@ public: +@@ -615,6 +616,9 @@ public: void provideDataForPasteboard(NSPasteboard *, NSString *type); NSArray *namesOfPromisedFilesDroppedAtDestination(NSURL *dropDestination); @@ -16609,10 +16496,10 @@ index d126a49ff1409f870e4af4fc389d5a191177d112..8497af03a2cc32e9d76827dab1115dfd RefPtr<ViewSnapshot> takeViewSnapshot(ForceSoftwareCapturingViewportSnapshot); void saveBackForwardSnapshotForCurrentItem(); diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.mm b/Source/WebKit/UIProcess/mac/WebViewImpl.mm -index ba090c4c4473c56592d5681f348bb5774ff05cc8..58bd1d87e363ec0706747c2b2571d3584a4efca9 100644 +index 3899b38da4dab24c275d8ac5e17e5ad39c54501a..e473f92023b209565c7e558503d25b847947e918 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.mm +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.mm -@@ -2571,6 +2571,11 @@ WebCore::DestinationColorSpace WebViewImpl::colorSpace() +@@ -2604,6 +2604,11 @@ WebCore::DestinationColorSpace WebViewImpl::colorSpace() if (!m_colorSpace) m_colorSpace = [NSColorSpace sRGBColorSpace]; } @@ -16624,7 +16511,7 @@ index ba090c4c4473c56592d5681f348bb5774ff05cc8..58bd1d87e363ec0706747c2b2571d358 ASSERT(m_colorSpace); return WebCore::DestinationColorSpace { [m_colorSpace CGColorSpace] }; -@@ -4944,6 +4949,17 @@ static RetainPtr<CGImageRef> takeWindowSnapshot(CGSWindowID windowID, bool captu +@@ -5059,6 +5064,17 @@ static RetainPtr<CGImageRef> takeWindowSnapshot(CGSWindowID windowID, bool captu return WebCore::cgWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions); } @@ -16890,6 +16777,48 @@ index 0000000000000000000000000000000000000000..135a60361fa8fbf907382625e7c8dd4e +} + +} // namespace WebKit +diff --git a/Source/WebKit/UIProcess/win/PageInspectorTargetProxyWin.cpp b/Source/WebKit/UIProcess/win/PageInspectorTargetProxyWin.cpp +new file mode 100644 +index 0000000000000000000000000000000000000000..6469d95bbe7abe4c2dd77848e17462467eda78d0 +--- /dev/null ++++ b/Source/WebKit/UIProcess/win/PageInspectorTargetProxyWin.cpp +@@ -0,0 +1,36 @@ ++/* ++ * 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. ++ */ ++ ++#include "config.h" ++#include "PageInspectorTargetProxy.h" ++#include "WebPageProxy.h" ++ ++namespace WebKit { ++ ++void PageInspectorTargetProxy::platformActivate(String& error) const ++{ ++} ++ ++} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp index 8017b507ce2f0d67922035b1d41b9898f5dddb8c..7e40f52a0e878aeaa0aa38199b432377a6dc4cfd 100644 --- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp @@ -17043,50 +16972,8 @@ index 0000000000000000000000000000000000000000..36fc7af8eb98b3f70d255ee858dccf58 +} + +} // namespace WebKit -diff --git a/Source/WebKit/UIProcess/win/WebPageInspectorTargetProxyWin.cpp b/Source/WebKit/UIProcess/win/WebPageInspectorTargetProxyWin.cpp -new file mode 100644 -index 0000000000000000000000000000000000000000..5b3222e904d3f56d8606b1f1158b2947263eac44 ---- /dev/null -+++ b/Source/WebKit/UIProcess/win/WebPageInspectorTargetProxyWin.cpp -@@ -0,0 +1,36 @@ -+/* -+ * 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. -+ */ -+ -+#include "config.h" -+#include "WebPageInspectorTargetProxy.h" -+#include "WebPageProxy.h" -+ -+namespace WebKit { -+ -+void WebPageInspectorTargetProxy::platformActivate(String& error) const -+{ -+} -+ -+} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebView.cpp b/Source/WebKit/UIProcess/win/WebView.cpp -index a78299e7e0227ed5637458a0917b3c6ee07a2f8d..5ad41f2b68b4d79f0a50ea3298df34a94064dfee 100644 +index 0dab0688f2a24f27477f346e9f1c791763a10b86..003b1ef6c8e9c292b870076677d6cfd915858b05 100644 --- a/Source/WebKit/UIProcess/win/WebView.cpp +++ b/Source/WebKit/UIProcess/win/WebView.cpp @@ -570,7 +570,7 @@ LRESULT WebView::onSizeEvent(HWND hwnd, UINT, WPARAM, LPARAM lParam, bool& handl @@ -17099,7 +16986,7 @@ index a78299e7e0227ed5637458a0917b3c6ee07a2f8d..5ad41f2b68b4d79f0a50ea3298df34a9 if (m_page && m_page->drawingArea()) { // FIXME specify correctly layerPosition. diff --git a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp -index c2cd4dae5b49952c6cde889c8cc1df048722b5de..ab01cc4fb26a421c6959c2c29a77dca268718bf2 100644 +index 0705d7a9536a44a09c410d9e0e14b99c7ce5623e..7c9d8a156147707740cd984c170271593dcdacbd 100644 --- a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp +++ b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp @@ -231,7 +231,7 @@ static Expected<SkImageInfo, String> getImageInfoFromBuffer(const GRefPtr<WPEBu @@ -17170,10 +17057,10 @@ index c2cd4dae5b49952c6cde889c8cc1df048722b5de..ab01cc4fb26a421c6959c2c29a77dca2 void AcceleratedBackingStore::renderPendingBuffer() diff --git a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h -index b1fb18805e67b336dd162a089d91bd3ff32f93e2..1c155698788c429f1fe1eb155a22a99090e16d7f 100644 +index dcb02699a62caf8b79e21259287419b76bb71b77..905c613a2550fe4442666b35b393e75784405f07 100644 --- a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h +++ b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h -@@ -72,7 +72,7 @@ public: +@@ -73,7 +73,7 @@ public: void updateSurfaceID(uint64_t); @@ -17182,9 +17069,55 @@ index b1fb18805e67b336dd162a089d91bd3ff32f93e2..1c155698788c429f1fe1eb155a22a990 RendererBufferDescription bufferDescription() const; +diff --git a/Source/WebKit/UIProcess/wpe/PageInspectorTargetProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/PageInspectorTargetProxyWPE.cpp +new file mode 100644 +index 0000000000000000000000000000000000000000..912e1919a1e2a29ad221114ff312ef118d323093 +--- /dev/null ++++ b/Source/WebKit/UIProcess/wpe/PageInspectorTargetProxyWPE.cpp +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2019 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. ++ */ ++ ++#include "config.h" ++#include "PageInspectorTargetProxy.h" ++ ++#include "WebPageProxy.h" ++#include <wpe/wpe.h> ++ ++namespace WebKit { ++ ++void PageInspectorTargetProxy::platformActivate(String& error) const ++{ ++ struct wpe_view_backend* backend = m_page->viewBackend(); ++ wpe_view_backend_add_activity_state(backend, wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window); ++} ++ ++} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..7df77e30c2e7303dc6aaad560434e5b8e35f4f3c +index 0000000000000000000000000000000000000000..b3c6d0a59daca4667ca8c709dad7816492389b47 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp @@ -0,0 +1,57 @@ @@ -17221,13 +17154,13 @@ index 0000000000000000000000000000000000000000..7df77e30c2e7303dc6aaad560434e5b8 +namespace WebKit { +using namespace WebCore; + -+Ref<WebColorPickerWPE> WebColorPickerWPE::create(WebPageProxy& page, const Color& initialColor, const IntRect& rect) ++Ref<WebColorPickerWPE> WebColorPickerWPE::create(WebPageProxy& page, const Color& initialColor, const IntRect& rect, std::optional<WebCore::FrameIdentifier> frameID) +{ -+ return adoptRef(*new WebColorPickerWPE(page, initialColor, rect)); ++ return adoptRef(*new WebColorPickerWPE(page, initialColor, rect, frameID)); +} + -+WebColorPickerWPE::WebColorPickerWPE(WebPageProxy& page, const Color& initialColor, const IntRect&) -+ : WebColorPicker(&page.colorPickerClient()) ++WebColorPickerWPE::WebColorPickerWPE(WebPageProxy& page, const Color& initialColor, const IntRect&, std::optional<WebCore::FrameIdentifier> frameID) ++ : WebColorPicker(&page.colorPickerClient(), frameID) +{ +} + @@ -17240,14 +17173,14 @@ index 0000000000000000000000000000000000000000..7df77e30c2e7303dc6aaad560434e5b8 +{ +} + -+void WebColorPickerWPE::showColorPicker(const Color& color) ++void WebColorPickerWPE::showColorPicker(const Color& color, const IntRect&) +{ +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h new file mode 100644 -index 0000000000000000000000000000000000000000..da58334235809cfed62e90150784bf2506f7a8f2 +index 0000000000000000000000000000000000000000..7f588248e107a19f5b700fb8e0fe51d1c5cf5aac --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h @@ -0,0 +1,54 @@ @@ -17292,14 +17225,14 @@ index 0000000000000000000000000000000000000000..da58334235809cfed62e90150784bf25 + +class WebColorPickerWPE : public WebColorPicker { +public: -+ static Ref<WebColorPickerWPE> create(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&); ++ static Ref<WebColorPickerWPE> create(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&, std::optional<WebCore::FrameIdentifier> = std::nullopt); + virtual ~WebColorPickerWPE(); + + void endPicker() override; -+ void showColorPicker(const WebCore::Color&) override; ++ void showColorPicker(const WebCore::Color&, const WebCore::IntRect&) override; + +protected: -+ WebColorPickerWPE(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&); ++ WebColorPickerWPE(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&, std::optional<WebCore::FrameIdentifier> = std::nullopt); +}; + +} // namespace WebKit @@ -17307,7 +17240,7 @@ index 0000000000000000000000000000000000000000..da58334235809cfed62e90150784bf25 +#endif // WebColorPickerWPE_h diff --git a/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.cpp b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..694eb24db4a407553da12fb0a25d8963fd0ef6ac +index 0000000000000000000000000000000000000000..c3ac81529d4dfb7070a9e1c30d4634eb10382713 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.cpp @@ -0,0 +1,55 @@ @@ -17353,7 +17286,7 @@ index 0000000000000000000000000000000000000000..694eb24db4a407553da12fb0a25d8963 +{ +} + -+void WebDataListSuggestionsDropdownWPE::show(WebCore::DataListSuggestionInformation&& information) ++void WebDataListSuggestionsDropdownWPE::platformShow(WebCore::DataListSuggestionInformation&& information) +{ +} + @@ -17368,7 +17301,7 @@ index 0000000000000000000000000000000000000000..694eb24db4a407553da12fb0a25d8963 +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.h b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.h new file mode 100644 -index 0000000000000000000000000000000000000000..5d4b0d204b7dc564564d2126e9f256fa4f4bd6f6 +index 0000000000000000000000000000000000000000..07a7cd3ab025616a41dc809e843a7f393b8e8e2f --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.h @@ -0,0 +1,51 @@ @@ -17417,7 +17350,7 @@ index 0000000000000000000000000000000000000000..5d4b0d204b7dc564564d2126e9f256fa +private: + WebDataListSuggestionsDropdownWPE(WebPageProxy&); + -+ void show(WebCore::DataListSuggestionInformation&&) final; ++ void platformShow(WebCore::DataListSuggestionInformation&&) final; + void handleKeydownWithIdentifier(const String&) final; + void close() final; +}; @@ -17661,52 +17594,6 @@ index 0000000000000000000000000000000000000000..c6af56767484e2889208c96d454a0924 +} + +} // namespace WebKit -diff --git a/Source/WebKit/UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp -new file mode 100644 -index 0000000000000000000000000000000000000000..83148bef5b410a70c29bbaf30bb833b9f033ae9a ---- /dev/null -+++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp -@@ -0,0 +1,40 @@ -+/* -+ * Copyright (C) 2019 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. -+ */ -+ -+#include "config.h" -+#include "WebPageInspectorTargetProxy.h" -+ -+#include "WebPageProxy.h" -+#include <wpe/wpe.h> -+ -+namespace WebKit { -+ -+void WebPageInspectorTargetProxy::platformActivate(String& error) const -+{ -+ struct wpe_view_backend* backend = m_page->viewBackend(); -+ wpe_view_backend_add_activity_state(backend, wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window); -+} -+ -+} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp index 9b688ad328317fea4fd96ce66e9714bad8f0f937..402a36a9c565e13ec298aa7f014f0d9208ebddb7 100644 --- a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp @@ -17723,10 +17610,10 @@ index 9b688ad328317fea4fd96ce66e9714bad8f0f937..402a36a9c565e13ec298aa7f014f0d92 } // namespace WebKit diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj -index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ecdbadf87c 100644 +index 1b110e60239dfe1599a356d71f02b9bfe2e9a17c..1af727420f121f24a564e7756d41b51a3623f040 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj -@@ -1555,6 +1555,7 @@ +@@ -1570,6 +1570,7 @@ 5CABDC8722C40FED001EDE8E /* APIMessageListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CABDC8322C40FA7001EDE8E /* APIMessageListener.h */; }; 5CADDE05215046BD0067D309 /* WKWebProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C74300E21500492004BFA17 /* WKWebProcess.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5CAECB6627465AE400AB78D0 /* UnifiedSource115.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */; }; @@ -17734,7 +17621,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 5CAF7AA726F93AB00003F19E /* adattributiond.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAF7AA526F93A950003F19E /* adattributiond.cpp */; }; 5CAFDE452130846300B1F7E1 /* _WKInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE422130843500B1F7E1 /* _WKInspector.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE442130843600B1F7E1 /* _WKInspectorInternal.h */; }; -@@ -2358,6 +2359,18 @@ +@@ -2393,6 +2394,18 @@ DF0C5F28252ECB8E00D921DB /* WKDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F24252ECB8D00D921DB /* WKDownload.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2A252ECB8E00D921DB /* WKDownloadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2B252ED44000D921DB /* WKDownloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */; }; @@ -17747,13 +17634,13 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec + D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */; }; + D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D76D6887238DBD80008D314B /* InspectorDialogAgent.h */; }; + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */; }; -+ D79902B2236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AF236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm */; }; ++ D79902B2236E9404005D6F7E /* PageInspectorTargetProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AF236E9404005D6F7E /* PageInspectorTargetProxyMac.mm */; }; + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */; }; + D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */; }; DF462E0F23F22F5500EFF35F /* WKHTTPCookieStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF462E1223F338BE00EFF35F /* WKContentWorldPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF7A231C291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF7A231B291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; -@@ -2463,6 +2476,8 @@ +@@ -2500,6 +2513,8 @@ E5BEF6822130C48000F31111 /* WebDataListSuggestionsDropdownIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = E5BEF6802130C47F00F31111 /* WebDataListSuggestionsDropdownIOS.h */; }; E5CB07DC20E1678F0022C183 /* WKFormColorControl.h in Headers */ = {isa = PBXBuildFile; fileRef = E5CB07DA20E1678F0022C183 /* WKFormColorControl.h */; }; E5CBA76427A318E100DF7858 /* UnifiedSource120.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA75F27A3187800DF7858 /* UnifiedSource120.cpp */; }; @@ -17762,7 +17649,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec E5CBA76527A318E100DF7858 /* UnifiedSource118.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */; }; E5CBA76627A318E100DF7858 /* UnifiedSource116.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */; }; E5CBA76727A318E100DF7858 /* UnifiedSource119.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76027A3187900DF7858 /* UnifiedSource119.cpp */; }; -@@ -2508,6 +2523,8 @@ +@@ -2546,6 +2561,8 @@ F3EEEE592DB318270038CC1D /* BidiBrowserAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EEEE572DB318270038CC1D /* BidiBrowserAgent.h */; }; F3EEEE5A2DB318270038CC1D /* BidiBrowserAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F3EEEE582DB318270038CC1D /* BidiBrowserAgent.cpp */; }; F404455C2D5CFB56000E587E /* AppKitSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F404455A2D5CFB56000E587E /* AppKitSoftLink.h */; }; @@ -17771,7 +17658,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec F409BA181E6E64BC009DA28E /* WKDragDestinationAction.h in Headers */ = {isa = PBXBuildFile; fileRef = F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; F40C3B712AB401C5007A3567 /* WKDatePickerPopoverController.h in Headers */ = {isa = PBXBuildFile; fileRef = F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */; }; F41145682CD939E0004CDBD1 /* _WKTouchEventGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = F41145652CD939E0004CDBD1 /* _WKTouchEventGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; -@@ -6669,6 +6686,7 @@ +@@ -6721,6 +6738,7 @@ 5CABDC8522C40FCC001EDE8E /* WKMessageListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKMessageListener.h; sourceTree = "<group>"; }; 5CABE07A28F60E8A00D83FD9 /* WebPushMessage.serialization.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebPushMessage.serialization.in; sourceTree = "<group>"; }; 5CADDE0D2151AA010067D309 /* AuthenticationChallengeDisposition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthenticationChallengeDisposition.h; sourceTree = "<group>"; }; @@ -17779,7 +17666,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource115.cpp; sourceTree = "<group>"; }; 5CAF7AA426F93A750003F19E /* adattributiond */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = adattributiond; sourceTree = BUILT_PRODUCTS_DIR; }; 5CAF7AA526F93A950003F19E /* adattributiond.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = adattributiond.cpp; sourceTree = "<group>"; }; -@@ -8486,6 +8504,19 @@ +@@ -8553,6 +8571,19 @@ DF0C5F24252ECB8D00D921DB /* WKDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownload.h; sourceTree = "<group>"; }; DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadInternal.h; sourceTree = "<group>"; }; DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadDelegate.h; sourceTree = "<group>"; }; @@ -17793,13 +17680,13 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserInspectorPipe.h; sourceTree = "<group>"; }; + D76D6887238DBD80008D314B /* InspectorDialogAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDialogAgent.h; sourceTree = "<group>"; }; + D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorEmulationAgentMac.mm; sourceTree = "<group>"; }; -+ D79902AF236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorTargetProxyMac.mm; sourceTree = "<group>"; }; ++ D79902AF236E9404005D6F7E /* PageInspectorTargetProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PageInspectorTargetProxyMac.mm; sourceTree = "<group>"; }; + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorInputAgentMac.mm; sourceTree = "<group>"; }; + D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorPlaywrightAgentClientMac.mm; sourceTree = "<group>"; }; DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKHTTPCookieStorePrivate.h; sourceTree = "<group>"; }; DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKContentWorldPrivate.h; sourceTree = "<group>"; }; DF58C6311371AC5800F9A37C /* NativeWebWheelEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeWebWheelEvent.h; sourceTree = "<group>"; }; -@@ -8674,6 +8705,8 @@ +@@ -8748,6 +8779,8 @@ E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource118.cpp; sourceTree = "<group>"; }; E5CBA76227A3187900DF7858 /* UnifiedSource117.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource117.cpp; sourceTree = "<group>"; }; E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource116.cpp; sourceTree = "<group>"; }; @@ -17808,7 +17695,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec E5DEFA6726F8F42600AB68DB /* PhotosUISPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhotosUISPI.h; sourceTree = "<group>"; }; E838FCAF2DE90BF800703353 /* ISO18013MobileDocumentRequest+Extras.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ISO18013MobileDocumentRequest+Extras.swift"; sourceTree = "<group>"; }; E88885662DC914C400C572B8 /* WKISO18013Request.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKISO18013Request.h; sourceTree = "<group>"; }; -@@ -8738,6 +8771,9 @@ +@@ -8812,6 +8845,9 @@ F404455A2D5CFB56000E587E /* AppKitSoftLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppKitSoftLink.h; sourceTree = "<group>"; }; F404455B2D5CFB56000E587E /* AppKitSoftLink.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppKitSoftLink.mm; sourceTree = "<group>"; }; F4063DDE2D71481E00F3FE6E /* LLVMProfiling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LLVMProfiling.h; sourceTree = "<group>"; }; @@ -17818,7 +17705,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDragDestinationAction.h; sourceTree = "<group>"; }; F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKDatePickerPopoverController.h; sourceTree = "<group>"; }; F40C3B702AB40167007A3567 /* WKDatePickerPopoverController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKDatePickerPopoverController.mm; sourceTree = "<group>"; }; -@@ -9277,6 +9313,7 @@ +@@ -9345,6 +9381,7 @@ 3766F9EE189A1241003CF19B /* JavaScriptCore.framework in Frameworks */, 3766F9F1189A1254003CF19B /* libicucore.dylib in Frameworks */, 7B9FC5BB28A5233B007570E7 /* libWebKitPlatform.a in Frameworks */, @@ -17826,7 +17713,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 3766F9EF189A1244003CF19B /* QuartzCore.framework in Frameworks */, 37694525184FC6B600CDE21F /* Security.framework in Frameworks */, 37BEC4DD1948FC6A008B4286 /* WebCore.framework in Frameworks */, -@@ -12636,6 +12673,7 @@ +@@ -12710,6 +12747,7 @@ 99788ACA1F421DCA00C08000 /* _WKAutomationSessionConfiguration.mm */, 990D28A81C6404B000986977 /* _WKAutomationSessionDelegate.h */, 990D28AF1C65203900986977 /* _WKAutomationSessionInternal.h */, @@ -17834,7 +17721,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 5C4609E222430E4C009943C2 /* _WKContentRuleListAction.h */, 5C4609E322430E4D009943C2 /* _WKContentRuleListAction.mm */, 5C4609E422430E4D009943C2 /* _WKContentRuleListActionInternal.h */, -@@ -14115,6 +14153,7 @@ +@@ -14517,6 +14555,7 @@ E34B110C27C46BC6006D2F2E /* libWebCoreTestShim.dylib */, E34B110F27C46D09006D2F2E /* libWebCoreTestSupport.dylib */, DDE992F4278D06D900F60D26 /* libWebKitAdditions.a */, @@ -17842,7 +17729,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 57A9FF15252C6AEF006A2040 /* libWTF.a */, 5750F32A2032D4E500389347 /* LocalAuthentication.framework */, 570DAAB0230273D200E8FC04 /* NearField.framework */, -@@ -14715,6 +14754,8 @@ +@@ -15117,6 +15156,8 @@ children = ( 9197940423DBC4BB00257892 /* InspectorBrowserAgent.cpp */, 9197940323DBC4BB00257892 /* InspectorBrowserAgent.h */, @@ -17851,7 +17738,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec ); path = Agents; sourceTree = "<group>"; -@@ -15509,6 +15550,7 @@ +@@ -15932,6 +15973,7 @@ E1513C65166EABB200149FCB /* AuxiliaryProcessProxy.h */, 46A2B6061E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.cpp */, 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */, @@ -17859,7 +17746,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 5C6D69352AC3935D0099BDAF /* BrowsingContextGroup.cpp */, 5C6D69362AC3935D0099BDAF /* BrowsingContextGroup.h */, 5CA98549210BEB5A0057EB6B /* BrowsingWarning.h */, -@@ -15539,6 +15581,8 @@ +@@ -15962,6 +16004,8 @@ BC06F43912DBCCFB002D78DE /* GeolocationPermissionRequestProxy.cpp */, BC06F43812DBCCFB002D78DE /* GeolocationPermissionRequestProxy.h */, 2DD5A72A1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h */, @@ -17868,7 +17755,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 5CEABA2B2333251400797797 /* LegacyGlobalSettings.cpp */, 5CEABA2A2333247700797797 /* LegacyGlobalSettings.h */, 31607F3819627002009B87DA /* LegacySessionStateCoding.h */, -@@ -15569,6 +15613,7 @@ +@@ -15992,6 +16036,7 @@ 4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */, 4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */, 411B89CB27B2B89600F9EBD3 /* QueryPermissionResultCallback.h */, @@ -17876,7 +17763,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 5CCB54DC2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.cpp */, 5CCB54DB2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.h */, FABBBC802D35AC6800820017 /* RemotePageFullscreenManagerProxy.cpp */, -@@ -15687,6 +15732,8 @@ +@@ -16113,6 +16158,8 @@ BC7B6204129A0A6700D174A4 /* WebPageGroup.h */, 2D9EA3101A96D9EB002D2807 /* WebPageInjectedBundleClient.cpp */, 2D9EA30E1A96CBFF002D2807 /* WebPageInjectedBundleClient.h */, @@ -17885,7 +17772,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 9B7F8A502C785725000057F3 /* WebPageLoadTiming.h */, BC111B0B112F5E4F00337BAB /* WebPageProxy.cpp */, BC032DCB10F4389F0058C15A /* WebPageProxy.h */, -@@ -15881,6 +15928,7 @@ +@@ -16307,6 +16354,7 @@ BC646C1911DD399F006455B0 /* WKBackForwardListItemRef.h */, BC646C1611DD399F006455B0 /* WKBackForwardListRef.cpp */, BC646C1711DD399F006455B0 /* WKBackForwardListRef.h */, @@ -17893,26 +17780,28 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec BCB9E24A1120E15C00A137E0 /* WKContext.cpp */, BCB9E2491120E15C00A137E0 /* WKContext.h */, 1AE52F9319201F6B00A1FA37 /* WKContextConfigurationRef.cpp */, -@@ -16474,6 +16522,8 @@ - 07EF07592745A8160066EA04 /* DisplayCaptureSessionManager.h */, - 07EF07582745A8160066EA04 /* DisplayCaptureSessionManager.mm */, +@@ -16890,8 +16938,11 @@ + B878B613133428DC006888E9 /* CorrectionPanel.h */, + B878B614133428DC006888E9 /* CorrectionPanel.mm */, 7AFA6F682A9F57C50055322A /* DisplayLinkMac.cpp */, + D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */, + D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */, - 1AFDE65B1954E8D500C48FFA /* LegacySessionStateCoding.cpp */, 0FCB4E5818BBE3D9000FCFC9 /* PageClientImplMac.h */, 0FCB4E5918BBE3D9000FCFC9 /* PageClientImplMac.mm */, -@@ -16497,6 +16547,9 @@ ++ D79902AF236E9404005D6F7E /* PageInspectorTargetProxyMac.mm */, + E18E6909169B563F009B6670 /* SecItemShimProxy.cpp */, + E18E690A169B563F009B6670 /* SecItemShimProxy.h */, + E18E690D169B57DF009B6670 /* SecItemShimProxy.messages.in */, +@@ -16911,6 +16962,8 @@ E568B92120A3AC6A00E3C856 /* WebDataListSuggestionsDropdownMac.mm */, E55CD20124D09F1F0042DB9C /* WebDateTimePickerMac.h */, E55CD20224D09F1F0042DB9C /* WebDateTimePickerMac.mm */, + D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */, + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */, -+ D79902AF236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm */, BC857E8512B71EBB00EDEB2E /* WebPageProxyMac.mm */, BC5750951268F3C6006F0F12 /* WebPopupMenuProxyMac.h */, BC5750961268F3C6006F0F12 /* WebPopupMenuProxyMac.mm */, -@@ -17625,6 +17678,7 @@ +@@ -17739,6 +17792,7 @@ 99788ACB1F421DDA00C08000 /* _WKAutomationSessionConfiguration.h in Headers */, 990D28AC1C6420CF00986977 /* _WKAutomationSessionDelegate.h in Headers */, 990D28B11C65208D00986977 /* _WKAutomationSessionInternal.h in Headers */, @@ -17920,7 +17809,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec CD89ACBD2EA696A300C76423 /* _WKCaptionStyleMenuController.h in Headers */, 97C476282ECD33A6004D1492 /* _WKCaptionStyleMenuControllerInternal.h in Headers */, 5C4609E7224317B4009943C2 /* _WKContentRuleListAction.h in Headers */, -@@ -17944,6 +17998,7 @@ +@@ -18059,6 +18113,7 @@ E170876C16D6CA6900F99226 /* BlobRegistryProxy.h in Headers */, 4F601432155C5AA2001FBDE0 /* BlockingResponseMap.h in Headers */, 1A5705111BE410E600874AF1 /* BlockSPI.h in Headers */, @@ -17928,7 +17817,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 5CA9854A210BEB640057EB6B /* BrowsingWarning.h in Headers */, A7E69BCC2B2117A100D43D3F /* BufferAndBackendInfo.h in Headers */, BC3065FA1259344E00E71278 /* CacheModel.h in Headers */, -@@ -18146,7 +18201,11 @@ +@@ -18265,7 +18320,11 @@ BC14DF77120B5B7900826C0C /* InjectedBundleScriptWorld.h in Headers */, CE550E152283752200D28791 /* InsertTextOptions.h in Headers */, 9197940523DBC4BB00257892 /* InspectorBrowserAgent.h in Headers */, @@ -17940,7 +17829,7 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec A5E391FD2183C1F800C8FB31 /* InspectorTargetProxy.h in Headers */, 07AE8FBD2F3BC4F300A4C0CA /* InteractionInformationAtPosition.h in Headers */, 07AE8FC22F3BC58200A4C0CA /* InteractionInformationRequest.h in Headers */, -@@ -18429,6 +18488,7 @@ +@@ -18550,6 +18609,7 @@ 07E065142F19E01000ECDA2E /* RemoteGPU.h in Headers */, 0F6E7C532C4C386800F1DB85 /* RemoteGraphicsContextMessages.h in Headers */, F451C0FE2703B263002BA03B /* RemoteGraphicsContextProxy.h in Headers */, @@ -17948,16 +17837,16 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 2D47B56D1810714E003A3AEE /* RemoteLayerBackingStore.h in Headers */, 2DDF731518E95060004F5A66 /* RemoteLayerBackingStoreCollection.h in Headers */, 5F4D67D682584880B7E5A569 /* RemoteLayerTreeCommitBundle.h in Headers */, -@@ -18875,6 +18935,8 @@ +@@ -18995,6 +19055,8 @@ 939EF87029D112EE00F23AEE /* WebPageInlines.h in Headers */, 9197940823DBC4CB00257892 /* WebPageInspectorAgentBase.h in Headers */, A513F5402154A5D700662841 /* WebPageInspectorController.h in Headers */, + D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */, + D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */, - A543E30C215C8A8D00279CD9 /* WebPageInspectorTarget.h in Headers */, - A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */, - F30EE4712E72226700935B60 /* WebPageInspectorTargetProxy.h in Headers */, -@@ -21728,6 +21790,7 @@ + C0CE72A11247E71D00BC0EC4 /* WebPageMessages.h in Headers */, + 2D5C9D0619C81D8F00B3C5C1 /* WebPageOverlay.h in Headers */, + 939EF86F29D0C17300F23AEE /* WebPageProxy.h in Headers */, +@@ -21880,6 +21942,7 @@ 522F792928D50EBB0069B45B /* HidService.mm in Sources */, 2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */, 2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */, @@ -17965,25 +17854,32 @@ index e18ecd2461bf060154fb5b5fe8c56d1cec7e12b9..291667a66f39db18c6108910cb6c71ec 074D6A652F385435006089F6 /* IntRectCG.swift in Sources */, 5CF250AF2EE06491006A7172 /* IPCTesterReceiver.swift in Sources */, 5C448C662EE06E11008931C7 /* IPCTesterReceiverMessageReceiver.swift in Sources */, -@@ -22092,6 +22155,9 @@ +@@ -21899,6 +21962,7 @@ + FA5AAE9C2E6A217A00FE693D /* NetworkSoftLink.mm in Sources */, + EEEEBCBD2EE35A8B000FF6AG /* NSGlassEffectView+Extras.swift in Sources */, + DD4BDE7B2CA38213001A3339 /* ObjectiveCBlockConversions.swift in Sources */, ++ D79902B2236E9404005D6F7E /* PageInspectorTargetProxyMac.mm in Sources */, + 1CB9138F2E8C6D500002BCB7 /* PlatformUnifiedSource1-ARC.mm in Sources */, + 1CB913932E8C71920002BCB7 /* PlatformUnifiedSource2-ARC.mm in Sources */, + A1B849382F3D9F02004256A1 /* PlaybackSessionInterfaceAVKit.mm in Sources */, +@@ -22242,6 +22306,8 @@ 078B04A02CF18EAB00B453A6 /* WebPage+NavigationPreferences.swift in Sources */, 071467782DFE84E500F77867 /* WebPage+Transferable.swift in Sources */, 07CB79962CE9435700199C49 /* WebPage.swift in Sources */, + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */, + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */, -+ D79902B2236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm in Sources */, 0715310F2F3037C100B56C0E /* WebPageProxy.swift in Sources */, 7CE9CE101FA0767A000177DE /* WebPageUpdatePreferences.cpp in Sources */, 079A4DA12D72CC0D00CA387F /* WebPageWebView.swift in Sources */, -diff --git a/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.cpp b/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.cpp -index a3a319b35af0882aaeb949b4e767334d9c264e0e..e81e2d903ceba50de27afeb4f04e3962f406630a 100644 ---- a/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.cpp -+++ b/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.cpp -@@ -90,4 +90,13 @@ String WebFrameInspectorTarget::toTargetID(WebCore::FrameIdentifier frameID) - return makeString("frame-"_s, frameID.toUInt64()); +diff --git a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp +index c49360b01f22bed75a9c92b9d4ea0dbbb66d5617..0b6f28c163680d51bfee78e37613fa73b31e05dc 100644 +--- a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp ++++ b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp +@@ -93,4 +93,13 @@ String FrameInspectorTarget::toTargetID(WebCore::FrameIdentifier frameID, WebCor + return makeString("frame-"_s, frameID.toUInt64(), '-', processID.toUInt64()); } -+void WebFrameInspectorTarget::didCreateSubframe(WebFrame& frame) ++void FrameInspectorTarget::didCreateSubframe(WebFrame& frame) +{ + if (!m_channel) + return; @@ -17993,21 +17889,21 @@ index a3a319b35af0882aaeb949b4e767334d9c264e0e..e81e2d903ceba50de27afeb4f04e3962 +} + } // namespace WebKit -diff --git a/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.h b/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.h -index eab417970287a2f342363bd42105c36bce74f2ba..6ae3babddbe7f375b8bf8f400c9e6fe6016a1345 100644 ---- a/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.h -+++ b/Source/WebKit/WebProcess/Inspector/WebFrameInspectorTarget.h -@@ -55,6 +55,8 @@ public: +diff --git a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h +index 2b2820a4ded07d459f3342d5457c0747c2db2215..261c255b95071b7e02365904935381c789970d48 100644 +--- a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h ++++ b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h +@@ -56,6 +56,8 @@ public: - static String toTargetID(WebCore::FrameIdentifier); + static String toTargetID(WebCore::FrameIdentifier, WebCore::ProcessIdentifier); + void didCreateSubframe(WebFrame&); + private: - Ref<WebFrame> protectedFrame(); - + WeakRef<WebFrame> m_frame; + std::unique_ptr<UIProcessForwardingFrontendChannel> m_channel; diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp -index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83aac25eee 100644 +index ef050f1bf94dc201a89055164a5c0c9f33b9bbad..2e228513e686dd67e3e8129670b0ad374a5f54d2 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp @@ -273,6 +273,11 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou @@ -18026,7 +17922,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 } if (InspectorInstrumentationWebKit::shouldInterceptRequest(resourceLoader)) { -- InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedThis = Ref { *this }, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource](const ResourceRequest& request) { +- InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedThis = Ref { *this }, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource = RefPtr { resource }](const ResourceRequest& request) { - auto& resourceLoader = protectedResourceLoader.get(); - WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: intercepted URL will be scheduled with the NetworkProcess"); - scheduleLoadFromNetworkProcess(resourceLoader, request, *trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource)); @@ -18035,7 +17931,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 + bool isMainFrameNavigation = resourceLoader.frame() && resourceLoader.frame()->isMainFrame() && resourceLoader.options().mode == FetchOptions::Mode::Navigate; + // Do not intercept navigation request which could already have been intercepted and resumed. + if (!(isMainFrameNavigation && m_existingNetworkResourceLoadIdentifierToResume)) { -+ InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedThis = Ref { *this }, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource](const ResourceRequest& request) { ++ InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedThis = Ref { *this }, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource = RefPtr { resource }](const ResourceRequest& request) { + auto& resourceLoader = protectedResourceLoader.get(); + WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: intercepted URL will be scheduled with the NetworkProcess"); + scheduleLoadFromNetworkProcess(resourceLoader, request, *trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource)); @@ -18044,7 +17940,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 + } } - WEBLOADERSTRATEGY_RELEASE_LOG_FORWARDABLE(WEBLOADERSTRATEGY_SCHEDULELOAD); + WEBLOADERSTRATEGY_RELEASE_LOG_FORWARDABLE(WebLoaderStrategyScheduleLoad); @@ -431,7 +440,7 @@ static void addParametersShared(const LocalFrame* frame, NetworkResourceLoadPara parameters.linkPreconnectEarlyHintsEnabled = mainFrame->settings().linkPreconnectEarlyHintsEnabled(); } @@ -18067,7 +17963,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 } } -@@ -456,14 +465,6 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -456,19 +465,6 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be scheduled with the NetworkProcess with priority %d, storedCredentialsPolicy %i", resourceLoader.url().string().latin1().data(), static_cast<int>(resourceLoader.request().priority()), (int)storedCredentialsPolicy); @@ -18077,21 +17973,17 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 - trackingParameters.frameID, - request - }; -- loadParameters.createSandboxExtensionHandlesIfNecessary(); +- if (!loadParameters.createSandboxExtensionHandlesIfNecessary()) { +- RunLoop::mainSingleton().dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] { +- resourceLoader->didFail(error); +- }); +- return; +- } - loadParameters.identifier = identifier; loadParameters.parentPID = legacyPresentingApplicationPID(); loadParameters.contentSniffingPolicy = contentSniffingPolicy; -@@ -498,7 +499,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL - - if (resourceLoader.options().crossOriginEmbedderPolicy) - loadParameters.crossOriginEmbedderPolicy = *resourceLoader.options().crossOriginEmbedderPolicy; -- -+ - auto* webFrameLoaderClient = frame ? dynamicDowncast<WebLocalFrameLoaderClient>(frame->loader().client()) : nullptr; - RefPtr webFrame = webFrameLoaderClient ? &webFrameLoaderClient->webFrame() : nullptr; - -@@ -549,14 +550,11 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -563,14 +559,11 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL if (loadParameters.options.mode != FetchOptions::Mode::Navigate) { ASSERT(loadParameters.sourceOrigin); @@ -18109,8 +18001,8 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 loadParameters.isMainFrameNavigation = isMainFrameNavigation; if (loadParameters.isMainFrameNavigation && document) { -@@ -621,6 +619,25 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL - if (CachedResourceHandle handle = resourceLoader.cachedResource()) +@@ -635,6 +628,30 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL + if (RefPtr handle = resourceLoader.cachedResource()) loadParameters.isInitiatorPrefetch = handle->type() == CachedResource::Type::LinkPrefetch; + return true; @@ -18124,7 +18016,12 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 + trackingParameters.frameID, + request + }; -+ loadParameters.createSandboxExtensionHandlesIfNecessary(); ++ if (!loadParameters.createSandboxExtensionHandlesIfNecessary()) { ++ RunLoop::mainSingleton().dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] { ++ resourceLoader->didFail(error); ++ }); ++ return; ++ } + + if (!fillParametersForNetworkProcessLoad(resourceLoader, request, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime, loadParameters)) { + WEBLOADERSTRATEGY_RELEASE_LOG_ERROR("scheduleLoad: no sourceOrigin (priority=%d)", static_cast<int>(resourceLoader.request().priority())); @@ -18135,7 +18032,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 std::optional<NetworkResourceLoadIdentifier> existingNetworkResourceLoadIdentifierToResume; if (loadParameters.isMainFrameNavigation) existingNetworkResourceLoadIdentifierToResume = std::exchange(m_existingNetworkResourceLoadIdentifierToResume, std::nullopt); -@@ -636,7 +653,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL +@@ -650,7 +667,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL } auto loader = WebResourceLoader::create(resourceLoader, trackingParameters); @@ -18144,7 +18041,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 } void WebLoaderStrategy::scheduleInternallyFailedLoad(WebCore::ResourceLoader& resourceLoader) -@@ -1056,7 +1073,7 @@ void WebLoaderStrategy::didFinishPreconnection(WebCore::ResourceLoaderIdentifier +@@ -1070,7 +1087,7 @@ void WebLoaderStrategy::didFinishPreconnection(WebCore::ResourceLoaderIdentifier bool WebLoaderStrategy::isOnLine() const { @@ -18153,7 +18050,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 } void WebLoaderStrategy::addOnlineStateChangeListener(Function<void(bool)>&& listener) -@@ -1082,6 +1099,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet +@@ -1096,6 +1113,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet void WebLoaderStrategy::setOnLineState(bool isOnLine) { @@ -18165,7 +18062,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 if (m_isOnLine == isOnLine) return; -@@ -1090,6 +1112,12 @@ void WebLoaderStrategy::setOnLineState(bool isOnLine) +@@ -1104,6 +1126,12 @@ void WebLoaderStrategy::setOnLineState(bool isOnLine) listener(isOnLine); } @@ -18179,7 +18076,7 @@ index 3937a61ef643ea8cf1648f63da8f03879ec77bd6..3bb2ec9a1b2093477779b3d000e57f83 { WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCaptureExtraNetworkLoadMetricsEnabled(enabled), 0); diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h -index 84563e315081cc3a2dbfc9eee47e8aad2ed91a7a..5c3115694d82289e3ec1c228eecec2852a2b1b5e 100644 +index ab7f322fc4e1b340bb0acdc84d4f7ba39a6e0df0..d79aea95dc4e2ead71a161b24c0e1f081fad4404 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h @@ -26,6 +26,7 @@ @@ -18209,7 +18106,7 @@ index 84563e315081cc3a2dbfc9eee47e8aad2ed91a7a..5c3115694d82289e3ec1c228eecec285 } // namespace WebKit diff --git a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp -index 3d392a8e4914fbc000c736a50cb3ec89df49ac21..b97d6c1edea5cd8b291ffb469b4ff5b4bf07f39f 100644 +index 24c2649b31ce74a91911c8d8ff9be630dc29d576..11e1b09f7fe0573374f887bcbe57e25e4a8f6b87 100644 --- a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp +++ b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp @@ -236,9 +236,6 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR @@ -18232,10 +18129,10 @@ index 3d392a8e4914fbc000c736a50cb3ec89df49ac21..b97d6c1edea5cd8b291ffb469b4ff5b4 } diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp -index 7031747251e5de30568d9eea2981b444877763ee..a7f3687cbfe7085faec75f7138658d4f49b3f537 100644 +index 83519d3b8b16ad84a162f99ec6e3c9f9a0525e73..5cb5b17e983ef538c12bcaa81fe9e425cd622f06 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp -@@ -500,6 +500,9 @@ void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel lev +@@ -503,6 +503,9 @@ void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel lev if (!page) return; @@ -18246,11 +18143,11 @@ index 7031747251e5de30568d9eea2981b444877763ee..a7f3687cbfe7085faec75f7138658d4f page->injectedBundleUIClient().willAddMessageToConsole(page.get(), source, level, message, lineNumber, columnNumber, sourceID); #endif diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp -index 81e673e5b8eda7af88955b2e3e768aaa7ae5718f..9e0817c626dd576cd6c6e2fc79a95a4ec725c2d3 100644 +index b3f2fc81270244d1e52568f2355b7e4390ce4ae3..7e34067a3c7dc61a355ac1ddd7c7a874d6bc0771 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp @@ -53,7 +53,7 @@ OptionSet<DragSourceAction> WebDragClient::dragSourceActionMaskForPoint(const In - return protect(m_page.get())->allowedDragSourceActions(); + return m_page.get()->allowedDragSourceActions(); } -#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE) @@ -18270,11 +18167,11 @@ index 23fdfa0d3d98fc703324372684208e5c4b190dbd..529870b21ab6f2ecd41eaea822186b32 #include <WebCore/UserMediaController.h> #include <WebCore/UserMediaRequest.h> #include <wtf/TZoneMallocInlines.h> -diff --git a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm -index 75066a132de26b5af0e753cf84ba924d075cd2b9..2df20e9af41d0d71065d49a93228669744787b1d 100644 ---- a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm -+++ b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm -@@ -131,7 +131,8 @@ static WebCore::CachedImage* cachedImage(Element& element) +diff --git a/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm b/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm +index bad45b79e581bd66fabf6c09189ed05317a1946e..08cbd2fa2d6283b29168ee3d0140bd35bb878098 100644 +--- a/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm ++++ b/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm +@@ -131,7 +131,8 @@ static RefPtr<WebCore::CachedImage> cachedImage(Element& element) void WebDragClient::declareAndWriteDragImage(const String& pasteboardName, Element& element, const URL& url, const String& label, LocalFrame*) { @@ -18282,7 +18179,7 @@ index 75066a132de26b5af0e753cf84ba924d075cd2b9..2df20e9af41d0d71065d49a932286697 + if (pasteboardName != String(NSPasteboardNameDrag)) + return; - WebCore::CachedImage* image = cachedImage(element); + RefPtr image = cachedImage(element); diff --git a/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp b/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp new file mode 100644 @@ -18348,44 +18245,8 @@ index 0000000000000000000000000000000000000000..741ef5b11fe8718529105339cda0fab5 +}; // namespace WebKit. + +#endif // ENABLE(DRAG_SUPPORT) -diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.h b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.h -index 1c63d62650122bc0265f4b319dfb15a18f899158..5ba9cbc7779f8dd7483576d4357bab57b3df8963 100644 ---- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.h -+++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.h -@@ -119,7 +119,7 @@ public: - #endif - } - --#if PLATFORM(GTK) || ENABLE(WPE_PLATFORM) -+#if PLATFORM(GTK) || PLATFORM(WPE) - bool usesGL() const { return m_swapChain.type() != SwapChain::Type::SharedMemoryWithoutGL; } - #endif - -@@ -354,7 +354,7 @@ private: - - enum class Type { - Invalid, --#if PLATFORM(GTK) || ENABLE(WPE_PLATFORM) -+#if PLATFORM(GTK) || PLATFORM(WPE) - #if USE(GBM) || OS(ANDROID) - EGLImage, - #endif -diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/NonCompositedFrameRenderer.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/NonCompositedFrameRenderer.cpp -index ea6f2b51641370c2c83cee836b5d949dbd8ce699..99435111df34247a014a7c2b6315495416822a6a 100644 ---- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/NonCompositedFrameRenderer.cpp -+++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/NonCompositedFrameRenderer.cpp -@@ -141,7 +141,8 @@ void NonCompositedFrameRenderer::display() - m_surface->willRenderFrame(scaledSize); - - auto* canvas = m_surface->canvas(); -- RELEASE_ASSERT(canvas); -+ if (!canvas) -+ return; - - if (m_context) - PlatformDisplay::sharedDisplay().skiaGLContext()->makeContextCurrent(); diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp -index 6f35eaf3781acc43b46f42bc8de7e15b375a8c75..087fd2b2360784eceb8610cc305268303310112b 100644 +index 5ac78eb5880335f49a9a6f2690626e46fbcac7f4..aa12d9c96279054e01cc9e82e78547a75702a85f 100644 --- a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp +++ b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp @@ -27,6 +27,7 @@ @@ -18397,7 +18258,7 @@ index 6f35eaf3781acc43b46f42bc8de7e15b375a8c75..087fd2b2360784eceb8610cc30526830 #include "WebPage.h" #include "WebPageCreationParameters.h" diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp -index 6abba16c7c9d87d269be9a30c834413260ce0e93..d38799151daac158688fc4e0acbe69d5e7d60f79 100644 +index 42644873c3a43e84452298c131d1d356eed6b36c..9718fb79e8918809099bc3eedd1cdfc7d751a575 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp @@ -43,6 +43,7 @@ @@ -18435,10 +18296,10 @@ index a7ad18fc1201e5de2cc1528539a765599ecfc41e..ebea233bc54ab6e56fb7093ff63e2368 WebCookieJar(); diff --git a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp -index 6af6ac22464070b3787dad277ddfeef0b3466fa1..2e9228d1c82ec1c4097ab2273052f74bc3910103 100644 +index 2a3aa30f08da8e00e790dbdbac574c986a3a4f0a..9b70be2682defadef10da8b69af50ca115878cf6 100644 --- a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp -@@ -175,6 +175,9 @@ Ref<WebFrame> WebFrame::createSubframe(WebPage& page, WebFrame& parent, const At +@@ -181,6 +181,9 @@ Ref<WebFrame> WebFrame::createSubframe(WebPage& page, WebFrame& parent, const At ASSERT(ownerElement.document().frame()); coreFrame->init(); @@ -18449,18 +18310,18 @@ index 6af6ac22464070b3787dad277ddfeef0b3466fa1..2e9228d1c82ec1c4097ab2273052f74b } diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp -index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12b352c768 100644 +index ead5b0db7cebdf2053358cc3a45c8298d0b0ad83..7b92d1d6e59cb5fbaaf9b0f638e25e7b2b2f2d63 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp -@@ -259,6 +259,7 @@ - #include <WebCore/HitTestResult.h> +@@ -264,6 +264,7 @@ #include <WebCore/ImageAnalysisQueue.h> #include <WebCore/ImageOverlay.h> + #include <WebCore/ImageUtilities.h> +#include <WebCore/InspectorInstrumentationWebKit.h> #include <WebCore/JSDOMExceptionHandling.h> #include <WebCore/JSNode.h> #include <WebCore/KeyboardEvent.h> -@@ -1208,6 +1209,14 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) +@@ -1227,6 +1228,14 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) setLinkDecorationFilteringData(WTF::move(parameters.linkDecorationFilteringData)); setAllowedQueryParametersForAdvancedPrivacyProtections(WTF::move(parameters.allowedQueryParametersForAdvancedPrivacyProtections)); #endif @@ -18475,7 +18336,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 if (parameters.windowFeatures) { page->applyWindowFeatures(*parameters.windowFeatures); page->chrome().show(); -@@ -2186,6 +2195,22 @@ void WebPage::loadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, st +@@ -2217,6 +2226,22 @@ void WebPage::loadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, st frame->loadDidCommitInAnotherProcess(layerHostingContextIdentifier); } @@ -18497,8 +18358,8 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 + void WebPage::loadRequest(LoadParameters&& loadParameters) { - WEBPAGE_RELEASE_LOG_FORWARDABLE(Loading, WEBPAGE_LOADREQUEST, loadParameters.navigationID ? loadParameters.navigationID->toUInt64() : 0, static_cast<unsigned>(loadParameters.shouldTreatAsContinuingLoad), loadParameters.request.isAppInitiated(), loadParameters.existingNetworkResourceLoadIdentifierToResume ? loadParameters.existingNetworkResourceLoadIdentifierToResume->toUInt64() : 0); -@@ -2372,7 +2397,9 @@ void WebPage::stopLoading() + WEBPAGE_RELEASE_LOG_FORWARDABLE(Loading, WebPageLoadRequest, loadParameters.navigationID ? loadParameters.navigationID->toUInt64() : 0, static_cast<unsigned>(loadParameters.shouldTreatAsContinuingLoad), loadParameters.request.isAppInitiated(), loadParameters.existingNetworkResourceLoadIdentifierToResume ? loadParameters.existingNetworkResourceLoadIdentifierToResume->toUInt64() : 0); +@@ -2408,7 +2433,9 @@ void WebPage::stopLoading() void WebPage::stopLoadingDueToProcessSwap() { SetForScope isStoppingLoadingDueToProcessSwap(m_isStoppingLoadingDueToProcessSwap, true); @@ -18508,7 +18369,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 } bool WebPage::defersLoading() const -@@ -2945,7 +2972,7 @@ void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArgum +@@ -2997,7 +3024,7 @@ void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArgum #if PLATFORM(IOS_FAMILY) if (m_viewportConfiguration.setViewportArguments(viewportArguments)) viewportConfigurationChanged(); @@ -18517,7 +18378,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 // Adjust view dimensions when using fixed layout. RefPtr localMainFrame = this->localMainFrame(); RefPtr view = localMainFrame ? localMainFrame->view() : nullptr; -@@ -3749,6 +3776,13 @@ void WebPage::flushDeferredIntersectionObservations() +@@ -3858,6 +3885,13 @@ void WebPage::flushDeferredIntersectionObservations() protect(corePage())->flushDeferredIntersectionObservations(); } @@ -18531,7 +18392,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 void WebPage::flushDeferredDidReceiveMouseEvent() { if (auto info = std::exchange(m_deferredDidReceiveMouseEvent, std::nullopt)) -@@ -4019,6 +4053,100 @@ void WebPage::touchEvent(const WebTouchEvent& touchEvent, CompletionHandler<void +@@ -4147,6 +4181,100 @@ void WebPage::touchEvent(const WebTouchEvent& touchEvent, CompletionHandler<void completionHandler(touchEvent.type(), handled); } @@ -18600,7 +18461,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 + MonotonicTime::now(), + force, + syntheticClickType, -+ MouseEventInputSource::Hardware ++ MouseEventInputSource::UserDriven + )); + localMainFrame->eventHandler().handleMousePressEvent(PlatformMouseEvent( + adjustedIntPoint, @@ -18612,7 +18473,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 + MonotonicTime::now(), + force, + syntheticClickType, -+ MouseEventInputSource::Hardware ++ MouseEventInputSource::UserDriven + )); + localMainFrame->eventHandler().handleMouseReleaseEvent(PlatformMouseEvent( + adjustedIntPoint, @@ -18624,7 +18485,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 + MonotonicTime::now(), + force, + syntheticClickType, -+ MouseEventInputSource::Hardware ++ MouseEventInputSource::UserDriven + )); + } + completionHandler(); @@ -18632,7 +18493,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 #endif void WebPage::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint) -@@ -4119,6 +4247,16 @@ void WebPage::sendMessageToTargetBackend(const String& message) +@@ -4247,6 +4375,16 @@ void WebPage::sendMessageToTargetBackend(const String& message) ensureInspectorTarget()->sendMessageToTargetBackend(message); } @@ -18649,7 +18510,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 void WebPage::insertNewlineInQuotedContent() { RefPtr frame = corePage()->focusController().focusedOrMainFrame(); -@@ -4354,6 +4492,7 @@ void WebPage::setMainFrameDocumentVisualUpdatesAllowed(bool allowed) +@@ -4489,6 +4627,7 @@ void WebPage::setMainFrameDocumentVisualUpdatesAllowed(bool allowed) void WebPage::show() { send(Messages::WebPageProxy::ShowPage()); @@ -18657,7 +18518,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 } void WebPage::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension) -@@ -5416,7 +5555,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana +@@ -5561,7 +5700,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana #if ENABLE(DRAG_SUPPORT) @@ -18666,7 +18527,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 void WebPage::performDragControllerAction(DragControllerAction action, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet<DragOperation> draggingSourceOperationMask, SelectionData&& selectionData, OptionSet<DragApplicationFlags> flags, CompletionHandler<void(std::optional<DragOperation>, DragHandlingMethod, bool, unsigned, IntRect, IntRect, std::optional<RemoteUserInputEventData>)>&& completionHandler) { if (!m_page) -@@ -7771,6 +7910,10 @@ void WebPage::didCommitLoad(WebFrame* frame) +@@ -7932,6 +8071,10 @@ void WebPage::didCommitLoad(WebFrame* frame) if (frame && frame->isMainFrame()) m_networkResourceRequestIdentifiersForPageLoadTiming.clear(); @@ -18677,7 +18538,7 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 } void WebPage::didFinishDocumentLoad(WebFrame& frame) -@@ -8090,6 +8233,9 @@ Ref<DocumentLoader> WebPage::createDocumentLoader(LocalFrame& frame, ResourceReq +@@ -8234,6 +8377,9 @@ Ref<DocumentLoader> WebPage::createDocumentLoader(LocalFrame& frame, ResourceReq m_allowsContentJavaScriptFromMostRecentNavigation = m_internals->pendingWebsitePolicies->allowsContentJavaScript; WebsitePoliciesData::applyToDocumentLoader(*std::exchange(m_internals->pendingWebsitePolicies, std::nullopt), documentLoader); } @@ -18688,10 +18549,10 @@ index c7119d1c990988fef393581236cc13838661ff55..84a3589afc555d2c9fc1ac52140b1f12 return documentLoader; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h -index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff63bd267f3 100644 +index 122efe1deb60835d3b834995d672374bae5ad557..1e9ad7f9665bb9256b3036e1dcb471d2bbe0f081 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit/WebProcess/WebPage/WebPage.h -@@ -48,6 +48,7 @@ +@@ -49,6 +49,7 @@ #include <WebCore/NodeIdentifier.h> #include <WebCore/NowPlayingMetadataObserver.h> #include <WebCore/OwnerPermissionsPolicyData.h> @@ -18699,7 +18560,7 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 #include <WebCore/PageIdentifier.h> #include <WebCore/PageOverlay.h> #include <WebCore/PlatformLayerIdentifier.h> -@@ -1368,11 +1369,11 @@ public: +@@ -1403,11 +1404,11 @@ public: void clearSelection(); void restoreSelectionInFocusedEditableElement(); @@ -18713,7 +18574,7 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 void performDragControllerAction(std::optional<WebCore::FrameIdentifier>, DragControllerAction, WebCore::DragData&&, CompletionHandler<void(std::optional<WebCore::DragOperation>, WebCore::DragHandlingMethod, bool, unsigned, WebCore::IntRect, WebCore::IntRect, std::optional<WebCore::RemoteUserInputEventData>)>&&); void performDragOperation(std::optional<WebCore::FrameIdentifier>, WebCore::DragData&&, SandboxExtension::Handle&&, Vector<SandboxExtension::Handle>&&, CompletionHandler<void(DragOperationResult dragOperationResult)>&&); #endif -@@ -1390,6 +1391,9 @@ public: +@@ -1425,6 +1426,9 @@ public: #if ENABLE(MODEL_PROCESS) void modelDragEnded(WebCore::NodeIdentifier); #endif @@ -18723,7 +18584,7 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 #endif #if ENABLE(MODEL_PROCESS) -@@ -1491,8 +1495,11 @@ public: +@@ -1526,8 +1530,11 @@ public: void gestureEvent(WebCore::FrameIdentifier, const WebGestureEvent&, CompletionHandler<void(std::optional<WebEventType>, bool, std::optional<WebCore::RemoteUserInputEventData>)>&&); #endif @@ -18736,7 +18597,7 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 void dynamicViewportSizeUpdate(const DynamicViewportSizeUpdate&); bool scaleWasSetByUIProcess() const { return m_scaleWasSetByUIProcess; } void willStartUserTriggeredZooming(); -@@ -1657,6 +1664,8 @@ public: +@@ -1688,6 +1695,8 @@ public: void connectInspector(Inspector::FrontendChannel::ConnectionType); void disconnectInspector(); void sendMessageToTargetBackend(const String& message); @@ -18745,7 +18606,7 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 void insertNewlineInQuotedContent(); -@@ -2099,6 +2108,7 @@ public: +@@ -2126,6 +2135,7 @@ public: void showContextMenuFromFrame(const FrameInfoData&, const ContextMenuContextData&, const UserData&); #endif void loadRequest(LoadParameters&&); @@ -18753,7 +18614,7 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 void setObscuredContentInsets(const WebCore::FloatBoxExtent&); -@@ -2319,6 +2329,7 @@ private: +@@ -2348,6 +2358,7 @@ private: void updatePotentialTapSecurityOrigin(const WebTouchEvent&, bool wasHandled); #elif ENABLE(TOUCH_EVENTS) void touchEvent(const WebTouchEvent&, CompletionHandler<void(std::optional<WebEventType>, bool)>&&); @@ -18761,7 +18622,7 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 #endif void cancelPointer(WebCore::PointerID, const WebCore::IntPoint&); -@@ -3125,6 +3136,7 @@ private: +@@ -3171,6 +3182,7 @@ private: bool m_isAppNapEnabled { true }; Markable<WebCore::NavigationIdentifier> m_pendingNavigationID; @@ -18770,11 +18631,11 @@ index 34a420895a1f98ef79ab84353983019d78d98acd..309fba05cb41f57a84bc33da6480cff6 bool m_mainFrameProgressCompleted { false }; bool m_shouldDispatchFakeMouseMoveEvents { true }; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in -index 6ddebd242df4b2332f38be56d8adb2091cba529f..159fad2888f5e605229c36243594551ec7cb4514 100644 +index 7ae88ddd41930501d121e488a5e2d96693a87865..323373fdcb1c47583b05ced86bc96a9ff3080ed7 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in -@@ -70,10 +70,13 @@ messages -> WebPage WantsAsyncDispatchMessage { - RequestPositionInformation(struct WebKit::InteractionInformationRequest request) +@@ -84,10 +84,13 @@ messages -> WebPage WantsAsyncDispatchMessage { + CancelPotentialTap() #endif +#if ENABLE(ORIENTATION_EVENTS) @@ -18787,8 +18648,8 @@ index 6ddebd242df4b2332f38be56d8adb2091cba529f..159fad2888f5e605229c36243594551e - SetDeviceOrientation(WebCore::IntDegrees deviceOrientation) SetOverrideViewportArguments(struct std::optional<WebCore::ViewportArguments> arguments) DynamicViewportSizeUpdate(struct WebKit::DynamicViewportSizeUpdate target) - -@@ -167,6 +170,7 @@ messages -> WebPage WantsAsyncDispatchMessage { + +@@ -174,6 +177,7 @@ messages -> WebPage WantsAsyncDispatchMessage { ConnectInspector(Inspector::FrontendChannel::ConnectionType connectionType) DisconnectInspector() SendMessageToTargetBackend(String message) @@ -18796,7 +18657,7 @@ index 6ddebd242df4b2332f38be56d8adb2091cba529f..159fad2888f5e605229c36243594551e #if ENABLE(REMOTE_INSPECTOR) SetIndicating(bool indicating); -@@ -177,6 +181,7 @@ messages -> WebPage WantsAsyncDispatchMessage { +@@ -184,6 +188,7 @@ messages -> WebPage WantsAsyncDispatchMessage { #endif #if !ENABLE(IOS_TOUCH_EVENTS) && ENABLE(TOUCH_EVENTS) TouchEvent(WebKit::WebTouchEvent event) -> (enum:uint32_t std::optional<WebKit::WebEventType> eventType, bool handled) @@ -18804,7 +18665,7 @@ index 6ddebd242df4b2332f38be56d8adb2091cba529f..159fad2888f5e605229c36243594551e #endif CancelPointer(WebCore::PointerID pointerId, WebCore::IntPoint documentPoint) -@@ -203,6 +208,7 @@ messages -> WebPage WantsAsyncDispatchMessage { +@@ -210,6 +215,7 @@ messages -> WebPage WantsAsyncDispatchMessage { LoadDataInFrame(std::span<const uint8_t> data, String MIMEType, String encodingName, URL baseURL, WebCore::FrameIdentifier frameID) LoadRequest(struct WebKit::LoadParameters loadParameters) LoadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, std::optional<WebCore::LayerHostingContextIdentifier> layerHostingContextIdentifier) @@ -18812,7 +18673,7 @@ index 6ddebd242df4b2332f38be56d8adb2091cba529f..159fad2888f5e605229c36243594551e LoadRequestWaitingForProcessLaunch(struct WebKit::LoadParameters loadParameters, URL resourceDirectoryURL, WebKit::WebPageProxyIdentifier pageID, bool checkAssumedReadAccessToResourceURL) LoadData(struct WebKit::LoadParameters loadParameters) LoadSimulatedRequestAndResponse(struct WebKit::LoadParameters loadParameters, WebCore::ResourceResponse simulatedResponse) -@@ -369,10 +375,10 @@ messages -> WebPage WantsAsyncDispatchMessage { +@@ -376,10 +382,10 @@ messages -> WebPage WantsAsyncDispatchMessage { RemoveLayerForFindOverlay() -> () # Drag and drop. @@ -18825,7 +18686,7 @@ index 6ddebd242df4b2332f38be56d8adb2091cba529f..159fad2888f5e605229c36243594551e PerformDragControllerAction(std::optional<WebCore::FrameIdentifier> frameID, enum:uint8_t WebKit::DragControllerAction action, WebCore::DragData dragData) -> (enum:uint8_t std::optional<WebCore::DragOperation> dragOperation, enum:uint8_t WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect, WebCore::IntRect editableElementRect, struct std::optional<WebCore::RemoteUserInputEventData> remoteUserInputEventData) PerformDragOperation(std::optional<WebCore::FrameIdentifier> frameID, WebCore::DragData dragData, WebKit::SandboxExtensionHandle sandboxExtensionHandle, Vector<WebKit::SandboxExtensionHandle> sandboxExtensionsForUpload) -> (WebKit::DragOperationResult dragOperationResult) #endif -@@ -392,6 +398,10 @@ messages -> WebPage WantsAsyncDispatchMessage { +@@ -399,6 +405,10 @@ messages -> WebPage WantsAsyncDispatchMessage { ModelDragEnded(WebCore::NodeIdentifier nodeID) #endif @@ -18837,10 +18698,10 @@ index 6ddebd242df4b2332f38be56d8adb2091cba529f..159fad2888f5e605229c36243594551e RequestDragStart(std::optional<WebCore::FrameIdentifier> remoteFrameID, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet<WebCore::DragSourceAction> allowedActionsMask) -> (struct WebKit::DragInitiationResult result) RequestAdditionalItemsForDragSession(std::optional<WebCore::FrameIdentifier> rootFrameID, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet<WebCore::DragSourceAction> allowedActionsMask) -> (struct WebKit::DragInitiationResult result) diff --git a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp -index 8ab01cf5bd5c7cb0323ca1d952ab07ce028e0295..1c6dd7af74f5efb7785c77370296f7307f9a4162 100644 +index 081c8dd9bc9402d909fba5359f90c686deb9987a..b9e548e8886861fa8013f5d8af1c893f5f4a3b99 100644 --- a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp +++ b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp -@@ -222,16 +222,23 @@ String WebPage::platformUserAgent(const URL& url) const +@@ -224,16 +224,23 @@ String WebPage::platformUserAgent(const URL& url) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { @@ -18864,7 +18725,7 @@ index 8ab01cf5bd5c7cb0323ca1d952ab07ce028e0295..1c6dd7af74f5efb7785c77370296f730 const auto& primaryPointingDevice = WebProcess::singleton().primaryPointingDevice(); if (primaryPointingDevice == AvailableInputDevices::Mouse) return PointerCharacteristics::Fine; -@@ -242,6 +249,9 @@ std::optional<PointerCharacteristics> WebPage::pointerCharacteristicsOfPrimaryPo +@@ -244,6 +251,9 @@ std::optional<PointerCharacteristics> WebPage::pointerCharacteristicsOfPrimaryPo OptionSet<PointerCharacteristics> WebPage::pointerCharacteristicsOfAllAvailablePointingDevices() const { @@ -18875,10 +18736,10 @@ index 8ab01cf5bd5c7cb0323ca1d952ab07ce028e0295..1c6dd7af74f5efb7785c77370296f730 const auto& availableInputs = WebProcess::singleton().availableInputDevices(); if (availableInputs.contains(AvailableInputDevices::Mouse)) diff --git a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm -index 9873086f33d9c9bf075fa93fd3ae991a9ddad632..fdae4deb4521c377d2c1d0e66c4a50bb9a8a3dd9 100644 +index 497cb8e358ace370d15803fda7c62bc51021e9e0..37a0f3a170729652cd74fd11d8e7e994c1305736 100644 --- a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm +++ b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm -@@ -708,21 +708,37 @@ String WebPage::platformUserAgent(const URL&) const +@@ -732,21 +732,37 @@ String WebPage::platformUserAgent(const URL&) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { @@ -18967,7 +18828,7 @@ index d32f7d2dd108647aeba05007a371b8c7381232a7..00da787b3ac4d312006a92475701c133 } diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp -index 96e4c8a6dd8104469a322b39d88df3d5904fddb1..0394f7aee646b8df4a5d50b79ec07eeac470e4db 100644 +index 09651c68a3694eda504e88f3dda0cad5cd97a3c6..f4a0d15d58a30b4fa059659ba99bd4aa91ed327d 100644 --- a/Source/WebKit/WebProcess/WebProcess.cpp +++ b/Source/WebKit/WebProcess/WebProcess.cpp @@ -95,6 +95,7 @@ @@ -18978,7 +18839,7 @@ index 96e4c8a6dd8104469a322b39d88df3d5904fddb1..0394f7aee646b8df4a5d50b79ec07eea #include <JavaScriptCore/JSLock.h> #include <JavaScriptCore/MemoryStatistics.h> #include <JavaScriptCore/WasmFaultSignalHandler.h> -@@ -412,6 +413,14 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter +@@ -427,6 +428,14 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter { JSC::Options::AllowUnfinalizedAccessScope scope; JSC::Options::allowNonSPTagging() = false; @@ -18993,7 +18854,7 @@ index 96e4c8a6dd8104469a322b39d88df3d5904fddb1..0394f7aee646b8df4a5d50b79ec07eea JSC::Options::notifyOptionsChanged(); } -@@ -419,6 +428,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter +@@ -434,6 +443,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter platformInitializeProcess(parameters); updateCPULimit(); @@ -19002,7 +18863,7 @@ index 96e4c8a6dd8104469a322b39d88df3d5904fddb1..0394f7aee646b8df4a5d50b79ec07eea } void WebProcess::initializeConnection(IPC::Connection* connection) -@@ -1040,6 +1051,7 @@ void WebProcess::createWebPage(PageIdentifier pageID, WebPageCreationParameters& +@@ -1058,6 +1069,7 @@ void WebProcess::createWebPage(PageIdentifier pageID, WebPageCreationParameters& m_hasPendingAccessibilityUnsuspension = false; accessibilityRelayProcessSuspended(false); } @@ -19011,7 +18872,7 @@ index 96e4c8a6dd8104469a322b39d88df3d5904fddb1..0394f7aee646b8df4a5d50b79ec07eea Awaitable<unsigned> WebProcess::countWebPagesForTesting() diff --git a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm -index 78783661a5997d86630cacb10bee23a50ec1297a..fe1aa080e76badf5953c6a7a58211a6bb6102ee3 100644 +index ba7911b2efe2ffdde8ab90f3c81817f65a43b2f0..259418a4eca2bb6ed9af2a62fbda155849c2f349 100644 --- a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm @@ -4207,7 +4207,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END @@ -19024,7 +18885,7 @@ index 78783661a5997d86630cacb10bee23a50ec1297a..fe1aa080e76badf5953c6a7a58211a6b - (void)touch:(WebEvent *)event { diff --git a/Source/WebKitLegacy/mac/WebView/WebView.mm b/Source/WebKitLegacy/mac/WebView/WebView.mm -index 6f2b7774cb172ebee4b1c6eddbb3d6dd9b623b9e..ff4618101c4eaadb55fedfa7e0feb321868e2625 100644 +index bec7313812c922a7175d0f9aca27818066d54df8..8af7c061efe469493d5e2f38679b7038fb483c34 100644 --- a/Source/WebKitLegacy/mac/WebView/WebView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebView.mm @@ -3976,7 +3976,7 @@ + (void)_doNotStartObservingNetworkReachability @@ -19046,7 +18907,7 @@ index 6f2b7774cb172ebee4b1c6eddbb3d6dd9b623b9e..ff4618101c4eaadb55fedfa7e0feb321 // For backwards compatibility with the WebBackForwardList API, we honor both // a per-WebView and a per-preferences setting for whether to use the back/forward cache. diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake -index 9e6347c784e45e4a8a1f96930746e8d7002146a9..d77c306921f013f14b4d49f7f875fee0cac45e0d 100644 +index 1f1b576f84c8ad254868d8e2b2f4f0429ea59d06..11e5f0d982166f5f5c6e44984d48b912409cfff4 100644 --- a/Source/cmake/OptionsGTK.cmake +++ b/Source/cmake/OptionsGTK.cmake @@ -9,6 +9,10 @@ set(USER_AGENT_BRANDING "" CACHE STRING "Branding to add to user agent string") @@ -19060,7 +18921,7 @@ index 9e6347c784e45e4a8a1f96930746e8d7002146a9..d77c306921f013f14b4d49f7f875fee0 find_package(Cairo 1.16.0 REQUIRED) find_package(LibGcrypt 1.7.0 REQUIRED) find_package(Soup3 3.0.0 REQUIRED) -@@ -68,6 +72,10 @@ WEBKIT_OPTION_DEFINE(USE_SYSTEM_UNIFDEF "Whether to use a system-provided unifde +@@ -72,6 +76,10 @@ WEBKIT_OPTION_DEFINE(USE_SYSTEM_UNIFDEF "Whether to use a system-provided unifde WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE) @@ -19071,7 +18932,7 @@ index 9e6347c784e45e4a8a1f96930746e8d7002146a9..d77c306921f013f14b4d49f7f875fee0 SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE}) if (DEVELOPER_MODE) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_API_TESTS PRIVATE ON) -@@ -143,6 +151,21 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_LIBRICE PRIVATE ON) +@@ -150,6 +158,21 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_SKIA PRIVATE ON) WEBKIT_OPTION_DEPEND(ENABLE_GPU_PROCESS USE_GBM) @@ -19094,10 +18955,10 @@ index 9e6347c784e45e4a8a1f96930746e8d7002146a9..d77c306921f013f14b4d49f7f875fee0 WEBKIT_OPTION_DEPEND(ENABLE_WEBXR ENABLE_GAMEPAD) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake -index 66ad374b5814b3964426d38e5fe4d11b0ca0c27d..7f15e1305568a85fd96532cc75e9470c068911bf 100644 +index 9be932f3cc9a86cc27ff355409f96a8e0501eba0..f89f186c5986a702b25bf844be36fbe293cbf43b 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake -@@ -33,6 +33,9 @@ else () +@@ -37,6 +37,9 @@ else () set(ENABLE_MEDIA_SESSION_DEFAULT ON) endif () @@ -19107,7 +18968,7 @@ index 66ad374b5814b3964426d38e5fe4d11b0ca0c27d..7f15e1305568a85fd96532cc75e9470c WEBKIT_OPTION_BEGIN() SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE}) -@@ -89,6 +92,22 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR PRIVATE ${ENABLE_EXPERIMENTAL_FEAT +@@ -94,6 +97,22 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR PRIVATE ${ENABLE_EXPERIMENTAL_FEAT WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR_HIT_TEST PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR_LAYERS PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) @@ -19130,7 +18991,7 @@ index 66ad374b5814b3964426d38e5fe4d11b0ca0c27d..7f15e1305568a85fd96532cc75e9470c # Public options specific to the WPE port. Do not add any options here unless # there is a strong reason we should support changing the value of the option, # and the option is not relevant to other WebKit ports. -@@ -126,6 +145,11 @@ WEBKIT_OPTION_DEPEND(ENABLE_DOCUMENTATION ENABLE_INTROSPECTION) +@@ -132,6 +151,11 @@ WEBKIT_OPTION_DEPEND(ENABLE_DOCUMENTATION ENABLE_INTROSPECTION) WEBKIT_OPTION_DEPEND(ENABLE_WPE_QT_API ENABLE_WPE_PLATFORM) WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE) @@ -19143,10 +19004,10 @@ index 66ad374b5814b3964426d38e5fe4d11b0ca0c27d..7f15e1305568a85fd96532cc75e9470c WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_BUBBLEWRAP_SANDBOX PUBLIC ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEMORY_SAMPLER PRIVATE ON) diff --git a/Source/cmake/OptionsWin.cmake b/Source/cmake/OptionsWin.cmake -index e24293987e34c12c1911db9d204dfb90d8b65a6c..59792bbeaaf8051a558201e914f6ce433a7ede05 100644 +index da6c3b5fd4901b64c616d2b38cb1d9b70c810e71..99380f834b6b3ac5b4afdf68dfa002c0cdf606d3 100644 --- a/Source/cmake/OptionsWin.cmake +++ b/Source/cmake/OptionsWin.cmake -@@ -111,6 +111,14 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF) +@@ -113,6 +113,14 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF) SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_KEYBOARD_INTERACTIONS ON) SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_MOUSE_INTERACTIONS ON) @@ -19162,10 +19023,10 @@ index e24293987e34c12c1911db9d204dfb90d8b65a6c..59792bbeaaf8051a558201e914f6ce43 set(USE_ANGLE_EGL ON) diff --git a/Source/cmake/WebKitCompilerFlags.cmake b/Source/cmake/WebKitCompilerFlags.cmake -index 54330d4ab44a5ac52c4f176688ec119f086e0b26..d4631e5943486bb9b14e403d9700bcf58bf8821e 100644 +index 5a9e12cee71f979e15f686f89a9bec6d992a2faf..1a79d778c8a36050fc2b0b42388bb050fa612d49 100644 --- a/Source/cmake/WebKitCompilerFlags.cmake +++ b/Source/cmake/WebKitCompilerFlags.cmake -@@ -122,7 +122,7 @@ macro(WEBKIT_ADD_TARGET_CXX_FLAGS _target) +@@ -152,7 +152,7 @@ macro(WEBKIT_ADD_TARGET_CXX_FLAGS _target) endmacro() @@ -19363,10 +19224,10 @@ index 1fd07efb828b85b6d8def6c6cd92a0c11debfe1b..da9fac7975d477857ead2adb1d67108d typedef struct _BrowserWindow BrowserWindow; diff --git a/Tools/MiniBrowser/gtk/main.c b/Tools/MiniBrowser/gtk/main.c -index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d8fc11d50 100644 +index dc20509081346978e0da4a7833f6d4ce733717ac..817bd32756f0c8279beb4c23bee4b1e6f2ded960 100644 --- a/Tools/MiniBrowser/gtk/main.c +++ b/Tools/MiniBrowser/gtk/main.c -@@ -65,9 +65,15 @@ static char* timeZone; +@@ -66,9 +66,15 @@ static char* timeZone; static gboolean enableITP; static gboolean exitAfterLoad; static gboolean webProcessCrashed; @@ -19382,7 +19243,7 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d #if !GTK_CHECK_VERSION(3, 98, 0) static gboolean enableSandbox; -@@ -172,6 +178,11 @@ static const GOptionEntry commandLineOptions[] = +@@ -174,6 +180,11 @@ static const GOptionEntry commandLineOptions[] = { "time-zone", 't', 0, G_OPTION_ARG_STRING, &timeZone, "Set time zone", "TIMEZONE" }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WebKitGTK version", NULL }, { "config", 'C', 0, G_OPTION_ARG_FILENAME, &configFile, "Path to a configuration file", "PATH" }, @@ -19394,7 +19255,7 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" }, { 0, 0, 0, 0, 0, 0, 0 } }; -@@ -728,6 +739,64 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul +@@ -730,6 +741,64 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } @@ -19459,7 +19320,7 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d static void startup(GApplication *application) { const char *actionAccels[] = { -@@ -786,17 +855,32 @@ static void setupDarkMode(GtkSettings *settings) +@@ -788,22 +857,39 @@ static void setupDarkMode(GtkSettings *settings) static void activate(GApplication *application, WebKitSettings *webkitSettings) { @@ -19493,11 +19354,9 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d networkSession = webkit_network_session_new_ephemeral(); - else { + } else { - char *dataDirectory = g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); - char *cacheDirectory = g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); + g_autofree char *dataDirectory = profileDirectory ? g_build_filename(profileDirectory, "data", NULL) : g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); + g_autofree char *cacheDirectory = profileDirectory ? g_build_filename(profileDirectory, "cache", NULL) : g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); networkSession = webkit_network_session_new(dataDirectory, cacheDirectory); -@@ -804,6 +888,8 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) - g_free(cacheDirectory); } + webkit_web_context_set_network_session_for_automation(webContext, networkSession); @@ -19517,10 +19376,10 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d manager = webkit_website_data_manager_new_ephemeral(); - else { + } else { - char *dataDirectory = g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); - char *cacheDirectory = g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); + g_autofree char *dataDirectory = profileDirectory ? g_build_filename(profileDirectory, "data", NULL) : g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); + g_autofree char *cacheDirectory = profileDirectory ? g_build_filename(profileDirectory, "cache", NULL) : g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); manager = webkit_website_data_manager_new("base-data-directory", dataDirectory, "base-cache-directory", cacheDirectory, NULL); -@@ -890,6 +979,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) +@@ -888,6 +977,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) // Enable the favicon database. webkit_web_context_set_favicon_database_directory(webContext, NULL); #endif @@ -19528,7 +19387,7 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d webkit_web_context_register_uri_scheme(webContext, BROWSER_ABOUT_SCHEME, (WebKitURISchemeRequestCallback)aboutURISchemeRequestCallback, NULL, NULL); -@@ -954,9 +1044,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) +@@ -952,9 +1042,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) if (exitAfterLoad) exitAfterWebViewLoadFinishes(webView, application); } @@ -19539,7 +19398,7 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d } } else { WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings, userContentManager, defaultWebsitePolicies); -@@ -1006,7 +1094,7 @@ int main(int argc, char *argv[]) +@@ -1004,7 +1092,7 @@ int main(int argc, char *argv[]) g_option_context_add_group(context, gst_init_get_option_group()); #endif @@ -19548,7 +19407,7 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d webkit_settings_set_enable_developer_extras(webkitSettings, TRUE); webkit_settings_set_enable_webgl(webkitSettings, TRUE); webkit_settings_set_enable_media_stream(webkitSettings, TRUE); -@@ -1058,9 +1146,11 @@ int main(int argc, char *argv[]) +@@ -1056,9 +1144,11 @@ int main(int argc, char *argv[]) } GtkApplication *application = gtk_application_new("org.webkitgtk.MiniBrowser", G_APPLICATION_NON_UNIQUE); @@ -19561,11 +19420,11 @@ index 3805d7e287ae5f7bb2ecb22f9d2e1b1a8457fd1e..89ca9c3a4c100fc1f9e40c0e4ee38c2d g_clear_object(&interfaceSettings); diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp -index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae8337aa65 100644 +index c8cd8719368bc3be7b97b315c64162ced5b7c351..7a7b2d3b0ebc31690f5877694118ddfc311ee5cf 100644 --- a/Tools/MiniBrowser/wpe/main.cpp +++ b/Tools/MiniBrowser/wpe/main.cpp -@@ -55,6 +55,9 @@ static gboolean headlessMode; - static gboolean privateMode; +@@ -56,6 +56,9 @@ static gboolean privateMode; + static const char* profileDirectory; static gboolean automationMode; static gboolean ignoreTLSErrors; +static gboolean inspectorPipe; @@ -19574,8 +19433,8 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae static const char* contentFilter; static const char* cookiesFile; static const char* cookiesPolicy; -@@ -139,6 +142,9 @@ static const GOptionEntry commandLineOptions[] = - #endif +@@ -141,6 +144,9 @@ static const GOptionEntry commandLineOptions[] = + { "config-file", 0, 0, G_OPTION_ARG_FILENAME, &configFile, "Config file to load for settings", "FILE" }, { "size", 's', 0, G_OPTION_ARG_CALLBACK, reinterpret_cast<gpointer>(parseWindowSize), "Specify the window size to use, e.g. --size=\"800x600\"", nullptr }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WPE version", nullptr }, + { "inspector-pipe", 'v', 0, G_OPTION_ARG_NONE, &inspectorPipe, "Expose remote debugging protocol over pipe", nullptr }, @@ -19584,7 +19443,7 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, nullptr, "[URL]" }, { nullptr, 0, 0, G_OPTION_ARG_NONE, nullptr, nullptr, nullptr } }; -@@ -329,15 +335,38 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul +@@ -331,15 +337,38 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } @@ -19625,7 +19484,7 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae { #if defined(USE_LIBWPE) && USE_LIBWPE auto backend = createViewBackend(defaultWindowWidthLegacyAPI, defaultWindowHeightLegacyAPI); -@@ -354,14 +383,31 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi +@@ -356,14 +385,31 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi } #endif @@ -19663,7 +19522,7 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae #if ENABLE_WPE_PLATFORM if (auto* wpeView = webkit_web_view_get_wpe_view(newWebView)) { -@@ -373,9 +419,13 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi +@@ -375,9 +421,13 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi g_signal_connect(newWebView, "create", G_CALLBACK(createWebView), user_data); g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), user_data); @@ -19679,8 +19538,8 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae return newWebView; } -@@ -455,16 +505,108 @@ void loadConfigFile(WPESettings* settings) - #endif +@@ -468,24 +518,112 @@ static void loadConfigFile(WebKitSettings* webkitSettings + } #if defined(USE_LIBWPE) && USE_LIBWPE +static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data) @@ -19777,19 +19636,26 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae #if ENABLE_2022_GLIB_API WebKitNetworkSession* networkSession = nullptr; if (!automationMode) { -- networkSession = privateMode ? webkit_network_session_new_ephemeral() : webkit_network_session_new(nullptr, nullptr); +- if (privateMode) + if (userDataDir) { + networkSession = webkit_network_session_new(userDataDir, userDataDir); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", nullptr); + } else if (inspectorPipe || privateMode || automationMode) { -+ networkSession = webkit_network_session_new_ephemeral(); + networkSession = webkit_network_session_new_ephemeral(); +- else if (profileDirectory) { ++ } else if (profileDirectory) { + g_autofree char* dataDirectory = g_build_filename(profileDirectory, "data", nullptr); + g_autofree char* cacheDirectory = g_build_filename(profileDirectory, "cache", nullptr); + networkSession = webkit_network_session_new(dataDirectory, cacheDirectory); +- } else + } else { -+ networkSession = webkit_network_session_new(nullptr, nullptr); + networkSession = webkit_network_session_new(nullptr, nullptr); +- + } webkit_network_session_set_itp_enabled(networkSession, enableITP); if (proxy) { -@@ -491,10 +633,18 @@ static void activate(GApplication* application, gpointer) +@@ -512,19 +650,22 @@ static void activate(GApplication* application, gpointer) webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesFile, storageType); } } @@ -19797,20 +19663,29 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae auto* webContext = WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "time-zone-override", timeZone, nullptr)); + webkit_web_context_set_network_session_for_automation(webContext, networkSession); #else -- auto* manager = (privateMode || automationMode) ? webkit_website_data_manager_new_ephemeral() : webkit_website_data_manager_new(nullptr); +- WebKitWebsiteDataManager* manager; +- if (privateMode || automationMode) + WebKitWebsiteDataManager *manager; + if (userDataDir) { + manager = webkit_website_data_manager_new("base-data-directory", userDataDir, "base-cache-directory", userDataDir, NULL); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL); + } else if (inspectorPipe || privateMode || automationMode) { -+ manager = webkit_website_data_manager_new_ephemeral(); + manager = webkit_website_data_manager_new_ephemeral(); +- else if (profileDirectory) { ++ } else if (profileDirectory) { + g_autofree char* dataDirectory = g_build_filename(profileDirectory, "data", nullptr); + g_autofree char* cacheDirectory = g_build_filename(profileDirectory, "cache", nullptr); + webkit_website_data_manager_new("base-data-directory", dataDirectory, "base-cache-directory", cacheDirectory, nullptr); +- } else +- webkit_website_data_manager_new(nullptr); +- + } else { + manager = webkit_website_data_manager_new(NULL); + } webkit_website_data_manager_set_itp_enabled(manager, enableITP); if (proxy) { -@@ -525,6 +675,7 @@ static void activate(GApplication* application, gpointer) +@@ -555,6 +696,7 @@ static void activate(GApplication* application, gpointer) } #endif @@ -19818,7 +19693,7 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae g_autoptr(WebKitUserContentManager) userContentManager = nullptr; if (contentFilter) { g_autoptr(GFile) contentFilterFile = g_file_new_for_commandline_arg(contentFilter); -@@ -607,6 +758,15 @@ static void activate(GApplication* application, gpointer) +@@ -637,6 +779,15 @@ static void activate(GApplication* application, gpointer) "autoplay", WEBKIT_AUTOPLAY_ALLOW, nullptr); @@ -19834,9 +19709,9 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae auto* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, #if defined(USE_LIBWPE) && USE_LIBWPE "backend", viewBackend, -@@ -662,12 +822,16 @@ static void activate(GApplication* application, gpointer) - } +@@ -699,12 +850,16 @@ static void activate(GApplication* application, gpointer) #endif + } - openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr); - @@ -19853,7 +19728,7 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae g_hash_table_add(openViews, webView); WebKitColor color; -@@ -675,16 +839,11 @@ static void activate(GApplication* application, gpointer) +@@ -712,16 +867,11 @@ static void activate(GApplication* application, gpointer) webkit_web_view_set_background_color(webView, &color); if (uriArguments) { @@ -19875,7 +19750,7 @@ index 5e8a7ea42ad74a655c26cf827f01d0a23a3533c8..db2af373497474273452057ee193c3ae webkit_web_view_load_uri(webView, "https://wpewebkit.org"); g_object_unref(webContext); -@@ -779,12 +938,18 @@ int main(int argc, char *argv[]) +@@ -816,12 +966,18 @@ int main(int argc, char *argv[]) } #endif @@ -19906,11 +19781,43 @@ index 1067b31bc989748dfcc5502209d36d001b9b239e..7629263fb8bc93dca6dfc01c75eed8d2 +if (ENABLE_WEBKIT) + add_subdirectory(Playwright/win) +endif () +diff --git a/Tools/Scripts/generate-bundle b/Tools/Scripts/generate-bundle +index 2050bc1c4e2f94461cfe25dbc53762afdc6b9f53..cd43f62318d661bf2558a1b8005f37de19eb0f15 100755 +--- a/Tools/Scripts/generate-bundle ++++ b/Tools/Scripts/generate-bundle +@@ -41,7 +41,6 @@ sys.path.insert(0, os.path.join(top_level_directory, 'Tools', 'flatpak')) + sys.path.insert(0, os.path.join(top_level_directory, 'Tools', 'jhbuild')) + sys.path.insert(0, os.path.join(top_level_directory, 'Tools', 'Scripts', 'webkitpy')) + import jhbuildutils +-import flatpakutils + from binary_bundling.ldd import SharedObjectResolver + from binary_bundling.bundle import BinaryBundler + +@@ -896,7 +895,7 @@ class BundleCreator(object): + _log.info('Copy basic GTK icons.') + icons_target_dir = os.path.join(target_sys_share_dir, 'icons') + os.makedirs(icons_target_dir) +- gtk_icon_basedir = '/run/host/share/icons' if flatpakutils.is_sandboxed() else '/usr/share/icons' ++ gtk_icon_basedir = '/usr/share/icons' + gtk_target_icon_dir = os.path.join(icons_target_dir, 'hicolor') + gtk_icon_dirs_copied = 0 + for gtk_icon_theme in ['Adwaita', 'hicolor', 'gnome']: +@@ -975,9 +974,7 @@ def main(): + parser.add_argument('--builder-name', action='store', dest='builder_name') + options = parser.parse_args() + +- flatpakutils.run_in_sandbox_if_available([sys.argv[0], '--flatpak-' + options.platform] + sys.argv[1:]) +- if not flatpakutils.is_sandboxed(): +- jhbuildutils.enter_jhbuild_environment_if_available(options.platform) ++ jhbuildutils.enter_jhbuild_environment_if_available(options.platform) + + configure_logging(options.log_level) + bundle_creator = BundleCreator(options.configuration, options.platform, options.bundle_binary, options.syslibs, options.ldd, diff --git a/Tools/WebKitTestRunner/CMakeLists.txt b/Tools/WebKitTestRunner/CMakeLists.txt -index 5b1f93a1d3bbe655ce8e97fb2c729bcf8b2ecaac..836895f798897c352eae48c8cb2d9bede6c4b088 100644 +index ba703658cf8c56ad1768333b70938e67e8b36777..804487a7082024733d5012dcc62b9784c268bb55 100644 --- a/Tools/WebKitTestRunner/CMakeLists.txt +++ b/Tools/WebKitTestRunner/CMakeLists.txt -@@ -93,6 +93,10 @@ set(TestRunnerInjectedBundle_PRIVATE_LIBRARIES +@@ -99,6 +99,10 @@ set(TestRunnerInjectedBundle_PRIVATE_LIBRARIES ) set(TestRunnerInjectedBundle_FRAMEWORKS ${WebKitTestRunner_FRAMEWORKS}) @@ -19922,10 +19829,10 @@ index 5b1f93a1d3bbe655ce8e97fb2c729bcf8b2ecaac..836895f798897c352eae48c8cb2d9bed "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityController.idl" "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityTextMarker.idl" diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp -index c86d950020f3e7e96d500a120122556b6486f0c6..def22c2a225d3f19b30015a84c20f1522e582c65 100644 +index 9a61e6421c74f12bc565fad0f706cbb246bb784f..0a2bf450b5577c39c8e3645205d9e6f3ff470d93 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp -@@ -777,6 +777,7 @@ PlatformWebView* TestController::createOtherPlatformWebView(PlatformWebView* par +@@ -792,6 +792,7 @@ PlatformWebView* TestController::createOtherPlatformWebView(PlatformWebView* par nullptr, // requestStorageAccessConfirm nullptr, // shouldAllowDeviceOrientationAndMotionAccess nullptr, // runWebAuthenticationPanel @@ -19933,7 +19840,7 @@ index c86d950020f3e7e96d500a120122556b6486f0c6..def22c2a225d3f19b30015a84c20f152 nullptr, // decidePolicyForSpeechRecognitionPermissionRequest nullptr, // decidePolicyForMediaKeySystemPermissionRequest nullptr, // queryPermission -@@ -1257,6 +1258,7 @@ void TestController::createWebViewWithOptions(const TestOptions& options) +@@ -1272,6 +1273,7 @@ void TestController::createWebViewWithOptions(const TestOptions& options) nullptr, // requestStorageAccessConfirm shouldAllowDeviceOrientationAndMotionAccess, runWebAuthenticationPanel, @@ -19942,12 +19849,12 @@ index c86d950020f3e7e96d500a120122556b6486f0c6..def22c2a225d3f19b30015a84c20f152 decidePolicyForMediaKeySystemPermissionRequest, queryPermission, diff --git a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm -index b39b3b2d74ea040b150a0ee73313f661bc60a3bc..f6490bc2a39d27f35d2aa6a4e2449ba70b4a30aa 100644 +index 12a89be783e49c44edfca8d27f1fc3ddd24255e9..2ba827c958fa3558b0cd36f9e5b7537493fef362 100644 --- a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm +++ b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm -@@ -968,4 +968,51 @@ void EventSenderProxy::waitForPendingMouseEvents() - } - } +@@ -1031,4 +1031,51 @@ void EventSenderProxy::scaleGestureEnd(double scale) + + #endif // ENABLE(MAC_GESTURE_EVENTS) +#if ENABLE(TOUCH_EVENTS) +void EventSenderProxy::addTouchPoint(int, int) @@ -19998,10 +19905,10 @@ index b39b3b2d74ea040b150a0ee73313f661bc60a3bc..f6490bc2a39d27f35d2aa6a4e2449ba7 + } // namespace WTR diff --git a/Tools/jhbuild/jhbuild-minimal.modules b/Tools/jhbuild/jhbuild-minimal.modules -index 8df87f54f63ebf9f7adbff626a12ef7079fff3d3..30ab6e8a0ca264cdebe673b806f125bb7cda0769 100644 +index d526231f288ca82f4928d75ee9847b919b72bbfb..c904fac94196a8eb9888abf83b0db5ab69b3a993 100644 --- a/Tools/jhbuild/jhbuild-minimal.modules +++ b/Tools/jhbuild/jhbuild-minimal.modules -@@ -67,8 +67,8 @@ +@@ -69,8 +69,8 @@ <cmake id="libwpe"> <branch repo="github-tarball" module="WebPlatformForEmbedded/libwpe/releases/download/${version}/libwpe-${version}.tar.xz" @@ -20012,7 +19919,7 @@ index 8df87f54f63ebf9f7adbff626a12ef7079fff3d3..30ab6e8a0ca264cdebe673b806f125bb </cmake> <meson id="wpebackend-fdo"> -@@ -77,8 +77,8 @@ +@@ -79,8 +79,8 @@ </dependencies> <branch repo="github-tarball" module="Igalia/WPEBackend-fdo/releases/download/${version}/wpebackend-fdo-${version}.tar.xz" @@ -20023,7 +19930,7 @@ index 8df87f54f63ebf9f7adbff626a12ef7079fff3d3..30ab6e8a0ca264cdebe673b806f125bb </branch> </meson> -@@ -186,7 +186,6 @@ +@@ -188,7 +188,6 @@ </meson> <meson id="libsoup" mesonargs="-Dgssapi=disabled -Dvapi=disabled -Dntlm=disabled -Dsysprof=disabled -Dautobahn=disabled -Dpkcs11_tests=disabled"> @@ -20031,7 +19938,7 @@ index 8df87f54f63ebf9f7adbff626a12ef7079fff3d3..30ab6e8a0ca264cdebe673b806f125bb <dependencies> <dep package="glib"/> <dep package="glib-networking"/> -@@ -194,8 +193,8 @@ +@@ -196,8 +195,8 @@ </dependencies> <branch module="GNOME/libsoup.git" repo="github.com" @@ -20105,7 +20012,7 @@ index 5d6492124eb520ce2b25f5c62775438103050ed3..1c0ea8a3258b5676b81fb00360e2c058 location = "group:Source/bmalloc/bmalloc.xcodeproj"> </FileRef> diff --git a/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme b/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme -index 68732987fc02d863415360d066bc2a45d16ec39a..f4f924cb859034306361e9e55cdf31c6a1ca3b32 100644 +index 30f8a76f6050c407ab563814f614b3b848c168ff..d5fd599e4865f147d7ca8cfbcd6a4bedf6baa9e5 100644 --- a/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme +++ b/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme @@ -202,6 +202,20 @@ diff --git a/docs/src/api/class-apiresponse.md b/docs/src/api/class-apiresponse.md index 8a8b4639261f5..48ca44eb8af15 100644 --- a/docs/src/api/class-apiresponse.md +++ b/docs/src/api/class-apiresponse.md @@ -58,8 +58,8 @@ An object with all the response HTTP headers associated with this response. ## method: APIResponse.headersArray * since: v1.16 - returns: <[Array]<[Object]>> - - alias-csharp: Header - - alias-java: HttpHeader + * alias: HttpHeader + * alias-csharp: Header - `name` <[string]> Name of the header. - `value` <[string]> Value of the header. @@ -90,6 +90,16 @@ This method will throw if the response body is not parsable via `JSON.parse`. Contains a boolean stating whether the response was successful (status in the range 200-299) or not. +## async method: APIResponse.securityDetails = %%-response-security-details-%% +* since: v1.61 + +Returns SSL and other security information. Resolves to `null` for non-HTTPS responses. For redirected requests, returns the information for the last request in the redirect chain. + +## async method: APIResponse.serverAddr = %%-response-server-addr-%% +* since: v1.61 + +Returns the IP address and port of the server. Resolves to `null` if the server address is not available. For redirected requests, returns the information for the last request in the redirect chain. + ## method: APIResponse.status * since: v1.16 - returns: <[int]> diff --git a/docs/src/api/class-browser.md b/docs/src/api/class-browser.md index b676c64dc04ac..2c07e98c57b2b 100644 --- a/docs/src/api/class-browser.md +++ b/docs/src/api/class-browser.md @@ -304,7 +304,8 @@ testing frameworks should explicitly create [`method: Browser.newContext`] follo ## async method: Browser.bind * since: v1.59 - returns: <[Object]> - - alias: BindResult + * alias: BindResult + * alias-csharp: BrowserBindResult - `endpoint` <[string]> Binds the browser to a named pipe or web socket, making it available for other clients to connect to. diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index e839f13a017d8..518b2f6059bcf 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -74,6 +74,13 @@ This event is not emitted. Playwright has ability to mock clock and passage of time. +## property: BrowserContext.credentials +* since: v1.61 +- type: <[Credentials]> + +Virtual WebAuthn authenticator for this context. Lets tests seed credentials and intercept +`navigator.credentials.create()` / `navigator.credentials.get()` ceremonies. + ## property: BrowserContext.debugger * since: v1.59 - type: <[Debugger]> @@ -367,7 +374,7 @@ await context.AddCookiesAsync(new[] { cookie1, cookie2 }); ### param: BrowserContext.addCookies.cookies * since: v1.8 - `cookies` <[Array]<[Object]>> - - alias-java: Cookie + * alias-java: Cookie - `name` <[string]> - `value` <[string]> - `url` ?<[string]> Either `url` or both `domain` and `path` are required. Optional. @@ -607,8 +614,8 @@ The default browser context cannot be closed. ## async method: BrowserContext.cookies * since: v1.8 - returns: <[Array]<[Object]>> - - alias-csharp: BrowserContextCookiesResult - - alias-java: Cookie + * alias: Cookie + * alias-csharp: BrowserContextCookiesResult - `name` <[string]> - `value` <[string]> - `domain` <[string]> @@ -769,7 +776,7 @@ Name of the function on the window object. ### param: BrowserContext.exposeBinding.callback * since: v1.8 - `callback` <[function]> - - alias-java: BindingCallback + * alias: BindingCallback Callback function that will be called in the Playwright's context. @@ -961,7 +968,7 @@ Name of the function on the window object. ### param: BrowserContext.exposeFunction.callback * since: v1.8 - `callback` <[function]> - - alias-java: FunctionCallback + * alias: FunctionCallback Callback function that will be called in the Playwright's context. @@ -1498,7 +1505,7 @@ its geolocation. ### param: BrowserContext.setGeolocation.geolocation * since: v1.8 - `geolocation` <[null]|[Object]> - - alias-java: Geolocation + * alias: Geolocation - `latitude` <[float]> Latitude between -90 and 90. - `longitude` <[float]> Longitude between -180 and 180. - `accuracy` ?<[float]> Non-negative accuracy value. Defaults to `0`. @@ -1706,6 +1713,7 @@ Receives the [ConsoleMessage] object and resolves to truthy value when the waiti ### option: BrowserContext.waitForConsoleMessage.timeout = %%-wait-for-event-timeout-%% * since: v1.34 +### option: BrowserContext.waitForConsoleMessage.signal = %%-wait-for-event-signal-%% ### param: BrowserContext.waitForConsoleMessage.callback = %%-java-wait-for-event-callback-%% * since: v1.34 @@ -1775,6 +1783,7 @@ Either a predicate that receives an event or an options object. Optional. ### option: BrowserContext.waitForEvent.timeout = %%-wait-for-event-timeout-%% * since: v1.8 +### option: BrowserContext.waitForEvent.signal = %%-wait-for-event-signal-%% ## async method: BrowserContext.waitForPage * since: v1.9 @@ -1804,6 +1813,7 @@ Receives the [Page] object and resolves to truthy value when the waiting should ### option: BrowserContext.waitForPage.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: BrowserContext.waitForPage.signal = %%-wait-for-event-signal-%% ### param: BrowserContext.waitForPage.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -1830,3 +1840,4 @@ Will throw an error if the browser context is closed before the `event` is fired ### option: BrowserContext.waitForEvent2.timeout = %%-wait-for-event-timeout-%% * since: v1.8 +### option: BrowserContext.waitForEvent2.signal = %%-wait-for-event-signal-%% diff --git a/docs/src/api/class-browsertype.md b/docs/src/api/class-browsertype.md index 05a999dd869db..9f94ff4beb68c 100644 --- a/docs/src/api/class-browsertype.md +++ b/docs/src/api/class-browsertype.md @@ -236,6 +236,12 @@ emulation is not enabled, and media emulation options (such as [`option: Browser browser where these overrides would interfere with existing browser state. New contexts created via [`method: Browser.newContext`] are not affected. Defaults to `false`. +### option: BrowserType.connectOverCDP.artifactsDir +* since: v1.61 +- `artifactsDir` <[path]> + +If specified, browser artifacts (such as traces and downloads) are saved into this directory. + ## method: BrowserType.executablePath * since: v1.8 diff --git a/docs/src/api/class-credentials.md b/docs/src/api/class-credentials.md new file mode 100644 index 0000000000000..59af7a54d358f --- /dev/null +++ b/docs/src/api/class-credentials.md @@ -0,0 +1,103 @@ +# class: Credentials +* since: v1.61 + +`Credentials` provides a virtual WebAuthn authenticator scoped to a [BrowserContext]. It lets tests +seed credentials, intercept `navigator.credentials.create()` / `navigator.credentials.get()` calls +in pages, and complete WebAuthn ceremonies without a real authenticator. + +Implemented in userland via an injected script, so it works across Chromium, Firefox and WebKit. + +**Usage** + +```js +const context = await browser.newContext(); +await context.credentials.install(); +await context.credentials.create({ rpId: 'example.com' }); +const page = await context.newPage(); +await page.goto('https://example.com/login'); +// Page's navigator.credentials.get() will be answered using the seeded credential. +``` + +## async method: Credentials.install +* since: v1.61 + +Installs the virtual WebAuthn authenticator into the context, overriding +`navigator.credentials.create()` and `navigator.credentials.get()` in all current +and future pages. Call this before the page first touches `navigator.credentials`. + +Required: until `install()` is called, no interception is in place and the page sees +the platform's native (or absent) WebAuthn behaviour. Seeding credentials with +[`method: Credentials.create`] without `install()` populates the registry but the +page will never see those credentials. + +## async method: Credentials.create +* since: v1.61 +- returns: <[Object]> + * alias: VirtualCredential + - `id` <[string]> Base64url-encoded credential id. + - `rpId` <[string]> Relying party id. + - `userHandle` <[string]> Base64url-encoded user handle. + - `privateKey` <[string]> Base64url-encoded PKCS#8 (DER) private key. + - `publicKey` <[string]> Base64url-encoded SPKI (DER) public key. + +Seeds a virtual WebAuthn credential. With only `rpId`, generates a fresh ECDSA P-256 keypair, +credential id and user handle. To import a pre-registered credential (e.g. authenticating as an +existing test user the server already knows about), supply all four of `id`, `userHandle`, +`privateKey` and `publicKey` together. Call [`method: Credentials.install`] before navigating to a +page that uses WebAuthn. + +### param: Credentials.create.options +* since: v1.61 +- `options` <[Object]> + - `rpId` <[string]> Relying party id (typically the site's effective domain). + - `id` ?<[string]> Base64url-encoded credential id. Auto-generated if omitted. + - `userHandle` ?<[string]> Base64url-encoded user handle. Auto-generated if omitted. + - `privateKey` ?<[string]> Base64url-encoded PKCS#8 (DER) private key. Auto-generated if omitted. + - `publicKey` ?<[string]> Base64url-encoded SPKI (DER) public key. Auto-generated if omitted. + +## async method: Credentials.delete +* since: v1.61 + +Removes a previously seeded credential. + +### param: Credentials.delete.id +* since: v1.61 +- `id` <[string]> + +Base64url-encoded credential id. + +## async method: Credentials.get +* since: v1.61 +- returns: <[Array]<[Object]>> + * alias: VirtualCredential + - `id` <[string]> + - `rpId` <[string]> + - `userHandle` <[string]> + - `privateKey` <[string]> + - `publicKey` <[string]> + +Returns seeded credentials, optionally filtered by `rpId` or `id`. + +### option: Credentials.get.rpId +* since: v1.61 +- `rpId` <[string]> + +Only return credentials for this relying party id. + +### option: Credentials.get.id +* since: v1.61 +- `id` <[string]> + +Only return the credential with this base64url-encoded id. + +## async method: Credentials.setUserVerified +* since: v1.61 + +Toggles whether the virtual authenticator auto-approves user-verification prompts. Useful for +simulating a user denying biometric verification. + +### param: Credentials.setUserVerified.value +* since: v1.61 +- `value` <[boolean]> + +`true` to auto-approve user verification (default), `false` to refuse. diff --git a/docs/src/api/class-debugger.md b/docs/src/api/class-debugger.md index 3382cd618977c..8f59f7cc688e7 100644 --- a/docs/src/api/class-debugger.md +++ b/docs/src/api/class-debugger.md @@ -12,9 +12,9 @@ Emitted when the debugger pauses or resumes. ## method: Debugger.pausedDetails * since: v1.59 - returns: <[null]|[Object]> - - alias: DebuggerPausedDetails + * alias: DebuggerPausedDetails - `location` <[Object]> - - alias-java: Location + * alias: Location - `file` <[string]> - `line` ?<[int]> - `column` ?<[int]> @@ -49,7 +49,7 @@ Resumes script execution and pauses when an action originates from the given sou ### param: Debugger.runTo.location * since: v1.59 - `location` <[Object]> - - alias-java: Location + * alias: Location - `file` <[string]> - `line` ?<[int]> - `column` ?<[int]> diff --git a/docs/src/api/class-elementhandle.md b/docs/src/api/class-elementhandle.md index 7032f0ca15d62..47f622a536655 100644 --- a/docs/src/api/class-elementhandle.md +++ b/docs/src/api/class-elementhandle.md @@ -109,8 +109,8 @@ await locator.ClickAsync(); ## async method: ElementHandle.boundingBox * since: v1.8 - returns: <[null]|[Object]> - - alias-csharp: ElementHandleBoundingBoxResult - - alias-java: BoundingBox + * alias: BoundingBox + * alias-csharp: ElementHandleBoundingBoxResult - `x` <[float]> the x coordinate of the element in pixels. - `y` <[float]> the y coordinate of the element in pixels. - `width` <[float]> the width of the element in pixels. diff --git a/docs/src/api/class-formdata.md b/docs/src/api/class-formdata.md index ad93869411125..ea714ef79ef2b 100644 --- a/docs/src/api/class-formdata.md +++ b/docs/src/api/class-formdata.md @@ -114,8 +114,8 @@ Field name. ### param: FormData.append.value * since: v1.44 -- `value` <[string]|[boolean]|[int]|[Path]|[Object]> - - alias: FilePayload +- `value` <[string]|[boolean]|[int]|[path]|[Object]> + * alias: FilePayload - `name` <[string]> File name - `mimeType` <[string]> File type - `buffer` <[Buffer]> File content @@ -126,7 +126,7 @@ Field value. * since: v1.44 * langs: csharp - `value` <[string]|[boolean]|[int]|[Object]> - - alias-csharp: FilePayload + * alias: FilePayload - `name` <[string]> File name - `mimeType` <[string]> File type - `buffer` <[Buffer]> File content @@ -215,8 +215,8 @@ Field name. ### param: FormData.set.value * since: v1.18 -- `value` <[string]|[boolean]|[int]|[Path]|[Object]> - - alias: FilePayload +- `value` <[string]|[boolean]|[int]|[path]|[Object]> + * alias: FilePayload - `name` <[string]> File name - `mimeType` <[string]> File type - `buffer` <[Buffer]> File content @@ -227,7 +227,7 @@ Field value. * since: v1.18 * langs: csharp - `value` <[string]|[boolean]|[int]|[Object]> - - alias-csharp: FilePayload + * alias: FilePayload - `name` <[string]> File name - `mimeType` <[string]> File type - `buffer` <[Buffer]> File content diff --git a/docs/src/api/class-frame.md b/docs/src/api/class-frame.md index b553b7180cf31..153a09ddaa66e 100644 --- a/docs/src/api/class-frame.md +++ b/docs/src/api/class-frame.md @@ -680,7 +680,7 @@ Console.WriteLine(await frame.EvaluateAsync<int>("1 + 2")); // prints "3" [ElementHandle] instances can be passed as an argument to the [`method: Frame.evaluate`]: ```js -const bodyHandle = await frame.evaluate('document.body'); +const bodyHandle = await frame.evaluateHandle('document.body'); const html = await frame.evaluate(([body, suffix]) => body.innerHTML + suffix, [bodyHandle, 'hello'], ); @@ -688,25 +688,25 @@ await bodyHandle.dispose(); ``` ```java -ElementHandle bodyHandle = frame.evaluate("document.body"); +ElementHandle bodyHandle = frame.evaluateHandle("document.body"); String html = (String) frame.evaluate("([body, suffix]) => body.innerHTML + suffix", Arrays.asList(bodyHandle, "hello")); bodyHandle.dispose(); ``` ```python async -body_handle = await frame.evaluate("document.body") +body_handle = await frame.evaluate_handle("document.body") html = await frame.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"]) await body_handle.dispose() ``` ```python sync -body_handle = frame.evaluate("document.body") +body_handle = frame.evaluate_handle("document.body") html = frame.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"]) body_handle.dispose() ``` ```csharp -var bodyHandle = await frame.EvaluateAsync("document.body"); +var bodyHandle = await frame.EvaluateHandleAsync("document.body"); var html = await frame.EvaluateAsync<string>("([body, suffix]) => body.innerHTML + suffix", new object [] { bodyHandle, "hello" }); await bodyHandle.DisposeAsync(); ``` @@ -773,11 +773,11 @@ JSHandle aHandle = frame.evaluateHandle("document"); // Handle for the "document ``` ```python async -a_handle = await page.evaluate_handle("document") # handle for the "document" +a_handle = await frame.evaluate_handle("document") # handle for the "document" ``` ```python sync -a_handle = page.evaluate_handle("document") # handle for the "document" +a_handle = frame.evaluate_handle("document") # handle for the "document" ``` ```csharp @@ -803,15 +803,15 @@ resultHandle.dispose(); ``` ```python async -a_handle = await page.evaluate_handle("document.body") -result_handle = await page.evaluate_handle("body => body.innerHTML", a_handle) +a_handle = await frame.evaluate_handle("document.body") +result_handle = await frame.evaluate_handle("body => body.innerHTML", a_handle) print(await result_handle.json_value()) await result_handle.dispose() ``` ```python sync -a_handle = page.evaluate_handle("document.body") -result_handle = page.evaluate_handle("body => body.innerHTML", a_handle) +a_handle = frame.evaluate_handle("document.body") +result_handle = frame.evaluate_handle("body => body.innerHTML", a_handle) print(result_handle.json_value()) result_handle.dispose() ``` @@ -2010,6 +2010,7 @@ await frame.WaitForLoadStateAsync(); // Defaults to LoadState.Load ### option: Frame.waitForLoadState.timeout = %%-navigation-timeout-js-%% * since: v1.8 +### option: Frame.waitForLoadState.signal = %%-wait-for-event-signal-%% ## async method: Frame.waitForNavigation * since: v1.8 @@ -2093,6 +2094,7 @@ a navigation. ### option: Frame.waitForNavigation.timeout = %%-navigation-timeout-js-%% * since: v1.8 +### option: Frame.waitForNavigation.signal = %%-wait-for-event-signal-%% ### param: Frame.waitForNavigation.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -2289,6 +2291,7 @@ await frame.WaitForURLAsync("**/target.html"); ### option: Frame.waitForURL.timeout = %%-navigation-timeout-js-%% * since: v1.11 +### option: Frame.waitForURL.signal = %%-wait-for-event-signal-%% ### option: Frame.waitForURL.waitUntil = %%-navigation-wait-until-%% * since: v1.11 diff --git a/docs/src/api/class-keyboard.md b/docs/src/api/class-keyboard.md index 0bcaf6a59f96a..77c561ce3c8c2 100644 --- a/docs/src/api/class-keyboard.md +++ b/docs/src/api/class-keyboard.md @@ -308,6 +308,8 @@ In most cases, you should use [`method: Locator.fill`] instead. You only need to Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. +When [`option: namedKeys`] is `true`, anything inside `{}` is treated as a key name (same format as [`method: Keyboard.press`]). + To press a special key, like `Control` or `ArrowDown`, use [`method: Keyboard.press`]. **Usage** @@ -315,6 +317,9 @@ To press a special key, like `Control` or `ArrowDown`, use [`method: Keyboard.pr ```js await page.keyboard.type('Hello'); // Types instantly await page.keyboard.type('World', { delay: 100 }); // Types slower, like a user + +// Mix text and special keys +await page.keyboard.type('Hello{Enter}World', { namedKeys: true }); ``` ```java @@ -322,21 +327,33 @@ await page.keyboard.type('World', { delay: 100 }); // Types slower, like a user page.keyboard().type("Hello"); // Types slower, like a user page.keyboard().type("World", new Keyboard.TypeOptions().setDelay(100)); + +// Mix text and special keys +page.keyboard().type("Hello{Enter}World", new Keyboard.TypeOptions().setNamedKeys(true)); ``` ```python async await page.keyboard.type("Hello") # types instantly await page.keyboard.type("World", delay=100) # types slower, like a user + +# Mix text and special keys +await page.keyboard.type("Hello{Enter}World", named_keys=True) ``` ```python sync page.keyboard.type("Hello") # types instantly page.keyboard.type("World", delay=100) # types slower, like a user + +# Mix text and special keys +page.keyboard.type("Hello{Enter}World", named_keys=True) ``` ```csharp await page.Keyboard.TypeAsync("Hello"); // types instantly await page.Keyboard.TypeAsync("World", new() { Delay = 100 }); // types slower, like a user + +// Mix text and special keys +await page.Keyboard.TypeAsync("Hello{Enter}World", new() { NamedKeys = true }); ``` :::note @@ -359,6 +376,13 @@ A text to type into a focused element. Time to wait between key presses in milliseconds. Defaults to 0. +### option: Keyboard.type.namedKeys +* since: v1.61 +- `namedKeys` <[boolean]> + +When [`option: namedKeys`] is `true`, anything inside `{}` is treated as a key name (same format as [`method: Keyboard.press`]). +Use `{{` to type a literal brace character. Defaults to `false`. + ## async method: Keyboard.up * since: v1.8 diff --git a/docs/src/api/class-locator.md b/docs/src/api/class-locator.md index d3a90c0844214..f2004c3318988 100644 --- a/docs/src/api/class-locator.md +++ b/docs/src/api/class-locator.md @@ -251,8 +251,8 @@ Calls [blur](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur) ## async method: Locator.boundingBox * since: v1.14 - returns: <[null]|[Object]> - - alias-csharp: LocatorBoundingBoxResult - - alias-java: BoundingBox + * alias: BoundingBox + * alias-csharp: LocatorBoundingBoxResult - `x` <[float]> the x coordinate of the element in pixels. - `y` <[float]> the y coordinate of the element in pixels. - `width` <[float]> the width of the element in pixels. @@ -2103,6 +2103,8 @@ In most cases, you should use [`method: Locator.fill`] instead. You only need to Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. +When [`option: namedKeys`] is `true`, anything inside `{}` is treated as a key name (same format as [`method: Locator.press`]). + To press a special key, like `Control` or `ArrowDown`, use [`method: Locator.press`]. **Usage** @@ -2110,26 +2112,43 @@ To press a special key, like `Control` or `ArrowDown`, use [`method: Locator.pre ```js await locator.pressSequentially('Hello'); // Types instantly await locator.pressSequentially('World', { delay: 100 }); // Types slower, like a user + +// Mix characters and named keys +await locator.pressSequentially('Hello{Enter}World', { namedKeys: true }); +// Use modifier combos +await locator.pressSequentially('{Control+A}{Delete}Hello', { namedKeys: true }); ``` ```java locator.pressSequentially("Hello"); // Types instantly locator.pressSequentially("World", new Locator.pressSequentiallyOptions().setDelay(100)); // Types slower, like a user + +// Mix characters and named keys +locator.pressSequentially("Hello{Enter}World", new Locator.pressSequentiallyOptions().setNamedKeys(true)); ``` ```python async await locator.press_sequentially("hello") # types instantly await locator.press_sequentially("world", delay=100) # types slower, like a user + +# Mix characters and named keys +await locator.press_sequentially("Hello{Enter}World", named_keys=True) ``` ```python sync locator.press_sequentially("hello") # types instantly locator.press_sequentially("world", delay=100) # types slower, like a user + +# Mix characters and named keys +locator.press_sequentially("Hello{Enter}World", named_keys=True) ``` ```csharp await locator.PressSequentiallyAsync("Hello"); // Types instantly await locator.PressSequentiallyAsync("World", new() { Delay = 100 }); // Types slower, like a user + +// Mix characters and named keys +await locator.PressSequentiallyAsync("Hello{Enter}World", new() { NamedKeys = true }); ``` An example of typing into a text field and then submitting the form: @@ -2168,7 +2187,7 @@ await locator.PressAsync("Enter"); * since: v1.38 - `text` <[string]> -String of characters to sequentially press into a focused element. +String of characters to sequentially press into a focused element. When [`option: namedKeys`] is `true`, anything inside `{}` is treated as a key name (same format as [`method: Locator.press`]). ### option: Locator.pressSequentially.delay * since: v1.38 @@ -2176,6 +2195,13 @@ String of characters to sequentially press into a focused element. Time to wait between key presses in milliseconds. Defaults to 0. +### option: Locator.pressSequentially.namedKeys +* since: v1.61 +- `namedKeys` <[boolean]> + +When [`option: namedKeys`] is `true`, anything inside `{}` is treated as a key name (same format as [`method: Locator.press`]). +Use `{{` to type a literal brace character. Defaults to `false`. + ### option: Locator.pressSequentially.noWaitAfter = %%-input-no-wait-after-removed-%% * since: v1.38 diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index 6f9a43f19a2e2..098d83af7275f 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -1522,7 +1522,7 @@ Console.WriteLine(await page.EvaluateAsync<int>("1 + 2")); // prints "3" [ElementHandle] instances can be passed as an argument to the [`method: Page.evaluate`]: ```js -const bodyHandle = await page.evaluate('document.body'); +const bodyHandle = await page.evaluateHandle('document.body'); const html = await page.evaluate<string, HTMLElement>(([body, suffix]) => body.innerHTML + suffix, [bodyHandle, 'hello'] ); @@ -1530,25 +1530,25 @@ await bodyHandle.dispose(); ``` ```java -ElementHandle bodyHandle = page.evaluate("document.body"); +ElementHandle bodyHandle = page.evaluateHandle("document.body"); String html = (String) page.evaluate("([body, suffix]) => body.innerHTML + suffix", Arrays.asList(bodyHandle, "hello")); bodyHandle.dispose(); ``` ```python async -body_handle = await page.evaluate("document.body") +body_handle = await page.evaluate_handle("document.body") html = await page.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"]) await body_handle.dispose() ``` ```python sync -body_handle = page.evaluate("document.body") +body_handle = page.evaluate_handle("document.body") html = page.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"]) body_handle.dispose() ``` ```csharp -var bodyHandle = await page.EvaluateAsync("document.body"); +var bodyHandle = await page.EvaluateHandleAsync("document.body"); var html = await page.EvaluateAsync<string>("([body, suffix]) => body.innerHTML + suffix", new object [] { bodyHandle, "hello" }); await bodyHandle.DisposeAsync(); ``` @@ -1829,7 +1829,7 @@ Name of the function on the window object. ### param: Page.exposeBinding.callback * since: v1.8 - `callback` <[function]> - - alias-java: BindingCallback + * alias: BindingCallback Callback function that will be called in the Playwright's context. @@ -2023,7 +2023,7 @@ Name of the function on the window object ### param: Page.exposeFunction.callback * since: v1.8 - `callback` <[function]> - - alias-java: FunctionCallback + * alias: FunctionCallback Callback function which will be called in Playwright's context. @@ -2694,6 +2694,28 @@ Clears all stored console messages from this page. Subsequent calls to [`method: Clears all stored page errors from this page. Subsequent calls to [`method: Page.pageErrors`] will only return errors thrown after the clear. +## property: Page.localStorage +* since: v1.61 +- type: <[WebStorage]> + +Provides access to the page's `localStorage` for the current origin. See [WebStorage]. + +```js +await page.localStorage.setItem('token', 'abc'); +const token = await page.localStorage.getItem('token'); +``` + +## property: Page.sessionStorage +* since: v1.61 +- type: <[WebStorage]> + +Provides access to the page's `sessionStorage` for the current origin. See [WebStorage]. + +```js +await page.sessionStorage.setItem('flag', '1'); +const flag = await page.sessionStorage.getItem('flag'); +``` + ## async method: Page.consoleMessages * since: v1.56 - returns: <[Array]<[ConsoleMessage]>> @@ -3006,7 +3028,7 @@ Paper margins, defaults to none. * since: v1.8 * langs: csharp, java - `margin` <[Object]> - - alias-java: Margin + * alias-java: Margin - `top` ?<[string]> Top margin, accepts values labeled with units. Defaults to `0`. - `right` ?<[string]> Right margin, accepts values labeled with units. Defaults to `0`. - `bottom` ?<[string]> Bottom margin, accepts values labeled with units. Defaults to `0`. @@ -4277,7 +4299,7 @@ When all steps combined have not finished during the specified [`option: timeout [TimeoutError]. Passing zero timeout disables this. :::note -[`method: Page.tap`] the method will throw if [`option: Browser.newContext.hasTouch`] option of the browser context is false. +[`method: Page.tap`] will throw if the [`option: Browser.newContext.hasTouch`] option of the browser context is false. ::: ### param: Page.tap.selector = %%-input-selector-%% @@ -4471,8 +4493,8 @@ Video object associated with this page. Can be used to access the video file whe ## method: Page.viewportSize * since: v1.8 - returns: <[null]|[Object]> - - alias-csharp: PageViewportSizeResult - - alias-java: ViewportSize + * alias: ViewportSize + * alias-csharp: PageViewportSizeResult - `width` <[int]> page width in pixels. - `height` <[int]> page height in pixels. @@ -4485,6 +4507,7 @@ Performs action and waits for the Page to close. ### option: Page.waitForClose.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Page.waitForClose.signal = %%-wait-for-event-signal-%% ### param: Page.waitForClose.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -4516,6 +4539,7 @@ Receives the [ConsoleMessage] object and resolves to truthy value when the waiti ### option: Page.waitForConsoleMessage.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Page.waitForConsoleMessage.signal = %%-wait-for-event-signal-%% ### param: Page.waitForConsoleMessage.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -4547,6 +4571,7 @@ Receives the [Download] object and resolves to truthy value when the waiting sho ### option: Page.waitForDownload.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Page.waitForDownload.signal = %%-wait-for-event-signal-%% ### param: Page.waitForDownload.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -4603,6 +4628,7 @@ Either a predicate that receives an event or an options object. Optional. ### option: Page.waitForEvent.timeout = %%-wait-for-event-timeout-%% * since: v1.8 +### option: Page.waitForEvent.signal = %%-wait-for-event-signal-%% ## async method: Page.waitForFileChooser * since: v1.9 @@ -4631,6 +4657,7 @@ Receives the [FileChooser] object and resolves to truthy value when the waiting ### option: Page.waitForFileChooser.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Page.waitForFileChooser.signal = %%-wait-for-event-signal-%% ### param: Page.waitForFileChooser.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -4868,6 +4895,7 @@ Console.WriteLine(await popup.TitleAsync()); // popup is ready to use. ### option: Page.waitForLoadState.timeout = %%-navigation-timeout-js-%% * since: v1.8 +### option: Page.waitForLoadState.signal = %%-wait-for-event-signal-%% ## async method: Page.waitForNavigation * since: v1.8 @@ -4954,6 +4982,7 @@ a navigation. ### option: Page.waitForNavigation.timeout = %%-navigation-timeout-js-%% * since: v1.8 +### option: Page.waitForNavigation.signal = %%-wait-for-event-signal-%% ### param: Page.waitForNavigation.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -4985,6 +5014,7 @@ Receives the [Page] object and resolves to truthy value when the waiting should ### option: Page.waitForPopup.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Page.waitForPopup.signal = %%-wait-for-event-signal-%% ### param: Page.waitForPopup.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -5094,6 +5124,8 @@ Request URL string, regex or predicate receiving [Request] object. Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can be changed by using the [`method: Page.setDefaultTimeout`] method. +### option: Page.waitForRequest.signal = %%-wait-for-event-signal-%% + ### param: Page.waitForRequest.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -5124,6 +5156,7 @@ Receives the [Request] object and resolves to truthy value when the waiting shou ### option: Page.waitForRequestFinished.timeout = %%-wait-for-event-timeout-%% * since: v1.12 +### option: Page.waitForRequestFinished.signal = %%-wait-for-event-signal-%% ### param: Page.waitForRequestFinished.callback = %%-java-wait-for-event-callback-%% * since: v1.12 @@ -5240,6 +5273,8 @@ it gets merged via the [`new URL()`](https://developer.mozilla.org/en-US/docs/We Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can be changed by using the [`method: BrowserContext.setDefaultTimeout`] or [`method: Page.setDefaultTimeout`] methods. +### option: Page.waitForResponse.signal = %%-wait-for-event-signal-%% + ### param: Page.waitForResponse.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -5491,6 +5526,7 @@ await page.WaitForURLAsync("**/target.html"); ### option: Page.waitForURL.timeout = %%-navigation-timeout-js-%% * since: v1.11 +### option: Page.waitForURL.signal = %%-wait-for-event-signal-%% ### option: Page.waitForURL.waitUntil = %%-navigation-wait-until-%% * since: v1.11 @@ -5522,6 +5558,7 @@ Receives the [WebSocket] object and resolves to truthy value when the waiting sh ### option: Page.waitForWebSocket.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Page.waitForWebSocket.signal = %%-wait-for-event-signal-%% ### param: Page.waitForWebSocket.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -5553,6 +5590,7 @@ Receives the [Worker] object and resolves to truthy value when the waiting shoul ### option: Page.waitForWorker.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Page.waitForWorker.signal = %%-wait-for-event-signal-%% ### param: Page.waitForWorker.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -5590,3 +5628,4 @@ Will throw an error if the page is closed before the `event` is fired. ### option: Page.waitForEvent2.timeout = %%-wait-for-event-timeout-%% * since: v1.8 +### option: Page.waitForEvent2.signal = %%-wait-for-event-signal-%% diff --git a/docs/src/api/class-request.md b/docs/src/api/class-request.md index 5f3bd280d68ea..a37a5d5953a6c 100644 --- a/docs/src/api/class-request.md +++ b/docs/src/api/class-request.md @@ -114,8 +114,8 @@ You can use [`method: Request.allHeaders`] for complete list of headers that inc ## async method: Request.headersArray * since: v1.15 - returns: <[Array]<[Object]>> - - alias-csharp: Header - - alias-java: HttpHeader + * alias: HttpHeader + * alias-csharp: Header - `name` <[string]> Name of the header. - `value` <[string]> Value of the header. @@ -313,8 +313,8 @@ Requests originated in a Service Worker do not have a [`method: Request.frame`] ## async method: Request.sizes * since: v1.15 - returns: <[Object]> - - alias-csharp: RequestSizesResult - - alias-java: Sizes + * alias-csharp: RequestSizesResult + * alias-java: Sizes - `requestBodySize` <[int]> Size of the request body (POST data payload) in bytes. Set to 0 if there was no body. - `requestHeadersSize` <[int]> Total number of bytes from the start of the HTTP request message until (and including) the double CRLF before the body. - `responseBodySize` <[int]> Size of the received response body (encoded) in bytes. @@ -325,8 +325,8 @@ Returns resource size information for given request. ## method: Request.timing * since: v1.8 - returns: <[Object]> - - alias-csharp: RequestTimingResult - - alias-java: Timing + * alias-csharp: RequestTimingResult + * alias-java: Timing - `startTime` <[float]> Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC - `domainLookupStart` <[float]> Time immediately before the browser starts the domain name lookup for the resource. The value is given in milliseconds relative to `startTime`, -1 if not available. diff --git a/docs/src/api/class-response.md b/docs/src/api/class-response.md index a89d0bc9471ec..555d2210c096d 100644 --- a/docs/src/api/class-response.md +++ b/docs/src/api/class-response.md @@ -49,8 +49,8 @@ You can use [`method: Response.allHeaders`] for complete list of headers that in ## async method: Response.headersArray * since: v1.15 - returns: <[Array]<[Object]>> - - alias-csharp: Header - - alias-java: HttpHeader + * alias: HttpHeader + * alias-csharp: Header - `name` <[string]> Name of the header. - `value` <[string]> Value of the header. @@ -118,30 +118,13 @@ Contains a boolean stating whether the response was successful (status in the ra Returns the matching [Request] object. -## async method: Response.securityDetails +## async method: Response.securityDetails = %%-response-security-details-%% * since: v1.13 -- returns: <[null]|[Object]> - - alias-csharp: ResponseSecurityDetailsResult - - alias-java: SecurityDetails - - `issuer` ?<[string]> Common Name component of the Issuer field. - from the certificate. This should only be used for informational purposes. Optional. - - `protocol` ?<[string]> The specific TLS protocol used. (e.g. `TLS 1.3`). Optional. - - `subjectName` ?<[string]> Common Name component of the Subject - field from the certificate. This should only be used for informational purposes. Optional. - - `validFrom` ?<[float]> Unix timestamp (in seconds) specifying - when this cert becomes valid. Optional. - - `validTo` ?<[float]> Unix timestamp (in seconds) specifying - when this cert becomes invalid. Optional. Returns SSL and other security information. -## async method: Response.serverAddr +## async method: Response.serverAddr = %%-response-server-addr-%% * since: v1.13 -- returns: <[null]|[Object]> - - alias-csharp: ResponseServerAddrResult - - alias-java: ServerAddr - - `ipAddress` <[string]> IPv4 or IPV6 address of the server. - - `port` <[int]> Returns the IP address and port of the server. diff --git a/docs/src/api/class-screencast.md b/docs/src/api/class-screencast.md index 4d1ba1843ea8e..12e3111ffe805 100644 --- a/docs/src/api/class-screencast.md +++ b/docs/src/api/class-screencast.md @@ -34,7 +34,7 @@ await page.screencast.stop(); ### option: Screencast.start.onFrame * since: v1.59 - `onFrame` <[function]\([Object]\): [Promise]> - - alias: ScreencastFrame + * alias: ScreencastFrame - `data` <[Buffer]> JPEG-encoded frame data. - `viewportWidth` <[int]> Width of the page viewport at the time the frame was captured. - `viewportHeight` <[int]> Height of the page viewport at the time the frame was captured. @@ -57,7 +57,7 @@ The quality of the image, between 0-100. * since: v1.59 * langs: js - `size` ?<[Object]> - - alias-csharp: ScreencastSize + * alias-csharp: ScreencastSize - `width` <[int]> Max frame width in pixels. - `height` <[int]> Max frame height in pixels. @@ -135,6 +135,14 @@ Position of the action title overlay. Defaults to `"top-right"`. Font size of the action title in pixels. Defaults to `24`. +### option: Screencast.showActions.cursor +* since: v1.61 +- `cursor` ?<[ScreencastCursor]<"none"|"pointer">> + +Cursor decoration shown for pointer actions. `"pointer"` (the default) renders +a mouse pointer that animates from the previous action point to the next one. +`"none"` disables the cursor decoration. + ## async method: Screencast.showOverlays * since: v1.59 diff --git a/docs/src/api/class-selectors.md b/docs/src/api/class-selectors.md index 4c3011430387a..fefd7ba394948 100644 --- a/docs/src/api/class-selectors.md +++ b/docs/src/api/class-selectors.md @@ -247,4 +247,5 @@ Defines custom attribute name to be used in [`method: Page.getByTestId`]. `data- * since: v1.27 - `attributeName` <[string]> -Test id attribute name. +Test id attribute name. To match elements with any of several attributes, pass them as a +comma-separated list, e.g. `"data-pw,data-ti"`. diff --git a/docs/src/api/class-touchscreen.md b/docs/src/api/class-touchscreen.md index d7871addd7a00..56af3301c1dbb 100644 --- a/docs/src/api/class-touchscreen.md +++ b/docs/src/api/class-touchscreen.md @@ -12,7 +12,7 @@ This class is limited to emulating tap gestures. For examples of other gestures Dispatches a `touchstart` and `touchend` event with a single touch at the position ([`param: x`],[`param: y`]). :::note -[`method: Page.tap`] the method will throw if [`option: Browser.newContext.hasTouch`] option of the browser context is false. +[`method: Touchscreen.tap`] will throw if the [`option: Browser.newContext.hasTouch`] option of the browser context is false. ::: ### param: Touchscreen.tap.x diff --git a/docs/src/api/class-tracing.md b/docs/src/api/class-tracing.md index 1af0427bfd888..256ae513a5327 100644 --- a/docs/src/api/class-tracing.md +++ b/docs/src/api/class-tracing.md @@ -444,7 +444,7 @@ Group name shown in the trace viewer. ### option: Tracing.group.location * since: v1.49 - `location` ?<[Object]> - - alias-java: Location + * alias: Location - `file` <[string]> - `line` ?<[int]> - `column` ?<[int]> diff --git a/docs/src/api/class-weberror.md b/docs/src/api/class-weberror.md index 455450861996f..8f3c91a960765 100644 --- a/docs/src/api/class-weberror.md +++ b/docs/src/api/class-weberror.md @@ -69,7 +69,7 @@ Unhandled error that was thrown. ## method: WebError.location * since: v1.60 - returns: <[Object]> - - alias: WebErrorLocation + * alias: WebErrorLocation - `url` <[string]> URL of the resource. - `line` <[int]> 0-based line number in the resource. - `column` <[int]> 0-based column number in the resource. diff --git a/docs/src/api/class-websocket.md b/docs/src/api/class-websocket.md index e33740eacaad6..354de8f874447 100644 --- a/docs/src/api/class-websocket.md +++ b/docs/src/api/class-websocket.md @@ -97,6 +97,7 @@ Either a predicate that receives an event or an options object. Optional. ### option: WebSocket.waitForEvent.timeout = %%-wait-for-event-timeout-%% * since: v1.8 +### option: WebSocket.waitForEvent.signal = %%-wait-for-event-signal-%% ## async method: WebSocket.waitForFrameReceived * since: v1.10 @@ -115,6 +116,7 @@ Receives the [WebSocketFrame] object and resolves to truthy value when the waiti ### option: WebSocket.waitForFrameReceived.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: WebSocket.waitForFrameReceived.signal = %%-wait-for-event-signal-%% ### param: WebSocket.waitForFrameReceived.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -136,6 +138,7 @@ Receives the [WebSocketFrame] object and resolves to truthy value when the waiti ### option: WebSocket.waitForFrameSent.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: WebSocket.waitForFrameSent.signal = %%-wait-for-event-signal-%% ### param: WebSocket.waitForFrameSent.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -162,3 +165,4 @@ Will throw an error if the socket is closed before the `event` is fired. ### option: WebSocket.waitForEvent2.timeout = %%-wait-for-event-timeout-%% * since: v1.8 +### option: WebSocket.waitForEvent2.signal = %%-wait-for-event-signal-%% diff --git a/docs/src/api/class-webstorage.md b/docs/src/api/class-webstorage.md new file mode 100644 index 0000000000000..e84f77707d68f --- /dev/null +++ b/docs/src/api/class-webstorage.md @@ -0,0 +1,105 @@ +# class: WebStorage +* since: v1.61 + +WebStorage exposes the page's `localStorage` or `sessionStorage` for the current origin via an async, +[browser-consistent](https://developer.mozilla.org/en-US/docs/Web/API/Storage) API. + +Instances are accessed through [`property: Page.localStorage`] and [`property: Page.sessionStorage`]. + +```js +await page.goto('https://example.com'); +await page.localStorage.setItem('token', 'abc'); +const token = await page.localStorage.getItem('token'); +const all = await page.localStorage.items(); +await page.localStorage.removeItem('token'); +await page.localStorage.clear(); +``` + +```python async +await page.goto("https://example.com") +await page.local_storage.set_item("token", "abc") +token = await page.local_storage.get_item("token") +all = await page.local_storage.items() +await page.local_storage.remove_item("token") +await page.local_storage.clear() +``` + +```python sync +page.goto("https://example.com") +page.local_storage.set_item("token", "abc") +token = page.local_storage.get_item("token") +all = page.local_storage.items() +page.local_storage.remove_item("token") +page.local_storage.clear() +``` + +```java +page.navigate("https://example.com"); +page.localStorage().setItem("token", "abc"); +String token = page.localStorage().getItem("token"); +List<NameValue> all = page.localStorage().items(); +page.localStorage().removeItem("token"); +page.localStorage().clear(); +``` + +```csharp +await page.GotoAsync("https://example.com"); +await page.LocalStorage.SetItemAsync("token", "abc"); +var token = await page.LocalStorage.GetItemAsync("token"); +var all = await page.LocalStorage.ItemsAsync(); +await page.LocalStorage.RemoveItemAsync("token"); +await page.LocalStorage.ClearAsync(); +``` + +## async method: WebStorage.items +* since: v1.61 +- returns: <[Array]<[Object]>> + - `name` <[string]> + - `value` <[string]> + +Returns all items in the storage as `name`/`value` pairs. + +## async method: WebStorage.getItem +* since: v1.61 +- returns: <[null]|[string]> + +Returns the value for the given `name`, or `null` if the key is not present. + +### param: WebStorage.getItem.name +* since: v1.61 +- `name` <[string]> + +Name of the item to retrieve. + +## async method: WebStorage.setItem +* since: v1.61 + +Sets the value for the given `name`. Overwrites any existing value for that name. + +### param: WebStorage.setItem.name +* since: v1.61 +- `name` <[string]> + +Name of the item to set. + +### param: WebStorage.setItem.value +* since: v1.61 +- `value` <[string]> + +New value for the item. + +## async method: WebStorage.removeItem +* since: v1.61 + +Removes the item with the given `name`. No-op if the item is absent. + +### param: WebStorage.removeItem.name +* since: v1.61 +- `name` <[string]> + +Name of the item to remove. + +## async method: WebStorage.clear +* since: v1.61 + +Removes all items from the storage. diff --git a/docs/src/api/class-worker.md b/docs/src/api/class-worker.md index 5fc5992affc23..9c7160335ae50 100644 --- a/docs/src/api/class-worker.md +++ b/docs/src/api/class-worker.md @@ -126,6 +126,7 @@ Performs action and waits for the Worker to close. ### option: Worker.waitForClose.timeout = %%-wait-for-event-timeout-%% * since: v1.9 +### option: Worker.waitForClose.signal = %%-wait-for-event-signal-%% ### param: Worker.waitForClose.callback = %%-java-wait-for-event-callback-%% * since: v1.9 @@ -145,6 +146,7 @@ Receives the [ConsoleMessage] object and resolves to true when the waiting shoul ### option: Worker.waitForConsoleMessage.timeout = %%-wait-for-event-timeout-%% * since: v1.57 +### option: Worker.waitForConsoleMessage.signal = %%-wait-for-event-signal-%% ### param: Worker.waitForConsoleMessage.callback = %%-java-wait-for-event-callback-%% * since: v1.57 @@ -203,3 +205,4 @@ Either a predicate that receives an event or an options object. Optional. ### option: Worker.waitForEvent.timeout = %%-wait-for-event-timeout-%% * since: v1.57 +### option: Worker.waitForEvent.signal = %%-wait-for-event-signal-%% diff --git a/docs/src/api/params.md b/docs/src/api/params.md index 350afc877b268..c59cb1e920f5e 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -97,7 +97,7 @@ A selector to search for an element to drop onto. If there are multiple elements ## input-position - `position` <[Object]> - - alias-java: Position + * alias: Position - `x` <[float]> - `y` <[float]> @@ -128,16 +128,16 @@ Defaults to `left`. ## input-files - `files` <[path]|[Array]<[path]>|[Object]|[Array]<[Object]>> - - alias: FilePayload + * alias: FilePayload - `name` <[string]> File name - `mimeType` <[string]> File type - `buffer` <[Buffer]> File content ## drop-payload - `payload` <[Object]> - - alias: DropPayload + * alias: DropPayload - `files` ?<[path]|[Array]<[path]>|[Object]|[Array]<[Object]>> - - alias: FilePayload + * alias: FilePayload - `name` <[string]> File name - `mimeType` <[string]> File type - `buffer` <[Buffer]> File content @@ -169,7 +169,7 @@ When set, this method only performs the [actionability](../actionability.md) che ## input-source-position - `sourcePosition` <[Object]> - - alias-java: Position + * alias-java: Position - `x` <[float]> - `y` <[float]> @@ -177,7 +177,7 @@ Clicks on the source element at this point relative to the top-left corner of th ## input-target-position - `targetPosition` <[Object]> - - alias-java: Position + * alias-java: Position - `x` <[float]> - `y` <[float]> @@ -253,7 +253,7 @@ Dangerous option; use with care. Defaults to `false`. ## browser-option-proxy - `proxy` <[Object]> - - alias-java: Proxy + * alias: Proxy - `server` <[string]> Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example `http://myproxy.com:3128` or `socks5://myproxy.com:3128`. Short form `myproxy.com:3128` is considered an HTTP proxy. @@ -350,7 +350,7 @@ When using [`method: Page.goto`], [`method: Page.route`], [`method: Page.waitFor * langs: js, java - alias-java: viewportSize - `viewport` <[null]|[Object]> - - alias-java: ViewportSize + * alias: ViewportSize - `width` <[int]> page width in pixels. - `height` <[int]> page height in pixels. @@ -384,7 +384,7 @@ It makes the execution of the tests non-deterministic. - alias-java: screenSize - alias-csharp: screenSize - `screen` <[Object]> - - alias-java: ScreenSize + * alias: ScreenSize - `width` <[int]> page width in pixels. - `height` <[int]> page height in pixels. @@ -616,7 +616,7 @@ Does not enforce fixed viewport, allows resizing window in the headed mode. ## context-option-clientCertificates - `clientCertificates` <[Array]<[Object]>> - - alias-java: ClientCertificate + * alias: ClientCertificate - `origin` <[string]> Exact origin that the certificate is valid for. Origin includes `https` protocol, a hostname and optionally a port. - `certPath` ?<[path]> Path to the file with the certificate in PEM format. - `cert` ?<[Buffer]> Direct value of the certificate in PEM format. @@ -671,7 +671,7 @@ for a list of supported timezone IDs. Defaults to the system timezone. ## context-option-geolocation - `geolocation` <[Object]> - - alias-java: Geolocation + * alias: Geolocation - `latitude` <[float]> Latitude between -90 and 90. - `longitude` <[float]> Longitude between -180 and 180. - `accuracy` ?<[float]> Non-negative accuracy value. Defaults to `0`. @@ -699,7 +699,7 @@ Whether to emulate network being offline. Defaults to `false`. Learn more about ## context-option-httpcredentials - `httpCredentials` <[Object]> - - alias-java: HttpCredentials + * alias: HttpCredentials - `username` <[string]> - `password` <[string]> - `origin` ?<[string]> Restrain sending http credentials on specific origin (scheme://host:port). @@ -821,11 +821,9 @@ When set to `minimal`, only record information necessary for routing from HAR. T - `size` ?<[Object]> Optional dimensions of the recorded videos. If not specified the size will be equal to `viewport` scaled down to fit into 800x800. If `viewport` is not configured explicitly the video size defaults to 800x450. Actual picture of each page will be scaled down if necessary to fit the specified size. - - alias-csharp: RecordVideoSize - `width` <[int]> Video frame width. - `height` <[int]> Video frame height. - `showActions` ?<[Object]> If specified, enables visual annotations on interacted elements during video recording. - - alias-csharp: ShowActionsOptions - `duration` ?<[float]> How long each annotation is displayed in milliseconds. Defaults to `500`. - `position` ?<[AnnotatePosition]<"top-left"|"top"|"top-right"|"bottom-left"|"bottom"|"bottom-right">> Position of the action title overlay. Defaults to `"top-right"`. - `fontSize` ?<[int]> Font size of the action title in pixels. Defaults to `24`. @@ -845,7 +843,7 @@ not recorded. Make sure to call [`method: BrowserContext.close`] for videos to b * langs: csharp, java, python - alias-python: record_video_size - `recordVideoSize` <[Object]> - - alias-java: RecordVideoSize + * alias-java: RecordVideoSize - `width` <[int]> Video frame width. - `height` <[int]> Video frame height. @@ -855,7 +853,7 @@ Actual picture of each page will be scaled down if necessary to fit the specifie ## context-option-proxy - `proxy` <[Object]> - - alias-java: Proxy + * alias: Proxy - `server` <[string]> Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example `http://myproxy.com:3128` or `socks5://myproxy.com:3128`. Short form `myproxy.com:3128` is considered an HTTP proxy. - `bypass` ?<[string]> Optional comma-separated domains to bypass proxy, for example `".com, chromium.org, .domain.com"`. @@ -903,7 +901,7 @@ Specifies whether to wait for already running handlers and what to do if they th ## select-options-values * langs: java, js, csharp - `values` <[null]|[string]|[ElementHandle]|[Array]<[string]>|[Object]|[Array]<[ElementHandle]>|[Array]<[Object]>> - - alias-java: SelectOption + * alias-java: SelectOption - `value` ?<[string]> Matches by `option.value`. Optional. - `label` ?<[string]> Matches by `option.label`. Optional. - `index` ?<[int]> Matches by the index. Optional. @@ -993,6 +991,14 @@ Receives the event data and resolves to truthy value when the waiting should res Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value can be changed by using the [`method: BrowserContext.setDefaultTimeout`]. +## wait-for-event-signal +* langs: js +* since: v1.61 +- `signal` <[AbortSignal]> + +Allows to cancel the waiting using an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal). If the signal is aborted, the waiting will be aborted and the operation will throw an error. +Note that providing a signal does not disable the default timeout; pass `timeout: 0` to disable the timeout entirely. + ## android-timeout * langs: js - `timeout` <[float]> @@ -1306,7 +1312,7 @@ When true, takes a screenshot of the full scrollable page, instead of the curren ## screenshot-option-clip - `clip` <[Object]> - - alias-java: Clip + * alias-java: Clip - `x` <[float]> x-coordinate of top-left corner of clip area - `y` <[float]> y-coordinate of top-left corner of clip area - `width` <[float]> width of clipping area @@ -1967,3 +1973,45 @@ In this config: 1. Since `snapshotPathTemplate` resolves to relative path, it will be resolved relative to `configDir`. 1. Forward slashes `"/"` can be used as path separators on any platform. +## test-config-web-server-options +* langs: js +- type: ?<[Object]|[Array]<[Object]>> + - `command` <[string]> Shell command to start. For example `npm run start`.. + - `cwd` ?<[string]> Current working directory of the spawned process, defaults to the directory of the configuration file. + - `env` ?<[Object]<[string], [string]>> Environment variables to set for the command, `process.env` by default. + - `gracefulShutdown` ?<[Object]> How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGTERM', timeout: 500 }`, the process group is sent a `SIGTERM` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGINT` as the signal instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGTERM` and `SIGINT` signals, so this option is ignored on Windows. Note that shutting down a Docker container requires `SIGTERM`. + - `signal` <["SIGINT"|"SIGTERM"]> + - `timeout` <[int]> + - `ignoreHTTPSErrors` ?<[boolean]> Whether to ignore HTTPS errors when fetching the `url`. Defaults to `false`. + - `name` ?<[string]> Specifies a custom name for the web server. This name will be prefixed to log messages. Defaults to `[WebServer]`. + - `port` ?<[int]> The port that your http server is expected to appear on. It does wait until it accepts connections. Either `port` or `url` should be specified. + - `reuseExistingServer` ?<[boolean]> If true, it will re-use an existing server on the `port` or `url` when available. If no server is running on that `port` or `url`, it will run the command to start a new server. If `false`, it will throw if an existing process is listening on the `port` or `url`. This should be commonly set to `!process.env.CI` to allow the local dev server when running tests locally. + - `stderr` ?<["pipe"|"ignore"]> Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to `"pipe"`. + - `stdout` ?<["pipe"|"ignore"]> If `"pipe"`, it will pipe the stdout of the command to the process stdout. If `"ignore"`, it will ignore the stdout of the command. Default to `"ignore"`. + - `wait` ?<[Object]> Consider command started only when given output has been produced. + - `stdout` ?<[RegExp]> Regular expression to wait for in the `stdout` of the command output. Named capture groups are stored in the environment, for example `/Listening on port (?<my_server_port>\d+)/` will store the port number in `process.env['MY_SERVER_PORT']`. + - `stderr` ?<[RegExp]> Regular expression to wait for in the `stderr` of the command output. Named capture groups are stored in the environment, for example `/Listening on port (?<my_server_port>\d+)/` will store the port number in `process.env['MY_SERVER_PORT']`. + - `timeout` ?<[int]> How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. + - `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is checked. Either `port` or `url` should be specified. + +## response-security-details +- returns: <[null]|[Object]> + * alias: SecurityDetails + * alias-csharp: ResponseSecurityDetailsResult + - `issuer` ?<[string]> Common Name component of the Issuer field. + from the certificate. This should only be used for informational purposes. Optional. + - `protocol` ?<[string]> The specific TLS protocol used. (e.g. `TLS 1.3`). Optional. + - `subjectName` ?<[string]> Common Name component of the Subject + field from the certificate. This should only be used for informational purposes. Optional. + - `validFrom` ?<[float]> Unix timestamp (in seconds) specifying + when this cert becomes valid. Optional. + - `validTo` ?<[float]> Unix timestamp (in seconds) specifying + when this cert becomes invalid. Optional. + +## response-server-addr +- returns: <[null]|[Object]> + * alias-csharp: ResponseServerAddrResult + * alias-java: ServerAddr + - `ipAddress` <[string]> IPv4 or IPV6 address of the server. + - `port` <[int]> + diff --git a/docs/src/aria-snapshots.md b/docs/src/aria-snapshots.md index 851de7a730a74..60bcd5e965ff3 100644 --- a/docs/src/aria-snapshots.md +++ b/docs/src/aria-snapshots.md @@ -156,7 +156,7 @@ Each accessible element in the tree is represented as a YAML node: - **role**: Specifies the ARIA or HTML role of the element (e.g., `heading`, `list`, `listitem`, `button`). - **"name"**: Accessible name of the element. Quoted strings indicate exact values, `/patterns/` are used for regular expression. - **[attribute=value]**: Attributes and values, in square brackets, represent specific ARIA attributes, such - as `checked`, `disabled`, `expanded`, `level`, `pressed`, or `selected`. + as `checked`, `disabled`, `expanded`, `invalid`, `level`, `pressed`, or `selected`. These values are derived from ARIA attributes or calculated based on HTML semantics. To inspect the accessibility tree structure of a page, use the [Chrome DevTools Accessibility Tab](https://developer.chrome.com/docs/devtools/accessibility/reference#tab). @@ -564,7 +564,7 @@ Groups capture nested elements, such as `<details>` elements with summary conten ### Attributes and states -Commonly used ARIA attributes, like `checked`, `disabled`, `expanded`, `level`, `pressed`, and `selected`, represent +Commonly used ARIA attributes, like `checked`, `disabled`, `expanded`, `invalid`, `level`, `pressed`, and `selected`, represent control states. #### Checkbox with `checked` attribute @@ -586,3 +586,24 @@ control states. ```yaml title="aria snapshot" - button "Toggle" [pressed=true] ``` + +#### Input with `aria-invalid` attribute + +The `aria-invalid` value is surfaced directly. A value of `true` renders as `[invalid]`, while `grammar` +and `spelling` render as `[invalid=grammar]` and `[invalid=spelling]`. A `false` value is omitted. + +```html +<input type="text" aria-label="Email" aria-invalid="true" value="not-an-email"> +``` + +```yaml title="aria snapshot" +- textbox "Email" [invalid]: not-an-email +``` + +```html +<input type="text" aria-label="Bio" aria-invalid="spelling"> +``` + +```yaml title="aria snapshot" +- textbox "Bio" [invalid=spelling] +``` diff --git a/docs/src/electron-api/class-electron.md b/docs/src/electron-api/class-electron.md index 3c11689c40243..60e64080e0551 100644 --- a/docs/src/electron-api/class-electron.md +++ b/docs/src/electron-api/class-electron.md @@ -2,10 +2,16 @@ * since: v1.9 * langs: js -Playwright has **experimental** support for Electron automation, exposed as `_electron`. An example of the Electron automation script would be: +Playwright has **experimental** support for Electron automation. You can access electron namespace via: ```js -import { _electron as electron } from 'playwright'; +const { _electron } = require('playwright'); +``` + +An example of the Electron automation script would be: + +```js +const { _electron: electron } = require('playwright'); (async () => { // Launch Electron app. @@ -45,108 +51,33 @@ If you are not able to launch Electron and it will end up in timeouts during lau * Ensure that `nodeCliInspect` ([FuseV1Options.EnableNodeCliInspectArguments](https://www.electronjs.org/docs/latest/tutorial/fuses#nodecliinspect)) fuse is **not** set to `false`. -**Migrating from v1.59** - -A number of launch options have been removed after v1.59. See below for alternatives. +**Mocking native dialogs:** -* `recordHar` - use [`method: Tracing.startHar`]. - ```js - const electronApp = await electron.launch({ args: ['main.js'] }); - await electronApp.context().tracing.startHar('network.har'); - // ... drive the app ... - await electronApp.context().tracing.stopHar(); - await electronApp.close(); - ``` - -* `recordVideo` - use [`method: Screencast.start`] on each window. - ```js - const electronApp = await electron.launch({ args: ['main.js'] }); - const window = await electronApp.firstWindow(); - await window.screencast.start({ path: 'video.webm' }); - // ... drive the window ... - await window.screencast.stop(); - await electronApp.close(); - ``` +Playwright does not intercept the native Electron [dialog](https://www.electronjs.org/docs/latest/api/dialog) API +(`dialog.showOpenDialog`, `dialog.showSaveDialog`, `dialog.showMessageBox`, etc.) because those calls happen in the +Electron main process and go straight to OS APIs. Use [`method: ElectronApplication.evaluate`] to replace the +relevant methods in the main process so tests run deterministically without any OS-level UI: -* `colorScheme` - use [`method: Page.emulateMedia`] on each window. - ```js - const window = await electronApp.firstWindow(); - await window.emulateMedia({ colorScheme: 'dark' }); - ``` - -* `extraHTTPHeaders` - use [`method: BrowserContext.setExtraHTTPHeaders`]. - ```js - await electronApp.context().setExtraHTTPHeaders({ 'X-My-Header': 'value' }); - ``` - -* `geolocation` - use [`method: BrowserContext.setGeolocation`]. - ```js - await electronApp.context().setGeolocation({ latitude: 48.858455, longitude: 2.294474 }); - ``` - -* `httpCredentials` - use [`method: BrowserContext.setHTTPCredentials`]. - ```js - await electronApp.context().setHTTPCredentials({ username: 'user', password: 'pass' }); - ``` - -* `offline` - use [`method: BrowserContext.setOffline`]. - ```js - await electronApp.context().setOffline(true); - ``` - -* `bypassCSP` - disable CSP at the `BrowserWindow` level via Electron's [web preferences](https://www.electronjs.org/docs/latest/api/structures/web-preferences). Note that `webSecurity: false` also disables CORS and the Same-Origin Policy. - - ```js - const win = new BrowserWindow({ - webPreferences: { - webSecurity: false, - }, - }); - ``` - -* `ignoreHTTPSErrors` - - There are several ways to relax HTTPS checks in Electron. Pick the one that matches the scope you need. - - Per-window, allow mixed content through [web preferences](https://www.electronjs.org/docs/latest/api/structures/web-preferences): - - ```js - const win = new BrowserWindow({ - webPreferences: { - allowRunningInsecureContent: true, - }, - }); - ``` - - Process-wide, ignore certificate errors via Chromium command-line switches - (must run before the `ready` event): - - ```js - const { app } = require('electron'); - app.commandLine.appendSwitch('ignore-certificate-errors'); - // Optional: also ignore localhost certificate errors when testing on an IP. - app.commandLine.appendSwitch('allow-insecure-localhost', 'true'); - ``` - - Per-request, accept the certificate manually via the - [`certificate-error`](https://www.electronjs.org/docs/latest/api/app#event-certificate-error) - event: - - ```js - app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { - event.preventDefault(); - callback(true); - }); - ``` - -* `timezoneId` - set an environment variable at the very top of the main file, before any other logic or Chromium windows are initialized. - ```js - // main.js - process.env.TZ = 'Europe/London'; +```js +// Stub the open dialog to always return a fixed path. +await electronApp.evaluate(({ dialog }, filePaths) => { + dialog.showOpenDialog = () => Promise.resolve({ canceled: false, filePaths }); +}, ['/path/to/file.txt']); + +// Stub the save dialog. +await electronApp.evaluate(({ dialog }, filePath) => { + dialog.showSaveDialog = () => Promise.resolve({ canceled: false, filePath }); +}, '/path/to/saved.txt'); + +// Stub showMessageBox to click the first button. +await electronApp.evaluate(({ dialog }) => { + dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false }); +}); +``` - const { app } = require('electron'); - // ... rest of your app logic - ``` +The replacement persists until the application is closed. Synchronous variants +(`showOpenDialogSync`, `showSaveDialogSync`, `showMessageBoxSync`) can be stubbed the same way — just return the +value directly instead of a `Promise`. ## async method: Electron.launch * since: v1.9 @@ -186,5 +117,59 @@ Specifies environment variables that will be visible to Electron. Defaults to `p Maximum time in milliseconds to wait for the application to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. +### option: Electron.launch.acceptdownloads = %%-context-option-acceptdownloads-%% +* since: v1.12 + +### option: Electron.launch.bypassCSP = %%-context-option-bypasscsp-%% +* since: v1.12 + +### option: Electron.launch.colorScheme = %%-context-option-colorscheme-%% +* since: v1.12 + +### option: Electron.launch.extraHTTPHeaders = %%-context-option-extrahttpheaders-%% +* since: v1.12 + +### option: Electron.launch.geolocation = %%-context-option-geolocation-%% +* since: v1.12 + +### option: Electron.launch.httpcredentials = %%-context-option-httpcredentials-%% +* since: v1.12 + +### option: Electron.launch.ignoreHTTPSErrors = %%-context-option-ignorehttpserrors-%% +* since: v1.12 + +### option: Electron.launch.locale = %%-context-option-locale-%% +* since: v1.12 + +### option: Electron.launch.offline = %%-context-option-offline-%% +* since: v1.12 + +### option: Electron.launch.recordhar = %%-context-option-recordhar-%% +* since: v1.12 + +### option: Electron.launch.recordharpath = %%-context-option-recordhar-path-%% +* since: v1.12 + +### option: Electron.launch.recordHarOmitContent = %%-context-option-recordhar-omit-content-%% +* since: v1.12 + +### option: Electron.launch.recordvideo = %%-context-option-recordvideo-%% +* since: v1.12 + +### option: Electron.launch.recordvideodir = %%-context-option-recordvideo-dir-%% +* since: v1.12 + +### option: Electron.launch.recordvideosize = %%-context-option-recordvideo-size-%% +* since: v1.12 + +### option: Electron.launch.timezoneId = %%-context-option-timezoneid-%% +* since: v1.12 + +### option: Electron.launch.tracesDir = %%-browser-option-tracesdir-%% +* since: v1.36 + +### option: Electron.launch.artifactsDir = %%-browser-option-artifactsdir-%% +* since: v1.59 + ### option: Electron.launch.chromiumSandbox = %%-browser-option-chromiumsandbox-%% * since: v1.59 diff --git a/docs/src/electron-api/class-electronapplication.md b/docs/src/electron-api/class-electronapplication.md index 725eef0da6e67..87e7975b352d7 100644 --- a/docs/src/electron-api/class-electronapplication.md +++ b/docs/src/electron-api/class-electronapplication.md @@ -7,7 +7,7 @@ obtain the application instance. This instance you can control main electron pro as well as work with Electron windows: ```js -import { _electron as electron } from 'playwright'; +const { _electron: electron } = require('playwright'); (async () => { // Launch Electron app. @@ -85,16 +85,6 @@ Page to retrieve the window for. Closes Electron application. -### option: ElectronApplication.close.timeout -* since: v1.60 -- `timeout` <[float]> - -Maximum time in milliseconds to wait for the Electron application to gracefully close before forcefully terminating it. -By default, [`method: ElectronApplication.close`] waits indefinitely for the application to exit, which can hang if the -app has `before-quit` handlers that prevent shutdown, leaky IPC handlers, or child processes that keep it alive. When -specified, the underlying process is force-killed (SIGKILL on POSIX, `taskkill /T /F` on Windows) if it does not exit -within the given timeout. - ## method: ElectronApplication.context * since: v1.9 - returns: <[BrowserContext]> diff --git a/docs/src/release-notes-csharp.md b/docs/src/release-notes-csharp.md index 52a786b29ffae..f24cd9eaaa98b 100644 --- a/docs/src/release-notes-csharp.md +++ b/docs/src/release-notes-csharp.md @@ -6,6 +6,87 @@ toc_max_heading_level: 2 import LiteYouTube from '@site/src/components/LiteYouTube'; +## Version 1.60 + +### 🌐 HAR recording on Tracing + +[`method: Tracing.startHar`] / [`method: Tracing.stopHar`] expose HAR recording as a first-class tracing API, with the same `Content`, `Mode` and `UrlFilter` options as `RecordHar`: + +```csharp +await context.Tracing.StartHarAsync("trace.har"); +var page = await context.NewPageAsync(); +await page.GotoAsync("https://playwright.dev"); +await context.Tracing.StopHarAsync(); +``` + +### 🪝 Drop API + +New [`method: Locator.drop`] simulates an external drag-and-drop of files or clipboard-like data onto an element. Playwright dispatches `dragenter`, `dragover`, and `drop` with a synthetic [DataTransfer] in the page context — works cross-browser and is great for testing upload zones: + +```csharp +await page.Locator("#dropzone").DropAsync(new() { + Files = new FilePayload() { + Name = "note.txt", + MimeType = "text/plain", + Buffer = Encoding.UTF8.GetBytes("hello"), + }, +}); + +await page.Locator("#dropzone").DropAsync(new() { + Data = new Dictionary<string, string> { + ["text/plain"] = "hello world", + ["text/uri-list"] = "https://example.com", + }, +}); +``` + +### 🎯 Aria snapshots + +- [`method: PageAssertions.toMatchAriaSnapshot`] now works on a [Page], in addition to a [Locator] — equivalent to asserting against `Page.Locator("body")`. +- New `Boxes` option on [`method: Locator.ariaSnapshot`] / [`method: Page.ariaSnapshot`] appends each element's bounding box as `[box=x,y,width,height]`, useful for AI consumption. + +### New APIs + +#### Browser, Context and Page + +- Event [`event: Browser.context`] — fired when a new context is created on the browser. +- [BrowserContext] now mirrors lifecycle events from its pages: [`event: BrowserContext.download`], [`event: BrowserContext.frameAttached`], [`event: BrowserContext.frameDetached`], [`event: BrowserContext.frameNavigated`], [`event: BrowserContext.pageClose`], [`event: BrowserContext.pageLoad`]. + +#### Locators and Assertions + +- New option `Description` in [`method: Page.getByRole`] / [`method: Locator.getByRole`] / [`method: Frame.getByRole`] / [`method: FrameLocator.getByRole`] for matching the [accessible description](https://www.w3.org/TR/wai-aria-1.2/#dfn-accessible-description). +- New option `Pseudo` in [`method: LocatorAssertions.toHaveCSS`] reads computed styles from `::before` or `::after`. +- New option `Style` in [`method: Locator.highlight`] applies extra inline CSS to the highlight overlay, plus new [`method: Page.hideHighlight`] to clear all highlights. + +#### Network + +- [`method: WebSocketRoute.protocols`] returns the WebSocket subprotocols requested by the page. +- New option `NoDefaults` in [`method: BrowserType.connectOverCDP`] disables Playwright's default overrides on the default context (download behavior, focus emulation, media emulation), so attaching to a user's daily-driver browser doesn't disturb its state. + +#### Errors + +- New [`method: WebError.location`] mirrors [`method: ConsoleMessage.location`]. + +### 🛠️ Other improvements + +- Trace Viewer adds a pretty-print toggle for JSON / form request and response bodies in the network details panel. + +### Breaking Changes ⚠️ + +- Removed long-deprecated `Handle` option on `BrowserContext.ExposeBindingAsync` and `Page.ExposeBindingAsync`. + +### Browser Versions + +- Chromium 148.0.7778.96 +- Mozilla Firefox 150.0.2 +- WebKit 26.4 + +This version was also tested against the following stable channels: + +- Google Chrome 147 +- Microsoft Edge 147 + + ## Version 1.59 ### 🎬 Screencast diff --git a/docs/src/release-notes-java.md b/docs/src/release-notes-java.md index c2e9ee1e2457d..70497e4a725f9 100644 --- a/docs/src/release-notes-java.md +++ b/docs/src/release-notes-java.md @@ -6,6 +6,80 @@ toc_max_heading_level: 2 import LiteYouTube from '@site/src/components/LiteYouTube'; +## Version 1.60 + +### 🌐 HAR recording on Tracing + +[`method: Tracing.startHar`] / [`method: Tracing.stopHar`] expose HAR recording as a first-class tracing API, with the same `content`, `mode` and `urlFilter` options as `recordHar`: + +```java +context.tracing().startHar(Paths.get("trace.har")); +Page page = context.newPage(); +page.navigate("https://playwright.dev"); +context.tracing().stopHar(); +``` + +### 🪝 Drop API + +New [`method: Locator.drop`] simulates an external drag-and-drop of files or clipboard-like data onto an element. Playwright dispatches `dragenter`, `dragover`, and `drop` with a synthetic [DataTransfer] in the page context — works cross-browser and is great for testing upload zones: + +```java +page.locator("#dropzone").drop(new Locator.DropPayload() + .setFiles(new FilePayload("note.txt", "text/plain", "hello".getBytes(StandardCharsets.UTF_8)))); + +page.locator("#dropzone").drop(new Locator.DropPayload() + .setData(Map.of( + "text/plain", "hello world", + "text/uri-list", "https://example.com"))); +``` + +### 🎯 Aria snapshots + +- [`method: PageAssertions.toMatchAriaSnapshot`] now works on a [Page], in addition to a [Locator] — equivalent to asserting against `page.locator("body")`. +- New `boxes` option on [`method: Locator.ariaSnapshot`] / [`method: Page.ariaSnapshot`] appends each element's bounding box as `[box=x,y,width,height]`, useful for AI consumption. + +### New APIs + +#### Browser, Context and Page + +- Event [`event: Browser.context`] — fired when a new context is created on the browser. +- [BrowserContext] now mirrors lifecycle events from its pages: [`event: BrowserContext.download`], [`event: BrowserContext.frameAttached`], [`event: BrowserContext.frameDetached`], [`event: BrowserContext.frameNavigated`], [`event: BrowserContext.pageClose`], [`event: BrowserContext.pageLoad`]. + +#### Locators and Assertions + +- New option `description` in [`method: Page.getByRole`] / [`method: Locator.getByRole`] / [`method: Frame.getByRole`] / [`method: FrameLocator.getByRole`] for matching the [accessible description](https://www.w3.org/TR/wai-aria-1.2/#dfn-accessible-description). +- New option `pseudo` in [`method: LocatorAssertions.toHaveCSS`] reads computed styles from `::before` or `::after`. +- New option `style` in [`method: Locator.highlight`] applies extra inline CSS to the highlight overlay, plus new [`method: Page.hideHighlight`] to clear all highlights. + +#### Network + +- [`method: WebSocketRoute.protocols`] returns the WebSocket subprotocols requested by the page. +- New option `noDefaults` in [`method: BrowserType.connectOverCDP`] disables Playwright's default overrides on the default context (download behavior, focus emulation, media emulation), so attaching to a user's daily-driver browser doesn't disturb its state. + +#### Errors + +- New [`method: WebError.location`] mirrors [`method: ConsoleMessage.location`]. + +### 🛠️ Other improvements + +- Trace Viewer adds a pretty-print toggle for JSON / form request and response bodies in the network details panel. + +### Breaking Changes ⚠️ + +- Removed long-deprecated `handle` option on `BrowserContext.exposeBinding` and `Page.exposeBinding`. + +### Browser Versions + +- Chromium 148.0.7778.96 +- Mozilla Firefox 150.0.2 +- WebKit 26.4 + +This version was also tested against the following stable channels: + +- Google Chrome 147 +- Microsoft Edge 147 + + ## Version 1.59 ### 🎬 Screencast diff --git a/docs/src/release-notes-js.md b/docs/src/release-notes-js.md index fd86883c571c2..9e0454a7f491d 100644 --- a/docs/src/release-notes-js.md +++ b/docs/src/release-notes-js.md @@ -6,6 +6,113 @@ toc_max_heading_level: 2 import LiteYouTube from '@site/src/components/LiteYouTube'; +## Version 1.60 + +### 🌐 HAR recording on Tracing + +[`method: Tracing.startHar`] / [`method: Tracing.stopHar`] expose HAR recording as a first-class tracing API, with the same `content`, `mode` and `urlFilter` options as `recordHar`. The returned [Disposable] makes it easy to scope a recording with `await using`: + +```js +await using har = await context.tracing.startHar('trace.har'); +const page = await context.newPage(); +await page.goto('https://playwright.dev'); +// HAR is finalized when `har` goes out of scope. +``` + +### 🪝 Drop API + +New [`method: Locator.drop`] simulates an external drag-and-drop of files or clipboard-like data onto an element. Playwright dispatches `dragenter`, `dragover`, and `drop` with a synthetic [DataTransfer] in the page context — works cross-browser and is great for testing upload zones: + +```js +await page.locator('#dropzone').drop({ + files: { name: 'note.txt', mimeType: 'text/plain', buffer: Buffer.from('hello') }, +}); + +await page.locator('#dropzone').drop({ + data: { + 'text/plain': 'hello world', + 'text/uri-list': 'https://example.com', + }, +}); +``` + +### 🎯 Aria snapshots + +- [`method: PageAssertions.toMatchAriaSnapshot`] now works on a [Page], in addition to a [Locator] — equivalent to asserting against `page.locator('body')`. +- New `boxes` option on [`method: Locator.ariaSnapshot`] / [`method: Page.ariaSnapshot`] appends each element's bounding box as `[box=x,y,width,height]`, useful for AI consumption. + +### 🛑 test.abort() + +New [`method: Test.abort`] aborts the currently running test from a fixture, hook, or route handler with an optional message. Use it when you have detected an unrecoverable misuse and want to fail the test right away: + +```js +test('does not publish to the shared page', async ({ page }) => { + await page.route('**/publish', route => { + test.abort('Tests must not publish to the shared page. Use the `clone` option.'); + return route.abort(); + }); + // ... +}); +``` + +### New APIs + +#### Browser, Context and Page + +- Event [`event: Browser.context`] — fired when a new context is created on the browser. +- [BrowserContext] now mirrors lifecycle events from its pages: [`event: BrowserContext.download`], [`event: BrowserContext.frameAttached`], [`event: BrowserContext.frameDetached`], [`event: BrowserContext.frameNavigated`], [`event: BrowserContext.pageClose`], [`event: BrowserContext.pageLoad`]. + +#### Locators and Assertions + +- New option `description` in [`method: Page.getByRole`] / [`method: Locator.getByRole`] / [`method: Frame.getByRole`] / [`method: FrameLocator.getByRole`] for matching the [accessible description](https://www.w3.org/TR/wai-aria-1.2/#dfn-accessible-description). +- New option `pseudo` in [`method: LocatorAssertions.toHaveCSS`] reads computed styles from `::before` or `::after`. +- New option `style` in [`method: Locator.highlight`] applies extra inline CSS to the highlight overlay, plus new [`method: Page.hideHighlight`] to clear all highlights. + +#### Network + +- [`method: WebSocketRoute.protocols`] returns the WebSocket subprotocols requested by the page. +- New option `noDefaults` in [`method: BrowserType.connectOverCDP`] disables Playwright's default overrides on the default context (download behavior, focus emulation, media emulation), so attaching to a user's daily-driver browser doesn't disturb its state. + +#### Errors and Reporting + +- New [`method: WebError.location`] mirrors [`method: ConsoleMessage.location`]. +- [`method: ConsoleMessage.location`] now exposes `line` / `column` properties (`lineNumber` / `columnNumber` are deprecated). +- New [`property: TestInfoError.errorContext`] surfaces additional diagnostic context, such as the aria snapshot of the receiver at the time of an `expect(...)` matcher failure. +- [`method: Reporter.onError`] now receives a `workerInfo` argument with details about the worker for fixture teardown errors. + +#### Test runner + +- New `{testFileBaseName}` token in [`property: TestProject.snapshotPathTemplate`] — file name without extension. +- Test runner now errors when a config tries to override a non-option fixture, and rejects `workers: 0` or negative values. + +### 🛠️ Other improvements + +- HTML reporter: + - `npx playwright show-report` accepts `.zip` files directly — no need to unzip first. + - Steps that contain attachments inside nested children show an indicator on the parent step. + - The `repeatEachIndex` is shown in the test header when non-zero. +- Trace Viewer adds a pretty-print toggle for JSON / form request and response bodies in the network details panel. + +### Breaking Changes ⚠️ + +- Removed long-deprecated APIs: + - `Locator.ariaRef()` — use the standard [`method: Locator.ariaSnapshot`] pipeline. + - `handle` option on `BrowserContext.exposeBinding` and `Page.exposeBinding`. + - `logger` option on `BrowserType.connect` and `BrowserType.connectOverCDP` — use [tracing](./trace-viewer.md) instead. + - Context options `videosPath` / `videoSize` — use `recordVideo` instead. + +### Browser Versions + +- Chromium 148.0.7778.96 +- Mozilla Firefox 150.0.2 +- WebKit 26.4 + +This version was also tested against the following stable channels: + +- Google Chrome 147 +- Microsoft Edge 147 + + ## Version 1.59 ### 🎬 Screencast @@ -270,6 +377,7 @@ await using page = await context.newPage(); - Removed macOS 14 support for WebKit. We recommend upgrading your macOS version, or keeping an older Playwright version. - Removed `@playwright/experimental-ct-svelte` package. +- `junit` test reporter now differentiates between types of errors, so some of the previous `<failure>`s are now reported as `<error>`s. ### Browser Versions diff --git a/docs/src/release-notes-python.md b/docs/src/release-notes-python.md index ea012876c75ac..91dd0a1fed3c2 100644 --- a/docs/src/release-notes-python.md +++ b/docs/src/release-notes-python.md @@ -6,6 +6,84 @@ toc_max_heading_level: 2 import LiteYouTube from '@site/src/components/LiteYouTube'; +## Version 1.60 + +### 🌐 HAR recording on Tracing + +[`method: Tracing.startHar`] / [`method: Tracing.stopHar`] expose HAR recording as a first-class tracing API, with the same `content`, `mode` and `url_filter` options as `record_har`: + +```python +context.tracing.start_har("trace.har") +page = context.new_page() +page.goto("https://playwright.dev") +context.tracing.stop_har() +``` + +### 🪝 Drop API + +New [`method: Locator.drop`] simulates an external drag-and-drop of files or clipboard-like data onto an element. Playwright dispatches `dragenter`, `dragover`, and `drop` with a synthetic [DataTransfer] in the page context — works cross-browser and is great for testing upload zones: + +```python +page.locator("#dropzone").drop( + files={"name": "note.txt", "mime_type": "text/plain", "buffer": b"hello"}, +) + +page.locator("#dropzone").drop( + data={ + "text/plain": "hello world", + "text/uri-list": "https://example.com", + }, +) +``` + +### 🎯 Aria snapshots + +- [`method: PageAssertions.toMatchAriaSnapshot`] now works on a [Page], in addition to a [Locator] — equivalent to asserting against `page.locator("body")`. +- New `boxes` option on [`method: Locator.ariaSnapshot`] / [`method: Page.ariaSnapshot`] appends each element's bounding box as `[box=x,y,width,height]`, useful for AI consumption. + +### New APIs + +#### Browser, Context and Page + +- Event [`event: Browser.context`] — fired when a new context is created on the browser. +- [BrowserContext] now mirrors lifecycle events from its pages: [`event: BrowserContext.download`], [`event: BrowserContext.frameAttached`], [`event: BrowserContext.frameDetached`], [`event: BrowserContext.frameNavigated`], [`event: BrowserContext.pageClose`], [`event: BrowserContext.pageLoad`]. + +#### Locators and Assertions + +- New option `description` in [`method: Page.getByRole`] / [`method: Locator.getByRole`] / [`method: Frame.getByRole`] / [`method: FrameLocator.getByRole`] for matching the [accessible description](https://www.w3.org/TR/wai-aria-1.2/#dfn-accessible-description). +- New option `pseudo` in [`method: LocatorAssertions.toHaveCSS`] reads computed styles from `::before` or `::after`. +- New option `style` in [`method: Locator.highlight`] applies extra inline CSS to the highlight overlay, plus new [`method: Page.hideHighlight`] to clear all highlights. + +#### Network + +- [`method: WebSocketRoute.protocols`] returns the WebSocket subprotocols requested by the page. +- New option `no_defaults` in [`method: BrowserType.connectOverCDP`] disables Playwright's default overrides on the default context (download behavior, focus emulation, media emulation), so attaching to a user's daily-driver browser doesn't disturb its state. + +#### Errors + +- New [`method: WebError.location`] mirrors [`method: ConsoleMessage.location`]. +- [`method: ConsoleMessage.location`] now exposes `line` / `column` properties (`line_number` / `column_number` are deprecated). + +### 🛠️ Other improvements + +- Trace Viewer adds a pretty-print toggle for JSON / form request and response bodies in the network details panel. + +### Breaking Changes ⚠️ + +- Removed long-deprecated `handle` option on `BrowserContext.expose_binding` and `Page.expose_binding`. + +### Browser Versions + +- Chromium 148.0.7778.96 +- Mozilla Firefox 150.0.2 +- WebKit 26.4 + +This version was also tested against the following stable channels: + +- Google Chrome 147 +- Microsoft Edge 147 + + ## Version 1.59 ### 🎬 Screencast diff --git a/docs/src/running-tests-js.md b/docs/src/running-tests-js.md index 32223fdd0e76c..0925ef7db8001 100644 --- a/docs/src/running-tests-js.md +++ b/docs/src/running-tests-js.md @@ -91,6 +91,11 @@ To run only the tests that failed in the last test run, first run your tests and npx playwright test --last-failed ``` +Playwright stores the list of failed tests from the previous run in `<outputDir>/.last-run.json` (see [`property: TestConfig.outputDir`](./test-configuration.md)). To use a different file path, pass `--last-failed-file=<path>` or set `PLAYWRIGHT_LAST_RUN_OUTPUT_FILE`. + +```bash +npx playwright test --last-failed --last-failed-file=.cache/last-run-shard-1.json +``` ### Run tests in VS Code diff --git a/docs/src/test-agents-js.md b/docs/src/test-agents-js.md index 6ef76dd03d144..e1a7bc1f04842 100644 --- a/docs/src/test-agents-js.md +++ b/docs/src/test-agents-js.md @@ -39,6 +39,10 @@ npx playwright init-agents --loop=vscode npx playwright init-agents --loop=claude ``` +```bash tab=bash-codex +npx playwright init-agents --loop=codex +``` + ```bash tab=bash-opencode npx playwright init-agents --loop=opencode ``` diff --git a/docs/src/test-api/class-fullconfig.md b/docs/src/test-api/class-fullconfig.md index 7ce3da974bb71..e3097cb16fa8b 100644 --- a/docs/src/test-api/class-fullconfig.md +++ b/docs/src/test-api/class-fullconfig.md @@ -4,12 +4,29 @@ Resolved configuration which is accessible via [`property: TestInfo.config`] and is passed to the test reporters. To see the format of Playwright configuration file, please see [TestConfig] instead. +## property: FullConfig.argv +* since: v1.61 +- type: <[Array]<[string]>> + +Snapshot of [`process.argv`](https://nodejs.org/api/process.html#processargv) +captured in the runner process. Useful for reading custom command-line +arguments — for example, args supplied after the `--` separator +(`npx playwright test -- --build-path=./out`). Playwright does not parse +these; consumers are responsible for slicing and interpreting them with +any argument-parsing library. + ## property: FullConfig.configFile * since: v1.20 - type: ?<[string]> Path to the configuration file used to run the tests. The value is an empty string if no config file was used. +## property: FullConfig.failOnFlakyTests +* since: v1.61 +- type: <[boolean]> + +See [`property: TestConfig.failOnFlakyTests`]. + ## property: FullConfig.forbidOnly * since: v1.10 - type: <[boolean]> diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index 88b059a35a145..83cae0624a263 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -690,26 +690,8 @@ export default defineConfig({ }); ``` -## property: TestConfig.webServer +## property: TestConfig.webServer = %%-test-config-web-server-options-%% * since: v1.10 -- type: ?<[Object]|[Array]<[Object]>> - - `command` <[string]> Shell command to start. For example `npm run start`.. - - `cwd` ?<[string]> Current working directory of the spawned process, defaults to the directory of the configuration file. - - `env` ?<[Object]<[string], [string]>> Environment variables to set for the command, `process.env` by default. - - `gracefulShutdown` ?<[Object]> How to shut down the process. If unspecified, the process group is forcefully `SIGKILL`ed. If set to `{ signal: 'SIGTERM', timeout: 500 }`, the process group is sent a `SIGTERM` signal, followed by `SIGKILL` if it doesn't exit within 500ms. You can also use `SIGINT` as the signal instead. A `0` timeout means no `SIGKILL` will be sent. Windows doesn't support `SIGTERM` and `SIGINT` signals, so this option is ignored on Windows. Note that shutting down a Docker container requires `SIGTERM`. - - `signal` <["SIGINT"|"SIGTERM"]> - - `timeout` <[int]> - - `ignoreHTTPSErrors` ?<[boolean]> Whether to ignore HTTPS errors when fetching the `url`. Defaults to `false`. - - `name` ?<[string]> Specifies a custom name for the web server. This name will be prefixed to log messages. Defaults to `[WebServer]`. - - `port` ?<[int]> The port that your http server is expected to appear on. It does wait until it accepts connections. Either `port` or `url` should be specified. - - `reuseExistingServer` ?<[boolean]> If true, it will re-use an existing server on the `port` or `url` when available. If no server is running on that `port` or `url`, it will run the command to start a new server. If `false`, it will throw if an existing process is listening on the `port` or `url`. This should be commonly set to `!process.env.CI` to allow the local dev server when running tests locally. - - `stderr` ?<["pipe"|"ignore"]> Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to `"pipe"`. - - `stdout` ?<["pipe"|"ignore"]> If `"pipe"`, it will pipe the stdout of the command to the process stdout. If `"ignore"`, it will ignore the stdout of the command. Default to `"ignore"`. - - `wait` ?<[Object]> Consider command started only when given output has been produced. - - `stdout` ?<[RegExp]> Regular expression to wait for in the `stdout` of the command output. Named capture groups are stored in the environment, for example `/Listening on port (?<my_server_port>\d+)/` will store the port number in `process.env['MY_SERVER_PORT']`. - - `stderr` ?<[RegExp]> Regular expression to wait for in the `stderr` of the command output. Named capture groups are stored in the environment, for example `/Listening on port (?<my_server_port>\d+)/` will store the port number in `process.env['MY_SERVER_PORT']`. - - `timeout` ?<[int]> How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. - - `url` ?<[string]> The url on your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is checked. Either `port` or `url` should be specified. Launch a development web server (or multiple) during the tests. diff --git a/docs/src/test-api/class-testoptions.md b/docs/src/test-api/class-testoptions.md index fdd5b13cb73d3..813a37f3ace87 100644 --- a/docs/src/test-api/class-testoptions.md +++ b/docs/src/test-api/class-testoptions.md @@ -540,7 +540,8 @@ test('not signed in test', async ({ page }) => { ## property: TestOptions.testIdAttribute * since: v1.27 -Custom attribute to be used in [`method: Page.getByTestId`]. `data-testid` is used by default. +Custom attribute to be used in [`method: Page.getByTestId`]. `data-testid` is used by default. To match +elements with any of several attributes, pass them as a comma-separated list. **Usage** @@ -554,6 +555,18 @@ export default defineConfig({ }); ``` +Multiple attributes: + +```js title="playwright.config.ts" +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + use: { + testIdAttribute: 'data-pw,data-ti', + }, +}); +``` + ## property: TestOptions.timezoneId = %%-context-option-timezoneid-%% * since: v1.10 @@ -578,14 +591,16 @@ export default defineConfig({ - `snapshots` ?<[boolean]> Whether to capture DOM snapshot on every action. Defaults to true. Optional. - `sources` ?<[boolean]> Whether to include source files for trace actions. Defaults to true. Optional. -Whether to record trace for each test. Defaults to `'off'`. +Whether to record trace for each test. Defaults to `'off'`. The initial run of a test is the "first run"; subsequent runs caused by [retries](../test-retries.md) are "retries". * `'off'`: Do not record trace. -* `'on'`: Record trace for each test. -* `'on-first-retry'`: Record trace only when retrying a test for the first time. -* `'on-all-retries'`: Record trace only when retrying a test. -* `'retain-on-failure'`: Record trace for each test. When test run passes, remove the recorded trace. -* `'retain-on-first-failure'`: Record trace for the first run of each test, but not for retries. When test run passes, remove the recorded trace. -* `'retain-on-failure-and-retries'`: Record trace for each test run. Retains all traces when an attempt fails. +* `'on'`: Record and keep a trace for every run. +* `'on-first-retry'`: Record and keep a trace only for the first retry of a test. +* `'on-all-retries'`: Record and keep a trace for every retry. +* `'retain-on-failure'`: Record a trace for every run, but keep it only for runs that failed. A failed run's trace is kept even when a later retry passes. +* `'retain-on-first-failure'`: Record a trace only for the first run of a test (not for retries), and keep it only if that run failed. +* `'retain-on-failure-and-retries'`: Record a trace for every run, and keep it for any run that failed or that is a retry. + +See [trace modes](../test-use-options.md#trace-modes) for a side-by-side comparison of what each mode records and keeps. For more control, pass an object that specifies `mode` and trace features to enable. @@ -620,8 +635,8 @@ export default defineConfig({ ## property: TestOptions.video * since: v1.10 -- type: <[Object]|[VideoMode]<"off"|"on"|"retain-on-failure"|"on-first-retry">> - - `mode` <[VideoMode]<"off"|"on"|"retain-on-failure"|"on-first-retry">> Video recording mode. +- type: <[Object]|[VideoMode]<"off"|"on"|"retain-on-failure"|"on-first-retry"|"on-all-retries"|"retain-on-first-failure"|"retain-on-failure-and-retries">> + - `mode` <[VideoMode]<"off"|"on"|"retain-on-failure"|"on-first-retry"|"on-all-retries"|"retain-on-first-failure"|"retain-on-failure-and-retries">> Video recording mode. - `size` ?<[Object]> Size of the recorded video. Optional. - `width` <[int]> - `height` <[int]> @@ -635,11 +650,16 @@ export default defineConfig({ - `position` ?<[AnnotatePosition]<"top-left"|"top"|"top-right"|"bottom-left"|"bottom"|"bottom-right">> Position of the test information overlay. Defaults to `"top-left"`. - `fontSize` ?<[int]> Font size of the test information in pixels. Defaults to `14`. -Whether to record video for each test. Defaults to `'off'`. +Whether to record video for each test. Defaults to `'off'`. The initial run of a test is the "first run"; subsequent runs caused by [retries](../test-retries.md) are "retries". * `'off'`: Do not record video. -* `'on'`: Record video for each test. -* `'retain-on-failure'`: Record video for each test, but remove all videos from successful test runs. -* `'on-first-retry'`: Record video only when retrying a test for the first time. +* `'on'`: Record and keep a video for every run. +* `'on-first-retry'`: Record and keep a video only for the first retry of a test. +* `'on-all-retries'`: Record and keep a video for every retry. +* `'retain-on-failure'`: Record a video for every run, but keep it only for runs that failed. A failed run's video is kept even when a later retry passes. +* `'retain-on-first-failure'`: Record a video only for the first run of a test (not for retries), and keep it only if that run failed. +* `'retain-on-failure-and-retries'`: Record a video for every run, and keep it for any run that failed or that is a retry. + +See [video modes](../test-use-options.md#video-modes) for a side-by-side comparison of what each mode records and keeps. To control video size, pass an object with `mode` and `size` properties. If video size is not specified, it will be equal to [`property: TestOptions.viewport`] scaled down to fit into 800x800. If `viewport` is not configured explicitly the video size defaults to 800x450. Actual picture of each page will be scaled down if necessary to fit the specified size. diff --git a/docs/src/test-api/class-testproject.md b/docs/src/test-api/class-testproject.md index d301719c7c5eb..6cb2a98e147c7 100644 --- a/docs/src/test-api/class-testproject.md +++ b/docs/src/test-api/class-testproject.md @@ -99,6 +99,7 @@ export default defineConfig({ - `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: Page.screenshot.scale`] in [`method: Page.screenshot`]. Defaults to `"css"`. - `stylePath` ?<[string]|[Array]<[string]>> See [`option: Page.screenshot.style`] in [`method: Page.screenshot`]. - `pathTemplate` ?<[string]> A template controlling location of the screenshots. See [`property: TestProject.snapshotPathTemplate`] for details. + - `timeout` ?<[int]> Default timeout for [`method: PageAssertions.toHaveScreenshot#1`] in milliseconds, defaults to the global expect timeout. Setting to `0` disables the timeout. - `toMatchAriaSnapshot` ?<[Object]> Configuration for the [`method: LocatorAssertions.toMatchAriaSnapshot#2`] method. - `pathTemplate` ?<[string]> A template controlling location of the aria snapshots. See [`property: TestProject.snapshotPathTemplate`] for details. - `children` ?<["contain" | "equal" | "deep-equal"]> Controls how children of the snapshot root are matched against the actual accessibility tree. This is equivalent to adding a `/children` property at the top of every aria snapshot template. Individual snapshots can override this by including an explicit `/children` property. @@ -394,6 +395,48 @@ export default defineConfig({ Use [`property: TestConfig.use`] to change this option for all projects. +## property: TestProject.webServer = %%-test-config-web-server-options-%% +* since: v1.61 + +Launch a development web server (or multiple) before running tests in this project. See [`property: TestConfig.webServer`] for the shape of each entry. + +A per-project `webServer` is only launched when the project is selected (either directly via `--project` or indirectly through dependencies). This is useful when only a subset of your projects need a local backend, while others run against a deployed environment. + +Per-project web servers are launched in addition to any top-level [`property: TestConfig.webServer`]. + +**Usage** + +```js title="playwright.config.ts" +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + projects: [ + { + name: 'functional', + grepInvert: /@smoke/, + use: { baseURL: 'http://localhost:3000' }, + webServer: [ + { + command: 'npm run start', + url: 'http://localhost:3000', + reuseExistingServer: !process.env.CI, + }, + { + command: 'npm run mock-server', + port: 3001, + reuseExistingServer: !process.env.CI, + }, + ], + }, + { + name: 'smoke', + grep: /@smoke/, + use: { baseURL: 'https://production.app.com' }, + }, + ], +}); +``` + ## property: TestProject.workers * since: v1.52 - type: ?<[int]|[string]> diff --git a/docs/src/test-assertions-csharp-java-python.md b/docs/src/test-assertions-csharp-java-python.md index 9ae8a462d1bcc..4d19503115fa0 100644 --- a/docs/src/test-assertions-csharp-java-python.md +++ b/docs/src/test-assertions-csharp-java-python.md @@ -36,6 +36,28 @@ title: "Assertions" | [`method: PageAssertions.toHaveURL`] | Page has a URL | | [`method: APIResponseAssertions.toBeOK`] | Response has an OK status | +## Soft assertions +* langs: python + +By default, failed assertion will terminate test execution. Playwright also +supports *soft assertions*: failed soft assertions **do not** terminate test +execution, but mark the test as failed. + +```python +# Make a few checks that will not stop the test when failed... +expect.soft(page.get_by_test_id("status")).to_have_text("Success") +expect.soft(page.get_by_test_id("eta")).to_have_text("1 day") + +# ... and continue the test to check more things. +page.get_by_role("link", name="next page").click() +expect.soft(page.get_by_role("heading", name="Make another order")).to_be_visible() +``` + +Note that soft assertions only work with the +[`pytest-playwright`](https://pypi.org/project/pytest-playwright/) (or +[`pytest-playwright-asyncio`](https://pypi.org/project/pytest-playwright-asyncio/)) +plugin, version `0.7.3` or newer. + ## Custom Expect Message * langs: python, csharp diff --git a/docs/src/test-assertions-js.md b/docs/src/test-assertions-js.md index a1f2f8d727115..69edc341e887f 100644 --- a/docs/src/test-assertions-js.md +++ b/docs/src/test-assertions-js.md @@ -234,16 +234,24 @@ await expect.poll(async () => { }).toBe(200); ``` -You can combine `expect.configure({ soft: true })` with expect.poll to perform soft assertions in polling logic. +You can combine `expect.soft` with `expect.poll` to perform soft assertions in polling logic. This allows the test to continue even if the assertion inside poll fails. + +```js +await expect.soft.poll(async () => { + const response = await page.request.get('https://api.example.com'); + return response.status(); +}).toBe(200); +``` + +`expect.configure({ soft: true })` also chains with `expect.poll` and is useful when you want to reuse a configured instance. ```js const softExpect = expect.configure({ soft: true }); await softExpect.poll(async () => { const response = await page.request.get('https://api.example.com'); return response.status(); -}, {}).toBe(200); +}).toBe(200); ``` -This allows the test to continue even if the assertion inside poll fails. ## expect.toPass diff --git a/docs/src/test-cli-js.md b/docs/src/test-cli-js.md index fabc0f62fe8d6..85171da62fe4c 100644 --- a/docs/src/test-cli-js.md +++ b/docs/src/test-cli-js.md @@ -86,11 +86,12 @@ npx playwright test --ui | `--fully-parallel` | Run all tests in parallel (default: false). | | `--global-timeout <timeout>` | Maximum time this test suite can run in milliseconds (default: unlimited). | | `-g <grep>` or `--grep <grep>` | Only run tests matching this regular expression (default: ".*"). | -| `--grep-invert <grep>` | Only run tests that do not match this regular expression. | +| `-G <grep>` or `--grep-invert <grep>` | Only run tests that do not match this regular expression. | | `--headed` | Run tests in headed browsers (default: headless). | | `--ignore-snapshots` | Ignore screenshot and snapshot expectations. | | `-j <workers>` or `--workers <workers>` | Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%). | | `--last-failed` | Only re-run the failures. | +| `--last-failed-file <file>` | Override the default last-run JSON path for `--last-failed` (default: `<outputDir>/.last-run.json`). Same as `PLAYWRIGHT_LAST_RUN_OUTPUT_FILE` environment variable. | | `--list` | Collect all the tests and report them, but do not run. | | `--max-failures <N>` or `-x` | Stop after the first `N` failures. Passing `-x` stops after the first failure. | | `--no-deps` | Do not run project dependencies. | diff --git a/docs/src/test-reporters-js.md b/docs/src/test-reporters-js.md index 57d34a9bb4c45..184527e930003 100644 --- a/docs/src/test-reporters-js.md +++ b/docs/src/test-reporters-js.md @@ -70,7 +70,7 @@ export default defineConfig({ }); ``` -Here is an example output in the middle of a test run. Failures will be listed at the end. +Here is an example output in the middle of a test run. Failures will be listed at the end by default. ```bash npx playwright test --reporter=list Running 124 tests using 6 workers @@ -97,13 +97,25 @@ export default defineConfig({ }); ``` +You can print failures inline as soon as they are available instead of waiting until the end of the run: + +```js title="playwright.config.ts" +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + reporter: [['list', { printFailuresInline: true }]], +}); +``` + List report supports the following configuration options and environment variables: | Environment Variable Name | Reporter Config Option| Description | Default |---|---|---|---| | `PLAYWRIGHT_LIST_PRINT_STEPS` | `printSteps` | Whether to print each step on its own line. | `false` +| `PLAYWRIGHT_LIST_PRINT_FAILURES_INLINE` | `printFailuresInline` | Whether to print failure details immediately after a failed test instead of at the end. | `false` | `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. Supports `true`, `1`, `false`, `0`, `[WIDTH]`, and `[WIDTH]x[HEIGHT]`. `[WIDTH]` and `[WIDTH]x[HEIGHT]` specifies the TTY dimensions. | `true` when terminal is in TTY mode, `false` otherwise. | `FORCE_COLOR` | | Whether to produce colored output. | `true` when terminal is in TTY mode, `false` otherwise. +| `NO_COLOR` | | Whether to disable colored output ([no-color.org](https://no-color.org/)). Any non-empty value disables colors. | unset ### Line reporter @@ -142,6 +154,7 @@ Line report supports the following configuration options and environment variabl |---|---|---|---| | `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. Supports `true`, `1`, `false`, `0`, `[WIDTH]`, and `[WIDTH]x[HEIGHT]`. `[WIDTH]` and `[WIDTH]x[HEIGHT]` specifies the TTY dimensions. | `true` when terminal is in TTY mode, `false` otherwise. | `FORCE_COLOR` | | Whether to produce colored output. | `true` when terminal is in TTY mode, `false` otherwise. +| `NO_COLOR` | | Whether to disable colored output ([no-color.org](https://no-color.org/)). Any non-empty value disables colors. | unset ### Dot reporter @@ -184,6 +197,7 @@ Dot report supports the following configuration options and environment variable |---|---|---|---| | `PLAYWRIGHT_FORCE_TTY` | | Whether to produce output suitable for a live terminal. Supports `true`, `1`, `false`, `0`, `[WIDTH]`, and `[WIDTH]x[HEIGHT]`. `[WIDTH]` and `[WIDTH]x[HEIGHT]` specifies the TTY dimensions. | `true` when terminal is in TTY mode, `false` otherwise. | `FORCE_COLOR` | | Whether to produce colored output. | `true` when terminal is in TTY mode, `false` otherwise. +| `NO_COLOR` | | Whether to disable colored output ([no-color.org](https://no-color.org/)). Any non-empty value disables colors. | unset ### HTML reporter diff --git a/docs/src/test-use-options-js.md b/docs/src/test-use-options-js.md index 50c9246e8661d..a88d3a76d65e9 100644 --- a/docs/src/test-use-options-js.md +++ b/docs/src/test-use-options-js.md @@ -152,6 +152,57 @@ export default defineConfig({ | [`property: TestOptions.trace`] | Playwright can produce test traces while running the tests. Later on, you can view the trace and get detailed information about Playwright execution by opening [Trace Viewer](./trace-viewer.md). Options include: `'off'`, `'on'`, `'retain-on-failure'` and `'on-first-retry'` | | [`property: TestOptions.video`] | Playwright can record [videos](./videos.md) for your tests. Options include: `'off'`, `'on'`, `'retain-on-failure'` and `'on-first-retry'` | +#### Trace modes + +The `trace` option supports several modes that differ in **which runs are recorded** and **which recordings are kept** after the test finishes. The initial run of a test is the "first run"; subsequent runs caused by [retries](./test-retries.md) are "retries". + +| Mode | Records a trace on | Keeps the trace when | +| :- | :- | :- | +| `'off'` | never | — | +| `'on'` | every run | always | +| `'retain-on-failure'` | every run | that run failed | +| `'retain-on-first-failure'` | first run only | the first run failed | +| `'retain-on-failure-and-retries'` | every run | that run failed, or it is a retry | +| `'on-first-retry'` | first retry only | always | +| `'on-all-retries'` | every retry | always | + +The following table shows which traces are kept in a few common scenarios, assuming `retries: 2` is configured: + +| Mode | Passes on first run | Fails, then passes on retry | Fails on every run | +| :- | :- | :- | :- | +| `'off'` | — | — | — | +| `'on'` | first run | first run + retry | all three runs | +| `'retain-on-failure'` | — | first run | all three runs | +| `'retain-on-first-failure'` | — | first run | first run | +| `'retain-on-failure-and-retries'` | — | first run + retry | all three runs | +| `'on-first-retry'` | — | first retry | first retry | +| `'on-all-retries'` | — | first retry | both retries | + +#### Video modes + +The `video` option supports the same set of modes as `trace`, and they record and keep recordings using the same rules. + +| Mode | Records a video on | Keeps the video when | +| :- | :- | :- | +| `'off'` | never | — | +| `'on'` | every run | always | +| `'retain-on-failure'` | every run | that run failed | +| `'retain-on-first-failure'` | first run only | the first run failed | +| `'retain-on-failure-and-retries'` | every run | that run failed, or it is a retry | +| `'on-first-retry'` | first retry only | always | +| `'on-all-retries'` | every retry | always | + +The following table shows which videos are kept in a few common scenarios, assuming `retries: 2` is configured: + +| Mode | Passes on first run | Fails, then passes on retry | Fails on every run | +| :- | :- | :- | :- | +| `'off'` | — | — | — | +| `'on'` | first run | first run + retry | all three runs | +| `'retain-on-failure'` | — | first run | all three runs | +| `'retain-on-first-failure'` | — | first run | first run | +| `'retain-on-failure-and-retries'` | — | first run + retry | all three runs | +| `'on-first-retry'` | — | first retry | first retry | +| `'on-all-retries'` | — | first retry | both retries | ### Other Options diff --git a/docs/src/webview2.md b/docs/src/webview2.md index 7aef7216ca57b..6e8fc62b2fddc 100644 --- a/docs/src/webview2.md +++ b/docs/src/webview2.md @@ -68,8 +68,6 @@ By default, the WebView2 control will use the same user data directory for all i Using the following, Playwright will run your WebView2 application as a sub-process, assign a unique user data directory to it and provide the [Page] instance to your test: -<!-- source code is available here to verify that the examples are working https://github.com/mxschmitt/playwright-webview2-demo --> - ```js title="webView2Test.ts" import { test as base } from '@playwright/test'; import fs from 'fs'; diff --git a/examples/webauthn/register-and-login.mjs b/examples/webauthn/register-and-login.mjs new file mode 100644 index 0000000000000..23855358a3ed3 --- /dev/null +++ b/examples/webauthn/register-and-login.mjs @@ -0,0 +1,20 @@ +import { chromium } from 'playwright'; + +(async () => { + const browser = await chromium.launch({ headless: false, slowMo: 250 }); + const context = await browser.newContext(); + await context.credentials.install(); + const page = await context.newPage(); + await page.goto('https://webauthn.io/'); + await page.locator('#input-email').fill(`pw-demo-${Date.now()}`); + await page.locator('#register-button').click(); + await page.getByText(/success!.*try to authenticate/i).waitFor(); + + const seeded = await context.credentials.get(); + console.log(` ✓ registered: id=${seeded[0].id.substring(0, 12)}… rpId=${seeded[0].rpId}`); + + await page.locator('#login-button').click(); + await page.getByText(/you're logged in/i).waitFor(); + console.log(` ✓ authenticated`); + await browser.close(); +})(); diff --git a/examples/webauthn/seed-credential.mjs b/examples/webauthn/seed-credential.mjs new file mode 100644 index 0000000000000..b08d79d85ec50 --- /dev/null +++ b/examples/webauthn/seed-credential.mjs @@ -0,0 +1,39 @@ +// Demonstrates `context.credentials.create()` — seeding a pre-existing +// credential into a fresh context. +// +// In a real test suite the keypair would live in a fixture file (saved once +// after registering a stable test user). Here we synthesise it by registering +// in context A, then importing into context B to authenticate without any +// further UI interaction. + +import { chromium } from 'playwright'; + +(async () => { + const browser = await chromium.launch({ headless: false, slowMo: 250 }); + const username = `pw-demo-${Date.now()}`; + + // Context A: register so webauthn.io stores the credential server-side. + const contextA = await browser.newContext(); + await contextA.credentials.install(); + const pageA = await contextA.newPage(); + await pageA.goto('https://webauthn.io/'); + await pageA.locator('#input-email').fill(username); + await pageA.locator('#register-button').click(); + await pageA.getByText(/success!.*try to authenticate/i).waitFor(); + const [registered] = await contextA.credentials.get(); + await contextA.close(); + console.log(` ✓ registered ${username}: id=${registered.id.substring(0, 12)}…`); + + // Context B: seed the same credential. webauthn.io's home page issues a + // discoverable `navigator.credentials.get()` on load — the seeded credential + // satisfies it and the site logs us in with no clicks needed. + const contextB = await browser.newContext(); + await contextB.credentials.install(); + await contextB.credentials.create(registered); + const pageB = await contextB.newPage(); + await pageB.goto('https://webauthn.io/'); + await pageB.getByText(/you're logged in/i).waitFor(); + console.log(` ✓ authenticated with seeded credential (no UI)`); + + await browser.close(); +})(); diff --git a/examples/webauthn/user-verification.mjs b/examples/webauthn/user-verification.mjs new file mode 100644 index 0000000000000..eb681d8ec9e40 --- /dev/null +++ b/examples/webauthn/user-verification.mjs @@ -0,0 +1,41 @@ +// Demonstrates `context.credentials.setUserVerified()` — simulating a user +// refusing biometric verification (e.g. a wrong fingerprint). +// +// We configure webauthn.io to require user verification, then flip the +// authenticator's UV flag off and try to log in. The relying party sees +// UV=0 in the assertion flags and rejects the login. Flipping UV back on +// makes the next attempt succeed. + +import { chromium } from 'playwright'; + +(async () => { + const browser = await chromium.launch({ headless: false, slowMo: 250 }); + const context = await browser.newContext(); + await context.credentials.install(); + const page = await context.newPage(); + await page.goto('https://webauthn.io/'); + + // Force the relying party to require user verification at both ends. + await page.locator('button:has-text("Advanced Settings")').click(); + await page.locator('#optRegUserVerification').selectOption('required'); + await page.locator('#optAuthUserVerification').selectOption('required'); + + await page.locator('#input-email').fill(`pw-demo-${Date.now()}`); + await page.locator('#register-button').click(); + await page.getByText(/success!.*try to authenticate/i).waitFor(); + console.log(` ✓ registered (UV=required)`); + + // Simulate failed biometric — UV bit will be 0 in the next assertion. + await context.credentials.setUserVerified(false); + await page.locator('#login-button').click(); + await page.getByText(/authentication failed/i).waitFor(); + console.log(` ✓ login rejected: server got UV=0 but required UV=1`); + + // Recovery: biometric succeeds, UV=1 in the assertion. + await context.credentials.setUserVerified(true); + await page.locator('#login-button').click(); + await page.getByText(/you're logged in/i).waitFor(); + console.log(` ✓ login succeeded after UV restored`); + + await browser.close(); +})(); diff --git a/package-lock.json b/package-lock.json index 32534544916fa..a490a41d52f7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "playwright-internal", - "version": "1.60.0-next", + "version": "1.61.0-next", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "playwright-internal", - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "workspaces": [ "packages/*" @@ -64,7 +64,7 @@ "@types/react-dom": "^19.2.1", "@types/retry": "^0.12.5", "@types/source-map-support": "^0.5.4", - "@types/ws": "8.2.2", + "@types/ws": "8.18.1", "@types/xml2js": "^0.4.9", "@types/yauzl": "^2.10.3", "@types/yazl": "^2.4.2", @@ -83,7 +83,7 @@ "debug": "^4.3.4", "diff": "^8.0.3", "dotenv": "^16.4.5", - "electron": "^39.8.4", + "electron": "^40.10.2", "enquirer": "2.3.6", "esbuild": "^0.25.0", "eslint": "^9.34.0", @@ -121,7 +121,7 @@ "ws": "8.17.1", "xml2js": "^0.5.0", "yaml": "^2.8.3", - "yauzl": "3.2.1", + "yauzl": "3.3.2", "yazl": "2.5.1", "zod": "^4.3.6", "zod-to-json-schema": "^3.25.1" @@ -2044,10 +2044,6 @@ "resolved": "packages/dashboard", "link": true }, - "node_modules/@playwright/electron": { - "resolved": "packages/playwright-electron", - "link": true - }, "node_modules/@playwright/experimental-ct-core": { "resolved": "packages/playwright-ct-core", "link": true @@ -2785,9 +2781,9 @@ } }, "node_modules/@types/ws": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", - "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, "license": "MIT", "dependencies": { @@ -4433,15 +4429,15 @@ "license": "MIT" }, "node_modules/electron": { - "version": "39.8.4", - "resolved": "https://registry.npmjs.org/electron/-/electron-39.8.4.tgz", - "integrity": "sha512-eXYKxr4y+s31xs78keVJYg+XY20tGQMQzyIhZvc5L0XRDH2Gp08mbeFlbR1OjAeM5h5l/T2JYT2MFK2kYe2fMg==", + "version": "40.10.2", + "resolved": "https://registry.npmjs.org/electron/-/electron-40.10.2.tgz", + "integrity": "sha512-Xj3Hy0Imbu4g0gDIW55w/jJYz94nMO2JRSGYA3LyAn5SwaERCelgZrA21vfH+Bi//SWAWQXddHsMwCqauyMT8g==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@electron/get": "^2.0.0", - "@types/node": "^22.7.7", + "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { @@ -4457,19 +4453,19 @@ "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==" }, "node_modules/electron/node_modules/@types/node": { - "version": "22.18.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.1.tgz", - "integrity": "sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==", + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.16.0" } }, "node_modules/electron/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, @@ -5197,13 +5193,13 @@ } }, "node_modules/express-rate-limit": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", - "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.1.tgz", + "integrity": "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "10.0.1" + "ip-address": "^10.2.0" }, "engines": { "node": ">= 16" @@ -5282,9 +5278,9 @@ "dev": true }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -5867,9 +5863,9 @@ } }, "node_modules/hono": { - "version": "4.12.14", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz", - "integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==", + "version": "4.12.18", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", + "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", "dev": true, "license": "MIT", "engines": { @@ -6033,9 +6029,9 @@ } }, "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "engines": { @@ -7706,9 +7702,9 @@ } }, "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9512,13 +9508,12 @@ } }, "node_modules/yauzl": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.1.tgz", - "integrity": "sha512-k1isifdbpNSFEHFJ1ZY4YDewv0IH9FR61lDetaRMD3j2ae3bIXGV+7c+LHCqtQGofSd8PIyV4X6+dHMAnSr60A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.3.2.tgz", + "integrity": "sha512-Md9ankxxN23wncAN8s7+Tn3Co52zLUPMtnrLAbVCnfG5d2tKBFfmygYSgXlqFgXObtzIgqkx7aNgDBpso9+4qA==", "dev": true, "license": "MIT", "dependencies": { - "buffer-crc32": "~0.2.3", "pend": "~1.2.0" }, "engines": { @@ -9590,7 +9585,7 @@ }, "packages/extension": { "name": "@playwright/extension", - "version": "0.2.0", + "version": "0.2.1", "license": "Apache-2.0", "engines": { "node": ">=18" @@ -9600,10 +9595,10 @@ "version": "0.0.0" }, "packages/playwright": { - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "bin": { "playwright": "cli.js" @@ -9617,11 +9612,11 @@ }, "packages/playwright-browser-chromium": { "name": "@playwright/browser-chromium", - "version": "1.60.0-next", + "version": "1.61.0-next", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "engines": { "node": ">=18" @@ -9629,11 +9624,11 @@ }, "packages/playwright-browser-firefox": { "name": "@playwright/browser-firefox", - "version": "1.60.0-next", + "version": "1.61.0-next", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "engines": { "node": ">=18" @@ -9641,22 +9636,22 @@ }, "packages/playwright-browser-webkit": { "name": "@playwright/browser-webkit", - "version": "1.60.0-next", + "version": "1.61.0-next", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "engines": { "node": ">=18" } }, "packages/playwright-chromium": { - "version": "1.60.0-next", + "version": "1.61.0-next", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "bin": { "playwright": "cli.js" @@ -9676,14 +9671,14 @@ "version": "0.0.0", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "engines": { "node": ">=18" } }, "packages/playwright-core": { - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -9694,11 +9689,11 @@ }, "packages/playwright-ct-core": { "name": "@playwright/experimental-ct-core", - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "dependencies": { - "playwright": "1.60.0-next", - "playwright-core": "1.60.0-next", + "playwright": "1.61.0-next", + "playwright-core": "1.61.0-next", "vite": "^6.4.1" }, "engines": { @@ -9707,10 +9702,10 @@ }, "packages/playwright-ct-react": { "name": "@playwright/experimental-ct-react", - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "dependencies": { - "@playwright/experimental-ct-core": "1.60.0-next", + "@playwright/experimental-ct-core": "1.61.0-next", "@vitejs/plugin-react": "^4.2.1" }, "bin": { @@ -9722,10 +9717,10 @@ }, "packages/playwright-ct-react17": { "name": "@playwright/experimental-ct-react17", - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "dependencies": { - "@playwright/experimental-ct-core": "1.60.0-next", + "@playwright/experimental-ct-core": "1.61.0-next", "@vitejs/plugin-react": "^4.2.1" }, "bin": { @@ -9737,10 +9732,10 @@ }, "packages/playwright-ct-vue": { "name": "@playwright/experimental-ct-vue", - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "dependencies": { - "@playwright/experimental-ct-core": "1.60.0-next", + "@playwright/experimental-ct-core": "1.61.0-next", "@vitejs/plugin-vue": "^5.2.0" }, "bin": { @@ -9750,23 +9745,12 @@ "node": ">=18" } }, - "packages/playwright-electron": { - "name": "@playwright/electron", - "version": "0.0.0", - "license": "Apache-2.0", - "dependencies": { - "playwright": "*" - }, - "engines": { - "node": ">=18" - } - }, "packages/playwright-firefox": { - "version": "1.60.0-next", + "version": "1.61.0-next", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "bin": { "playwright": "cli.js" @@ -9777,10 +9761,10 @@ }, "packages/playwright-test": { "name": "@playwright/test", - "version": "1.60.0-next", + "version": "1.61.0-next", "license": "Apache-2.0", "dependencies": { - "playwright": "1.60.0-next" + "playwright": "1.61.0-next" }, "bin": { "playwright": "cli.js" @@ -9790,11 +9774,11 @@ } }, "packages/playwright-webkit": { - "version": "1.60.0-next", + "version": "1.61.0-next", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0-next" + "playwright-core": "1.61.0-next" }, "bin": { "playwright": "cli.js" diff --git a/package.json b/package.json index 9b26ef6399638..d7cf36693ecae 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "playwright-internal", "private": true, - "version": "1.60.0-next", + "version": "1.61.0-next", "description": "A high-level API to automate web browsers", "repository": { "type": "git", @@ -19,6 +19,7 @@ "ctest": "playwright test --config=tests/library/playwright.config.ts --project=chromium-*", "ftest": "playwright test --config=tests/library/playwright.config.ts --project=firefox-*", "wtest": "playwright test --config=tests/library/playwright.config.ts --project=webkit-*", + "wvtest": "playwright test --config=tests/webview/playwright.config.ts", "atest": "playwright test --config=tests/android/playwright.config.ts", "etest": "playwright test --config=tests/electron/playwright.config.ts", "itest": "playwright test --config=tests/installation/playwright.config.ts", @@ -105,7 +106,7 @@ "@types/react-dom": "^19.2.1", "@types/retry": "^0.12.5", "@types/source-map-support": "^0.5.4", - "@types/ws": "8.2.2", + "@types/ws": "8.18.1", "@types/xml2js": "^0.4.9", "@types/yauzl": "^2.10.3", "@types/yazl": "^2.4.2", @@ -124,7 +125,7 @@ "debug": "^4.3.4", "diff": "^8.0.3", "dotenv": "^16.4.5", - "electron": "^39.8.4", + "electron": "^40.10.2", "enquirer": "2.3.6", "esbuild": "^0.25.0", "eslint": "^9.34.0", @@ -162,7 +163,7 @@ "ws": "8.17.1", "xml2js": "^0.5.0", "yaml": "^2.8.3", - "yauzl": "3.2.1", + "yauzl": "3.3.2", "yazl": "2.5.1", "zod": "^4.3.6", "zod-to-json-schema": "^3.25.1" diff --git a/packages/dashboard/src/annotateView.tsx b/packages/dashboard/src/annotateView.tsx new file mode 100644 index 0000000000000..4eb339bf16c86 --- /dev/null +++ b/packages/dashboard/src/annotateView.tsx @@ -0,0 +1,221 @@ +/** + * 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 React from 'react'; +import { DownloadIcon } from './icons'; +import { Annotations } from './annotations'; +import { buildAnnotatedImage, saveAnnotationAsDownload } from './annotationImage'; +import { ToolbarButton } from '@web/components/toolbarButton'; + +import type { Annotation, AnnotationsHandle } from './annotations'; +import type { DashboardModel, AnnotateFrame } from './dashboardModel'; + +export type AnnotateSidebarProps = { + model: DashboardModel; + session: NonNullable<DashboardModel['state']['annotateSession']>; + onSubmit: () => Promise<void> | void; +}; + +export const AnnotateSidebar: React.FC<AnnotateSidebarProps> = ({ model, session, onSubmit }) => { + const [submitting, setSubmitting] = React.useState(false); + const [hoveredAnnotationId, setHoveredAnnotationId] = React.useState<string | null>(null); + + return ( + <aside className='annotate-sidebar' aria-label='Annotation screenshots'> + <div className='annotate-sidebar-header dashboard-shell-sidebar-header'> + <h2 className='dashboard-shell-sidebar-title'>UI Review</h2> + </div> + <div className='annotate-sidebar-list'> + {session.frames.map(frame => { + const selected = frame.id === session.selectedFrameId; + const comments = frame.annotations; + return ( + <div + key={frame.id} + className={'annotate-sidebar-thumb' + (selected ? ' selected' : '')} + > + <button + className='annotate-sidebar-thumb-button' + onClick={() => model.selectAnnotateFrame(frame.id)} + title={`${frame.sessionTitle || 'session'} · ${frame.title || 'tab'}\n${frame.url}`} + aria-pressed={selected} + > + <span + className='annotate-sidebar-thumb-img-wrap' + style={{ aspectRatio: `${frame.viewportWidth} / ${frame.viewportHeight}` }} + > + <img + className='annotate-sidebar-thumb-img' + alt='' + src={'data:image/png;base64,' + frame.data} + /> + {frame.annotations.map(a => ( + <span + key={a.id} + className={'annotate-sidebar-thumb-rect' + (a.id === hoveredAnnotationId ? ' hovered' : '')} + style={{ + left: `${(a.x / frame.viewportWidth) * 100}%`, + top: `${(a.y / frame.viewportHeight) * 100}%`, + width: `${(a.width / frame.viewportWidth) * 100}%`, + height: `${(a.height / frame.viewportHeight) * 100}%`, + ['--annotation-color' as any]: a.color, + }} + /> + ))} + </span> + </button> + {comments.length > 0 && ( + <ul className='annotate-sidebar-comments'> + {comments.map(a => ( + <li key={a.id}> + <button + className={'annotate-sidebar-comment' + (a.text ? '' : ' empty')} + style={{ '--annotation-color': a.color } as React.CSSProperties} + onClick={() => model.selectAnnotateFrame(frame.id, a.id)} + onMouseEnter={() => setHoveredAnnotationId(a.id)} + onMouseLeave={() => setHoveredAnnotationId(null)} + title='Edit comment' + > + {a.text || 'Empty comment'} + </button> + </li> + ))} + </ul> + )} + <ToolbarButton + className='annotate-sidebar-thumb-remove' + icon='close' + title='Remove screenshot' + onClick={e => { + e.stopPropagation(); + model.removeAnnotateFrame(frame.id); + }} + /> + </div> + ); + })} + </div> + <div + className='annotate-sidebar-feedback-wrap' + data-value={session.feedback} + > + <textarea + className='annotate-sidebar-feedback' + placeholder='Feedback…' + value={session.feedback} + onChange={e => model.updateFeedback(e.target.value)} + /> + </div> + <button + className='annotate-sidebar-submit' + disabled={submitting} + onClick={async () => { + setSubmitting(true); + try { + await onSubmit(); + } finally { + setSubmitting(false); + } + }} + > + {submitting ? 'Submitting…' : 'Submit'} + </button> + </aside> + ); +}; + +export type AnnotateOverlayProps = { + model: DashboardModel; + frame: AnnotateFrame; + focusAnnotationId?: string | null; +}; + +export const AnnotateOverlay: React.FC<AnnotateOverlayProps> = ({ model, frame, focusAnnotationId }) => { + const annotationsRef = React.useRef<AnnotationsHandle>(null); + const displayRef = React.useRef<HTMLImageElement>(null); + const containerRef = React.useRef<HTMLDivElement>(null); + + const onAnnotationsChange = React.useCallback((next: Annotation[]) => { + model.updateFrameAnnotations(frame.id, next); + }, [model, frame.id]); + + const onSave = React.useCallback(async () => { + const img = displayRef.current; + if (!img) + return; + const blob = await buildAnnotatedImage(img, frame.viewportWidth, frame.viewportHeight, frame.annotations); + if (!blob) + return; + const safe = (frame.title || frame.url || 'screenshot').replace(/[^a-z0-9]+/gi, '-').slice(0, 40) || 'screenshot'; + const stamp = new Date().toISOString().replace(/[:.]/g, '-'); + await saveAnnotationAsDownload(blob, `annotations-${stamp}-${safe}.png`); + }, [frame]); + + const onClear = React.useCallback(() => { + model.updateFrameAnnotations(frame.id, []); + annotationsRef.current?.clearSelection(); + }, [model, frame.id]); + + return ( + <div className='annotate-overlay' role='dialog' aria-label={`Annotate screenshot from ${frame.title || frame.url || 'page'}`}> + <div className='annotate-overlay-window'> + <div className='annotate-overlay-chrome'> + <span className='annotate-overlay-titlebar'> + <span className='annotate-overlay-title-text'>{frame.title || 'untitled'}</span> + <span className='annotate-overlay-title-sep'>·</span> + <span className='annotate-overlay-title-url'>{frame.url}</span> + </span> + <ToolbarButton + title='Save screenshot' + onClick={onSave} + > + <DownloadIcon /> + </ToolbarButton> + <ToolbarButton + title='Clear annotations' + icon='circle-slash' + disabled={frame.annotations.length === 0} + onClick={onClear} + /> + <ToolbarButton + title='Done annotating' + icon='check' + onClick={() => model.deselectFrame()} + /> + </div> + <div ref={containerRef} className='annotate-overlay-canvas'> + <img + ref={displayRef} + className='annotate-modal-image' + alt='annotation' + src={'data:image/png;base64,' + frame.data} + /> + <Annotations + ref={annotationsRef} + active={true} + displayRef={displayRef} + screenRef={containerRef} + viewportWidth={frame.viewportWidth} + viewportHeight={frame.viewportHeight} + annotations={frame.annotations} + onAnnotationsChange={onAnnotationsChange} + focusAnnotationId={focusAnnotationId} + /> + </div> + </div> + </div> + ); +}; diff --git a/packages/dashboard/src/annotationImage.ts b/packages/dashboard/src/annotationImage.ts new file mode 100644 index 0000000000000..2881aa2c49cce --- /dev/null +++ b/packages/dashboard/src/annotationImage.ts @@ -0,0 +1,108 @@ +/** + * 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. + */ + +export type RectAnnotation = { x: number; y: number; width: number; height: number; text: string; color: string }; + +export async function buildAnnotatedImage( + img: HTMLImageElement, + viewportWidth: number, + viewportHeight: number, + annotations: RectAnnotation[], +): Promise<Blob | null> { + if (!img.naturalWidth || !img.naturalHeight || !viewportWidth || !viewportHeight) + return null; + const canvas = document.createElement('canvas'); + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + const ctx = canvas.getContext('2d'); + if (!ctx) + return null; + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + const sx = canvas.width / viewportWidth; + const sy = canvas.height / viewportHeight; + const fontSize = Math.max(11, Math.round(14 * sy)); + ctx.font = `500 ${fontSize}px -apple-system, system-ui, sans-serif`; + ctx.textBaseline = 'middle'; + for (const a of annotations) { + const [r, g, b] = a.color.split(' ').map(Number); + const solid = `rgb(${r}, ${g}, ${b})`; + const wash = `rgba(${r}, ${g}, ${b}, 0.12)`; + const x = a.x * sx; + const y = a.y * sy; + const w = a.width * sx; + const h = a.height * sy; + ctx.fillStyle = wash; + ctx.fillRect(x, y, w, h); + ctx.lineWidth = Math.max(2, Math.round(2 * sy)); + ctx.strokeStyle = solid; + ctx.strokeRect(x, y, w, h); + if (a.text) { + const padX = Math.max(4, Math.round(6 * sy)); + const padY = Math.max(2, Math.round(3 * sy)); + const metrics = ctx.measureText(a.text); + const labelW = metrics.width + padX * 2; + const labelH = fontSize + padY * 2; + const labelX = x - ctx.lineWidth / 2; + const labelY = y - labelH; + ctx.fillStyle = solid; + ctx.fillRect(labelX, labelY, labelW, labelH); + ctx.fillStyle = '#fff'; + ctx.fillText(a.text, labelX + padX, labelY + labelH / 2); + } + } + return await new Promise<Blob | null>(resolve => canvas.toBlob(resolve, 'image/png')); +} + +export async function saveAnnotationAsDownload(blob: Blob, suggestedName?: string): Promise<boolean> { + const stamp = new Date().toISOString().replace(/[:.]/g, '-'); + const name = suggestedName ?? `annotations-${stamp}.png`; + const ext = (name.match(/\.[^./\\]+$/)?.[0] ?? '.bin').toLowerCase(); + const mime = blob.type || ({ + '.png': 'image/png', + '.zip': 'application/zip', + } as Record<string, string>)[ext] || 'application/octet-stream'; + const description = ({ + '.png': 'PNG image', + '.zip': 'Zip archive', + } as Record<string, string>)[ext] || 'File'; + const picker = (window as any).showSaveFilePicker as undefined | ((opts: any) => Promise<any>); + if (picker) { + try { + const handle = await picker({ + suggestedName: name, + startIn: 'downloads', + types: [{ description, accept: { [mime]: [ext] } }], + }); + const writable = await handle.createWritable(); + await writable.write(blob); + await writable.close(); + } catch (e: any) { + if (e?.name === 'AbortError') + return false; + throw e; + } + return true; + } + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = name; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + return true; +} diff --git a/packages/dashboard/src/annotationZip.ts b/packages/dashboard/src/annotationZip.ts new file mode 100644 index 0000000000000..bba3fe9e33ce0 --- /dev/null +++ b/packages/dashboard/src/annotationZip.ts @@ -0,0 +1,62 @@ +/** + * 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-ignore +import * as zipImport from '@zip.js/zip.js/lib/zip-no-worker-deflate.js'; + +import type * as zip from '@zip.js/zip.js'; +import type { SubmittedAnnotationFrame } from './dashboardChannel'; + +const zipjs = zipImport as typeof zip; + +export async function buildAnnotationZip(frames: SubmittedAnnotationFrame[], feedback: string): Promise<Blob> { + zipjs.configure({ useWebWorkers: false } as any); + const writer = new zipjs.ZipWriter(new zipjs.BlobWriter('application/zip')); + + const mdLines: string[] = []; + if (feedback) + mdLines.push(feedback, ''); + + for (let i = 0; i < frames.length; i++) { + const idx = i + 1; + const frame = frames[i]; + const session = frame.sessionTitle || 'session'; + const tab = frame.title || 'tab'; + const header = `screenshot ${idx}: ${session} / ${tab} @ ${frame.url} (${frame.viewportWidth}x${frame.viewportHeight})`; + + mdLines.push(`## ${header}`); + if (frame.data) { + const pngFile = `annotations-${idx}.png`; + await writer.add(pngFile, new zipjs.Uint8ArrayReader(Uint8Array.fromBase64(frame.data))); + mdLines.push(`- [Screenshot ${idx}](${pngFile})`); + } + if (frame.ariaSnapshot) { + const yamlFile = `annotations-${idx}.yaml`; + const annotationLines = frame.annotations.map(a => `# { x: ${a.x}, y: ${a.y}, width: ${a.width}, height: ${a.height} }: ${a.text}`); + const yamlContent = [...annotationLines, frame.ariaSnapshot].join('\n'); + await writer.add(yamlFile, new zipjs.TextReader(yamlContent)); + mdLines.push(`- [Aria snapshot ${idx}](${yamlFile})`); + } + for (const a of frame.annotations) { + if (a.text) + mdLines.push(`- { x: ${a.x}, y: ${a.y}, width: ${a.width}, height: ${a.height} }: ${a.text}`); + } + mdLines.push(''); + } + + await writer.add('feedback.md', new zipjs.TextReader(mdLines.join('\n'))); + return writer.close(); +} diff --git a/packages/dashboard/src/annotations.css b/packages/dashboard/src/annotations.css index 41bdfd35f4053..a6c9f75700fbf 100644 --- a/packages/dashboard/src/annotations.css +++ b/packages/dashboard/src/annotations.css @@ -232,3 +232,317 @@ -webkit-user-drag: none; box-shadow: 0 0 0 1px var(--color-border-muted), 0 0 8px var(--color-border-muted); } + + +/* -- Annotate sidebar -- */ +.annotate-sidebar { + width: 260px; + flex-shrink: 0; + display: flex; + flex-direction: column; + background: var(--color-canvas-subtle); + border-left: 1px solid var(--color-border-muted); + min-height: 0; +} + +.annotate-sidebar-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 6px; + height: 40px; + min-height: 40px; + padding: 0 8px; + border-bottom: 1px solid var(--color-border-muted); + background: var(--color-canvas-overlay); +} + +:root.light-mode .annotate-sidebar-header { + background: var(--color-canvas-subtle); +} + +.annotate-sidebar-list { + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 8px; + display: flex; + flex-direction: column; + gap: 6px; +} + +.annotate-sidebar-thumb { + position: relative; + flex-shrink: 0; + border: 1px solid var(--color-border-muted); + border-radius: 6px; + background: var(--color-canvas-default); + overflow: hidden; +} + +.annotate-sidebar-thumb:hover { + border-color: var(--color-border-default); +} + +.annotate-sidebar-thumb.selected { + border-color: var(--color-accent-fg, #2f81f7); + box-shadow: 0 0 0 1px var(--color-accent-fg, #2f81f7); +} + +.annotate-sidebar-thumb-button { + display: block; + width: 100%; + padding: 0; + background: transparent; + border: 0; + text-align: left; + color: inherit; + font: inherit; + cursor: pointer; +} + +.annotate-sidebar-thumb-img-wrap { + position: relative; + display: block; + width: 100%; + background: var(--color-canvas-overlay); + overflow: hidden; +} + +.annotate-sidebar-thumb-img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; +} + +.annotate-sidebar-thumb-overlay { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; +} + +.annotate-sidebar-thumb-rect { + position: absolute; + border: 1.5px solid rgb(var(--annotation-color)); + background: rgb(var(--annotation-color) / 0.12); + border-radius: 2px; + pointer-events: none; + box-sizing: border-box; +} + +.annotate-sidebar-thumb-rect.hovered { + background: rgb(var(--annotation-color) / 0.32); +} + +.annotate-sidebar-thumb-remove.toolbar-button { + position: absolute; + top: 4px; + right: 4px; + padding: 2px; + background: rgba(0, 0, 0, 0.55); + color: #fff; + border-radius: 50%; + opacity: 0; + transition: opacity 120ms ease; + z-index: 1; +} + +.annotate-sidebar-thumb-remove.toolbar-button:not(:disabled):hover { + background: rgba(0, 0, 0, 0.75); + color: #fff; +} + +.annotate-sidebar-thumb:hover .annotate-sidebar-thumb-remove, +.annotate-sidebar-thumb-remove:focus-visible { + opacity: 1; +} + +.annotate-sidebar-comments { + list-style: none; + margin: 0; + padding: 4px 8px 6px; + display: flex; + flex-direction: column; + gap: 3px; +} + +.annotate-sidebar-comment { + display: block; + width: 100%; + text-align: left; + background: rgb(var(--annotation-color) / 0.12); + border: 1px solid rgb(var(--annotation-color) / 0.35); + border-radius: 4px; + color: var(--color-fg-default); + font-size: 11px; + line-height: 1.4; + padding: 3px 6px; + cursor: pointer; + white-space: pre-wrap; + word-break: break-word; +} + +.annotate-sidebar-comment:hover { + background: rgb(var(--annotation-color) / 0.2); +} + +.annotate-sidebar-comment.empty { + color: var(--color-fg-muted); + font-style: italic; +} + +/* auto-grow textarea: the wrapper mirrors content in ::after so the grid row + expands to fit, and the textarea fills the same cell */ +.annotate-sidebar-feedback-wrap { + display: grid; + margin: 8px 8px 4px; + flex-shrink: 0; +} + +.annotate-sidebar-feedback-wrap::after { + content: attr(data-value) ' '; + white-space: pre-wrap; + word-break: break-word; + visibility: hidden; + /* same box-model as the textarea */ + padding: 6px 8px; + font-size: 12px; + font-family: inherit; + border: 1px solid transparent; + border-radius: 4px; + min-height: 56px; + grid-area: 1 / 1 / 2 / 2; +} + +.annotate-sidebar-feedback { + grid-area: 1 / 1 / 2 / 2; + padding: 6px 8px; + background: var(--vscode-input-background, #1e1e1e); + color: var(--vscode-input-foreground, #cccccc); + border: 1px solid var(--color-border-muted); + border-radius: 4px; + font-size: 12px; + font-family: inherit; + resize: none; + min-height: 56px; + overflow: hidden; + outline: none; +} + +.annotate-sidebar-feedback:focus { + border-color: var(--vscode-focusBorder, #007fd4); +} + +.annotate-sidebar-submit { + margin: 4px 8px 8px; + padding: 8px 12px; + background: var(--color-accent-fg, #2f81f7); + color: white; + border: 0; + border-radius: 6px; + cursor: pointer; + font-weight: 500; + font-size: 13px; + flex-shrink: 0; +} + +.annotate-sidebar-submit:hover:not(:disabled) { + filter: brightness(1.05); +} + +.annotate-sidebar-submit:disabled { + opacity: 0.55; + cursor: not-allowed; +} + +/* -- Annotate overlay (drawn on top of the live screen) -- */ +.annotate-overlay { + position: fixed; + inset: 0; + display: flex; + align-items: stretch; + justify-content: center; + padding: 16px; + background: rgba(0, 0, 0, 0.55); + z-index: 100; + min-height: 0; +} + +.annotate-overlay-window { + flex: 1; + display: flex; + flex-direction: column; + border: 1px solid var(--color-border-default); + border-radius: 10px; + overflow: hidden; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35); + background: var(--color-canvas-default); + min-height: 0; +} + +.annotate-overlay-chrome { + display: flex; + align-items: center; + gap: 4px; + height: 40px; + min-height: 40px; + padding: 0 8px; + background: var(--color-canvas-overlay); + border-bottom: 1px solid var(--color-border-muted); +} + +:root.light-mode .annotate-overlay-chrome { + background: var(--color-canvas-subtle); +} + +.annotate-overlay-titlebar { + flex: 1; + display: flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 4px; + font-size: 13px; + color: var(--color-fg-default); + min-width: 0; + overflow: hidden; + white-space: nowrap; +} + +.annotate-overlay-title-text { + font-weight: 500; + color: var(--color-fg-default); + overflow: hidden; + text-overflow: ellipsis; + flex-shrink: 0; + max-width: 40%; +} + +.annotate-overlay-title-sep { + color: var(--color-fg-subtle); +} + +.annotate-overlay-title-url { + flex: 1; + font-family: var(--monospace-font, monospace); + font-size: 12px; + color: var(--color-fg-muted); + overflow: hidden; + text-overflow: ellipsis; +} + +.annotate-overlay-canvas { + flex: 1; + position: relative; + display: flex; + align-items: center; + justify-content: center; + min-height: 0; + padding: 12px; + background: var(--color-canvas-default); +} + + diff --git a/packages/dashboard/src/annotations.tsx b/packages/dashboard/src/annotations.tsx index 5430e82cef82f..6d2a41ca44c57 100644 --- a/packages/dashboard/src/annotations.tsx +++ b/packages/dashboard/src/annotations.tsx @@ -17,15 +17,14 @@ import React from 'react'; import './modal.css'; import './annotations.css'; -import { DownloadIcon } from './icons'; -import { ToolbarButton } from '@web/components/toolbarButton'; import { clientToViewport, getImageLayout } from './imageLayout'; import type { ImageLayout } from './imageLayout'; -import type { AnnotateFrame } from './dashboardModel'; export type Annotation = { id: string; x: number; y: number; width: number; height: number; text: string; color: string }; +export { buildAnnotatedImage, saveAnnotationAsDownload } from './annotationImage'; + // Palette is 6 rgb triples — matches the `--annotations-blue` pattern so they // compose nicely via `rgb(var(--annotation-color))` / `rgb(var(...) / 0.12)`. const ANNOTATION_COLORS = [ @@ -103,90 +102,8 @@ function viewportRectToScreenStyle(layout: ImageLayout, screenRect: DOMRect, vw: }; } -export async function saveAnnotationAsDownload(blob: Blob): Promise<void> { - const stamp = new Date().toISOString().replace(/[:.]/g, '-'); - const suggestedName = `annotations-${stamp}.png`; - const picker = (window as any).showSaveFilePicker as undefined | ((opts: any) => Promise<any>); - if (picker) { - try { - const handle = await picker({ - suggestedName, - startIn: 'downloads', - types: [{ description: 'PNG image', accept: { 'image/png': ['.png'] } }], - }); - const writable = await handle.createWritable(); - await writable.write(blob); - await writable.close(); - } catch (e: any) { - if (e?.name !== 'AbortError') - throw e; - } - return; - } - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = suggestedName; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(url); -} - -export async function buildAnnotatedImage( - img: HTMLImageElement, - viewportWidth: number, - viewportHeight: number, - annotations: Annotation[], -): Promise<Blob | null> { - if (!img.naturalWidth || !img.naturalHeight || !viewportWidth || !viewportHeight) - return null; - const canvas = document.createElement('canvas'); - canvas.width = img.naturalWidth; - canvas.height = img.naturalHeight; - const ctx = canvas.getContext('2d'); - if (!ctx) - return null; - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - const sx = canvas.width / viewportWidth; - const sy = canvas.height / viewportHeight; - const fontSize = Math.max(11, Math.round(14 * sy)); - ctx.font = `500 ${fontSize}px -apple-system, system-ui, sans-serif`; - ctx.textBaseline = 'middle'; - for (const a of annotations) { - const [r, g, b] = a.color.split(' ').map(Number); - const solid = `rgb(${r}, ${g}, ${b})`; - const wash = `rgba(${r}, ${g}, ${b}, 0.12)`; - const x = a.x * sx; - const y = a.y * sy; - const w = a.width * sx; - const h = a.height * sy; - ctx.fillStyle = wash; - ctx.fillRect(x, y, w, h); - ctx.lineWidth = Math.max(2, Math.round(2 * sy)); - ctx.strokeStyle = solid; - ctx.strokeRect(x, y, w, h); - if (a.text) { - const padX = Math.max(4, Math.round(6 * sy)); - const padY = Math.max(2, Math.round(3 * sy)); - const metrics = ctx.measureText(a.text); - const labelW = metrics.width + padX * 2; - const labelH = fontSize + padY * 2; - const labelX = x - ctx.lineWidth / 2; - const labelY = y - labelH; - ctx.fillStyle = solid; - ctx.fillRect(labelX, labelY, labelW, labelH); - ctx.fillStyle = '#fff'; - ctx.fillText(a.text, labelX + padX, labelY + labelH / 2); - } - } - return await new Promise<Blob | null>(resolve => canvas.toBlob(resolve, 'image/png')); -} - export type AnnotationsHandle = { - clear(): void; - submit(): Promise<void>; - save(): Promise<void>; + clearSelection(): void; }; type AnnotationsProps = { @@ -195,8 +112,9 @@ type AnnotationsProps = { screenRef: React.RefObject<HTMLDivElement | null>; viewportWidth: number; viewportHeight: number; - onSubmit: (blob: Blob, annotations: Annotation[]) => Promise<void> | void; - onAnnotationsChange?: (count: number) => void; + annotations: Annotation[]; + onAnnotationsChange: (annotations: Annotation[]) => void; + focusAnnotationId?: string | null; }; const ColorPicker: React.FC<{ color: string; onChange: (color: string) => void }> = ({ color, onChange }) => ( @@ -216,8 +134,7 @@ const ColorPicker: React.FC<{ color: string; onChange: (color: string) => void } </div> ); -export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps>(({ active, displayRef, screenRef, viewportWidth, viewportHeight, onSubmit, onAnnotationsChange }, ref) => { - const [annotations, setAnnotations] = React.useState<Annotation[]>([]); +export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps>(({ active, displayRef, screenRef, viewportWidth, viewportHeight, annotations, onAnnotationsChange, focusAnnotationId }, ref) => { const [draft, setDraft] = React.useState<{ startX: number; startY: number; x: number; y: number } | null>(null); const [selection, setSelection] = React.useState<Selection>(null); const [drag, setDrag] = React.useState<DragState | null>(null); @@ -229,6 +146,14 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> const [, setTick] = React.useState(0); const forceRender = React.useCallback(() => setTick(t => t + 1), []); const layerRef = React.useRef<HTMLDivElement>(null); + // Refs kept in sync each render so effects can read current values without + // listing them as dependencies (avoids spurious effect re-runs). + const annotationsRef = React.useRef(annotations); + const focusAnnotationIdRef = React.useRef(focusAnnotationId); + React.useLayoutEffect(() => { + annotationsRef.current = annotations; + focusAnnotationIdRef.current = focusAnnotationId; + }); const selectedId = selection?.id ?? null; const editingId = selection?.editing ? selection.id : null; @@ -248,10 +173,20 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> }, [active, displayRef, forceRender]); React.useEffect(() => { - if (active) + if (active) { + const fid = focusAnnotationIdRef.current; + if (fid) { + const annotation = annotationsRef.current.find(a => a.id === fid); + if (annotation) { + setEditSnapshot({ ...annotation }); + setSelection({ id: fid, editing: true }); + return; + } + } layerRef.current?.focus(); - else + } else { setSelection(null); + } }, [active]); React.useEffect(() => { @@ -266,7 +201,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> const dvy = vp.y - drag.startVy; if (dvx === 0 && dvy === 0) return; - setAnnotations(prev => prev.map(a => a.id === drag.id ? { ...a, ...applyDrag(drag.orig, drag.kind, dvx, dvy) } : a)); + onAnnotationsChange(annotationsRef.current.map(a => a.id === drag.id ? { ...a, ...applyDrag(drag.orig, drag.kind, dvx, dvy) } : a)); }; const onUp = () => setDrag(null); window.addEventListener('mousemove', onMove); @@ -275,7 +210,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); }; - }, [drag, displayRef, viewportWidth, viewportHeight]); + }, [drag, displayRef, viewportWidth, viewportHeight, onAnnotationsChange]); function imgCoords(e: React.MouseEvent): { x: number; y: number } | null { if (!viewportWidth || !viewportHeight) @@ -333,7 +268,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> if (rect.width < MIN_ANNOTATION_SIZE || rect.height < MIN_ANNOTATION_SIZE) return; const id = newAnnotationId(); - setAnnotations(prev => [...prev, { id, ...rect, text: '', color: activeColor }]); + onAnnotationsChange([...annotations, { id, ...rect, text: '', color: activeColor }]); setSelection({ id, editing: true }); } @@ -351,7 +286,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> function nudgeSelected(dx: number, dy: number) { if (!selectedId) return; - setAnnotations(prev => prev.map(a => a.id === selectedId ? { ...a, x: a.x + dx, y: a.y + dy } : a)); + onAnnotationsChange(annotations.map(a => a.id === selectedId ? { ...a, x: a.x + dx, y: a.y + dy } : a)); } function closeEditor() { @@ -372,7 +307,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> } if ((e.key === 'Delete' || e.key === 'Backspace') && selectedId && !editingId) { e.preventDefault(); - setAnnotations(prev => prev.filter(a => a.id !== selectedId)); + onAnnotationsChange(annotations.filter(a => a.id !== selectedId)); setSelection(null); return; } @@ -385,10 +320,6 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> } } - React.useEffect(() => { - onAnnotationsChange?.(annotations.length); - }, [annotations.length, onAnnotationsChange]); - // Snapshot is only meaningful while an annotation is actively being edited. React.useEffect(() => { if (!editingId) @@ -396,33 +327,11 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> }, [editingId]); React.useImperativeHandle(ref, () => ({ - clear: () => { - setAnnotations([]); + clearSelection: () => { setDraft(null); setSelection(null); }, - submit: async () => { - const img = displayRef.current; - if (!img) - return; - const blob = await buildAnnotatedImage(img, viewportWidth, viewportHeight, annotations); - if (!blob) - return; - await onSubmit(blob, annotations); - setAnnotations([]); - setSelection(null); - setDraft(null); - }, - save: async () => { - const img = displayRef.current; - if (!img) - return; - const blob = await buildAnnotatedImage(img, viewportWidth, viewportHeight, annotations); - if (!blob) - return; - await saveAnnotationAsDownload(blob); - }, - }), [displayRef, viewportWidth, viewportHeight, annotations, onSubmit]); + }), []); if (!active) return null; @@ -515,11 +424,12 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> <textarea className='annotations-textarea' autoFocus + onFocus={e => { const len = e.target.value.length; e.target.setSelectionRange(len, len); }} value={editingAnnotation.text} placeholder='Task or comment…' onChange={e => { const text = e.target.value; - setAnnotations(prev => prev.map(a => a.id === editingAnnotation.id ? { ...a, text } : a)); + onAnnotationsChange(annotations.map(a => a.id === editingAnnotation.id ? { ...a, text } : a)); }} onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.metaKey) { @@ -537,7 +447,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> <ColorPicker color={editingAnnotation.color} onChange={color => { - setAnnotations(prev => prev.map(a => a.id === editingAnnotation.id ? { ...a, color } : a)); + onAnnotationsChange(annotations.map(a => a.id === editingAnnotation.id ? { ...a, color } : a)); setActiveColor(color); }} /> @@ -548,7 +458,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> className='annotations-action-btn' onClick={() => { const snap = editSnapshot; - setAnnotations(prev => prev.map(a => a.id === snap.id ? snap : a)); + onAnnotationsChange(annotations.map(a => a.id === snap.id ? snap : a)); setSelection(null); layerRef.current?.focus(); }} @@ -567,7 +477,7 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> <button className='annotations-action-btn danger' onClick={() => { - setAnnotations(prev => prev.filter(a => a.id !== editingAnnotation.id)); + onAnnotationsChange(annotations.filter(a => a.id !== editingAnnotation.id)); setSelection(null); layerRef.current?.focus(); }} @@ -592,70 +502,3 @@ export const Annotations = React.forwardRef<AnnotationsHandle, AnnotationsProps> ); }); Annotations.displayName = 'Annotations'; - -type AnnotateModalProps = { - frame: AnnotateFrame; - showSubmit: boolean; - onSubmit: (blob: Blob, annotations: Annotation[]) => Promise<void>; - onClose: () => void; -}; - -export const AnnotateModal: React.FC<AnnotateModalProps> = ({ frame, showSubmit, onSubmit, onClose }) => { - const [annotationCount, setAnnotationCount] = React.useState(0); - const annotationsRef = React.useRef<AnnotationsHandle>(null); - const displayRef = React.useRef<HTMLImageElement>(null); - const viewRef = React.useRef<HTMLDivElement>(null); - - return ( - <div className='modal-overlay' role='dialog' aria-modal='true' aria-label='Annotate screenshot'> - <div className='modal'> - <div className='modal-toolbar'> - <div className='modal-title'>Annotate screenshot</div> - {showSubmit && ( - <ToolbarButton - title='Submit annotation' - icon='check' - disabled={annotationCount === 0} - onClick={() => annotationsRef.current?.submit()} - /> - )} - <ToolbarButton - title='Save annotated image' - onClick={() => annotationsRef.current?.save()} - > - <DownloadIcon /> - </ToolbarButton> - <ToolbarButton - title='Clear annotations' - icon='circle-slash' - disabled={annotationCount === 0} - onClick={() => annotationsRef.current?.clear()} - /> - <ToolbarButton - title='Discard' - icon='close' - onClick={onClose} - /> - </div> - <div ref={viewRef} className='modal-body'> - <img - ref={displayRef} - className='annotate-modal-image' - alt='annotation' - src={'data:image/png;base64,' + frame.data} - /> - <Annotations - ref={annotationsRef} - active={true} - displayRef={displayRef} - screenRef={viewRef} - viewportWidth={frame.viewportWidth} - viewportHeight={frame.viewportHeight} - onSubmit={onSubmit} - onAnnotationsChange={setAnnotationCount} - /> - </div> - </div> - </div> - ); -}; diff --git a/packages/dashboard/src/dashboard.css b/packages/dashboard/src/dashboard.css index 4444e70521d0d..288a4fbdce08e 100644 --- a/packages/dashboard/src/dashboard.css +++ b/packages/dashboard/src/dashboard.css @@ -25,6 +25,18 @@ position: relative; } +.dashboard-view.has-annotate-sidebar { + flex-direction: row; +} + +.dashboard-main { + display: flex; + flex-direction: column; + flex: 1; + min-width: 0; + min-height: 0; +} + /* -- Mode toggle buttons (interactive / record) -- */ .mode-toggle.toolbar-button.toggled, .mode-toggle.toolbar-button.toggled > .codicon { diff --git a/packages/dashboard/src/dashboard.tsx b/packages/dashboard/src/dashboard.tsx index 184e536a20d87..d4a0adf380ba5 100644 --- a/packages/dashboard/src/dashboard.tsx +++ b/packages/dashboard/src/dashboard.tsx @@ -17,11 +17,10 @@ import React from 'react'; import './dashboard.css'; import { ChevronLeftIcon, ChevronRightIcon, LockIcon, LockOpenIcon, ReloadIcon, ScreenshotRegionIcon } from './icons'; -import { AnnotateModal } from './annotations'; import { clientToViewport, getImageLayout } from './imageLayout'; import { Recording } from './recording'; +import { AnnotateSidebar, AnnotateOverlay } from './annotateView'; -import type { Annotation } from './annotations'; import { ToolbarButton } from '@web/components/toolbarButton'; import { useMeasureForRef } from '@web/uiUtils'; @@ -67,8 +66,10 @@ export const Dashboard: React.FC<DashboardProps> = ({ model }) => { const [, setRevision] = React.useState(0); React.useEffect(() => model.subscribe(() => setRevision(r => r + 1)), [model]); - const { tabs, mode, recording, liveFrame, annotateFrame, annotateInitiator, pendingAnnotate } = model.state; + const { tabs, mode, recording, liveFrame, annotateSession, pendingCapture } = model.state; const interactive = mode === 'interactive'; + const annotateActive = !!annotateSession; + const selectedFrame = annotateSession?.frames.find(f => f.id === annotateSession.selectedFrameId) ?? null; const [flashTick, setFlashTick] = React.useState(0); @@ -131,17 +132,6 @@ export const Dashboard: React.FC<DashboardProps> = ({ model }) => { interactiveBtnRef.current?.classList.remove('flash'); }, [interactive]); - const onSubmitAnnotations = React.useCallback(async (blob: Blob, annotations: Annotation[]) => { - const dataUrl = await new Promise<string>((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result as string); - reader.onerror = () => reject(reader.error); - reader.readAsDataURL(blob); - }); - const data = dataUrl.slice(dataUrl.indexOf(',') + 1); - await model.submitAnnotation(data, annotations); - }, [model]); - function flashInteractiveHint() { setFlashTick(tick => tick + 1); } @@ -155,13 +145,6 @@ export const Dashboard: React.FC<DashboardProps> = ({ model }) => { model.discardRecording(); }, [model]); - const onCloseAnnotate = React.useCallback(() => { - if (annotateInitiator === 'cli') - model.completeAnnotation(); - else - model.cancelAnnotate(); - }, [model, annotateInitiator]); - const selectedTab = tabs?.find(t => t.selected); const ready = !!selectedTab; @@ -247,148 +230,162 @@ export const Dashboard: React.FC<DashboardProps> = ({ model }) => { const overlayText = selectedTab ? undefined : 'Select a session'; const isRecording = recording?.phase === 'recording'; - const showAnnotateModal = !!annotateFrame; const showRecording = recording?.phase === 'stopped'; - const modeLabel = showAnnotateModal ? 'Dashboard: annotate' : isRecording ? 'Dashboard: record' : 'Dashboard'; + const modeLabel = annotateActive ? 'Dashboard: annotate' : isRecording ? 'Dashboard: record' : 'Dashboard'; + const overlayOpen = !!selectedFrame; return ( - <main className={'dashboard-view' + (interactive ? ' interactive' : '')} aria-label={modeLabel}> - {/* Toolbar */} - <div ref={toolbarRef} className='toolbar'> - <ToolbarButton - ref={interactiveBtnRef} - className='mode-toggle mode-interactive' - title={interactive ? 'Disable interactive mode' : 'Enable interactive mode'} - toggled={interactive} - disabled={!ready} - onClick={() => { - if (interactive) - model.toggleInteractive(); - else - model.enterInteractive(); - }} - > - {interactive ? <LockOpenIcon /> : <LockIcon />} - </ToolbarButton> - <ToolbarButton - className='mode-annotate' - title='Annotate screenshot' - disabled={!ready || !!pendingAnnotate || showAnnotateModal} - onClick={() => model.enterAnnotate('user')} - > - <ScreenshotRegionIcon /> - </ToolbarButton> - <ToolbarButton - className='mode-toggle mode-record' - title={isRecording ? 'Stop recording' : 'Record video'} - icon='record' - toggled={isRecording} - disabled={!ready || showRecording} - onClick={() => { - if (isRecording) - model.stopRecording(); - else - model.startRecording(); - }} - > - {isRecording && <span className='mode-record-label'>Recording...</span>} - </ToolbarButton> - </div> + <main className={'dashboard-view' + (interactive ? ' interactive' : '') + (annotateActive ? ' has-annotate-sidebar' : '')} aria-label={modeLabel}> + <div className='dashboard-main'> + {/* Toolbar */} + <div ref={toolbarRef} className='toolbar' hidden={overlayOpen}> + <ToolbarButton + ref={interactiveBtnRef} + className='mode-toggle mode-interactive' + title={interactive ? 'Disable interactive mode' : 'Enable interactive mode'} + toggled={interactive} + disabled={!ready} + onClick={() => { + if (interactive) + model.toggleInteractive(); + else + model.enterInteractive(); + }} + > + {interactive ? <LockOpenIcon /> : <LockIcon />} + </ToolbarButton> + <ToolbarButton + className='mode-annotate' + title={annotateActive ? 'Add screenshot' : 'Take screenshot'} + disabled={!ready || pendingCapture} + onClick={() => { + if (annotateActive) + model.addAnnotateFrame(); + else + model.enterAnnotate('user'); + }} + > + <ScreenshotRegionIcon /> + </ToolbarButton> + <ToolbarButton + className='mode-toggle mode-record' + title={isRecording ? 'Stop recording' : 'Record video'} + icon='record' + toggled={isRecording} + disabled={!ready || showRecording} + onClick={() => { + if (isRecording) + model.stopRecording(); + else + model.startRecording(); + }} + > + {isRecording && <span className='mode-record-label'>Recording...</span>} + </ToolbarButton> + </div> - {/* Viewport */} - <div className='viewport-wrapper'> - <div ref={viewportMainRef} className='viewport-main'> - <div className='browser-window' style={windowStyle}> - {showBrowserChrome && ( - <div ref={browserChromeRef} className='browser-chrome'> - <button className='nav-btn' title='Back' aria-disabled={!interactive || undefined} onClick={() => { - if (!interactive) { - flashInteractiveHint(); - return; - } - model.back(); - }}> - <ChevronLeftIcon /> - </button> - <button className='nav-btn' title='Forward' aria-disabled={!interactive || undefined} onClick={() => { - if (!interactive) { - flashInteractiveHint(); - return; - } - model.forward(); - }}> - <ChevronRightIcon /> - </button> - <button className='nav-btn' title='Reload' aria-disabled={!interactive || undefined} onClick={() => { - if (!interactive) { - flashInteractiveHint(); - return; - } - model.reload(); - }}> - <ReloadIcon /> - </button> - <div className='omnibox-wrap'> - <input - id='omnibox' - className='omnibox' - type='text' - placeholder='Search or enter URL' - spellCheck={false} - autoComplete='off' - value={omniboxValue} - onChange={e => setOmniboxValue(e.target.value)} - onKeyDown={e => { - if (!interactive) - return; - onOmniboxKeyDown(e); - }} - onFocus={e => { - if (!interactive) { - flashInteractiveHint(); - e.target.blur(); - return; - } - e.target.select(); - }} - aria-disabled={!interactive || undefined} - readOnly={!interactive} - /> + {/* Viewport */} + <div className='viewport-wrapper'> + <div ref={viewportMainRef} className='viewport-main'> + <div className='browser-window' style={windowStyle}> + {showBrowserChrome && ( + <div ref={browserChromeRef} className='browser-chrome'> + <button className='nav-btn' title='Back' aria-disabled={!interactive || undefined} onClick={() => { + if (!interactive) { + flashInteractiveHint(); + return; + } + model.back(); + }}> + <ChevronLeftIcon /> + </button> + <button className='nav-btn' title='Forward' aria-disabled={!interactive || undefined} onClick={() => { + if (!interactive) { + flashInteractiveHint(); + return; + } + model.forward(); + }}> + <ChevronRightIcon /> + </button> + <button className='nav-btn' title='Reload' aria-disabled={!interactive || undefined} onClick={() => { + if (!interactive) { + flashInteractiveHint(); + return; + } + model.reload(); + }}> + <ReloadIcon /> + </button> + <div className='omnibox-wrap'> + <input + id='omnibox' + className='omnibox' + type='text' + placeholder='Search or enter URL' + spellCheck={false} + autoComplete='off' + value={omniboxValue} + onChange={e => setOmniboxValue(e.target.value)} + onKeyDown={e => { + if (!interactive) + return; + onOmniboxKeyDown(e); + }} + onFocus={e => { + if (!interactive) { + flashInteractiveHint(); + e.target.blur(); + return; + } + e.target.select(); + }} + aria-disabled={!interactive || undefined} + aria-label={interactive ? 'Search or enter URL' : 'URL input - enable interactive mode to use this field'} + readOnly={!interactive} + /> + </div> </div> + )} + <div + ref={screenRef} + className='screen' + tabIndex={0} + style={{ display: liveFrame ? '' : 'none' }} + onMouseDown={onScreenMouseDown} + onMouseUp={onScreenMouseUp} + onMouseMove={onScreenMouseMove} + onWheel={onScreenWheel} + onKeyDown={onScreenKeyDown} + onKeyUp={onScreenKeyUp} + onContextMenu={e => e.preventDefault()} + > + <img + ref={displayRef} + id='display' + className='display' + alt='screencast' + src={liveFrame ? 'data:image/jpeg;base64,' + liveFrame.data : undefined} + /> </div> - )} - <div - ref={screenRef} - className='screen' - tabIndex={0} - style={{ display: liveFrame ? '' : 'none' }} - onMouseDown={onScreenMouseDown} - onMouseUp={onScreenMouseUp} - onMouseMove={onScreenMouseMove} - onWheel={onScreenWheel} - onKeyDown={onScreenKeyDown} - onKeyUp={onScreenKeyUp} - onContextMenu={e => e.preventDefault()} - > - <img - ref={displayRef} - id='display' - className='display' - alt='screencast' - src={liveFrame ? 'data:image/jpeg;base64,' + liveFrame.data : undefined} - /> + {overlayText && <div className={'screen-overlay' + (liveFrame ? ' has-frame' : '')}><span>{overlayText}</span></div>} </div> - {overlayText && <div className={'screen-overlay' + (liveFrame ? ' has-frame' : '')}><span>{overlayText}</span></div>} </div> </div> </div> - - {showAnnotateModal && annotateFrame && ( - <AnnotateModal - frame={annotateFrame} - showSubmit={annotateInitiator === 'cli'} - onSubmit={onSubmitAnnotations} - onClose={onCloseAnnotate} + {selectedFrame && ( + <AnnotateOverlay + key={selectedFrame.id + (annotateSession?.focusAnnotationId ?? '')} + model={model} + frame={selectedFrame} + focusAnnotationId={annotateSession?.focusAnnotationId} + /> + )} + {annotateSession && ( + <AnnotateSidebar + model={model} + session={annotateSession} + onSubmit={() => model.submitAnnotateSession()} /> )} diff --git a/packages/dashboard/src/dashboardChannel.ts b/packages/dashboard/src/dashboardChannel.ts index 2fe3b8799ec91..b09fc47e66e20 100644 --- a/packages/dashboard/src/dashboardChannel.ts +++ b/packages/dashboard/src/dashboardChannel.ts @@ -32,6 +32,17 @@ export type Tab = { export type AnnotationData = { x: number; y: number; width: number; height: number; text: string }; +export type SubmittedAnnotationFrame = { + data: string; + ariaSnapshot: string; + annotations: AnnotationData[]; + sessionTitle: string; + title: string; + url: string; + viewportWidth: number; + viewportHeight: number; +}; + export type DashboardChannelEvents = { sessions: { sessions: SessionStatus[]; clientInfo: ClientInfo }; tabs: { tabs: Tab[] }; @@ -62,8 +73,9 @@ export interface DashboardChannel { startRecording(): Promise<void>; stopRecording(): Promise<{ streamId: string }>; readStream(params: { streamId: string }): Promise<{ data: string; eof: boolean }>; - screenshot(): Promise<{ data: string; viewportWidth: number; viewportHeight: number, ariaSnapshot: string }>; - submitAnnotation(params: { data: string | undefined; annotations: AnnotationData[], ariaSnapshot: string }): Promise<void>; + screenshot(): Promise<{ data: string; viewportWidth: number; viewportHeight: number; ariaSnapshot: string }>; + submitAnnotation(params: { frames: SubmittedAnnotationFrame[]; feedback: string }): Promise<void>; + cancelAnnotation(): Promise<void>; on<K extends keyof DashboardChannelEvents>(event: K, listener: (params: DashboardChannelEvents[K]) => void): void; off<K extends keyof DashboardChannelEvents>(event: K, listener: (params: DashboardChannelEvents[K]) => void): void; diff --git a/packages/dashboard/src/dashboardModel.ts b/packages/dashboard/src/dashboardModel.ts index 3896ab71d1da9..30f4c38bf04b9 100644 --- a/packages/dashboard/src/dashboardModel.ts +++ b/packages/dashboard/src/dashboardModel.ts @@ -14,8 +14,11 @@ * limitations under the License. */ +import { buildAnnotatedImage, saveAnnotationAsDownload } from './annotationImage'; +import { buildAnnotationZip } from './annotationZip'; + import type { Annotation } from './annotations'; -import type { DashboardChannel, DashboardChannelEvents, MouseButton, SessionStatus, Tab } from './dashboardChannel'; +import type { DashboardChannel, DashboardChannelEvents, MouseButton, SessionStatus, SubmittedAnnotationFrame, Tab } from './dashboardChannel'; import type { ClientInfo } from '../../playwright-core/src/tools/cli-client/registry'; import type { BrowserDescriptor } from '../../playwright-core/src/serverRegistry'; @@ -27,7 +30,25 @@ export type RecordingState = | { phase: 'recording' } | { phase: 'stopped'; blob: Blob; blobUrl: string }; -export type AnnotateFrame = { data: string; viewportWidth: number; viewportHeight: number; ariaSnapshot: string }; +export type AnnotateFrame = { + id: string; + data: string; + viewportWidth: number; + viewportHeight: number; + ariaSnapshot: string; + sessionTitle: string; + title: string; + url: string; + annotations: Annotation[]; +}; + +export type AnnotateSession = { + initiator: 'cli' | 'user'; + frames: AnnotateFrame[]; + selectedFrameId: string | null; + focusAnnotationId: string | null; + feedback: string; +}; export type DashboardState = { // Session model state. @@ -37,9 +58,8 @@ export type DashboardState = { // Dashboard / page state. tabs: Tab[] | null; liveFrame: DashboardChannelEvents['frame'] | undefined; - annotateFrame: AnnotateFrame | undefined; - pendingAnnotate: { initiator: 'cli' | 'user' } | null; - annotateInitiator: 'cli' | 'user' | null; + annotateSession: AnnotateSession | null; + pendingCapture: boolean; mode: Mode; recording: RecordingState | null; }; @@ -52,9 +72,8 @@ const initialState: DashboardState = { loadingSessions: true, tabs: null, liveFrame: undefined, - annotateFrame: undefined, - pendingAnnotate: null, - annotateInitiator: null, + annotateSession: null, + pendingCapture: false, mode: 'readonly', recording: null, }; @@ -74,7 +93,7 @@ export class DashboardModel { client.on('tabs', params => this._emit({ tabs: params.tabs })); client.on('frame', params => this._emit({ liveFrame: params })); client.on('annotate', () => this.enterAnnotate('cli')); - client.on('cancelAnnotate', () => this.cancelAnnotate()); + client.on('cancelAnnotate', () => this.cancelAnnotate(false)); } subscribe(listener: Listener): () => void { @@ -158,7 +177,10 @@ export class DashboardModel { toggleInteractive() { const next: Mode = this.state.mode === 'interactive' ? 'readonly' : 'interactive'; - this._emit({ mode: next }); + if (next === 'interactive') + void this._enterInteractive(); + else + this._emit({ mode: next }); } // Public action methods are sync fire-and-forget wrappers around the @@ -174,6 +196,62 @@ export class DashboardModel { void this._enterAnnotate(initiator); } + addAnnotateFrame() { + void this._addAnnotateFrame(); + } + + selectAnnotateFrame(id: string, focusAnnotationId?: string) { + const session = this.state.annotateSession; + if (!session || !session.frames.find(f => f.id === id)) + return; + this._emit({ annotateSession: { ...session, selectedFrameId: id, focusAnnotationId: focusAnnotationId ?? null }, mode: 'annotate' }); + } + + toggleSelectFrame(id: string) { + const session = this.state.annotateSession; + if (!session) + return; + if (session.selectedFrameId === id) + this._emit({ annotateSession: { ...session, selectedFrameId: null, focusAnnotationId: null }, mode: 'readonly' }); + else + this.selectAnnotateFrame(id); + } + + deselectFrame() { + const session = this.state.annotateSession; + if (!session || session.selectedFrameId === null) + return; + this._emit({ annotateSession: { ...session, selectedFrameId: null, focusAnnotationId: null }, mode: 'readonly' }); + } + + removeAnnotateFrame(id: string) { + const session = this.state.annotateSession; + if (!session) + return; + const frames = session.frames.filter(f => f.id !== id); + if (frames.length === 0) { + this.cancelAnnotate(); + return; + } + const selectedFrameId = session.selectedFrameId === id ? null : session.selectedFrameId; + this._emit({ annotateSession: { ...session, frames, selectedFrameId } }); + } + + updateFrameAnnotations(frameId: string, annotations: Annotation[]) { + const session = this.state.annotateSession; + if (!session) + return; + const frames = session.frames.map(f => f.id === frameId ? { ...f, annotations } : f); + this._emit({ annotateSession: { ...session, frames } }); + } + + updateFeedback(feedback: string) { + const session = this.state.annotateSession; + if (!session) + return; + this._emit({ annotateSession: { ...session, feedback } }); + } + completeAnnotation() { void this._completeAnnotation(); } @@ -190,47 +268,122 @@ export class DashboardModel { void this._discardRecording(); } - cancelAnnotate() { + cancelAnnotate(notifyServer = true) { this._requestId++; const s = this.state; + if (notifyServer && s.annotateSession?.initiator === 'cli') + void this._client.cancelAnnotation(); this._emit({ mode: s.mode === 'annotate' ? 'readonly' : s.mode, - annotateFrame: undefined, - pendingAnnotate: null, - annotateInitiator: null, + annotateSession: null, + pendingCapture: false, }); } - async submitAnnotation(data: string | undefined, annotations: Annotation[]) { - await this._client.submitAnnotation({ - data, - ariaSnapshot: this.state.annotateFrame?.ariaSnapshot ?? '', - annotations: annotations.map(a => ({ x: a.x, y: a.y, width: a.width, height: a.height, text: a.text })), - }); + async submitAnnotateSession() { + const session = this.state.annotateSession; + if (!session) + return; + const frames: SubmittedAnnotationFrame[] = []; + for (const frame of session.frames) { + const data = await renderFrameToBase64Png(frame); + frames.push({ + data: data ?? frame.data, + ariaSnapshot: frame.ariaSnapshot, + annotations: frame.annotations.map(a => ({ x: a.x, y: a.y, width: a.width, height: a.height, text: a.text })), + sessionTitle: frame.sessionTitle, + title: frame.title, + url: frame.url, + viewportWidth: frame.viewportWidth, + viewportHeight: frame.viewportHeight, + }); + } + if (session.initiator === 'cli') { + await this._client.submitAnnotation({ frames, feedback: session.feedback }); + } else { + const blob = await buildAnnotationZip(frames, session.feedback); + const stamp = new Date().toISOString().replace(/[:.]/g, '-'); + const saved = await saveAnnotationAsDownload(blob, `annotations-${stamp}.zip`); + if (!saved) + return; // user cancelled the file picker — keep the session open + } this.cancelAnnotate(); } private async _enterInteractive() { - // Interactive mode coexists with recording so the user can drive the - // page while it is being captured. Only in-flight annotation is cleared. - await this._completeAnnotation(); - this._emit({ mode: 'interactive' }); + const s = this.state; + // Interactive coexists with the annotate sidebar; only the overlay is + // dismissed so the live page is reachable. + this._emit({ + mode: 'interactive', + annotateSession: s.annotateSession?.selectedFrameId + ? { ...s.annotateSession, selectedFrameId: null, focusAnnotationId: null } + : s.annotateSession, + }); } private async _enterAnnotate(initiator: 'cli' | 'user') { - await this._cleanupOnModeSwitch(); - this._requestAnnotate(initiator); + const s = this.state; + if (s.annotateSession) { + // Session already open: capture another frame and select it. + if (initiator === 'cli' && s.annotateSession.initiator !== 'cli') + this._emit({ annotateSession: { ...s.annotateSession, initiator: 'cli' } }); + await this._addAnnotateFrame(); + return; + } + await this._discardRecording(); + await this._addAnnotateFrame(initiator); + } + + private async _addAnnotateFrame(initiator?: 'cli' | 'user') { + if (this.state.pendingCapture) + return; + const myId = ++this._requestId; + this._emit({ pendingCapture: true }); + let frameData: Awaited<ReturnType<DashboardChannel['screenshot']>> | undefined; + try { + frameData = await this._client.screenshot(); + } catch { + // ignore + } + if (myId !== this._requestId) + return; + if (!frameData) { + this._emit({ pendingCapture: false }); + return; + } + const selectedTab = this.state.tabs?.find(t => t.selected); + const sessionTitle = this.state.sessions.find(s => s.browser.guid === selectedTab?.browser)?.title ?? ''; + const frame: AnnotateFrame = { + id: 'frm-' + Math.random().toString(36).slice(2, 10), + data: frameData.data, + viewportWidth: frameData.viewportWidth, + viewportHeight: frameData.viewportHeight, + ariaSnapshot: frameData.ariaSnapshot, + sessionTitle, + title: selectedTab?.title ?? '', + url: selectedTab?.url ?? '', + annotations: [], + }; + const existing = this.state.annotateSession; + const session: AnnotateSession = existing + ? { ...existing, frames: [...existing.frames, frame], selectedFrameId: frame.id, focusAnnotationId: null } + : { initiator: initiator ?? 'user', frames: [frame], selectedFrameId: frame.id, focusAnnotationId: null, feedback: '' }; + this._emit({ annotateSession: session, pendingCapture: false, mode: 'annotate' }); } private async _completeAnnotation() { const s = this.state; - if (s.mode === 'annotate' && s.annotateInitiator === 'cli' && s.annotateFrame) - await this.submitAnnotation(undefined, []).catch(() => {}); - this.cancelAnnotate(); + if (s.annotateSession?.initiator === 'cli') + await this.submitAnnotateSession().catch(() => {}); + else + this.cancelAnnotate(); } private async _startRecording() { - await this._cleanupOnModeSwitch(); + // Recording closes any open annotate session. + if (this.state.annotateSession) + this.cancelAnnotate(); await this._client.startRecording(); this._emit({ recording: { phase: 'recording' } }); } @@ -269,52 +422,6 @@ export class DashboardModel { this._emit({ recording: null }); } - private async _cleanupOnModeSwitch() { - await this._discardRecording(); - await this._completeAnnotation(); - } - - private _requestAnnotate(initiator: 'cli' | 'user') { - const s = this.state; - if (s.mode === 'annotate') { - if (initiator === 'cli' && s.annotateInitiator !== 'cli') - this._emit({ annotateInitiator: 'cli' }); - return; - } - if (s.pendingAnnotate) { - if (initiator === 'cli' && s.pendingAnnotate.initiator !== 'cli') - this._emit({ pendingAnnotate: { initiator: 'cli' } }); - return; - } - const myId = ++this._requestId; - this._emit({ pendingAnnotate: { initiator } }); - void this._fetchScreenshot(myId); - } - - private async _fetchScreenshot(id: number) { - let frame: AnnotateFrame | undefined; - try { - frame = await this._client.screenshot(); - } catch { - // frame stays undefined - } - if (id !== this._requestId) - return; - const s = this.state; - if (!s.pendingAnnotate) - return; - if (!frame) { - this._emit({ pendingAnnotate: null }); - return; - } - this._emit({ - mode: 'annotate', - annotateFrame: frame, - annotateInitiator: s.pendingAnnotate.initiator, - pendingAnnotate: null, - }); - } - private _emit(partial: Partial<DashboardState>) { this.state = { ...this.state, ...partial }; for (const listener of this._listeners) @@ -322,6 +429,21 @@ export class DashboardModel { } } +async function renderFrameToBase64Png(frame: AnnotateFrame): Promise<string | undefined> { + const img = new Image(); + img.src = 'data:image/png;base64,' + frame.data; + try { + await img.decode(); + } catch { + return undefined; + } + const blob = await buildAnnotatedImage(img, frame.viewportWidth, frame.viewportHeight, frame.annotations); + if (!blob) + return undefined; + const buf = await blob.arrayBuffer(); + return new Uint8Array(buf).toBase64(); +} + function base64ToBlob(base64: string, mime: string): Blob { - return new Blob([(Uint8Array as any).fromBase64(base64)], { type: mime }); + return new Blob([Uint8Array.fromBase64(base64)], { type: mime }); } diff --git a/packages/extension/manifest.json b/packages/extension/manifest.json index 19a2c399b62b3..dec34378cfd07 100644 --- a/packages/extension/manifest.json +++ b/packages/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Playwright Extension", - "version": "0.2.0", + "version": "0.2.1", "description": "Connect your browser to AI agents through Playwright MCP server and CLI. Enables AI-driven web testing, debugging, and automation.", "permissions": [ "debugger", diff --git a/packages/extension/package.json b/packages/extension/package.json index 4a269e08b28a2..3a3ef1b47b9d7 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,6 +1,6 @@ { "name": "@playwright/extension", - "version": "0.2.0", + "version": "0.2.1", "description": "Playwright Browser Extension", "private": true, "repository": { diff --git a/packages/extension/vite.config.mts b/packages/extension/vite.config.mts index 89ec56c6898a2..01bc27c9c3847 100644 --- a/packages/extension/vite.config.mts +++ b/packages/extension/vite.config.mts @@ -19,7 +19,6 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { viteStaticCopy } from 'vite-plugin-static-copy'; -// https://vitejs.dev/config/ export default defineConfig({ plugins: [ react(), @@ -37,17 +36,35 @@ export default defineConfig({ }) ], root: resolve(__dirname, 'src/ui'), - build: { - outDir: resolve(__dirname, 'dist/'), - emptyOutDir: false, - minify: false, - rollupOptions: { - input: ['src/ui/connect.html', 'src/ui/status.html'], - output: { - manualChunks: undefined, - entryFileNames: 'lib/ui/[name].js', - chunkFileNames: 'lib/ui/[name].js', - assetFileNames: 'lib/ui/[name].[ext]' + builder: {}, + environments: { + client: { + build: { + outDir: resolve(__dirname, 'dist/'), + emptyOutDir: false, + minify: false, + rollupOptions: { + input: ['src/ui/connect.html', 'src/ui/status.html'], + output: { + manualChunks: undefined, + entryFileNames: 'lib/ui/[name].js', + chunkFileNames: 'lib/ui/[name].js', + assetFileNames: 'lib/ui/[name].[ext]' + } + } + } + }, + sw: { + consumer: 'client', + build: { + outDir: resolve(__dirname, 'dist/'), + emptyOutDir: false, + minify: false, + lib: { + entry: resolve(__dirname, 'src/background.ts'), + fileName: 'lib/background', + formats: ['es'] + } } } } diff --git a/packages/extension/vite.sw.config.mts b/packages/extension/vite.sw.config.mts deleted file mode 100644 index a383e4b4a50e9..0000000000000 --- a/packages/extension/vite.sw.config.mts +++ /dev/null @@ -1,31 +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. - */ - -import { resolve } from 'path'; -import { defineConfig } from 'vite'; - -export default defineConfig({ - build: { - lib: { - entry: resolve(__dirname, 'src/background.ts'), - fileName: 'lib/background', - formats: ['es'] - }, - outDir: 'dist', - emptyOutDir: false, - minify: false - } -}); diff --git a/packages/html-reporter/src/gantt.tsx b/packages/html-reporter/src/gantt.tsx index de875e87101cb..0151773157beb 100644 --- a/packages/html-reporter/src/gantt.tsx +++ b/packages/html-reporter/src/gantt.tsx @@ -157,7 +157,6 @@ export const GanttChart = ({ height={barHeight} fill={color} rx='2' - tabIndex={0} > <title>{entry.tooltip} diff --git a/packages/html-reporter/src/tabbedPane.tsx b/packages/html-reporter/src/tabbedPane.tsx index a1e533348b873..76dc35c2d3c90 100644 --- a/packages/html-reporter/src/tabbedPane.tsx +++ b/packages/html-reporter/src/tabbedPane.tsx @@ -32,16 +32,40 @@ export const TabbedPane: React.FunctionComponent<{ setSelectedTab: (tab: string) => void }> = ({ tabs, selectedTab, setSelectedTab }) => { const idPrefix = React.useId(); + const tabStripRef = React.useRef(null); + + const handleKeyDown = (e: React.KeyboardEvent) => { + const tabElements = Array.from(tabStripRef.current?.querySelectorAll('[role="tab"]') ?? []) as HTMLElement[]; + const currentIndex = tabElements.findIndex(el => el === document.activeElement); + if (currentIndex === -1) + return; + let nextIndex = currentIndex; + if (e.key === 'ArrowRight') + nextIndex = (currentIndex + 1) % tabElements.length; + else if (e.key === 'ArrowLeft') + nextIndex = (currentIndex - 1 + tabElements.length) % tabElements.length; + else if (e.key === 'Home') + nextIndex = 0; + else if (e.key === 'End') + nextIndex = tabElements.length - 1; + else + return; + e.preventDefault(); + tabElements[nextIndex].focus(); + setSelectedTab(tabs[nextIndex].id); + }; + return
-
{ +
{ tabs.map(tab => (
setSelectedTab(tab.id)} id={`${idPrefix}-${tab.id}`} key={tab.id} role='tab' + tabIndex={selectedTab === tab.id ? 0 : -1} aria-selected={selectedTab === tab.id}>
{tab.title}
diff --git a/packages/injected/src/ariaSnapshot.ts b/packages/injected/src/ariaSnapshot.ts index 17b438dc13616..d99727d47640f 100644 --- a/packages/injected/src/ariaSnapshot.ts +++ b/packages/injected/src/ariaSnapshot.ts @@ -270,6 +270,11 @@ function toAriaNode(element: Element, options: InternalOptions): aria.AriaNode | if (roleUtils.kAriaExpandedRoles.includes(role)) result.expanded = roleUtils.getAriaExpanded(element); + if (roleUtils.kAriaInvalidRoles.includes(role)) { + const invalid = roleUtils.getAriaInvalid(element); + result.invalid = invalid === 'false' ? false : invalid === 'true' ? true : invalid; + } + if (roleUtils.kAriaLevelRoles.includes(role)) result.level = roleUtils.getAriaLevel(element); @@ -423,6 +428,8 @@ function matchesNode(node: aria.AriaNode | string, template: aria.AriaTemplateNo return false; if (template.expanded !== undefined && template.expanded !== node.expanded) return false; + if (template.invalid !== undefined && template.invalid !== node.invalid) + return false; if (template.level !== undefined && template.level !== node.level) return false; if (template.pressed !== undefined && template.pressed !== node.pressed) @@ -614,6 +621,10 @@ export function renderAriaTree(ariaSnapshot: AriaSnapshot, publicOptions: AriaTr key += ` [expanded]`; if (ariaNode.active && options.renderActive) key += ` [active]`; + if (ariaNode.invalid === 'grammar' || ariaNode.invalid === 'spelling') + key += ` [invalid=${ariaNode.invalid}]`; + if (ariaNode.invalid === true) + key += ` [invalid]`; if (ariaNode.level) key += ` [level=${ariaNode.level}]`; if (ariaNode.pressed === 'mixed') diff --git a/packages/injected/src/highlight.css b/packages/injected/src/highlight.css index bfa4ee6e19754..61a376f4eb502 100644 --- a/packages/injected/src/highlight.css +++ b/packages/injected/src/highlight.css @@ -18,6 +18,7 @@ font-size: 13px; font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif; color: #333; + color-scheme: light; } svg { @@ -107,6 +108,21 @@ x-pw-action-point { z-index: 2; } +x-pw-action-cursor { + position: absolute; + width: 18px; + height: 22px; + pointer-events: none; + z-index: 4; + filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4)); +} + +x-pw-action-cursor svg { + width: 100%; + height: 100%; + position: static; +} + x-pw-title { position: absolute; backdrop-filter: blur(5px); diff --git a/packages/injected/src/highlight.ts b/packages/injected/src/highlight.ts index e1c927bc62dfe..fbd012c4bcd31 100644 --- a/packages/injected/src/highlight.ts +++ b/packages/injected/src/highlight.ts @@ -55,6 +55,7 @@ export class Highlight { private _glassPaneShadow: ShadowRoot; private _renderedEntries: RenderedHighlightEntry[] = []; private _actionPointElement: HTMLElement; + private _actionCursorElement: HTMLElement; private _titleElement: HTMLElement; private _userOverlayContainer: HTMLElement; private _userOverlays = new Map(); @@ -85,6 +86,9 @@ export class Highlight { this._glassPaneElement.style.backgroundColor = 'transparent'; this._actionPointElement = document.createElement('x-pw-action-point'); this._actionPointElement.setAttribute('hidden', 'true'); + this._actionCursorElement = document.createElement('x-pw-action-cursor'); + this._actionCursorElement.style.visibility = 'hidden'; + this._actionCursorElement.appendChild(this._createCursorSvg(document)); this._titleElement = document.createElement('x-pw-title'); this._titleElement.setAttribute('hidden', 'true'); this._userOverlayContainer = document.createElement('x-pw-user-overlays'); @@ -102,6 +106,7 @@ export class Highlight { this._glassPaneShadow.appendChild(styleElement); } this._glassPaneShadow.appendChild(this._actionPointElement); + this._glassPaneShadow.appendChild(this._actionCursorElement); this._glassPaneShadow.appendChild(this._titleElement); this._glassPaneShadow.appendChild(this._userOverlayContainer); } @@ -186,6 +191,32 @@ export class Highlight { this._actionPointElement.hidden = true; } + moveActionCursor(x: number, y: number, fadeDuration?: number) { + const moveDuration = fadeDuration ? Math.max(80, Math.min(fadeDuration * 0.6, 400)) : 0; + this._actionCursorElement.style.transition = `top ${moveDuration}ms ease, left ${moveDuration}ms ease`; + this._actionCursorElement.style.left = x + 'px'; + this._actionCursorElement.style.top = y + 'px'; + this._actionCursorElement.style.visibility = 'visible'; + } + + hideActionCursor() { + this._actionCursorElement.style.visibility = 'hidden'; + } + + private _createCursorSvg(document: Document): SVGSVGElement { + const svgNs = 'http://www.w3.org/2000/svg'; + const svg = document.createElementNS(svgNs, 'svg'); + svg.setAttribute('viewBox', '0 0 18 22'); + const path = document.createElementNS(svgNs, 'path'); + path.setAttribute('d', 'M1 1 L1 17 L5.5 13 L8 20.5 L11 19.5 L8.5 12 L15 12 Z'); + path.setAttribute('fill', 'white'); + path.setAttribute('stroke', 'black'); + path.setAttribute('stroke-width', '1.5'); + path.setAttribute('stroke-linejoin', 'round'); + svg.appendChild(path); + return svg; + } + showActionTitle(text: string, fadeDuration: number, position?: string, fontSize?: number) { this._titleElement.textContent = text; this._titleElement.hidden = false; diff --git a/packages/injected/src/injectedScript.ts b/packages/injected/src/injectedScript.ts index 3d15105369070..22b118974a324 100644 --- a/packages/injected/src/injectedScript.ts +++ b/packages/injected/src/injectedScript.ts @@ -16,6 +16,7 @@ import { parseAriaSnapshot } from '@isomorphic/ariaSnapshot'; import { asLocator } from '@isomorphic/locatorGenerators'; +import { splitTestIdAttributeNames } from '@isomorphic/locatorUtils'; import { parseAttributeSelector, parseSelector, stringifySelector, visitAllSelectorParts } from '@isomorphic/selectorParser'; import { cacheNormalizedWhitespaces, normalizeWhiteSpace, trimStringWithEllipsis } from '@isomorphic/stringUtils'; @@ -35,7 +36,7 @@ import { UtilityScript } from './utilityScript'; import type { AriaTemplateNode } from '@isomorphic/ariaSnapshot'; import type { CSSComplexSelectorList } from '@isomorphic/cssParser'; import type { Language } from '@isomorphic/locatorGenerators'; -import type { NestedSelectorBody, ParsedSelector, ParsedSelectorPart } from '@isomorphic/selectorParser'; +import type { AttributeSelectorPart, NestedSelectorBody, ParsedSelector, ParsedSelectorPart } from '@isomorphic/selectorParser'; import type * as channels from '@protocol/channels'; import type { AriaSnapshot, AriaTreeOptions } from './ariaSnapshot'; import type { LayoutSelectorName } from './layoutSelectorUtils'; @@ -47,7 +48,6 @@ import type { Builtins } from './utilityScript'; export type FrameExpectParams = Omit & { expectedValue?: any; - timeoutForLogs?: number; noAutoWaiting?: boolean; }; @@ -93,7 +93,6 @@ export class InjectedScript { readonly isUnderTest: boolean; private _sdkLanguage: Language; private _testIdAttributeNameForStrictErrorAndConsoleCodegen: string = 'data-testid'; - private _markedElements?: { callId: string, elements: Set }; readonly window: Window & typeof globalThis; readonly document: Document; readonly consoleApi: ConsoleAPI; @@ -230,7 +229,7 @@ export class InjectedScript { this._engines.set('internal:has-text', this._createInternalHasTextEngine()); this._engines.set('internal:has-not-text', this._createInternalHasNotTextEngine()); this._engines.set('internal:attr', this._createNamedAttributeEngine()); - this._engines.set('internal:testid', this._createNamedAttributeEngine()); + this._engines.set('internal:testid', this._createTestIdEngine()); this._engines.set('internal:role', createRoleEngine(true)); this._engines.set('internal:describe', this._createDescribeEngine()); this._engines.set('aria-ref', this._createAriaRefEngine()); @@ -492,21 +491,31 @@ export class InjectedScript { const parsed = parseAttributeSelector(selector, true); if (parsed.name || parsed.attributes.length !== 1) throw new Error('Malformed attribute selector: ' + selector); - const { name, value, caseSensitive } = parsed.attributes[0]; - const lowerCaseValue = caseSensitive ? null : value.toLowerCase(); - let matcher: (s: string) => boolean; - if (value instanceof RegExp) - matcher = s => !!s.match(value); - else if (caseSensitive) - matcher = s => s === value; - else - matcher = s => s.toLowerCase().includes(lowerCaseValue!); + const { name } = parsed.attributes[0]; + const matcher = createAttributeMatcher(parsed.attributes[0]); const elements = this._evaluator._queryCSS({ scope: root as Document | Element, pierceShadow: true }, `[${name}]`); return elements.filter(e => matcher(e.getAttribute(name)!)); }; return { queryAll }; } + private _createTestIdEngine(): SelectorEngine { + const queryAll = (root: SelectorRoot, selector: string): Element[] => { + const parsed = parseAttributeSelector(selector, true); + if (parsed.name || parsed.attributes.length !== 1) + throw new Error('Malformed test id selector: ' + selector); + const names = splitTestIdAttributeNames(parsed.attributes[0].name); + const matcher = createAttributeMatcher(parsed.attributes[0]); + const cssQuery = names.map(n => `[${n}]`).join(','); + const elements = this._evaluator._queryCSS({ scope: root as Document | Element, pierceShadow: true }, cssQuery); + return elements.filter(e => names.some(n => { + const actual = e.getAttribute(n); + return actual !== null && matcher(actual); + })); + }; + return { queryAll }; + } + private _createDescribeEngine(): SelectorEngine { const queryAll = (root: SelectorRoot): Element[] => { if (root.nodeType !== 1 /* Node.ELEMENT_NODE */) @@ -1103,8 +1112,9 @@ export class InjectedScript { return; // Playwright only issues trusted events, so allow any custom events originating from - // the page or content scripts. - if (!event.isTrusted) + // the page or content scripts. The WebView backend cannot produce trusted events, so + // it marks synthetic events with __pwTrustedSynthetic to opt back into interception. + if (!event.isTrusted && !(event as any).__pwTrustedSynthetic) return; // Determine the event point. Note that Firefox does not always have window.TouchEvent. @@ -1328,12 +1338,13 @@ export class InjectedScript { highlight.removeElementHighlight(selector); } - setScreencastAnnotation(annotation: { point?: channels.Point, box?: channels.Rect, actionTitle?: string, duration?: number, position?: string, fontSize?: number } | null) { + setScreencastAnnotation(annotation: { point?: channels.Point, box?: channels.Rect, actionTitle?: string, duration?: number, position?: string, fontSize?: number, cursor?: 'none' | 'pointer' } | null) { const highlight = this._ensureHighlight(); if (!annotation) { highlight.updateHighlight([]); highlight.hideActionPoint(); highlight.hideActionTitle(); + highlight.hideActionCursor(); return; } const fadeDuration = annotation.duration ?? 500; @@ -1346,8 +1357,11 @@ export class InjectedScript { fadeDuration, }]); } - if (annotation.point) + if (annotation.point) { + if (annotation.cursor !== 'none') + highlight.moveActionCursor(annotation.point.x, annotation.point.y, fadeDuration); highlight.showActionPoint(annotation.point.x, annotation.point.y, fadeDuration); + } if (annotation.actionTitle) highlight.showActionTitle(annotation.actionTitle, fadeDuration, annotation.position, annotation.fontSize); } @@ -1379,34 +1393,21 @@ export class InjectedScript { } } - markTargetElements(markedElements: Set, callId: string) { - if (this._markedElements?.callId !== callId) - this._markedElements = undefined; - const previous = this._markedElements?.elements || new Set(); - - const unmarkEvent = new CustomEvent('__playwright_unmark_target__', { + markTargetElements(markedElements: Set) { + const resetEvent = new CustomEvent('__playwright_reset_targets__', { bubbles: true, cancelable: true, - detail: callId, composed: true, }); - for (const element of previous) { - if (!markedElements.has(element)) - element.dispatchEvent(unmarkEvent); - } + this.document.dispatchEvent(resetEvent); const markEvent = new CustomEvent('__playwright_mark_target__', { bubbles: true, cancelable: true, - detail: callId, composed: true, }); - for (const element of markedElements) { - if (!previous.has(element)) - element.dispatchEvent(markEvent); - } - - this._markedElements = { callId, elements: markedElements }; + for (const element of markedElements) + element.dispatchEvent(markEvent); } private _setupGlobalListenersRemovalDetection() { @@ -1742,6 +1743,16 @@ function oneLine(s: string): string { return s.replace(/\n/g, '↵').replace(/\t/g, '⇆'); } +function createAttributeMatcher(part: AttributeSelectorPart): (s: string) => boolean { + const { value, caseSensitive } = part; + if (value instanceof RegExp) + return s => !!s.match(value); + if (caseSensitive) + return s => s === value; + const lowerCaseValue = value.toLowerCase(); + return s => s.toLowerCase().includes(lowerCaseValue); +} + function cssUnquote(s: string): string { // Trim quotes. s = s.substring(1, s.length - 1); diff --git a/packages/injected/src/recorder/recorder.ts b/packages/injected/src/recorder/recorder.ts index 7b4c98f59ba99..22a22144e4b7f 100644 --- a/packages/injected/src/recorder/recorder.ts +++ b/packages/injected/src/recorder/recorder.ts @@ -414,7 +414,8 @@ class RecordActionTool implements RecorderTool { if (target.nodeName === 'INPUT' && (target as HTMLInputElement).type.toLowerCase() === 'file') { this._recordAction({ name: 'setInputFiles', - selector: this._activeModel!.selector, + // webkit doesn't focus file inputs on click, so activeModel is unreliable here. + selector: this._hoveredModel!.selector, signals: [], files: [...((target as HTMLInputElement).files || [])].map(file => file.name), }); @@ -614,13 +615,7 @@ class RecordActionTool implements RecorderTool { } private _shouldIgnoreMouseEvent(event: MouseEvent): boolean { - const target = this._recorder.deepEventTarget(event); - const nodeName = target.nodeName; - if (nodeName === 'SELECT' || nodeName === 'OPTION') - return true; - if (nodeName === 'INPUT' && ['date', 'range'].includes((target as HTMLInputElement).type)) - return true; - return false; + return shouldIgnoreMouseEvent(this._recorder.deepEventTarget(event)); } private _actionInProgress(event: Event): boolean { @@ -891,13 +886,7 @@ class JsonRecordActionTool implements RecorderTool { } private _shouldIgnoreMouseEvent(event: MouseEvent): boolean { - const target = this._recorder.deepEventTarget(event); - const nodeName = target.nodeName; - if (nodeName === 'SELECT' || nodeName === 'OPTION') - return true; - if (nodeName === 'INPUT' && ['date', 'range'].includes((target as HTMLInputElement).type)) - return true; - return false; + return shouldIgnoreMouseEvent(this._recorder.deepEventTarget(event)); } private _shouldGenerateKeyPressFor(event: KeyboardEvent): boolean { @@ -1886,6 +1875,18 @@ function isRangeInput(node: Node | null): node is HTMLInputElement { return inputElement.type.toLowerCase() === 'range'; } +// Non-text input types that open native pickers. +const kNativePickerInputTypes = new Set(['color', 'date', 'datetime-local', 'file', 'month', 'range', 'time', 'week']); + +function shouldIgnoreMouseEvent(target: Node): boolean { + const nodeName = target.nodeName; + if (nodeName === 'SELECT' || nodeName === 'OPTION') + return true; + if (nodeName === 'INPUT' && kNativePickerInputTypes.has((target as HTMLInputElement).type)) + return true; + return false; +} + function addEventListener(target: EventTarget, eventName: string, listener: EventListener, useCapture?: boolean): () => void { target.addEventListener(eventName, listener, useCapture); const remove = () => { diff --git a/packages/injected/src/roleUtils.ts b/packages/injected/src/roleUtils.ts index 12f79efef26b0..5a10136eb3e0a 100644 --- a/packages/injected/src/roleUtils.ts +++ b/packages/injected/src/roleUtils.ts @@ -559,7 +559,26 @@ export function getElementAccessibleDescription(element: Element, includeHidden: return accessibleDescription; } -function getAriaInvalid(element: Element): 'false' | 'true' | 'grammar' | 'spelling' { +// Roles where `aria-invalid` is conceptually meaningful per WAI-ARIA 1.2. +// See https://www.w3.org/TR/wai-aria-1.2/#aria-invalid for the supported list. +export const kAriaInvalidRoles = [ + 'application', + 'checkbox', + 'columnheader', + 'combobox', + 'gridcell', + 'listbox', + 'radiogroup', + 'rowheader', + 'searchbox', + 'slider', + 'spinbutton', + 'switch', + 'textbox', + 'tree', +]; + +export function getAriaInvalid(element: Element): 'false' | 'true' | 'grammar' | 'spelling' { // https://www.w3.org/TR/wai-aria-1.2/#aria-invalid // This state is being deprecated as a global state in ARIA 1.2. // In future versions it will only be allowed on roles where it is specifically supported. diff --git a/packages/injected/src/selectorGenerator.ts b/packages/injected/src/selectorGenerator.ts index c7d40e7bea4ed..25de3c184d00b 100644 --- a/packages/injected/src/selectorGenerator.ts +++ b/packages/injected/src/selectorGenerator.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { splitTestIdAttributeNames } from '@isomorphic/locatorUtils'; import { escapeForAttributeSelector, escapeForTextSelector, escapeRegExp, quoteCSSAttributeValue } from '@isomorphic/stringUtils'; import { beginDOMCaches, closestCrossShadow, endDOMCaches, isElementVisible, isInsideScope, parentElementOrShadowHost } from './domUtils'; @@ -231,11 +232,12 @@ function generateSelectorFor(cache: Cache, injectedScript: InjectedScript, targe function buildNoTextCandidates(injectedScript: InjectedScript, element: Element, options: InternalOptions): SelectorToken[] { const candidates: SelectorToken[] = []; + const testIdAttributeNames = splitTestIdAttributeNames(options.testIdAttributeName); // CSS selectors are applicable to elements via locator() and iframes via frameLocator(). { for (const attr of ['data-testid', 'data-test-id', 'data-test']) { - if (attr !== options.testIdAttributeName && element.getAttribute(attr)) + if (!testIdAttributeNames.includes(attr) && element.getAttribute(attr)) candidates.push({ engine: 'css', selector: `[${attr}=${quoteCSSAttributeValue(element.getAttribute(attr)!)}]`, score: kOtherTestIdScore }); } @@ -255,16 +257,20 @@ function buildNoTextCandidates(injectedScript: InjectedScript, element: Element, } // Locate by testId via CSS selector. - if (element.getAttribute(options.testIdAttributeName)) - candidates.push({ engine: 'css', selector: `[${options.testIdAttributeName}=${quoteCSSAttributeValue(element.getAttribute(options.testIdAttributeName)!)}]`, score: kTestIdScore }); + for (const testIdAttr of testIdAttributeNames) { + if (element.getAttribute(testIdAttr)) + candidates.push({ engine: 'css', selector: `[${testIdAttr}=${quoteCSSAttributeValue(element.getAttribute(testIdAttr)!)}]`, score: kTestIdScore }); + } penalizeScoreForLength([candidates]); return candidates; } // Everything below is not applicable to iframes (getBy* methods). - if (element.getAttribute(options.testIdAttributeName)) - candidates.push({ engine: 'internal:testid', selector: `[${options.testIdAttributeName}=${escapeForAttributeSelector(element.getAttribute(options.testIdAttributeName)!, true)}]`, score: kTestIdScore }); + for (const testIdAttr of testIdAttributeNames) { + if (element.getAttribute(testIdAttr)) + candidates.push({ engine: 'internal:testid', selector: `[${testIdAttr}=${escapeForAttributeSelector(element.getAttribute(testIdAttr)!, true)}]`, score: kTestIdScore }); + } if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { const input = element as HTMLInputElement | HTMLTextAreaElement; @@ -353,7 +359,7 @@ function buildTextCandidates(injectedScript: InjectedScript, element: Element, i if (ariaDescription) { candidates.push([{ engine: 'internal:role', selector: `${ariaRole}[name=${escapeForAttributeSelector(ariaName, true)}][description=${escapeForAttributeSelector(ariaDescription, true)}]`, score: kRoleWithNameScoreExact + 1 }]); for (const alternative of suitableTextAlternatives(ariaName)) - candidates.push([{ engine: 'internal:role', selector: `${ariaRole}[name=${escapeForAttributeSelector(alternative.text, false)}][description=${escapeForAttributeSelector(ariaDescription, true)}]`, score: kRoleWithNameScore - alternative.scoreBonus + 1 }]); + candidates.push([{ engine: 'internal:role', selector: `${ariaRole}[name=${escapeForAttributeSelector(alternative.text, false)}][description=${escapeForAttributeSelector(ariaDescription, false)}]`, score: kRoleWithNameScore - alternative.scoreBonus + 1 }]); } } else { const roleToken = { engine: 'internal:role', selector: `${ariaRole}`, score: kRoleWithoutNameScore }; diff --git a/packages/injected/src/webAuthn.ts b/packages/injected/src/webAuthn.ts new file mode 100644 index 0000000000000..deb940ba32bfd --- /dev/null +++ b/packages/injected/src/webAuthn.ts @@ -0,0 +1,211 @@ +/** + * 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. + */ + +// Wire format passed through the page binding (JSON-only; binary is base64url). +export type CreateRequest = { + type: 'create', + origin: string, + challenge: string, + rp: { id?: string, name: string }, + user: { id: string, name: string, displayName: string }, + pubKeyCredParams: { type: string, alg: number }[], + excludeCredentials?: { type: string, id: string }[], + userVerification?: string, + residentKey?: string, +}; + +export type GetRequest = { + type: 'get', + origin: string, + challenge: string, + rpId: string, + allowCredentials?: { type: string, id: string }[], + userVerification?: string, +}; + +export type CreateResponse = { + ok: true, + id: string, + clientDataJSON: string, + attestationObject: string, +} | { ok: false, name: string, message: string }; + +export type GetResponse = { + ok: true, + id: string, + clientDataJSON: string, + authenticatorData: string, + signature: string, + userHandle: string | null, +} | { ok: false, name: string, message: string }; + +type GlobalThis = typeof globalThis; + +export function inject(globalThis: GlobalThis) { + if ((globalThis as any).__pwWebAuthnInstalled) + return; + (globalThis as any).__pwWebAuthnInstalled = true; + + const binding = (globalThis as any).__pwWebAuthnBinding as (payload: any) => Promise; + if (!binding || !globalThis.navigator) + return; + if (!globalThis.navigator.credentials) { + Object.defineProperty(globalThis.navigator, 'credentials', { + value: { create: async () => null, get: async () => null }, + writable: true, + configurable: true, + }); + } + + function toBase64Url(buf: ArrayBuffer | ArrayBufferView): string { + const bytes = buf instanceof ArrayBuffer ? new Uint8Array(buf) : new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); + let s = ''; + for (let i = 0; i < bytes.length; i++) + s += String.fromCharCode(bytes[i]); + return globalThis.btoa(s).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', ''); + } + + function fromBase64Url(s: string): ArrayBuffer { + let str = s.replaceAll('-', '+').replaceAll('_', '/'); + while (str.length % 4) + str += '='; + const bin = globalThis.atob(str); + const out = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; i++) + out[i] = bin.charCodeAt(i); + return out.buffer; + } + + const PublicKeyCredentialCtor: any = (globalThis as any).PublicKeyCredential; + const AuthAttestationResponseCtor: any = (globalThis as any).AuthenticatorAttestationResponse; + const AuthAssertionResponseCtor: any = (globalThis as any).AuthenticatorAssertionResponse; + + function defineReadonly(target: any, props: Record) { + for (const k of Object.keys(props)) + Object.defineProperty(target, k, { value: props[k], enumerable: true, configurable: true }); + } + + function makeAttestationResponse(clientDataJSON: ArrayBuffer, attestationObject: ArrayBuffer) { + const proto = AuthAttestationResponseCtor?.prototype || Object.prototype; + const r = Object.create(proto); + defineReadonly(r, { clientDataJSON, attestationObject }); + r.getTransports = () => ['internal']; + r.getAuthenticatorData = () => { + // Extract authData from attestationObject (CBOR: { fmt, attStmt, authData }). + // For simplicity, return the whole attestationObject — callers rarely use this in tests. + return attestationObject; + }; + r.getPublicKey = () => null; + r.getPublicKeyAlgorithm = () => -7; + return r; + } + + function makeAssertionResponse(clientDataJSON: ArrayBuffer, authenticatorData: ArrayBuffer, signature: ArrayBuffer, userHandle: ArrayBuffer | null) { + const proto = AuthAssertionResponseCtor?.prototype || Object.prototype; + const r = Object.create(proto); + defineReadonly(r, { clientDataJSON, authenticatorData, signature, userHandle }); + return r; + } + + function makePublicKeyCredential(id: string, response: any) { + const proto = PublicKeyCredentialCtor?.prototype || Object.prototype; + const cred = Object.create(proto); + defineReadonly(cred, { + id, + rawId: fromBase64Url(id), + type: 'public-key', + authenticatorAttachment: 'platform', + response, + }); + cred.getClientExtensionResults = () => ({}); + cred.toJSON = () => ({ id, rawId: id, type: 'public-key', response: {} }); + return cred; + } + + function toBuf(x: ArrayBuffer | ArrayBufferView | undefined): ArrayBuffer { + if (!x) + return new ArrayBuffer(0); + if (x instanceof ArrayBuffer) + return x; + const v = x as ArrayBufferView; + const out = new Uint8Array(v.byteLength); + out.set(new Uint8Array(v.buffer as ArrayBuffer, v.byteOffset, v.byteLength)); + return out.buffer; + } + + function failure(name: string, message: string): never { + const Ctor: any = (globalThis as any).DOMException || Error; + throw new Ctor(message, name); + } + + const origCreate = globalThis.navigator.credentials.create.bind(globalThis.navigator.credentials); + const origGet = globalThis.navigator.credentials.get.bind(globalThis.navigator.credentials); + + globalThis.navigator.credentials.create = async function(options?: CredentialCreationOptions): Promise { + if (!options || !(options as any).publicKey) + return origCreate(options); + const pk = (options as any).publicKey; + const req: CreateRequest = { + type: 'create', + origin: globalThis.location.origin, + challenge: toBase64Url(toBuf(pk.challenge)), + rp: { id: pk.rp?.id, name: pk.rp?.name || '' }, + user: { + id: toBase64Url(toBuf(pk.user?.id)), + name: pk.user?.name || '', + displayName: pk.user?.displayName || '', + }, + pubKeyCredParams: (pk.pubKeyCredParams || []).map((p: any) => ({ type: p.type, alg: p.alg })), + excludeCredentials: (pk.excludeCredentials || []).map((c: any) => ({ type: c.type, id: toBase64Url(toBuf(c.id)) })), + userVerification: pk.authenticatorSelection?.userVerification, + residentKey: pk.authenticatorSelection?.residentKey, + }; + const result: CreateResponse = await binding(req); + if (!result.ok) + failure(result.name, result.message); + const resp = makeAttestationResponse(fromBase64Url(result.clientDataJSON), fromBase64Url(result.attestationObject)); + return makePublicKeyCredential(result.id, resp); + }; + + globalThis.navigator.credentials.get = async function(options?: CredentialRequestOptions): Promise { + if (!options || !(options as any).publicKey) + return origGet(options); + const pk = (options as any).publicKey; + const req: GetRequest = { + type: 'get', + origin: globalThis.location.origin, + challenge: toBase64Url(toBuf(pk.challenge)), + rpId: pk.rpId || new URL(globalThis.location.origin).hostname, + allowCredentials: (pk.allowCredentials || []).map((c: any) => ({ type: c.type, id: toBase64Url(toBuf(c.id)) })), + userVerification: pk.userVerification, + }; + const result: GetResponse = await binding(req); + if (!result.ok) + failure(result.name, result.message); + const resp = makeAssertionResponse( + fromBase64Url(result.clientDataJSON), + fromBase64Url(result.authenticatorData), + fromBase64Url(result.signature), + result.userHandle ? fromBase64Url(result.userHandle) : null, + ); + return makePublicKeyCredential(result.id, resp); + }; + + if (PublicKeyCredentialCtor) { + PublicKeyCredentialCtor.isUserVerifyingPlatformAuthenticatorAvailable = async () => true; + PublicKeyCredentialCtor.isConditionalMediationAvailable = async () => true; + } +} diff --git a/packages/injected/src/webview/webViewDialog.ts b/packages/injected/src/webview/webViewDialog.ts new file mode 100644 index 0000000000000..85205b7ce9ca6 --- /dev/null +++ b/packages/injected/src/webview/webViewDialog.ts @@ -0,0 +1,55 @@ +/** + * 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. + */ + +function toMessage(message: any): string { + return String(message === undefined || message === null ? '' : message); +} + +// Stock WebKit RDP has no dialog API. We override window.alert/confirm/prompt +// to tunnel calls through a synchronous XHR to our DialogBridge HTTP server, +// which holds the response until the host-side Dialog handler resolves. +export function installDialogBridge(window: Window & typeof globalThis, endpoint: string) { + function post(type: string, message: string, defaultValue: string): any { + const xhr = new window.XMLHttpRequest(); + try { xhr.open('POST', endpoint, false); } catch (e) { return null; } + // text/plain body keeps this a "simple" CORS request — no preflight. + try { xhr.send(JSON.stringify({ type, message, defaultValue })); } catch (e) { return null; } + if (xhr.status !== 200) + return null; + try { return JSON.parse(xhr.responseText); } catch (e) { return null; } + } + Object.defineProperty(window, 'alert', { + configurable: true, writable: false, + value: function(message: any) { post('alert', toMessage(message), ''); }, + }); + Object.defineProperty(window, 'confirm', { + configurable: true, writable: false, + value: function(message: any) { + const r = post('confirm', toMessage(message), ''); + return !!(r && r.accept); + }, + }); + Object.defineProperty(window, 'prompt', { + configurable: true, writable: false, + value: function(message: any, defaultValue: any) { + const def = toMessage(defaultValue); + const r = post('prompt', toMessage(message), def); + if (!r || !r.accept) + return null; + return typeof r.promptText === 'string' ? r.promptText : def; + }, + }); +} diff --git a/packages/injected/src/webview/webViewInput.ts b/packages/injected/src/webview/webViewInput.ts new file mode 100644 index 0000000000000..bddc78ae40621 --- /dev/null +++ b/packages/injected/src/webview/webViewInput.ts @@ -0,0 +1,364 @@ +/** + * 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. + */ + +type Modifiers = { + ctrlKey: boolean; + shiftKey: boolean; + altKey: boolean; + metaKey: boolean; +}; + +export type KeyEventParams = Modifiers & { + code: string; + key: string; + keyCode: number; + location: number; + repeat: boolean; + // Present for printable keys; absent for non-text keys (arrows, modifiers, etc.). + text?: string; +}; + +export type MouseEventParams = Modifiers & { + type: 'mousedown' | 'mouseup' | 'click' | 'auxclick' | 'dblclick' | 'contextmenu'; + x: number; + y: number; + button: number; + buttons: number; + clickCount: number; +}; + +export type MouseMoveParams = Modifiers & { + x: number; + y: number; + button: number; + buttons: number; +}; + +export type WheelParams = Modifiers & { + x: number; + y: number; + deltaX: number; + deltaY: number; +}; + +export type TapParams = Modifiers & { + x: number; + y: number; +}; + +const kTrustedSynthetic = '__pwTrustedSynthetic'; + +function markAndDispatch(node: EventTarget, event: Event): boolean { + Object.defineProperty(event, kTrustedSynthetic, { value: true }); + return node.dispatchEvent(event); +} + +// Legacy WebKit-only KeyboardEvent.keyIdentifier (a DOM Level 3 draft property +// dropped by every other engine). It cannot be supplied via the constructor, so +// compute it from the virtual key code and define it on the event before +// dispatch. Mirrors WebCore's keyIdentifierForWindowsKeyCode. +const kNamedKeyIdentifiers: Record = { + 8: 'U+0008', // Backspace + 9: 'U+0009', // Tab + 13: 'Enter', + 16: 'Shift', + 17: 'Control', + 18: 'Alt', + 27: 'U+001B', // Escape + 33: 'PageUp', + 34: 'PageDown', + 35: 'End', + 36: 'Home', + 37: 'Left', + 38: 'Up', + 39: 'Right', + 40: 'Down', + 45: 'Insert', + 46: 'U+007F', // Delete +}; + +function keyIdentifierFor(keyCode: number, key: string): string { + const named = kNamedKeyIdentifiers[keyCode]; + if (named !== undefined) + return named; + if (keyCode >= 112 && keyCode <= 135) + return 'F' + (keyCode - 111); + if (key.length === 1) + return 'U+' + key.toUpperCase().charCodeAt(0).toString(16).toUpperCase().padStart(4, '0'); + return ''; +} + +function dispatchKeyEvent(node: EventTarget, type: string, init: KeyboardEventInit, keyCode: number, key: string): boolean { + const event = new KeyboardEvent(type, init); + Object.defineProperty(event, 'keyIdentifier', { value: keyIdentifierFor(keyCode, key), configurable: true }); + return markAndDispatch(node, event); +} + +export class WebViewInput { + private _window: Window & typeof globalThis; + private _document: Document; + private _hoverTarget: Element | null = null; + private _setTimeout: typeof globalThis.setTimeout; + + constructor(window: Window & typeof globalThis, document: Document) { + this._window = window; + this._document = document; + this._setTimeout = ((window as any).__pwSnapshotGlobals || window).setTimeout; + } + + // Run each event in its own task (like real input). + private _postTask(task: () => void): Promise { + return new Promise(resolve => { + this._setTimeout.call(this._window, () => { + try { + task(); + } finally { + resolve(); + } + }); + }); + } + + // Descend through open shadow roots so synthetic events land on the actual + // element under the pointer rather than on the shadow host. + private _deepElementFromPoint(x: number, y: number): Element | null { + let el = this._document.elementFromPoint(x, y); + while (el && el.shadowRoot) { + const inner = el.shadowRoot.elementFromPoint(x, y); + if (!inner || inner === el) + break; + el = inner; + } + return el; + } + + // The focused element may live inside one or more shadow roots, where + // document.activeElement only reports the outermost shadow host. + private _deepActiveElement(): Element | null { + let active = this._document.activeElement; + while (active && active.shadowRoot && active.shadowRoot.activeElement) + active = active.shadowRoot.activeElement; + return active; + } + + private _insertText(target: Element | null, text: string) { + if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) { + const start = target.selectionStart ?? target.value.length; + const end = target.selectionEnd ?? target.value.length; + target.value = target.value.slice(0, start) + text + target.value.slice(end); + const pos = start + text.length; + try { + target.setSelectionRange(pos, pos); + } catch { + } + target.dispatchEvent(new InputEvent('input', { bubbles: true, cancelable: false, data: text, inputType: 'insertText' })); + } else if (target && (target as HTMLElement).isContentEditable) { + this._document.execCommand('insertText', false, text); + } + } + + keydown(params: KeyEventParams): Promise { + const target = this._deepActiveElement() || this._document.body; + if (!target) + return Promise.resolve(); + const init: KeyboardEventInit = { + bubbles: true, + cancelable: true, + view: this._window, + code: params.code, + key: params.key, + keyCode: params.keyCode, + which: params.keyCode, + location: params.location, + repeat: params.repeat, + ctrlKey: params.ctrlKey, + shiftKey: params.shiftKey, + altKey: params.altKey, + metaKey: params.metaKey, + }; + let notPrevented = true; + let charNotPrevented = true; + let lastTask = this._postTask(() => { + notPrevented = dispatchKeyEvent(target, 'keydown', init, params.keyCode, params.key); + }); + // Non-text keys produce only keydown; a cancelled keydown also suppresses the + // keypress and the default text insertion. + if (params.text !== undefined) { + const text = params.text; + void this._postTask(() => { + if (!notPrevented) + return; + const charCode = text.charCodeAt(0); + charNotPrevented = markAndDispatch(target, new KeyboardEvent('keypress', { ...init, charCode, keyCode: charCode, which: charCode })); + }); + lastTask = this._postTask(() => { + if (!notPrevented || !charNotPrevented) + return; + // Real WebKit fires a `textInput` (TextEvent) whose default action performs + // the insertion (and the subsequent beforeinput/input). Replicate it; the + // event's default does the insertion, so we do not insert manually. Enter's + // text is '\r' but the inserted/textInput data is a newline. + this._dispatchTextInput(target, text === '\r' ? '\n' : text); + }); + } + return lastTask; + } + + private _dispatchTextInput(target: EventTarget, text: string) { + // TextEvent has no usable constructor in WebKit — initTextEvent is the only + // way to create one (initTextEvent(type, bubbles, cancelable, view, data)). + const event = this._document.createEvent('TextEvent') as any; + event.initTextEvent('textInput', true, true, this._window, text); + markAndDispatch(target, event); + } + + keyup(params: KeyEventParams): Promise { + const target = this._deepActiveElement() || this._document.body; + if (!target) + return Promise.resolve(); + return this._postTask(() => { + dispatchKeyEvent(target, 'keyup', { + bubbles: true, + cancelable: true, + view: this._window, + code: params.code, + key: params.key, + keyCode: params.keyCode, + which: params.keyCode, + location: params.location, + ctrlKey: params.ctrlKey, + shiftKey: params.shiftKey, + altKey: params.altKey, + metaKey: params.metaKey, + }, params.keyCode, params.key); + }); + } + + insertText(text: string): Promise { + return this._postTask(() => this._insertText(this._deepActiveElement(), text)); + } + + mouseMove(params: MouseMoveParams): Promise { + const target = this._deepElementFromPoint(params.x, params.y) || this._document.documentElement; + const base: MouseEventInit = { + bubbles: true, + cancelable: true, + view: this._window, + clientX: params.x, + clientY: params.y, + screenX: params.x, + screenY: params.y, + button: params.button, + buttons: params.buttons, + ctrlKey: params.ctrlKey, + shiftKey: params.shiftKey, + altKey: params.altKey, + metaKey: params.metaKey, + }; + const pointer: PointerEventInit = { ...base, pointerId: 1, pointerType: 'mouse', isPrimary: true }; + const prev = this._hoverTarget; + if (prev !== target) { + if (prev && prev.isConnected) { + void this._postTask(() => markAndDispatch(prev, new PointerEvent('pointerout', { ...pointer, relatedTarget: target }))); + void this._postTask(() => markAndDispatch(prev, new MouseEvent('mouseout', { ...base, relatedTarget: target }))); + void this._postTask(() => markAndDispatch(prev, new PointerEvent('pointerleave', { ...pointer, bubbles: false, cancelable: false, relatedTarget: target }))); + void this._postTask(() => markAndDispatch(prev, new MouseEvent('mouseleave', { ...base, bubbles: false, cancelable: false, relatedTarget: target }))); + } + void this._postTask(() => markAndDispatch(target, new PointerEvent('pointerover', { ...pointer, relatedTarget: prev }))); + void this._postTask(() => markAndDispatch(target, new MouseEvent('mouseover', { ...base, relatedTarget: prev }))); + void this._postTask(() => markAndDispatch(target, new PointerEvent('pointerenter', { ...pointer, bubbles: false, cancelable: false, relatedTarget: prev }))); + void this._postTask(() => markAndDispatch(target, new MouseEvent('mouseenter', { ...base, bubbles: false, cancelable: false, relatedTarget: prev }))); + this._hoverTarget = target; + } + void this._postTask(() => markAndDispatch(target, new PointerEvent('pointermove', pointer))); + return this._postTask(() => markAndDispatch(target, new MouseEvent('mousemove', base))); + } + + mouseEvent(params: MouseEventParams): Promise { + // Resolve the hit target at dispatch time, not enqueue time: a queued move + // ahead of this may reveal an overlay that should receive the press. + return this._postTask(() => { + const target = this._deepElementFromPoint(params.x, params.y) || this._document.documentElement; + markAndDispatch(target, new MouseEvent(params.type, { + bubbles: true, + cancelable: true, + view: this._window, + clientX: params.x, + clientY: params.y, + screenX: params.x, + screenY: params.y, + button: params.button, + buttons: params.buttons, + detail: params.clickCount, + ctrlKey: params.ctrlKey, + shiftKey: params.shiftKey, + altKey: params.altKey, + metaKey: params.metaKey, + })); + }); + } + + wheel(params: WheelParams): Promise { + return this._postTask(() => { + const target = this._deepElementFromPoint(params.x, params.y) || this._document.documentElement; + markAndDispatch(target, new WheelEvent('wheel', { + bubbles: true, + cancelable: true, + view: this._window, + clientX: params.x, + clientY: params.y, + screenX: params.x, + screenY: params.y, + deltaX: params.deltaX, + deltaY: params.deltaY, + deltaMode: 0, + ctrlKey: params.ctrlKey, + shiftKey: params.shiftKey, + altKey: params.altKey, + metaKey: params.metaKey, + })); + this._window.scrollBy(params.deltaX, params.deltaY); + }); + } + + tap(params: TapParams): Promise { + const target = this._deepElementFromPoint(params.x, params.y) || this._document.documentElement; + const init: MouseEventInit = { + bubbles: true, + cancelable: true, + view: this._window, + clientX: params.x, + clientY: params.y, + screenX: params.x, + screenY: params.y, + ctrlKey: params.ctrlKey, + shiftKey: params.shiftKey, + altKey: params.altKey, + metaKey: params.metaKey, + }; + try { + const touch = new Touch({ identifier: 0, target, clientX: params.x, clientY: params.y, screenX: params.x, screenY: params.y, pageX: params.x, pageY: params.y, radiusX: 1, radiusY: 1, rotationAngle: 0, force: 1 }); + void this._postTask(() => markAndDispatch(target, new TouchEvent('touchstart', { ...init, touches: [touch], targetTouches: [touch], changedTouches: [touch] }))); + void this._postTask(() => markAndDispatch(target, new TouchEvent('touchend', { ...init, touches: [], targetTouches: [], changedTouches: [touch] }))); + } catch { + } + void this._postTask(() => markAndDispatch(target, new MouseEvent('mousedown', { ...init, button: 0, buttons: 1, detail: 1 }))); + void this._postTask(() => markAndDispatch(target, new MouseEvent('mouseup', { ...init, button: 0, buttons: 0, detail: 1 }))); + return this._postTask(() => markAndDispatch(target, new MouseEvent('click', { ...init, button: 0, buttons: 0, detail: 1 }))); + } +} + +export default WebViewInput; diff --git a/packages/isomorphic/ariaSnapshot.ts b/packages/isomorphic/ariaSnapshot.ts index a051692bd7b56..6a856f31f6124 100644 --- a/packages/isomorphic/ariaSnapshot.ts +++ b/packages/isomorphic/ariaSnapshot.ts @@ -30,6 +30,7 @@ export type AriaProps = { disabled?: boolean; expanded?: boolean; active?: boolean; + invalid?: boolean | 'grammar' | 'spelling'; level?: number; pressed?: boolean | 'mixed'; selected?: boolean; @@ -67,7 +68,7 @@ export function hasPointerCursor(ariaNode: AriaNode): boolean { } function ariaPropsEqual(a: AriaProps, b: AriaProps): boolean { - return a.active === b.active && a.checked === b.checked && a.disabled === b.disabled && a.expanded === b.expanded && a.selected === b.selected && a.level === b.level && a.pressed === b.pressed; + return a.active === b.active && a.checked === b.checked && a.disabled === b.disabled && a.expanded === b.expanded && a.invalid === b.invalid && a.selected === b.selected && a.level === b.level && a.pressed === b.pressed; } // We pass parsed template between worlds using JSON, make it easy. @@ -496,6 +497,11 @@ export class KeyParser { node.active = value === 'true'; return; } + if (key === 'invalid') { + this._assert(value === 'true' || value === 'false' || value === 'grammar' || value === 'spelling', 'Value of "invalid" attribute must be a boolean, "grammar" or "spelling"', errorPos); + node.invalid = value === 'true' ? true : value === 'false' ? false : value; + return; + } if (key === 'level') { this._assert(!isNaN(Number(value)), 'Value of "level" attribute must be a number', errorPos); node.level = Number(value); diff --git a/packages/playwright-electron/index.js b/packages/isomorphic/base64.ts similarity index 70% rename from packages/playwright-electron/index.js rename to packages/isomorphic/base64.ts index 227eee0fde3b0..74af5669dd0d3 100644 --- a/packages/playwright-electron/index.js +++ b/packages/isomorphic/base64.ts @@ -14,4 +14,9 @@ * limitations under the License. */ -module.exports = require('./lib/index'); +export function base64ByteLength(data: string): number { + if (!data) + return 0; + const padding = (data[data.length - 2] === '=') ? 2 : ((data[data.length - 1] === '=') ? 1 : 0); + return Math.max(0, Math.floor(data.length * 3 / 4) - padding); +} diff --git a/packages/isomorphic/index.ts b/packages/isomorphic/index.ts index 23884d42e3ec4..fd97cdfbcfffb 100644 --- a/packages/isomorphic/index.ts +++ b/packages/isomorphic/index.ts @@ -17,6 +17,7 @@ export * from './ariaSnapshot'; export * from './expectUtils'; export * from './assert'; +export * from './base64'; export * from './colors'; export * from './headers'; export * from './imageUtils'; diff --git a/packages/isomorphic/locatorGenerators.ts b/packages/isomorphic/locatorGenerators.ts index 40464bea33b7e..00d1e23f0facd 100644 --- a/packages/isomorphic/locatorGenerators.ts +++ b/packages/isomorphic/locatorGenerators.ts @@ -163,9 +163,13 @@ function innerAsLocators(factory: LocatorFactory, parsed: ParsedSelector, isFram const options: LocatorOptions = { attrs: [] }; for (const attr of attrSelector.attributes) { if (attr.name === 'name') { + if (options.exact !== undefined && options.exact !== attr.caseSensitive) + throw new Error(`Conflicting exactness in internal:role selector: ${stringifySelector({ parts: [part] })}`); options.exact = attr.caseSensitive; options.name = attr.value; } else if (attr.name === 'description') { + if (options.exact !== undefined && options.exact !== attr.caseSensitive) + throw new Error(`Conflicting exactness in internal:role selector: ${stringifySelector({ parts: [part] })}`); options.exact = attr.caseSensitive; options.description = attr.value; } else { diff --git a/packages/isomorphic/locatorParser.ts b/packages/isomorphic/locatorParser.ts index ee98271f7a043..35212cc571bdd 100644 --- a/packages/isomorphic/locatorParser.ts +++ b/packages/isomorphic/locatorParser.ts @@ -15,6 +15,7 @@ */ import { asLocators } from './locatorGenerators'; +import { encodeTestIdAttributeName } from './locatorUtils'; import { parseSelector } from './selectorParser'; import { escapeForAttributeSelector, escapeForTextSelector } from './stringUtils'; @@ -165,7 +166,7 @@ function transform(template: string, params: TemplateParams, testIdAttributeName .replace(/getbyrole\(([^)]+)\)/g, 'internal:role=$1') .replace(/getbytext\(([^)]+)\)/g, 'internal:text=$1') .replace(/getbylabel\(([^)]+)\)/g, 'internal:label=$1') - .replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${testIdAttributeName}=$1]`) + .replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${encodeTestIdAttributeName(testIdAttributeName)}=$1]`) .replace(/getby(placeholder|alt|title)(?:text)?\(([^)]+)\)/g, 'internal:attr=[$1=$2]') .replace(/first(\(\))?/g, 'nth=0') .replace(/last(\(\))?/g, 'nth=-1') @@ -219,7 +220,7 @@ function transform(template: string, params: TemplateParams, testIdAttributeName }).join(' >> '); } -export function locatorOrSelectorAsSelector(language: Language, locator: string, testIdAttributeName: string): string { +export function locatorOrSelectorAsSelector(language: Language, locator: string, testIdAttributeName: string = 'data-testid'): string { try { return unsafeLocatorOrSelectorAsSelector(language, locator, testIdAttributeName); } catch (e) { @@ -227,7 +228,7 @@ export function locatorOrSelectorAsSelector(language: Language, locator: string, } } -export function unsafeLocatorOrSelectorAsSelector(language: Language, locator: string, testIdAttributeName: string): string { +export function unsafeLocatorOrSelectorAsSelector(language: Language, locator: string, testIdAttributeName: string = 'data-testid'): string { try { parseSelector(locator); return locator; diff --git a/packages/isomorphic/locatorUtils.ts b/packages/isomorphic/locatorUtils.ts index 50078679200b4..77cb2d715a7ef 100644 --- a/packages/isomorphic/locatorUtils.ts +++ b/packages/isomorphic/locatorUtils.ts @@ -33,8 +33,17 @@ function getByAttributeTextSelector(attrName: string, text: string | RegExp, opt return `internal:attr=[${attrName}=${escapeForAttributeSelector(text, options?.exact || false)}]`; } +// Multiple test id attribute names can be joined with a comma. Attribute names cannot contain commas. +export function splitTestIdAttributeNames(testIdAttributeName: string): string[] { + return testIdAttributeName.split(','); +} + +export function encodeTestIdAttributeName(testIdAttributeName: string): string { + return testIdAttributeName.includes(',') ? JSON.stringify(testIdAttributeName) : testIdAttributeName; +} + export function getByTestIdSelector(testIdAttributeName: string, testId: string | RegExp): string { - return `internal:testid=[${testIdAttributeName}=${escapeForAttributeSelector(testId, true)}]`; + return `internal:testid=[${encodeTestIdAttributeName(testIdAttributeName)}=${escapeForAttributeSelector(testId, true)}]`; } export function getByLabelSelector(text: string | RegExp, options?: { exact?: boolean }): string { diff --git a/packages/isomorphic/manualPromise.ts b/packages/isomorphic/manualPromise.ts index 3b237a0fe0257..bb16ada8e217d 100644 --- a/packages/isomorphic/manualPromise.ts +++ b/packages/isomorphic/manualPromise.ts @@ -113,6 +113,18 @@ export class LongStandingScope { } } +export function signalToPromise(signal: AbortSignal): { promise: Promise, dispose: () => void } { + if (signal.aborted) + return { promise: Promise.resolve(), dispose: () => {} }; + let dispose: (() => void) | undefined; + const promise = new Promise(resolve => { + const onAbort = () => resolve(); + signal.addEventListener('abort', onAbort, { once: true }); + dispose = () => signal.removeEventListener('abort', onAbort); + }); + return { promise, dispose: dispose! }; +} + function cloneError(error: Error, frames: string[]) { const clone = new Error(); clone.name = error.name; diff --git a/packages/isomorphic/protocolMetainfo.ts b/packages/isomorphic/protocolMetainfo.ts index 6fac0420d9486..b0e779d1b061a 100644 --- a/packages/isomorphic/protocolMetainfo.ts +++ b/packages/isomorphic/protocolMetainfo.ts @@ -16,7 +16,7 @@ // This file is generated by generate_channels.js, do not edit manually. -export type MethodMetainfo = { internal?: boolean, title?: string, slowMo?: boolean, snapshot?: boolean, pause?: boolean, isAutoWaiting?: boolean, input?: boolean, group?: string }; +export type MethodMetainfo = { internal?: boolean, title?: string, slowMo?: boolean, snapshot?: boolean, pause?: boolean, isAutoWaiting?: boolean, input?: boolean, potentiallyClosesScope?: boolean, group?: string }; export const methodMetainfo = new Map([ ['Android.devices', { internal: true, }], @@ -51,22 +51,22 @@ export const methodMetainfo = new Map([ ['APIRequestContext.fetchLog', { internal: true, }], ['APIRequestContext.storageState', { title: 'Get storage state', group: 'configuration', }], ['APIRequestContext.disposeAPIResponse', { internal: true, }], - ['APIRequestContext.dispose', { internal: true, }], + ['APIRequestContext.dispose', { internal: true, potentiallyClosesScope: true, }], ['Artifact.pathAfterFinished', { internal: true, }], ['Artifact.saveAs', { internal: true, }], ['Artifact.saveAsStream', { internal: true, }], ['Artifact.failure', { internal: true, }], ['Artifact.stream', { internal: true, }], ['Artifact.cancel', { internal: true, }], - ['Artifact.delete', { internal: true, }], + ['Artifact.delete', { internal: true, potentiallyClosesScope: true, }], ['Stream.read', { internal: true, }], ['Stream.close', { internal: true, }], ['WritableStream.write', { internal: true, }], ['WritableStream.close', { internal: true, }], ['Browser.startServer', { title: 'Start server', }], ['Browser.stopServer', { title: 'Stop server', }], - ['Browser.close', { title: 'Close browser', pause: true, }], - ['Browser.killForTests', { internal: true, }], + ['Browser.close', { title: 'Close browser', pause: true, potentiallyClosesScope: true, }], + ['Browser.killForTests', { internal: true, potentiallyClosesScope: true, }], ['Browser.defaultUserAgentForTest', { internal: true, }], ['Browser.newContext', { title: 'Create context', }], ['Browser.newContextForReuse', { internal: true, }], @@ -78,7 +78,7 @@ export const methodMetainfo = new Map([ ['BrowserContext.addInitScript', { title: 'Add init script', group: 'configuration', }], ['BrowserContext.clearCookies', { title: 'Clear cookies', group: 'configuration', }], ['BrowserContext.clearPermissions', { title: 'Clear permissions', group: 'configuration', }], - ['BrowserContext.close', { title: 'Close context', pause: true, }], + ['BrowserContext.close', { title: 'Close context', pause: true, potentiallyClosesScope: true, }], ['BrowserContext.cookies', { title: 'Get cookies', group: 'getter', }], ['BrowserContext.exposeBinding', { title: 'Expose binding', group: 'configuration', }], ['BrowserContext.grantPermissions', { title: 'Grant permissions', group: 'configuration', }], @@ -107,18 +107,21 @@ export const methodMetainfo = new Map([ ['BrowserContext.clockRunFor', { title: 'Run clock "{ticksNumber|ticksString}"', }], ['BrowserContext.clockSetFixedTime', { title: 'Set fixed time "{timeNumber|timeString}"', }], ['BrowserContext.clockSetSystemTime', { title: 'Set system time "{timeNumber|timeString}"', }], + ['BrowserContext.credentialsInstall', { title: 'Install virtual WebAuthn authenticator', }], + ['BrowserContext.credentialsCreate', { title: 'Create virtual credential for "{rpId}"', }], + ['BrowserContext.credentialsGet', { title: 'Get virtual credentials', }], + ['BrowserContext.credentialsDelete', { title: 'Delete virtual credential', }], + ['BrowserContext.credentialsSetUserVerified', { title: 'Set virtual authenticator user verified', }], ['BrowserType.launch', { title: 'Launch browser', }], ['BrowserType.launchPersistentContext', { title: 'Launch persistent context', }], ['BrowserType.connectOverCDP', { title: 'Connect over CDP', }], ['BrowserType.connectToWorker', { title: 'Connect to worker', }], - ['Disposable.dispose', { internal: true, }], - ['EventTarget.waitForEventInfo', { title: 'Wait for event "{info.event}"', snapshot: true, }], - ['AndroidDevice.waitForEventInfo', { title: 'Wait for event "{info.event}"', snapshot: true, }], - ['BrowserContext.waitForEventInfo', { title: 'Wait for event "{info.event}"', snapshot: true, }], - ['WebSocket.waitForEventInfo', { title: 'Wait for event "{info.event}"', snapshot: true, }], - ['Page.waitForEventInfo', { title: 'Wait for event "{info.event}"', snapshot: true, }], - ['Debugger.waitForEventInfo', { title: 'Wait for event "{info.event}"', snapshot: true, }], - ['Worker.waitForEventInfo', { title: 'Wait for event "{info.event}"', snapshot: true, }], + ['Disposable.dispose', { internal: true, potentiallyClosesScope: true, }], + ['Electron.launch', { title: 'Launch electron', }], + ['ElectronApplication.browserWindow', { internal: true, }], + ['ElectronApplication.evaluateExpression', { title: 'Evaluate', }], + ['ElectronApplication.evaluateExpressionHandle', { title: 'Evaluate', }], + ['ElectronApplication.updateSubscription', { internal: true, }], ['Frame.evalOnSelector', { title: 'Evaluate', snapshot: true, pause: true, }], ['Frame.evalOnSelectorAll', { title: 'Evaluate', snapshot: true, pause: true, }], ['Frame.addScriptTag', { title: 'Add script tag', snapshot: true, pause: true, }], @@ -126,7 +129,7 @@ export const methodMetainfo = new Map([ ['Frame.ariaSnapshot', { title: 'Aria snapshot', group: 'getter', }], ['Frame.blur', { title: 'Blur', slowMo: true, snapshot: true, pause: true, }], ['Frame.check', { title: 'Check', slowMo: true, snapshot: true, pause: true, input: true, isAutoWaiting: true, }], - ['Frame.click', { title: 'Click', slowMo: true, snapshot: true, pause: true, input: true, isAutoWaiting: true, }], + ['Frame.click', { title: 'Click', slowMo: true, snapshot: true, pause: true, input: true, isAutoWaiting: true, potentiallyClosesScope: true, }], ['Frame.content', { title: 'Get content', snapshot: true, pause: true, }], ['Frame.dragAndDrop', { title: 'Drag and drop', slowMo: true, snapshot: true, pause: true, input: true, isAutoWaiting: true, }], ['Frame.drop', { title: 'Drop files or data onto an element', slowMo: true, snapshot: true, pause: true, input: true, isAutoWaiting: true, }], @@ -168,8 +171,8 @@ export const methodMetainfo = new Map([ ['Frame.waitForFunction', { title: 'Wait for function', snapshot: true, pause: true, }], ['Frame.waitForSelector', { title: 'Wait for selector', snapshot: true, }], ['Frame.expect', { title: 'Expect "{expression}"', snapshot: true, pause: true, }], - ['JSHandle.dispose', { internal: true, }], - ['ElementHandle.dispose', { internal: true, }], + ['JSHandle.dispose', { internal: true, potentiallyClosesScope: true, }], + ['ElementHandle.dispose', { internal: true, potentiallyClosesScope: true, }], ['JSHandle.evaluateExpression', { title: 'Evaluate', snapshot: true, pause: true, }], ['ElementHandle.evaluateExpression', { title: 'Evaluate', snapshot: true, pause: true, }], ['JSHandle.evaluateExpressionHandle', { title: 'Evaluate', snapshot: true, pause: true, }], @@ -245,7 +248,8 @@ export const methodMetainfo = new Map([ ['Response.httpVersion', { internal: true, }], ['Response.sizes', { internal: true, }], ['Page.addInitScript', { title: 'Add init script', group: 'configuration', }], - ['Page.close', { title: 'Close page', pause: true, }], + ['Page.close', { title: 'Close page', pause: true, potentiallyClosesScope: true, }], + ['Page.runBeforeUnload', { title: 'Run beforeunload', pause: true, }], ['Page.clearConsoleMessages', { title: 'Clear console messages', }], ['Page.consoleMessages', { title: 'Get console messages', group: 'getter', }], ['Page.emulateMedia', { title: 'Emulate media', snapshot: true, pause: true, }], @@ -296,6 +300,11 @@ export const methodMetainfo = new Map([ ['Page.screencastStop', { title: 'Stop screencast', group: 'configuration', }], ['Page.updateSubscription', { internal: true, }], ['Page.setDockTile', { internal: true, }], + ['Page.webStorageItems', { title: 'Get WebStorage items', group: 'getter', }], + ['Page.webStorageGetItem', { title: 'Get WebStorage item', group: 'getter', }], + ['Page.webStorageSetItem', { title: 'Set WebStorage item', group: 'configuration', }], + ['Page.webStorageRemoveItem', { title: 'Remove WebStorage item', group: 'configuration', }], + ['Page.webStorageClear', { title: 'Clear WebStorage', group: 'configuration', }], ['Root.initialize', { internal: true, }], ['Playwright.newRequest', { title: 'Create request context', }], ['DebugController.initialize', { internal: true, }], @@ -313,7 +322,7 @@ export const methodMetainfo = new Map([ ['JsonPipe.send', { internal: true, }], ['JsonPipe.close', { internal: true, }], ['CDPSession.send', { title: 'Send CDP command', group: 'configuration', }], - ['CDPSession.detach', { title: 'Detach CDP session', group: 'configuration', }], + ['CDPSession.detach', { title: 'Detach CDP session', potentiallyClosesScope: true, group: 'configuration', }], ['BindingCall.reject', { internal: true, }], ['BindingCall.resolve', { internal: true, }], ['Debugger.requestPause', { title: 'Pause on next call', group: 'configuration', }], @@ -330,7 +339,7 @@ export const methodMetainfo = new Map([ ['Tracing.tracingStop', { title: 'Stop tracing', group: 'configuration', }], ['Tracing.harStart', { internal: true, }], ['Tracing.harExport', { internal: true, }], - ['Worker.disconnect', { title: 'Disconnect from worker', }], + ['Worker.disconnect', { title: 'Disconnect from worker', potentiallyClosesScope: true, }], ['Worker.evaluateExpression', { title: 'Evaluate', }], ['Worker.evaluateExpressionHandle', { title: 'Evaluate', }], ['Worker.updateSubscription', { internal: true, }] diff --git a/packages/isomorphic/rtti.ts b/packages/isomorphic/rtti.ts index ffef6c1cad4ca..b139d3290fd6e 100644 --- a/packages/isomorphic/rtti.ts +++ b/packages/isomorphic/rtti.ts @@ -20,6 +20,15 @@ export function isRegExp(obj: any): obj is RegExp { return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]'; } +export function isRegexString(value: string): boolean { + try { + new RegExp(value); + return true; + } catch { + return false; + } +} + export function isObject(obj: any): obj is NonNullable { return typeof obj === 'object' && obj !== null; } diff --git a/packages/isomorphic/stringUtils.ts b/packages/isomorphic/stringUtils.ts index 6e8a9115071ba..c4a3476818962 100644 --- a/packages/isomorphic/stringUtils.ts +++ b/packages/isomorphic/stringUtils.ts @@ -189,7 +189,25 @@ export function parseRegex(regex: string): RegExp { return new RegExp(source, flags); } -export const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g'); +export function tomlBasicString(value: string): string { + // JSON.stringify produces a valid TOML basic string: escapes \", \\, \n, \r, \t and uses \uXXXX for control chars. + return JSON.stringify(value); +} + +export function tomlArray(values: string[]): string { + return `[${values.map(value => tomlBasicString(value)).join(', ')}]`; +} + +export function tomlMultilineBasicString(value: string): string { + // Triple-quoted basic string: escape backslashes first, then any literal """ sequences. + const escaped = value.replace(/\\/g, '\\\\').replace(/"""/g, '\\"\\"\\"'); + return `"""\n${escaped}\n"""`; +} + +// Semicolons removed from [[\]()#;?] to avoid polynomial backtracking +// when both that group and (?:;...)* can match runs of semicolons. +// \d{1,4} relaxed to \d{0,4} so empty params (e.g. ESC[;H) still match. +export const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{0,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g'); export function stripAnsiEscapes(str: string): string { return str.replace(ansiRegex, ''); } diff --git a/packages/isomorphic/trace/snapshotRenderer.ts b/packages/isomorphic/trace/snapshotRenderer.ts index 368bd33448101..7001dea03f89a 100644 --- a/packages/isomorphic/trace/snapshotRenderer.ts +++ b/packages/isomorphic/trace/snapshotRenderer.ts @@ -99,29 +99,51 @@ export class SnapshotRenderer { } } else if (isNodeNameAttributesChildNodesSnapshot(n)) { const [name, nodeAttrs, ...children] = n; + // Filter SCRIPT elements. The capture side already strips these, but a + // crafted trace file could include them to achieve XSS. + if (name.toUpperCase() === 'SCRIPT') + return; // Element node. // Note that