diff --git a/.eslintrc.js b/.eslintrc.js index ddb2ec8561bb95..7bc5a0868f09b1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -71,6 +71,7 @@ module.exports = { "valid-typeof": 2, "no-implicit-globals": [2], "no-unused-expressions": [2, { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true}], + "no-proto": 2, // es2015 features "require-yield": 2, diff --git a/.gitattributes b/.gitattributes index 653dde78b55b52..c2515b4ffe5174 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ # text files must be lf for golden file tests to work * text=auto eol=lf - # make project show as TS on GitHub *.js linguist-detectable=false diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 6b212dcc6931be..370d836a4e0a75 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -7,43 +7,66 @@ assignees: '' --- -**Context:** -- Playwright Version: [what Playwright version do you use?] -- Operating System: [e.g. Windows, Linux or Mac] -- Node.js version: [e.g. 12.22, 14.6] -- Browser: [e.g. All, Chromium, Firefox, WebKit] -- Extra: [any specific details about your environment] - - - - -**Code Snippet** - -Help us help you! Put down a short code snippet that illustrates your bug and -that we can run and debug locally. For example: - -```javascript -const {chromium, webkit, firefox} = require('playwright'); - -(async () => { - const browser = await chromium.launch(); - const context = await browser.newContext(); - const page = await context.newPage(); - - // Please include a snippet of HTML that shows an example of the content - // you are testing. - await page.setContent(` -
- … -
- `); - // Alternatively, if you are testing a public application, include the URL: - // await page.goto('https://example.com/') - - await page.locator(…); -})(); + + + + + + +### System info +- Playwright Version: [v1.XX] +- Operating System: [All, Windows 11, Ubuntu 20, macOS 13.2, etc.] +- Browser: [All, Chromium, Firefox, WebKit] +- Other info: + +### Source code + +- [ ] I provided exact source code that allows reproducing the issue locally. + + + + + + +**Link to the GitHub repository with the repro** + +[https://github.com/your_profile/playwright_issue_title] + +or + +**Config file** + +```js +// playwright.config.ts +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'], }, + }, +}); +``` + +**Test file (self-contained)** + +```js +it('should check the box using setChecked', async ({ page }) => { + await page.setContent(``); + await page.getByRole('checkbox').check(); + await expect(page.getByRole('checkbox')).toBeChecked(); +}); ``` -**Describe the bug** +**Steps** +- [Run the test] +- [...] + +**Expected** + +[Describe expected behavior] + +**Actual** -Add any other details about the problem here. +[Describe actual behavior] diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index ee5b58e0a72458..de718587756aa6 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ contact_links: - - name: Join our GitHub Discussions community - url: https://github.com/microsoft/playwright/discussions - about: Ask questions and discuss with other community members + - name: Join our Discord Server + url: https://aka.ms/playwright/discord + about: Ask questions and discuss with other community members \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 55abfc3ec011b6..00000000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: I have a question -about: Feel free to ask us your questions! -title: "[Question]" -labels: '' -assignees: '' - ---- - - diff --git a/.github/ISSUE_TEMPLATE/vscode-extension.md b/.github/ISSUE_TEMPLATE/vscode-extension.md new file mode 100644 index 00000000000000..e623fa9de1ca81 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/vscode-extension.md @@ -0,0 +1,26 @@ +--- +name: VSCode extension bug +about: Something doesn't work like it should inside the Visual Studio Code extension or you have a feature request? Tell us! +title: "[BUG]" +labels: '' +assignees: '' + +--- + +**Context:** +- Playwright Version: [what Playwright version do you use?] +- Operating System: [e.g. Windows, Linux or Mac] +- Node.js version: [e.g. 12.22, 14.6] +- Visual Studio Code version: [e.g. 1.65] +- Playwright for VSCode extension version: [e.g. 1.2.3] +- Browser: [e.g. All, Chromium, Firefox, WebKit] +- Extra: [any specific details about your environment] + +**Code Snippet** + +Help us help you! Put down a short code snippet that illustrates your bug and +that we can run and debug locally. For example: + +**Describe the bug** + +Add any other details about the problem here. diff --git a/.github/actions/download-artifact/action.yml b/.github/actions/download-artifact/action.yml new file mode 100644 index 00000000000000..874b202c060ae8 --- /dev/null +++ b/.github/actions/download-artifact/action.yml @@ -0,0 +1,40 @@ +name: 'Download blob report' +description: 'Download blob report from GitHub artifacts' +inputs: + name: + description: 'Name of the artifact to download' + required: true + type: string + default: 'blob-report' + path: + description: 'Directory with downloaded artifacts' + required: true + type: string + default: 'blob-report' +runs: + using: "composite" + steps: + - name: Download blob report + uses: actions/github-script@v6 + with: + script: | + console.log(`downloading artifacts for workflow_run: ${context.payload.workflow_run.id}`); + console.log(`workflow_run: ${JSON.stringify(context.payload.workflow_run, null, 2)}`); + const { data } = await github.rest.actions.listWorkflowRunArtifacts({ + ...context.repo, + run_id: context.payload.workflow_run.id + }); + console.log('total = ', data.total_count); + const name = '${{ inputs.name }}'; + const report = data.artifacts.filter(a => a.name === name)[0]; + const result = await github.rest.actions.downloadArtifact({ + ...context.repo, + artifact_id: report.id, + archive_format: 'zip' + }); + console.log('download result', result); + const fs = require('fs'); + fs.writeFileSync(`${name}.zip`, Buffer.from(result.data)); + - name: Unzip blob report + shell: bash + run: unzip ${{ inputs.name }}.zip -d ${{ inputs.path }} diff --git a/.github/actions/download-blob-report-from-azure/action.yml b/.github/actions/download-blob-report-from-azure/action.yml new file mode 100644 index 00000000000000..8026de64ea2e50 --- /dev/null +++ b/.github/actions/download-blob-report-from-azure/action.yml @@ -0,0 +1,29 @@ +name: 'Download blob report from Azure' +description: 'Download blob report from Azure blob storage' +inputs: + blob_prefix: + description: 'Name of the Azure blob storage directory containing blob report' + required: true + type: string + output_dir: + description: 'Output directory where downloaded blobs will be stored' + required: true + type: string + default: 'blob-report' + connection_string: + description: 'Azure connection string' + required: true + type: string +runs: + using: "composite" + steps: + - name: Download Blob Reports from Azure Blob Storage + shell: bash + run: | + OUTPUT_DIR='${{ inputs.output_dir }}' + mkdir -p $OUTPUT_DIR + LIST=$(az storage blob list -c '$web' --prefix ${{ inputs.blob_prefix }} --connection-string "${{ inputs.connection_string }}") + for name in $(echo $LIST | jq --raw-output '.[].name | select(test("report-.*\\.zip$"))'); + do + az storage blob download -c '$web' --name $name -f $OUTPUT_DIR/$(basename $name) --connection-string "${{ inputs.connection_string }}" + done diff --git a/.github/actions/upload-blob-report/action.yml b/.github/actions/upload-blob-report/action.yml new file mode 100644 index 00000000000000..1747c5f69c26e6 --- /dev/null +++ b/.github/actions/upload-blob-report/action.yml @@ -0,0 +1,38 @@ +name: 'Upload blob report' +description: 'Upload blob to Azure blob storage or to GitHub artifacts (for pull requests)' +inputs: + report_dir: + description: 'Directory containing blob report' + required: true + type: string + default: 'test-results/blob-report' + connection_string: + description: 'Azure connection string' + required: true + type: string +runs: + using: "composite" + steps: + - name: Upload blob report to Azure + if: always() && github.event_name == 'push' + shell: bash + run: | + REPORT_DIR='run-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.sha }}' + az storage blob upload-batch -s "${{ inputs.report_dir }}" -d "\$web/$REPORT_DIR" --connection-string "${{ inputs.connection_string }}" + - name: Upload blob report to GitHub + if: always() && github.event_name == 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: blob-report-${{ github.run_attempt }} + path: ${{ inputs.report_dir }} + retention-days: 30 + - name: Write triggering pull request number in a file + if: always() && github.event_name == 'pull_request' + shell: bash + run: echo '${{ github.event.number }}' > pull_request_number.txt; + - name: Upload artifact with the pull request number + if: always() && github.event_name == 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: pull-request + path: pull_request_number.txt diff --git a/.github/workflows/cherry_pick_into_release_branch.yml b/.github/workflows/cherry_pick_into_release_branch.yml index 30fff595246470..c326509e35b99c 100644 --- a/.github/workflows/cherry_pick_into_release_branch.yml +++ b/.github/workflows/cherry_pick_into_release_branch.yml @@ -23,7 +23,7 @@ jobs: echo "Version is not a two digit semver version" exit 1 fi - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: release-${{ github.event.inputs.version }} fetch-depth: 0 @@ -42,27 +42,27 @@ jobs: console.log(process.argv[1]); process.exit(0); } - console.log(`chery-pick${match[2]}: ${match[1]}`); + console.log(`cherry-pick${match[2]}: ${match[1]}`); ' "$COMMIT_MESSAGE") git commit -m "$COMMIT_MESSAGE" done LAST_COMMIT_MESSAGE=$(git show -s --format=%B) - echo "::set-output name=PR_TITLE::$LAST_COMMIT_MESSAGE" + echo "PR_TITLE=$LAST_COMMIT_MESSAGE" >> $GITHUB_OUTPUT - name: Prepare branch id: prepare-branch run: | BRANCH_NAME="cherry-pick-${{ github.event.inputs.version }}-$(date +%Y-%m-%d-%H-%M-%S)" - echo "::set-output name=BRANCH_NAME::$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT git checkout -b "$BRANCH_NAME" git push origin $BRANCH_NAME - name: Create Pull Request - uses: actions/github-script@v4 + uses: actions/github-script@v6 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | const readableCommitHashesList = '${{ github.event.inputs.commit_hashes }}'.split(',').map(hash => `- ${hash}`).join('\n'); - const response = await github.pulls.create({ + const response = await github.rest.pulls.create({ owner: 'microsoft', repo: 'playwright', head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', @@ -70,7 +70,7 @@ jobs: title: '${{ steps.cherry-pick.outputs.PR_TITLE }}', body: `This PR cherry-picks the following commits:\n\n${readableCommitHashesList}`, }); - await github.issues.addLabels({ + await github.rest.issues.addLabels({ owner: 'microsoft', repo: 'playwright', issue_number: response.data.number, diff --git a/.github/workflows/create_test_report.yml b/.github/workflows/create_test_report.yml new file mode 100644 index 00000000000000..026589613bc672 --- /dev/null +++ b/.github/workflows/create_test_report.yml @@ -0,0 +1,127 @@ +name: Publish Test Results +on: + workflow_run: + workflows: ["tests 1", "tests 2"] + types: + - completed +jobs: + merge-reports: + permissions: + pull-requests: write + checks: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - run: npm ci + env: + DEBUG: pw:install + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + - run: npm run build + + - name: Download blob report artifact + if: ${{ always() && github.event.workflow_run.event == 'pull_request' }} + uses: ./.github/actions/download-artifact + with: + name: 'blob-report-${{ github.event.workflow_run.run_attempt }}' + path: 'blob-report' + - name: Download blob report from Azure + if: ${{ always() && github.event.workflow_run.event == 'push' }} + uses: ./.github/actions/download-blob-report-from-azure + with: + blob_prefix: 'run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}' + output_dir: 'blob-report' + connection_string: '${{ secrets.AZURE_CONNECTION_STRING_FOR_BLOB_REPORT }}' + + - name: Merge reports + run: | + npx playwright merge-reports --reporter markdown,html --attachments missing blob-report + + - name: Upload HTML report to Azure + run: | + REPORT_DIR='run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}' + az storage blob upload-batch -s playwright-report -d "\$web/$REPORT_DIR" --connection-string "${{ secrets.AZURE_CONNECTION_STRING_FOR_BLOB_REPORT }}" + echo "Report url: https://mspwblobreport.z1.web.core.windows.net/$REPORT_DIR/index.html" + + - name: Upload blob report to Azure + if: ${{ github.event.workflow_run.event == 'pull_request' }} + run: | + REPORT_DIR='run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}' + az storage blob upload-batch -s blob-report -d "\$web/$REPORT_DIR" --connection-string "${{ secrets.AZURE_CONNECTION_STRING_FOR_BLOB_REPORT }}" + + - name: Read pull request number + if: ${{ always() && github.event.workflow_run.event == 'pull_request' }} + uses: ./.github/actions/download-artifact + with: + name: 'pull-request' + path: './' + + - name: Comment on PR + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + let prNumber; + if (context.payload.workflow_run.event === 'pull_request') { + const prs = context.payload.workflow_run.pull_requests; + if (prs.length) { + prNumber = prs[0].number; + } else { + prNumber = parseInt(fs.readFileSync('pull_request_number.txt').toString()); + console.log('Read pull request number from file: ' + prNumber); + } + } else if (context.payload.workflow_run.event === 'push') { + const { data } = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + ...context.repo, + commit_sha: context.sha, + }); + if (!data.length) { + core.info(`No pull request found for commit ${context.sha}. Not publishing anything.`); + return; + } + prNumber = data[0].number; + } else { + core.error('Unsupported workflow trigger event: ' + context.payload.workflow_run.event); + return; + } + if (!prNumber) { + core.error('No pull request found for commit ' + context.sha + ' and workflow triggered by: ' + context.payload.workflow_run.event); + return; + } + const reportDir = 'run-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}-${{ github.sha }}'; + const reportUrl = `https://mspwblobreport.z1.web.core.windows.net/${reportDir}/index.html#?q=s%3Afailed%20s%3Aflaky`; + core.notice('Report url: ' + reportUrl); + const mergeWorkflowUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + const reportMd = await fs.promises.readFile('report.md', 'utf8'); + const { data: response } = await github.rest.issues.createComment({ + ...context.repo, + issue_number: prNumber, + body: [ + `### [Test results](${reportUrl}) for "${{ github.event.workflow_run.name }}"`, + reportMd, + '', + `Merge [workflow run](${mergeWorkflowUrl}).` + ].join('\n'), + }); + core.info('Posted comment: ' + response.html_url); + + const check = await github.rest.checks.create({ + ...context.repo, + name: 'Merge report (${{ github.event.workflow_run.name }})', + head_sha: '${{ github.event.workflow_run.head_sha }}', + status: 'completed', + conclusion: 'success', + details_url: reportUrl, + output: { + title: 'Test results for "${{ github.event.workflow_run.name }}"', + summary: [ + reportMd, + '---', + `Full [HTML report](${reportUrl}). Merge [workflow run](${mergeWorkflowUrl}).` + ].join('\n'), + } + }); diff --git a/.github/workflows/infra.yml b/.github/workflows/infra.yml index 29d3c57386f5c1..7f42f62676acad 100644 --- a/.github/workflows/infra.yml +++ b/.github/workflows/infra.yml @@ -10,15 +10,18 @@ on: - main - release-* +env: + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + jobs: doc-and-lint: name: "docs & lint" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - run: npm i -g npm@8 - run: npm ci - run: npm run build diff --git a/.github/workflows/pr_check_client_side_changes.yml b/.github/workflows/pr_check_client_side_changes.yml index fc8e5cbd1614fd..57c96a60ad6e57 100644 --- a/.github/workflows/pr_check_client_side_changes.yml +++ b/.github/workflows/pr_check_client_side_changes.yml @@ -13,11 +13,11 @@ jobs: if: github.repository == 'microsoft/playwright' steps: - name: Create GitHub issue - uses: actions/github-script@v4 + uses: actions/github-script@v6 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | - const { data } = await github.git.getCommit({ + const { data } = await github.rest.git.getCommit({ owner: context.repo.owner, repo: context.repo.repo, commit_sha: context.sha, @@ -26,7 +26,7 @@ jobs: const title = '[Ports]: Backport client side changes'; for (const repo of ['playwright-python', 'playwright-java', 'playwright-dotnet']) { - const { data: issuesData } = await github.search.issuesAndPullRequests({ + const { data: issuesData } = await github.rest.search.issuesAndPullRequests({ q: `is:issue is:open repo:microsoft/${repo} in:title "${title}"` }) let issueNumber = null; @@ -35,7 +35,7 @@ jobs: issueNumber = issuesData.items[0].number issueBody = issuesData.items[0].body } else { - const { data: issueCreateData } = await github.issues.create({ + const { data: issueCreateData } = await github.rest.issues.create({ owner: context.repo.owner, repo: repo, title, @@ -46,7 +46,7 @@ jobs: } const newBody = issueBody.trimEnd() + ` - [ ] https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${context.sha} (${commitHeader})`; - const data = await github.issues.update({ + const data = await github.rest.issues.update({ owner: context.repo.owner, repo: repo, issue_number: issueNumber, diff --git a/.github/workflows/publish_canary.yml b/.github/workflows/publish_canary.yml index b390b9ea98a9f5..9fa09f1ef4acd1 100644 --- a/.github/workflows/publish_canary.yml +++ b/.github/workflows/publish_canary.yml @@ -8,16 +8,19 @@ on: branches: - release-* +env: + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + jobs: publish-canary: name: "publish canary NPM & Publish canary Docker" runs-on: ubuntu-20.04 if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 registry-url: 'https://registry.npmjs.org' - run: npm i -g npm@8 - run: npm ci @@ -58,7 +61,7 @@ jobs: username: playwright password: ${{ secrets.DOCKER_PASSWORD }} - name: Set up Docker QEMU for arm64 docker builds - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 with: platforms: arm64 - name: publish docker canary @@ -69,10 +72,10 @@ jobs: runs-on: ubuntu-20.04 if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - run: npm i -g npm@8 - name: Deploy Canary run: bash utils/build/deploy-trace-viewer.sh --canary diff --git a/.github/workflows/publish_release_docker.yml b/.github/workflows/publish_release_docker.yml index 6d13fbcd80a504..fe41b5f0bce680 100644 --- a/.github/workflows/publish_release_docker.yml +++ b/.github/workflows/publish_release_docker.yml @@ -11,16 +11,19 @@ on: release: types: [published] +env: + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + jobs: publish-docker-release: name: "publish to DockerHub" runs-on: ubuntu-20.04 if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 registry-url: 'https://registry.npmjs.org' - uses: azure/docker-login@v1 with: @@ -28,7 +31,7 @@ jobs: username: playwright password: ${{ secrets.DOCKER_PASSWORD }} - name: Set up Docker QEMU for arm64 docker builds - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 with: platforms: arm64 - run: npm i -g npm@8 diff --git a/.github/workflows/publish_release_driver.yml b/.github/workflows/publish_release_driver.yml index bbc7fd60c5acba..f97ce2e884f363 100644 --- a/.github/workflows/publish_release_driver.yml +++ b/.github/workflows/publish_release_driver.yml @@ -4,16 +4,19 @@ on: release: types: [published] +env: + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + jobs: publish-driver-release: name: "publish playwright driver to CDN" runs-on: ubuntu-20.04 if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 registry-url: 'https://registry.npmjs.org' - run: npm i -g npm@8 - run: npm ci diff --git a/.github/workflows/publish_release_npm.yml b/.github/workflows/publish_release_npm.yml index 0f71a5d8376297..474157edf1e12c 100644 --- a/.github/workflows/publish_release_npm.yml +++ b/.github/workflows/publish_release_npm.yml @@ -4,16 +4,19 @@ on: release: types: [published] +env: + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + jobs: publish-npm-release: name: "publish to NPM" runs-on: ubuntu-20.04 if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 registry-url: 'https://registry.npmjs.org' - run: npm i -g npm@8 - run: npm ci diff --git a/.github/workflows/publish_release_traceviewer.yml b/.github/workflows/publish_release_traceviewer.yml index bb69f98a29da03..5d2de305fcff57 100644 --- a/.github/workflows/publish_release_traceviewer.yml +++ b/.github/workflows/publish_release_traceviewer.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-20.04 if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - run: npm i -g npm@8 - name: Deploy Stable run: bash utils/build/deploy-trace-viewer.sh --stable diff --git a/.github/workflows/roll_browser_into_playwright.yml b/.github/workflows/roll_browser_into_playwright.yml index 2085178edf8884..53f3244b15a0cb 100644 --- a/.github/workflows/roll_browser_into_playwright.yml +++ b/.github/workflows/roll_browser_into_playwright.yml @@ -4,14 +4,17 @@ on: repository_dispatch: types: [roll_into_pw] +env: + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + jobs: roll: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - run: npm i -g npm@8 - run: npm ci - run: npm run build @@ -25,7 +28,7 @@ jobs: id: prepare-branch run: | BRANCH_NAME="roll-into-pw-${{ github.event.client_payload.browser }}/${{ github.event.client_payload.revision }}" - echo "::set-output name=BRANCH_NAME::$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT git config --global user.name github-actions git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com git checkout -b "$BRANCH_NAME" @@ -33,18 +36,18 @@ jobs: git commit -m "feat(${{ github.event.client_payload.browser }}): roll to r${{ github.event.client_payload.revision }}" git push origin $BRANCH_NAME - name: Create Pull Request - uses: actions/github-script@v4 + uses: actions/github-script@v6 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | - const response = await github.pulls.create({ + const response = await github.rest.pulls.create({ owner: 'microsoft', repo: 'playwright', head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', base: 'main', title: 'feat(${{ github.event.client_payload.browser }}): roll to r${{ github.event.client_payload.revision }}', }); - await github.issues.addLabels({ + await github.rest.issues.addLabels({ owner: 'microsoft', repo: 'playwright', issue_number: response.data.number, diff --git a/.github/workflows/roll_chromium_build.yml b/.github/workflows/roll_chromium_build.yml deleted file mode 100644 index 9a766e1197b319..00000000000000 --- a/.github/workflows/roll_chromium_build.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: "PR: bump chromium/BUILD_NUMBER" -on: - workflow_dispatch: - schedule: - # At 10:00am UTC (3AM PST) every day to build every new Chromium beta - - cron: "0 10 * * *" -jobs: - trigger-chromium-build: - name: Trigger Build - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - run: ./browser_patches/chromium/roll_to_current_beta.sh - - name: Prepare branch - id: prepare-branch - run: | - if [[ "$(git status --porcelain)" == "" ]]; then - echo "there are no changes"; - exit 0; - fi - echo "::set-output name=HAS_CHANGES::1" - CURRENT_DATE=$(date +%Y-%b-%d) - BRANCH_NAME="roll-chromium/${CURRENT_DATE}" - echo "::set-output name=BRANCH_NAME::$BRANCH_NAME" - echo "::set-output name=CURRENT_DATE::$CURRENT_DATE" - git config --global user.name github-actions - git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com - git checkout -b "$BRANCH_NAME" - git add . - git commit -m "browser(chromium): roll to $CURRENT_DATE" - git push origin $BRANCH_NAME - - name: Create Pull Request - if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@v4 - with: - script: | - await github.pulls.create({ - owner: 'microsoft', - repo: 'playwright', - head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', - base: 'main', - title: 'browser(chromium): roll to ${{ steps.prepare-branch.outputs.CURRENT_DATE }}', - }); diff --git a/.github/workflows/roll_chromium_tip_of_treebuild.yml b/.github/workflows/roll_chromium_tip_of_treebuild.yml deleted file mode 100644 index a55d64144415c3..00000000000000 --- a/.github/workflows/roll_chromium_tip_of_treebuild.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: "PR: bump chromium-tip-of-tree/BUILD_NUMBER" -on: - workflow_dispatch: - schedule: - # At 10:00am UTC (3AM PST) every tuesday and thursday to build new Chromium Tip-of-tree - - cron: "0 10 * * 2,4" -jobs: - trigger-chromium-build: - name: Trigger Build - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - run: ./browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh - - name: Prepare branch - id: prepare-branch - run: | - if [[ "$(git status --porcelain)" == "" ]]; then - echo "there are no changes"; - exit 0; - fi - echo "::set-output name=HAS_CHANGES::1" - CURRENT_DATE=$(date +%Y-%b-%d) - BRANCH_NAME="roll-tip-of-tree-chromium/${CURRENT_DATE}" - echo "::set-output name=BRANCH_NAME::$BRANCH_NAME" - echo "::set-output name=CURRENT_DATE::$CURRENT_DATE" - git config --global user.name github-actions - git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com - git checkout -b "$BRANCH_NAME" - git add . - git commit -m "browser(chromium-tip-of-tree): roll to $CURRENT_DATE" - git push origin $BRANCH_NAME - - name: Create Pull Request - if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@v4 - with: - script: | - await github.pulls.create({ - owner: 'microsoft', - repo: 'playwright', - head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', - base: 'main', - title: 'browser(chromium-tip-of-tree): roll to ${{ steps.prepare-branch.outputs.CURRENT_DATE }}', - }); diff --git a/.github/workflows/roll_driver_nodejs.yml b/.github/workflows/roll_driver_nodejs.yml index 5a2ade5977edbd..bef065ca716efd 100644 --- a/.github/workflows/roll_driver_nodejs.yml +++ b/.github/workflows/roll_driver_nodejs.yml @@ -8,11 +8,12 @@ jobs: trigger-nodejs-roll: name: Trigger Roll runs-on: ubuntu-22.04 + if: github.repository == 'microsoft/playwright' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - run: node utils/build/update-playwright-driver-version.mjs - name: Prepare branch id: prepare-branch @@ -21,9 +22,9 @@ jobs: echo "there are no changes"; exit 0; fi - echo "::set-output name=HAS_CHANGES::1" + echo "HAS_CHANGES=1" >> $GITHUB_OUTPUT BRANCH_NAME="roll-driver-nodejs/$(date +%Y-%b-%d)" - echo "::set-output name=BRANCH_NAME::$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT git config --global user.name github-actions git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com git checkout -b "$BRANCH_NAME" @@ -32,10 +33,11 @@ jobs: git push origin $BRANCH_NAME - name: Create Pull Request if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@v4 + uses: actions/github-script@v6 with: + github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | - await github.pulls.create({ + await github.rest.pulls.create({ owner: 'microsoft', repo: 'playwright', head: 'microsoft:${{ steps.prepare-branch.outputs.BRANCH_NAME }}', diff --git a/.github/workflows/tests_components.yml b/.github/workflows/tests_components.yml index 7567b5bebc9964..bd1d4396b36793 100644 --- a/.github/workflows/tests_components.yml +++ b/.github/workflows/tests_components.yml @@ -15,6 +15,7 @@ on: env: FORCE_COLOR: 1 + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 jobs: test_components: @@ -25,10 +26,9 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - # Component tests require Node.js 16+ (they require ESM via TS) node-version: 16 - run: npm i -g npm@8 - run: npm ci diff --git a/.github/workflows/tests_electron.yml b/.github/workflows/tests_electron.yml index c278439322c20d..f11d9b17a5bf2c 100644 --- a/.github/workflows/tests_electron.yml +++ b/.github/workflows/tests_electron.yml @@ -28,10 +28,10 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - run: npm i -g npm@8 - run: npm ci env: @@ -47,8 +47,3 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: always() && matrix.os == 'ubuntu-latest' - with: - name: electron-linux-test-results - path: test-results diff --git a/.github/workflows/tests_primary.yml b/.github/workflows/tests_primary.yml index 9283e931027d06..5d74c721a32a23 100644 --- a/.github/workflows/tests_primary.yml +++ b/.github/workflows/tests_primary.yml @@ -23,6 +23,7 @@ env: # Force terminal colors. @see https://www.npmjs.com/package/colors FORCE_COLOR: 1 FLAKINESS_CONNECTION_STRING: ${{ secrets.FLAKINESS_CONNECTION_STRING }} + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 jobs: test_linux: @@ -32,21 +33,20 @@ jobs: matrix: browser: [chromium, firefox, webkit] os: [ubuntu-22.04] - node-version: [14] + node-version: [16] include: - os: ubuntu-22.04 - node-version: 16 + node-version: 18 browser: chromium - os: ubuntu-22.04 - node-version: 18 + node-version: 20 browser: chromium runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - run: npm i -g npm@8 - run: npm ci env: DEBUG: pw:install @@ -54,15 +54,18 @@ jobs: - run: npm run build - run: npx playwright install --with-deps ${{ matrix.browser }} chromium - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project=${{ matrix.browser }} + env: + PWTEST_BLOB_SUFFIX: "-${{ matrix.os }}-node${{ matrix.node-version }}" - run: node tests/config/checkCoverage.js ${{ matrix.browser }} - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 + - name: Upload blob report if: always() + uses: ./.github/actions/upload-blob-report with: - name: ${{ matrix.browser }}-${{ matrix.os }}-test-results - path: test-results + report_dir: test-results/blob-report + connection_string: '${{ secrets.AZURE_CONNECTION_STRING_FOR_BLOB_REPORT }}' test_linux_chromium_tot: name: ${{ matrix.os }} (chromium tip-of-tree) @@ -72,11 +75,10 @@ jobs: os: [ubuntu-20.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install @@ -86,14 +88,10 @@ jobs: - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project=chromium env: PWTEST_CHANNEL: chromium-tip-of-tree + PWTEST_BLOB_SUFFIX: "-${{ matrix.os }}-chromium-tip-of-tree" - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: always() - with: - name: ${{ matrix.browser }}-chromium-tip-of-tree-test-results - path: test-results test_test_runner: name: Test Runner @@ -101,60 +99,97 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [14] + node-version: [16] + shard: [1/2, 2/2] include: - os: ubuntu-latest - node-version: 16 + node-version: 18 + shard: 1/2 - os: ubuntu-latest node-version: 18 - - os: windows-latest - node-version: 16 + shard: 2/2 + - os: ubuntu-latest + node-version: 20 + shard: 1/2 + - os: ubuntu-latest + node-version: 20 + shard: 2/2 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{matrix.node-version}} - - run: npm i -g npm@8 - run: npm ci env: DEBUG: pw:install - run: npm run build - run: npx playwright install --with-deps - - run: npm run ttest + - run: npm run ttest -- --shard ${{ matrix.shard }} + env: + PWTEST_BLOB_SUFFIX: "-${{ matrix.os }}-node${{ matrix.node-version }}" if: matrix.os != 'ubuntu-latest' - - run: xvfb-run npm run ttest + - run: xvfb-run npm run ttest -- --shard ${{ matrix.shard }} + env: + PWTEST_BLOB_SUFFIX: "-${{ matrix.os }}-node${{ matrix.node-version }}" if: matrix.os == 'ubuntu-latest' - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash + - name: Upload blob report + if: always() + uses: ./.github/actions/upload-blob-report + with: + report_dir: test-results/blob-report + connection_string: '${{ secrets.AZURE_CONNECTION_STRING_FOR_BLOB_REPORT }}' test_web_components: name: Web Components runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - # Component tests require Node.js 16+ (they require ESM via TS) node-version: 16 - - run: npm i -g npm@8 - run: npm ci env: DEBUG: pw:install - run: npm run build - run: npx playwright install --with-deps - run: npm run test-html-reporter - if: always() && matrix.os != 'ubuntu-latest' - - run: xvfb-run npm run test-html-reporter - if: always() && matrix.os == 'ubuntu-latest' - run: npm run test-web - if: always() && matrix.os != 'ubuntu-latest' - - run: xvfb-run npm run test-web - if: always() && matrix.os == 'ubuntu-latest' + if: always() + + test_vscode_extension: + name: VSCode Extension + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + - run: npm ci + env: + DEBUG: pw:install + - run: npm run build + - run: npx playwright install chromium + - name: Checkout extension + run: git clone https://github.com/microsoft/playwright-vscode.git + - name: Print extension revision + run: git rev-parse HEAD + working-directory: ./playwright-vscode + - name: Remove @playwright/test from extension dependencies + run: node -e "const p = require('./package.json'); delete p.devDependencies['@playwright/test']; fs.writeFileSync('./package.json', JSON.stringify(p, null, 2));" + working-directory: ./playwright-vscode + - name: Build extension + run: npm install && npm run build + working-directory: ./playwright-vscode + - name: Run extension tests + run: npm run test -- --workers=1 + working-directory: ./playwright-vscode test-package-installations: - name: "Installation Test ${{ matrix.os }} (${{ matrix.node_version }})" + name: "Installation Test ${{ matrix.os }}" runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -163,15 +198,12 @@ jobs: - ubuntu-latest - macos-latest - windows-latest - node_version: - - "^14.1.0" # pre 14.1, zip extraction was broken (https://github.com/microsoft/playwright/issues/1988) timeout-minutes: 30 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node_version }} - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install diff --git a/.github/workflows/tests_secondary.yml b/.github/workflows/tests_secondary.yml index be87590123ec40..02b5fbb466c645 100644 --- a/.github/workflows/tests_secondary.yml +++ b/.github/workflows/tests_secondary.yml @@ -18,6 +18,7 @@ env: # Force terminal colors. @see https://www.npmjs.com/package/colors FORCE_COLOR: 1 FLAKINESS_CONNECTION_STRING: ${{ secrets.FLAKINESS_CONNECTION_STRING }} + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 jobs: test_linux: @@ -26,14 +27,13 @@ jobs: fail-fast: false matrix: browser: [chromium, firefox, webkit] - os: [ubuntu-18.04, ubuntu-20.04] + os: [ubuntu-20.04, ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install @@ -45,26 +45,20 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: always() - with: - name: ${{ matrix.browser }}-${{ matrix.os }}-test-results - path: test-results test_mac: name: ${{ matrix.os }} (${{ matrix.browser }}) strategy: fail-fast: false matrix: - os: [macos-11, macos-12] + os: [macos-12, macos-13] browser: [chromium, firefox, webkit] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install @@ -75,11 +69,6 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: ${{ matrix.browser }}-${{ matrix.os }}-test-results - path: test-results test_win: name: "Windows" @@ -89,11 +78,10 @@ jobs: browser: [chromium, firefox, webkit] runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install @@ -105,11 +93,6 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: ${{ matrix.browser }}-win-test-results - path: test-results test-package-installations-other-node-versions: name: "Installation Test ${{ matrix.os }} (${{ matrix.node_version }})" @@ -119,16 +102,15 @@ jobs: matrix: include: - os: ubuntu-latest - node_version: "^18.0.0" + node_version: 18 - os: ubuntu-latest - node_version: "^16.0.0" + node_version: 20 timeout-minutes: 30 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node_version }} - - run: npm i -g npm@8 - run: npm ci env: DEBUG: pw:install @@ -151,11 +133,10 @@ jobs: os: [ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install @@ -169,11 +150,6 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: always() && startsWith(matrix.os, 'ubuntu-') - with: - name: headful-${{ matrix.browser }}-linux-test-results - path: test-results transport_linux: name: "Transport" @@ -183,33 +159,22 @@ jobs: mode: [driver, service] runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 - run: npm run build - run: npx playwright install --with-deps chromium - - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project='Chromium page tests' - if: matrix.mode == 'service' - env: - PWTEST_MODE: ${{ matrix.mode }} - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run ctest - if: matrix.mode != 'service' env: PWTEST_MODE: ${{ matrix.mode }} - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: mode-${{ matrix.mode }}-linux-test-results - path: test-results tracing_linux: name: Tracing ${{ matrix.browser }} ${{ matrix.channel }} @@ -224,11 +189,10 @@ jobs: channel: chromium-tip-of-tree runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: DEBUG: pw:install @@ -239,19 +203,25 @@ jobs: env: PWTEST_TRACE: 1 PWTEST_CHANNEL: ${{ matrix.channel }} + PWTEST_BLOB_SUFFIX: ${{ (matrix.channel && format('-{0}', matrix.channel)) || '' }} - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash + - name: Upload blob report + if: always() + uses: ./.github/actions/upload-blob-report + with: + report_dir: test-results/blob-report + connection_string: '${{ secrets.AZURE_CONNECTION_STRING_FOR_BLOB_REPORT }}' chrome_stable_linux: name: "Chrome Stable (Linux)" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -263,21 +233,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: chrome-stable-linux-test-results - path: test-results chrome_stable_win: name: "Chrome Stable (Win)" runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -290,21 +254,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: chrome-stable-win-test-results - path: test-results chrome_stable_mac: name: "Chrome Stable (Mac)" runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -316,11 +274,6 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: chrome-stable-mac-test-results - path: test-results chromium_tot: name: Chromium TOT ${{ matrix.os }} @@ -328,34 +281,28 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-18.04, macos-12, windows-latest] + os: [ubuntu-20.04, macos-12, windows-latest] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 - run: npm run build - run: npx playwright install --with-deps chromium-tip-of-tree - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run ctest - if: matrix.os == 'ubuntu-18.04' + if: matrix.os == 'ubuntu-20.04' env: PWTEST_CHANNEL: chromium-tip-of-tree - run: npm run ctest - if: matrix.os != 'ubuntu-18.04' + if: matrix.os != 'ubuntu-20.04' env: PWTEST_CHANNEL: chromium-tip-of-tree - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: always() - with: - name: chromium-tot-${{ matrix.os }}-test-results - path: test-results chromium_tot_headed: name: Chromium TOT headed ${{ matrix.os }} @@ -365,11 +312,10 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -386,21 +332,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: always() - with: - name: chromium-tot-headed-${{ matrix.os }}-test-results - path: test-results firefox_beta_linux: name: "Firefox Beta (Linux)" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -412,21 +352,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: firefox-beta-linux-test-results - path: test-results firefox_beta_win: name: "Firefox Beta (Win)" runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -439,21 +373,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: firefox-beta-win-test-results - path: test-results firefox_beta_mac: name: "Firefox Beta (Mac)" runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -465,21 +393,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: firefox-beta-mac-test-results - path: test-results edge_stable_mac: name: "Edge Stable (Mac)" runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -491,22 +413,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: msedge-stable-mac-test-results - path: test-results - edge_stable_win: name: "Edge Stable (Win)" runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -519,21 +434,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: edge-stable-win-test-results - path: test-results edge_stable_linux: name: "Edge Stable (Linux)" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -545,21 +454,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: edge-stable-linux-test-results - path: test-results edge_beta_mac: name: "Edge Beta (Mac)" runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -571,21 +474,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: msedge-beta-mac-test-results - path: test-results edge_beta_win: name: "Edge Beta (Win)" runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -598,21 +495,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: edge-beta-win-test-results - path: test-results edge_beta_linux: name: "Edge Beta (Linux)" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -624,21 +515,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: edge-beta-linux-test-results - path: test-results edge_dev_mac: name: "Edge Dev (Mac)" runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -650,21 +535,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: msedge-dev-mac-test-results - path: test-results edge_dev_win: name: "Edge Dev (Win)" runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -677,21 +556,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: edge-dev-win-test-results - path: test-results edge_dev_linux: name: "Edge Dev (Linux)" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -703,21 +576,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: edge-dev-linux-test-results - path: test-results chrome_beta_linux: name: "Chrome Beta (Linux)" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -729,21 +596,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: chrome-beta-linux-test-results - path: test-results chrome_beta_win: name: "Chrome Beta (Win)" runs-on: windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -756,21 +617,15 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: chrome-beta-win-test-results - path: test-results chrome_beta_mac: name: "Chrome Beta (Mac)" runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci env: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 @@ -782,22 +637,38 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: chrome-beta-mac-test-results - path: test-results build-playwright-driver: name: "build-playwright-driver" runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 - - run: npm i -g npm@8 + node-version: 16 - run: npm ci - run: npm run build - run: npx playwright install-deps - run: utils/build/build-playwright-driver.sh + + test_linux_chromium_headless_new: + name: Linux Chromium Headless New + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + - run: npm ci + env: + DEBUG: pw:install + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + - run: npm run build + - run: npx playwright install --with-deps chromium + - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project=chromium + env: + PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW: 1 + - run: node tests/config/checkCoverage.js chromium + - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json + if: always() + shell: bash diff --git a/.github/workflows/tests_stress.yml b/.github/workflows/tests_stress.yml index 8d1c0b0efa5e31..20cd7dff7c5895 100644 --- a/.github/workflows/tests_stress.yml +++ b/.github/workflows/tests_stress.yml @@ -16,6 +16,7 @@ on: env: FORCE_COLOR: 1 + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 jobs: test_components: @@ -26,8 +27,8 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 - run: npm i -g npm@8 - run: npm ci - run: npm run build diff --git a/.github/workflows/tests_video.yml b/.github/workflows/tests_video.yml index a8fbd0d3e338c3..27f1643ef8ed65 100644 --- a/.github/workflows/tests_video.yml +++ b/.github/workflows/tests_video.yml @@ -10,6 +10,7 @@ env: # Force terminal colors. @see https://www.npmjs.com/package/colors FORCE_COLOR: 1 FLAKINESS_CONNECTION_STRING: ${{ secrets.FLAKINESS_CONNECTION_STRING }} + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 jobs: video_linux: @@ -21,10 +22,10 @@ jobs: os: [ubuntu-20.04, ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - run: npm i -g npm@8 - run: npm ci env: @@ -38,8 +39,3 @@ jobs: - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json if: always() shell: bash - - uses: actions/upload-artifact@v1 - if: ${{ always() }} - with: - name: video-${{ matrix.browser }}-linux-test-results - path: test-results diff --git a/.github/workflows/tests_webview2.yml b/.github/workflows/tests_webview2.yml new file mode 100644 index 00000000000000..da0270c2484470 --- /dev/null +++ b/.github/workflows/tests_webview2.yml @@ -0,0 +1,45 @@ +name: "WebView2 Tests" + +on: + push: + branches: + - main + - release-* + pull_request: + paths-ignore: + - 'browser_patches/**' + - 'docs/**' + types: [ labeled ] + branches: + - main + - release-* + +env: + # Force terminal colors. @see https://www.npmjs.com/package/colors + FORCE_COLOR: 1 + FLAKINESS_CONNECTION_STRING: ${{ secrets.FLAKINESS_CONNECTION_STRING }} + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + +jobs: + test_webview2: + name: WebView2 + runs-on: windows-2022 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - uses: actions/setup-dotnet@v2 + with: + dotnet-version: '6.0.x' + - run: npm i -g npm@8 + - run: npm ci + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + - run: npm run build + - run: dotnet build + working-directory: tests/webview2/webview2-app/ + - run: npm run webview2test + - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json + if: always() + shell: bash diff --git a/.github/workflows/trigger_build_chromium.yml b/.github/workflows/trigger_build_chromium.yml deleted file mode 100644 index e2b2314624402f..00000000000000 --- a/.github/workflows/trigger_build_chromium.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: "Trigger: Chromium Builds" - -on: - workflow_dispatch: - inputs: - ref: - description: 'Playwright SHA / ref to build Chromium' - required: true - default: 'main' - push: - branches: - - main - - release-* - paths: - - browser_patches/chromium/BUILD_NUMBER - - .github/workflows/trigger_build_chromium.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data "{\"event_type\": \"build_chromium\", \"client_payload\": {\"ref\": \"${GHREF}\"}}" \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} - GHREF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.sha }} diff --git a/.github/workflows/trigger_build_chromium_tip_of_tree.yml b/.github/workflows/trigger_build_chromium_tip_of_tree.yml deleted file mode 100644 index bdab67cb4de48d..00000000000000 --- a/.github/workflows/trigger_build_chromium_tip_of_tree.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: "Trigger: Chromium Tip Of Tree Builds" - -on: - workflow_dispatch: - inputs: - ref: - description: 'Playwright SHA / ref to build Chromium Tip Of Tree' - required: true - default: 'main' - push: - branches: - - main - - release-* - paths: - - browser_patches/chromium-tip-of-tree/BUILD_NUMBER - - .github/workflows/trigger_build_chromium_tip_of_tree.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data "{\"event_type\": \"build_chromium_tip_of_tree\", \"client_payload\": {\"ref\": \"${GHREF}\"}}" \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} - GHREF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.sha }} diff --git a/.github/workflows/trigger_build_chromium_with_symbols.yml b/.github/workflows/trigger_build_chromium_with_symbols.yml index 8fd161a5a72978..b9dfe00fca07c2 100644 --- a/.github/workflows/trigger_build_chromium_with_symbols.yml +++ b/.github/workflows/trigger_build_chromium_with_symbols.yml @@ -1,33 +1,30 @@ name: "Trigger: Chromium with Symbols Builds" - on: workflow_dispatch: - inputs: - ref: - description: 'Playwright SHA / ref to build Chromium With Symbols' - required: true - default: 'main' release: types: [published] - push: - branches: - - release-* - paths: - - browser_patches/chromium/BUILD_NUMBER - - .github/workflows/trigger_build_chromium_with_symbols.yml jobs: trigger: name: "trigger" - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '16' + - name: Get Chromium revision + id: chromium-version + run: | + REVISION=$(node -e "console.log(require('./packages/playwright-core/browsers.json').browsers.find(b => b.name === 'chromium-with-symbols').revision)") + echo "REVISION=$REVISION" >> $GITHUB_OUTPUT - run: | curl -X POST \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token ${GH_TOKEN}" \ - --data "{\"event_type\": \"build_chromium_with_symbols\", \"client_payload\": {\"ref\": \"${GHREF}\"}}" \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches + --data "{\"event_type\": \"build_chromium_with_symbols\", \"client_payload\": {\"revision\": \"${CHROMIUM_REVISION}\"}}" \ + https://api.github.com/repos/microsoft/playwright-browsers/dispatches env: GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} - GHREF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.sha }} + CHROMIUM_REVISION: ${{ steps.chromium-version.outputs.REVISION }} diff --git a/.github/workflows/trigger_build_ffmpeg.yml b/.github/workflows/trigger_build_ffmpeg.yml deleted file mode 100644 index 6202c68a16abf8..00000000000000 --- a/.github/workflows/trigger_build_ffmpeg.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "FFMPEG Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/ffmpeg/BUILD_NUMBER - - .github/workflows/trigger_build_ffmpeg.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_ffmpeg"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_firefox.yml b/.github/workflows/trigger_build_firefox.yml deleted file mode 100644 index f0dc3b3daf914e..00000000000000 --- a/.github/workflows/trigger_build_firefox.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "Firefox Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/firefox/BUILD_NUMBER - - .github/workflows/trigger_build_firefox.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_firefox"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_firefox_beta.yml b/.github/workflows/trigger_build_firefox_beta.yml deleted file mode 100644 index 762dd95e184289..00000000000000 --- a/.github/workflows/trigger_build_firefox_beta.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "Firefox Beta Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/firefox-beta/BUILD_NUMBER - - .github/workflows/trigger_build_firefox_beta.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_firefox_beta"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_webkit.yml b/.github/workflows/trigger_build_webkit.yml deleted file mode 100644 index 3dd79da40ca4a9..00000000000000 --- a/.github/workflows/trigger_build_webkit.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "WebKit Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/webkit/BUILD_NUMBER - - .github/workflows/trigger_build_webkit.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_webkit"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_build_winldd.yml b/.github/workflows/trigger_build_winldd.yml deleted file mode 100644 index dfb2f4bfeb25bf..00000000000000 --- a/.github/workflows/trigger_build_winldd.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: "WinLDD Builder" - -on: - push: - branches: - - main - - release-* - paths: - - browser_patches/winldd/BUILD_NUMBER - - .github/workflows/trigger_build_winldd.yml - -jobs: - trigger: - name: "trigger" - runs-on: ubuntu-20.04 - steps: - - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "build_winldd"}' \ - https://api.github.com/repos/microsoft/playwright-internal/dispatches - env: - GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.github/workflows/trigger_tests.yml b/.github/workflows/trigger_tests.yml index 7267c843ba03f2..dcd68dca374400 100644 --- a/.github/workflows/trigger_tests.yml +++ b/.github/workflows/trigger_tests.yml @@ -16,6 +16,6 @@ jobs: -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-internal/dispatches + https://api.github.com/repos/microsoft/playwright-browsers/dispatches env: GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} diff --git a/.gitignore b/.gitignore index deea03bdb9e82f..3d261328095518 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ test-results /tests/installation/output/ /tests/installation/.registry.json .cache/ +.eslintcache \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e4b58fa5cdb6f..cfc111a1dbc6ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,14 @@ ### Getting Code +Make sure you're running Node.js 16+ and NPM 8+, to verify and upgrade NPM do: + +```bash +node --version +npm --version +npm i -g npm@latest +``` + 1. Clone this repository ```bash @@ -27,7 +35,7 @@ cd playwright 2. Install dependencies ```bash -npm install +npm ci ``` 3. Build Playwright @@ -142,14 +150,24 @@ These are integration tests, making sure public API methods and events work as e - To run all tests: ```bash +npx playwright install npm run test ``` +Be sure to run `npm run build` or let `npm run watch` run before you re-run the +tests after making your changes to check them. + - To run all tests in Chromium ```bash npm run ctest # also `ftest` for firefox and `wtest` for WebKit ``` +- To run the Playwright test runner tests +```bash +npm run ttest +npm run ttest -- --grep "specific test" +``` + - To run a specific test, substitute `it` with `it.only`, or use the `--grep 'My test'` CLI parameter: ```js diff --git a/README.md b/README.md index 111b5c7d17ad7e..78fe4814c4c7f4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🎭 Playwright -[![npm version](https://img.shields.io/npm/v/playwright.svg?style=flat)](https://www.npmjs.com/package/playwright) [![Chromium version](https://img.shields.io/badge/chromium-105.0.5195.28-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-103.0-blue.svg?logo=mozilla-firefox)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-16.0-blue.svg?logo=safari)](https://webkit.org/) +[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) [![Chromium version](https://img.shields.io/badge/chromium-115.0.5790.98-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-115.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-17.0-blue.svg?logo=safari)](https://webkit.org/) ## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright) @@ -8,11 +8,11 @@ Playwright is a framework for Web Testing and Automation. It allows testing [Chr | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium 105.0.5195.28 | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| WebKit 16.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Firefox 103.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Chromium 115.0.5790.98 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| WebKit 17.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Firefox 115.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | -Headless execution is supported for all the browsers on all platforms. Check out [system requirements](https://playwright.dev/docs/library#system-requirements) for details. +Headless execution is supported for all browsers on all platforms. Check out [system requirements](https://playwright.dev/docs/intro#system-requirements) for details. Looking for Playwright for [Python](https://playwright.dev/python/docs/intro), [.NET](https://playwright.dev/dotnet/docs/intro), or [Java](https://playwright.dev/java/docs/intro)? @@ -53,19 +53,19 @@ You can optionally install only selected browsers, see [install browsers](https: ### Resilient • No flaky tests -**Auto-wait**. Playwright waits for elements to be actionable prior to performing actions. It also has rich set of introspection events. The combination of the two eliminate the need for artificial timeouts - primary cause of flaky tests. +**Auto-wait**. Playwright waits for elements to be actionable prior to performing actions. It also has a rich set of introspection events. The combination of the two eliminates the need for artificial timeouts - a primary cause of flaky tests. **Web-first assertions**. Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met. -**Tracing**. Configure test retry strategy, capture execution trace, videos, screenshots to eliminate flakes. +**Tracing**. Configure test retry strategy, capture execution trace, videos and screenshots to eliminate flakes. ### No trade-offs • No limits -Browsers run web content belonging to different origins in different processes. Playwright is aligned with the modern browsers architecture and runs tests out-of-process. This makes Playwright free of the typical in-process test runner limitations. +Browsers run web content belonging to different origins in different processes. Playwright is aligned with the architecture of the modern browsers and runs tests out-of-process. This makes Playwright free of the typical in-process test runner limitations. **Multiple everything**. Test scenarios that span multiple tabs, multiple origins and multiple users. Create scenarios with different contexts for different users and run them against your server, all in one test. -**Trusted events**. Hover elements, interact with dynamic controls, produce trusted events. Playwright uses real browser input pipeline indistinguishable from the real user. +**Trusted events**. Hover elements, interact with dynamic controls and produce trusted events. Playwright uses real browser input pipeline indistinguishable from the real user. Test frames, pierce Shadow DOM. Playwright selectors pierce shadow DOM and allow entering frames seamlessly. @@ -79,7 +79,7 @@ Test frames, pierce Shadow DOM. Playwright selectors pierce shadow DOM and allow **[Codegen](https://playwright.dev/docs/codegen)**. Generate tests by recording your actions. Save them into any language. -**[Playwright inspector](https://playwright.dev/docs/inspector)**. Inspect page, generate selectors, step through the test execution, see click points, explore execution logs. +**[Playwright inspector](https://playwright.dev/docs/inspector)**. Inspect page, generate selectors, step through the test execution, see click points and explore execution logs. **[Trace Viewer](https://playwright.dev/docs/trace-viewer)**. Capture all the information to investigate the test failure. Playwright trace contains test execution screencast, live DOM snapshots, action explorer, test source and many more. @@ -91,20 +91,20 @@ To learn how to run these Playwright Test examples, check out our [getting start #### Page screenshot -This code snippet navigates to whatsmyuseragent.org and saves a screenshot. +This code snippet navigates to Playwright homepage and saves a screenshot. ```TypeScript import { test } from '@playwright/test'; test('Page Screenshot', async ({ page }) => { - await page.goto('http://whatsmyuseragent.org/'); + await page.goto('https://playwright.dev/'); await page.screenshot({ path: `example.png` }); }); ``` #### Mobile and geolocation -This snippet emulates Mobile Safari on a device at a given geolocation, navigates to maps.google.com, performs action and takes a screenshot. +This snippet emulates Mobile Safari on a device at given geolocation, navigates to maps.google.com, performs the action and takes a screenshot. ```TypeScript import { test, devices } from '@playwright/test'; @@ -118,7 +118,7 @@ test.use({ test('Mobile and geolocation', async ({ page }) => { await page.goto('https://maps.google.com'); - await page.locator('text="Your location"').click(); + await page.getByText('Your location').click(); await page.waitForRequest(/.*preview\/pwa/); await page.screenshot({ path: 'colosseum-iphone.png' }); }); @@ -165,6 +165,5 @@ test('Intercept network requests', async ({ page }) => { * [Documentation](https://playwright.dev/docs/intro) * [API reference](https://playwright.dev/docs/api/class-playwright/) -* [Community showcase](https://playwright.dev/docs/showcase/) * [Contribution guide](CONTRIBUTING.md) * [Changelog](https://github.com/microsoft/playwright/releases) diff --git a/browser_patches/README.md b/browser_patches/README.md deleted file mode 100644 index e56d6eae3bee4c..00000000000000 --- a/browser_patches/README.md +++ /dev/null @@ -1,194 +0,0 @@ -- [Contributing Browser Patches](#Contributing-browser-patches) - * [1. Setting up local browser checkout](#1-setting-up-local-browser-checkout) - * [2. Developing a new change](#2-developing-a-new-change) - * [3. Exporting your change to playwright repo](#3-exporting-your-change-to-playwright-repo) - * [4. Rolling Playwright to the new browser build](#4-rolling-playwright-to-the-new-browser-build) -- [Cheatsheet](#cheatsheet) - * [Firefox](#firefox) - - [stack trace](#stack-trace) - - [logging](#logging) - * [WebKit](#webkit) - - [Debugging Windows](#degugging-windows) - - [Enable core dumps on Linux](#enable-core-dumps-on-linux) - -# Contributing Browser Patches - -Firefox and WebKit have additional patches atop to expose necessary capabilities. - -Ideally, all these changes should be upstreamed. -For the time being, it is possible to setup a browser checkout -and develop from there. - -[WebKit upstream status](webkit/upstream_status.md) - -## 1. Setting up local browser checkout - -From the `playwright` repo, run the following command: - -```bash -$ ./browser_patches/prepare_checkout.sh firefox -``` -(you can optionally pass "webkit" for a webkit checkout) - -This will create a firefox checkout at `$HOME/firefox` - -> **NOTE:** this command downloads GBs of data. - - -This command will: -- create a `browser_upstream` remote in the checkout -- create a `playwright-build` branch and apply all playwright-required patches to it. - -## 2. Developing a new change - -### Creating new branch - -You want to create a new branch off the `playwright-build` branch. - -Assuming that you're under `$HOME/firefox` checkout: - -```bash -$ git checkout -b my-new-feature playwright-build -$ # develop my feature on the my-new-feature branch .... -``` - -### Building - -Each browser has corresponding build script. `--full` options normally takes care of also installing required build dependencies on Linux. - -```bash -./browser_patches/firefox/build.sh --full -``` - -### Running tests with local browser build - -Playwright test suite may run against local browser build without bundling it. -```bash -# Run webkit tests with local webkit build -WKPATH=./browser_patches/webkit/pw_run.sh npm run wtest - -# Run firefox tests with local firefox build on macos -FFPATH=/tmp/repackaged-firefox/firefox/Nightly.app/Contents/MacOS/firefox npm run ftest - -# Run chromium tests with local chromium build on linux -CRPATH=~/chromium/src/out/Release/chrome npm run ctest -``` - -### Flakiness dashboard - -You can look at the [flakiness dashboard](http://flaky.aslushnikov.com/) to see recent history of any playwright test. - -## 3. Exporting your change to playwright repo - -Once you're happy with the work you did in the browser-land, you want to export it to the `playwright` repo. - -Assuming that you're in the root of the `playwright` repo and that your browser checkout has your feature branch checked out: - -```bash -$ ./browser_patches/export.sh firefox -``` - -This script will: -- create a new patch and put it to the `./browser_patches/firefox/patches/` -- update the `./browser_patches/firefox/UPSTREAM_CONFIG.sh` if necessary -- bump the `./browser_patches/firefox/BUILD_NUMBER` number. - -The script will assume Firefox checkout is located at `$HOME/firefox` - -Send a PR to the Playwright repo to be reviewed. - -## 4. Rolling Playwright to the new browser build - -Once the patch has been committed, the build bots will kick in, compile and upload a new browser version to all the platforms. Then you can roll the browser: - -```bash -$ node utils/roll_browser.js chromium 123456 -``` - -# Cheatsheet - -## See browser stdout/stderr - -Set the `DEBUG=pw:browser` environment variable to see it. - -## Firefox - -### Debug build - -When compiling set the `FF_DEBUG_BUILD=1` environment variable. - -#### Stack trace - -In `//mozglue/misc/StackWalk.cpp` add - -```c++ -#define MOZ_DEMANGLE_SYMBOLS 1 -``` - -In native code use - -```c++ -#include "mozilla/StackWalk.h" -// ... -MozWalkTheStack(stderr); -``` - -If the stack trace is still mangled `cat` it to `tools/rb/fix_linux_stack.py` - -#### Logging - -Upstream documentation: https://firefox-source-docs.mozilla.org/xpcom/logging.html - -```bash -MOZ_LOG=nsHttp:5 -``` - -Module name is a string passed to the `mozilla::LazyLogModule` of the corresponding component, e.g.: - -```c++ -LazyLogModule gHttpLog("nsHttp"); -``` - -Inside Juggler, you can use `dump('foo\n')`. - -## WebKit - -#### Logging - -Inside Objective-C you can use [NSLog](https://developer.apple.com/documentation/foundation/1395275-nslog). - -``` -NSLog(@"Foobar value: %@", value); -``` - -#### Debugging windows - -In `Source\WTF\wtf\win\DbgHelperWin.cpp` replace - -```#if !defined(NDEBUG)``` with ```#if 1``` - -Then regular `WTFReportBacktrace()` works. - -#### Debugging linux - -`WTFReportBacktrace()` has been broken since [r283707](https://github.com/WebKit/WebKit/commit/de4ba48c8f229bc45042b543a514f6d88b551a64), see [this comment](https://bugs.webkit.org/show_bug.cgi?id=181916#c96). Revert that change locally to make backtraces work again. Otherwise addr2line -f can still be used to map addresses to function names. - -#### Enable core dumps on Linux - -```bash -mkdir -p /tmp/coredumps -sudo bash -c 'echo "/tmp/coredumps/core-pid_%p.dump" > /proc/sys/kernel/core_pattern' -ulimit -c unlimited -``` - -Then to read stack traces run the following command: -```bash -# To find out crashing process name -file core-pid_29652.dump -# Point gdb to the local binary of the crashed process and the core file -gdb $HOME/.cache/ms-playwright/webkit-1292/minibrowser-gtk/WebKitWebProcess core-pid_29652 -# Inside gdb update .so library search path to the local one -set solib-search-path /home/yurys/.cache/ms-playwright/webkit-1292/minibrowser-gtk -# Finally print backtrace -bt -``` diff --git a/browser_patches/build.sh b/browser_patches/build.sh deleted file mode 100755 index 509307f9e074a3..00000000000000 --- a/browser_patches/build.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: build.sh [firefox|webkit|firefox-beta]" - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './build.sh --help' for more information" - exit 1 -fi - -CMD="$1" -shift -if [[ ("$CMD" == "firefox") || ("$CMD" == "firefox/") || ("$CMD" == "ff") ]]; then - bash ./firefox/build.sh "$@" -elif [[ ("$CMD" == "firefox-beta") || ("$CMD" == "ff-beta") ]]; then - bash ./firefox-beta/build.sh "$@" -elif [[ ("$CMD" == "webkit") || ("$CMD" == "webkit/") || ("$CMD" == "wk") ]]; then - bash ./webkit/build.sh "$@" -elif [[ ("$CMD" == "chromium") || ("$CMD" == "chromium/") || ("$CMD" == "cr") ]]; then - bash ./chromium/build.sh "$@" -elif [[ ("$CMD" == "winldd") ]]; then - bash ./winldd/build.sh "$@" -elif [[ ("$CMD" == "ffmpeg") ]]; then - bash ./ffmpeg/build.sh "$@" -else - echo ERROR: unknown browser to build - "$CMD" - exit 1 -fi - diff --git a/browser_patches/checkout_build_archive_upload.sh b/browser_patches/checkout_build_archive_upload.sh deleted file mode 100755 index 3d6e6ce179764d..00000000000000 --- a/browser_patches/checkout_build_archive_upload.sh +++ /dev/null @@ -1,548 +0,0 @@ -#!/bin/bash -set -e -set +x -set -o pipefail - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [firefox-linux|firefox-win64|webkit-gtk|webkit-wpe|webkit-gtk-wpe|webkit-win64|webkit-mac-10.15] [-f|--force]" - echo - echo "Prepares checkout under browser folder, applies patches, builds, archives, and uploads if build is missing." - echo "Script will bail out early if the build for the browser version is already present." - echo - echo "Pass -f to upload anyway." - echo - echo "NOTE: This script is safe to run in a cronjob - it aquires a lock so that it does not run twice." - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing build flavor!" - echo "try './$(basename "$0") --help' for more information" - exit 1 -fi - -CURRENT_ARCH="$(uname -m)" -CURRENT_HOST_OS="$(uname)" -CURRENT_HOST_OS_VERSION="" -if [[ "$CURRENT_HOST_OS" == "Darwin" ]]; then - CURRENT_HOST_OS_VERSION=$(sw_vers -productVersion | grep -o '^\d\+.\d\+') -elif [[ "$CURRENT_HOST_OS" == "Linux" ]]; then - CURRENT_HOST_OS="$(bash -c 'source /etc/os-release && echo $NAME')" - CURRENT_HOST_OS_VERSION="$(bash -c 'source /etc/os-release && echo $VERSION_ID')" -fi - -BROWSER_NAME="" -BROWSER_DISPLAY_NAME="" -EXTRA_BUILD_ARGS="" -EXTRA_ARCHIVE_ARGS="" -BUILD_FLAVOR="$1" -BUILD_BLOB_NAME="" -EXPECTED_HOST_OS="" -EXPECTED_HOST_OS_VERSION="" -EXPECTED_ARCH="x86_64" -BUILDS_LIST="EXPECTED_BUILDS" - -# =========================== -# WINLDD COMPILATION -# =========================== -if [[ "$BUILD_FLAVOR" == "winldd-win64" ]]; then - BROWSER_NAME="winldd" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="winldd-win64.zip" - - -# =========================== -# FFMPEG COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "ffmpeg-mac" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--mac --full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - BUILD_BLOB_NAME="ffmpeg-mac.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-mac-arm64" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--mac --full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="ffmpeg-mac-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-linux" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--linux" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="ffmpeg-linux.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-linux-arm64" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--cross-compile-linux-arm64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="ffmpeg-linux-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "ffmpeg-cross-compile-win64" ]]; then - BROWSER_NAME="ffmpeg" - EXTRA_BUILD_ARGS="--cross-compile-win64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="ffmpeg-win64.zip" - -# =========================== -# CHROMIUM COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "chromium-win64" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="chromium-win64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-mac" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-mac.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-mac-arm64" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-mac-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-linux" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="chromium-linux.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-linux-arm64" ]]; then - BROWSER_NAME="chromium" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="chromium-linux-arm64.zip" - -# =========================== -# CHROMIUM-TIP-OF-TREE COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-win64" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="chromium-tip-of-tree-win64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-mac" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-tip-of-tree-mac.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-mac-arm64" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-tip-of-tree-mac-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-linux" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="chromium-tip-of-tree-linux.zip" -elif [[ "$BUILD_FLAVOR" == "chromium-tip-of-tree-linux-arm64" ]]; then - BROWSER_NAME="chromium-tip-of-tree" - EXTRA_BUILD_ARGS="--arm64 --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="chromium-tip-of-tree-linux-arm64.zip" - -# =========================== -# CHROMIUM-WITH-SYMBOLS COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-win64" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--symbols --full --goma" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="chromium-with-symbols-win64.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-mac" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--symbols --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-with-symbols-mac.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-mac-arm64" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--arm64 --symbols --full --goma" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="chromium-with-symbols-mac-arm64.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-linux" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols" - EXTRA_BUILD_ARGS="--symbols --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="chromium-with-symbols-linux.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" -elif [[ "$BUILD_FLAVOR" == "chromium-with-symbols-linux-arm64" ]]; then - BROWSER_NAME="chromium" - BROWSER_DISPLAY_NAME="chromium-with-symbols-arm64" - EXTRA_BUILD_ARGS="--arm64 --symbols --full --goma" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="chromium-with-symbols-linux-arm64.zip" - BUILDS_LIST="EXPECTED_BUILDS_WITH_SYMBOLS" - -# =========================== -# FIREFOX COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-18.04" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="firefox-ubuntu-18.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-20.04" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-ubuntu-20.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-20.04-arm64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-ubuntu-20.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-22.04" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-ubuntu-22.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-ubuntu-22.04-arm64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-ubuntu-22.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-debian-11" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Debian" - EXPECTED_HOST_OS_VERSION="11" - BUILD_BLOB_NAME="firefox-debian-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-mac-11" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="x86_64" - BUILD_BLOB_NAME="firefox-mac-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-mac-11-arm64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="firefox-mac-11-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-win64" ]]; then - BROWSER_NAME="firefox" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="firefox-win64.zip" - # This is the architecture that is set by mozilla-build bash. - EXPECTED_ARCH="i686" - - -# =============================== -# FIREFOX-BETA COMPILATION -# =============================== -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-18.04" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-18.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-20.04" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-20.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-20.04-arm64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-20.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-22.04" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-22.04.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-ubuntu-22.04-arm64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_ARCH="aarch64" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="firefox-beta-ubuntu-22.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-debian-11" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Debian" - EXPECTED_HOST_OS_VERSION="11" - BUILD_BLOB_NAME="firefox-beta-debian-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-mac-11" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="x86_64" - BUILD_BLOB_NAME="firefox-beta-mac-11.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-mac-11-arm64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="firefox-beta-mac-11-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "firefox-beta-win64" ]]; then - BROWSER_NAME="firefox-beta" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="firefox-beta-win64.zip" - # This is the architecture that is set by mozilla-build bash. - EXPECTED_ARCH="i686" - -# =========================== -# WEBKIT COMPILATION -# =========================== -elif [[ "$BUILD_FLAVOR" == "webkit-debian-11" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Debian" - EXPECTED_HOST_OS_VERSION="11" - BUILD_BLOB_NAME="webkit-debian-11.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-18.04" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="18.04" - BUILD_BLOB_NAME="webkit-ubuntu-18.04.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-20.04" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - BUILD_BLOB_NAME="webkit-ubuntu-20.04.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-20.04-arm64" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="20.04" - EXPECTED_ARCH="aarch64" - BUILD_BLOB_NAME="webkit-ubuntu-20.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-22.04" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - BUILD_BLOB_NAME="webkit-ubuntu-22.04.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-ubuntu-22.04-arm64" ]]; then - BROWSER_NAME="webkit" - EXTRA_BUILD_ARGS="--full" - EXPECTED_HOST_OS="Ubuntu" - EXPECTED_HOST_OS_VERSION="22.04" - EXPECTED_ARCH="aarch64" - BUILD_BLOB_NAME="webkit-ubuntu-22.04-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-win64" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="MINGW" - BUILD_BLOB_NAME="webkit-win64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-10.15" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="10.15" - BUILD_BLOB_NAME="webkit-mac-10.15.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-12" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - BUILD_BLOB_NAME="webkit-mac-12.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-12-arm64" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="12.2" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="webkit-mac-12-arm64.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-11" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - BUILD_BLOB_NAME="webkit-mac-11.zip" -elif [[ "$BUILD_FLAVOR" == "webkit-mac-11-arm64" ]]; then - BROWSER_NAME="webkit" - EXPECTED_HOST_OS="Darwin" - EXPECTED_HOST_OS_VERSION="11.6" - EXPECTED_ARCH="arm64" - BUILD_BLOB_NAME="webkit-mac-11-arm64.zip" - - -# =========================== -# Unknown input -# =========================== -else - echo ERROR: unknown build flavor - "$BUILD_FLAVOR" - exit 1 -fi - -if [[ -z "$BROWSER_DISPLAY_NAME" ]]; then - BROWSER_DISPLAY_NAME="${BROWSER_NAME}" -fi - -if [[ "$CURRENT_ARCH" != "$EXPECTED_ARCH" ]]; then - echo "ERROR: cannot build $BUILD_FLAVOR" - echo " -- expected arch: $EXPECTED_ARCH" - echo " -- current arch: $CURRENT_ARCH" - exit 1 -fi - -if [[ "$CURRENT_HOST_OS" != $EXPECTED_HOST_OS* ]]; then - echo "ERROR: cannot build $BUILD_FLAVOR" - echo " -- expected OS: $EXPECTED_HOST_OS" - echo " -- current OS: $CURRENT_HOST_OS" - exit 1 -fi - -if [[ "$CURRENT_HOST_OS_VERSION" != "$EXPECTED_HOST_OS_VERSION" ]]; then - echo "ERROR: cannot build $BUILD_FLAVOR" - echo " -- expected OS Version: $EXPECTED_HOST_OS_VERSION" - echo " -- current OS Version: $CURRENT_HOST_OS_VERSION" - exit 1 -fi - -if [[ $(uname) == MINGW* || "$(uname)" == MSYS* ]]; then - ZIP_PATH="$PWD/archive-$BROWSER_NAME.zip" - LOG_PATH="$PWD/log-$BROWSER_NAME.zip" -else - ZIP_PATH="/tmp/archive-$BROWSER_NAME.zip" - LOG_PATH="/tmp/log-$BROWSER_NAME.zip" -fi - -if [[ -f "$ZIP_PATH" ]]; then - echo "Archive $ZIP_PATH already exists - remove and re-run the script." - exit 1 -fi -trap "rm -rf ${ZIP_PATH}; rm -rf ${LOG_PATH}; cd $(pwd -P);" INT TERM EXIT -cd "$(dirname "$0")" -BUILD_NUMBER=$(head -1 ./$BROWSER_NAME/BUILD_NUMBER) -BUILD_BLOB_PATH="${BROWSER_NAME}/${BUILD_NUMBER}/${BUILD_BLOB_NAME}" -LOG_BLOB_NAME="${BUILD_BLOB_NAME%.zip}.log.gz" -LOG_BLOB_PATH="${BROWSER_NAME}/${BUILD_NUMBER}/${LOG_BLOB_NAME}" - -# pull from upstream and check if a new build has to be uploaded. -if ! [[ ($2 == '-f') || ($2 == '--force') ]]; then - if ./upload.sh "${BUILD_BLOB_PATH}" --check; then - echo "Build is already uploaded - no changes." - exit 0 - fi -else - echo "Force-rebuilding the build." -fi - -function generate_and_upload_browser_build { - echo "-- preparing checkout" - if ! ./prepare_checkout.sh $BROWSER_NAME; then - return 20 - fi - - echo "-- cleaning" - if ! ./$BROWSER_NAME/clean.sh; then - return 21 - fi - - echo "-- building" - if ! ./$BROWSER_NAME/build.sh $EXTRA_BUILD_ARGS; then - return 22 - fi - - echo "-- archiving to $ZIP_PATH" - if ! ./$BROWSER_NAME/archive.sh "$ZIP_PATH" $EXTRA_ARCHIVE_ARGS; then - return 23 - fi - - echo "-- uploading" - if ! ./upload.sh "$BUILD_BLOB_PATH" "$ZIP_PATH"; then - return 24 - fi - return 0 -} - -function create_roll_into_playwright_pr { - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${GH_TOKEN}" \ - --data '{"event_type": "roll_into_pw", "client_payload": {"browser": "'"$1"'", "revision": "'"$2"'"}}' \ - https://api.github.com/repos/microsoft/playwright/dispatches -} - -BUILD_ALIAS="$BUILD_FLAVOR r$BUILD_NUMBER" -node send_telegram_message.js "$BUILD_ALIAS -- started" - -if generate_and_upload_browser_build 2>&1 | ./sanitize_and_compress_log.js $LOG_PATH; then - # Report successful build. Note: MINGW might not have `du` command. - UPLOAD_SIZE="" - if command -v du >/dev/null && command -v awk >/dev/null; then - UPLOAD_SIZE="$(du -h "$ZIP_PATH" | awk '{print $1}') " - fi - node send_telegram_message.js "$BUILD_ALIAS -- ${UPLOAD_SIZE}uploaded" - - # Check if we uploaded the last build. - ( - for i in $(cat "${BROWSER_NAME}/${BUILDS_LIST}"); do - URL="https://playwright2.blob.core.windows.net/builds/${BROWSER_NAME}/${BUILD_NUMBER}/$i" - if ! [[ $(curl -s -L -I "$URL" | head -1 | cut -f2 -d' ') == 200 ]]; then - # Exit subshell - echo "Missing build at ${URL}" - exit - fi - done; - LAST_COMMIT_MESSAGE=$(git log --format=%s -n 1 HEAD -- "./${BROWSER_NAME}/BUILD_NUMBER") - node send_telegram_message.js "${BROWSER_DISPLAY_NAME} r${BUILD_NUMBER} COMPLETE! ✅ ${LAST_COMMIT_MESSAGE}" - if [[ "${BROWSER_DISPLAY_NAME}" != "chromium-with-symbols" ]]; then - create_roll_into_playwright_pr $BROWSER_NAME $BUILD_NUMBER - fi - ) -else - RESULT_CODE="$?" - if (( RESULT_CODE == 10 )); then - FAILED_STEP="./download_gtk_and_wpe_and_zip_together.sh" - elif (( RESULT_CODE == 11 )); then - FAILED_STEP="./upload.sh" - elif (( RESULT_CODE == 20 )); then - FAILED_STEP="./prepare_checkout.sh" - elif (( RESULT_CODE == 21 )); then - FAILED_STEP="./clean.sh" - elif (( RESULT_CODE == 22 )); then - FAILED_STEP="./build.sh" - elif (( RESULT_CODE == 23 )); then - FAILED_STEP="./archive.sh" - elif (( RESULT_CODE == 24 )); then - FAILED_STEP="./upload.sh" - else - FAILED_STEP="" - fi - # Upload logs only in case of failure and report failure. - ./upload.sh "${LOG_BLOB_PATH}" ${LOG_PATH} || true - node send_telegram_message.js "$BUILD_ALIAS -- ${FAILED_STEP} failed! ❌ ${LOG_BLOB_NAME} -- GitHub Action Logs" - exit 1 -fi - diff --git a/browser_patches/chromium-tip-of-tree/BUILD_NUMBER b/browser_patches/chromium-tip-of-tree/BUILD_NUMBER deleted file mode 100644 index 95e145d5beb485..00000000000000 --- a/browser_patches/chromium-tip-of-tree/BUILD_NUMBER +++ /dev/null @@ -1 +0,0 @@ -1035 diff --git a/browser_patches/chromium-tip-of-tree/EXPECTED_BUILDS b/browser_patches/chromium-tip-of-tree/EXPECTED_BUILDS deleted file mode 100644 index 2575021ad4c5c3..00000000000000 --- a/browser_patches/chromium-tip-of-tree/EXPECTED_BUILDS +++ /dev/null @@ -1,5 +0,0 @@ -chromium-tip-of-tree-mac.zip -chromium-tip-of-tree-mac-arm64.zip -chromium-tip-of-tree-linux.zip -chromium-tip-of-tree-linux-arm64.zip -chromium-tip-of-tree-win64.zip diff --git a/browser_patches/chromium-tip-of-tree/UPSTREAM_CONFIG.sh b/browser_patches/chromium-tip-of-tree/UPSTREAM_CONFIG.sh deleted file mode 100644 index ead22a6954c40e..00000000000000 --- a/browser_patches/chromium-tip-of-tree/UPSTREAM_CONFIG.sh +++ /dev/null @@ -1,3 +0,0 @@ -# CURRENT_VERSION: 106.0.5247.0 -# BRANCH_BASE_POSITION: 1036354 -BRANCH_COMMIT="18d7ce4d777fa2c7de03f6a01c026b0f9394037e" diff --git a/browser_patches/chromium-tip-of-tree/archive.sh b/browser_patches/chromium-tip-of-tree/archive.sh deleted file mode 100755 index 3e260dfb0af71b..00000000000000 --- a/browser_patches/chromium-tip-of-tree/archive.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -bash "../chromium/archive.sh" "$@" diff --git a/browser_patches/chromium-tip-of-tree/build.sh b/browser_patches/chromium-tip-of-tree/build.sh deleted file mode 100755 index efc6479c616f7a..00000000000000 --- a/browser_patches/chromium-tip-of-tree/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -bash "../chromium/build.sh" "$@" diff --git a/browser_patches/chromium-tip-of-tree/clean.sh b/browser_patches/chromium-tip-of-tree/clean.sh deleted file mode 100755 index 3ea4237e9cf70b..00000000000000 --- a/browser_patches/chromium-tip-of-tree/clean.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -bash "../chromium/clean.sh" "$@" diff --git a/browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh b/browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh deleted file mode 100755 index 4ddf20bf329a3e..00000000000000 --- a/browser_patches/chromium-tip-of-tree/roll_to_current_tip_of_tree.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -# 1. get current version -CURRENT_BETA_VERSION=$(curl https://omahaproxy.appspot.com/all | grep "win64,canary," | cut -d ',' -f 3) -VERSION_INFO_JSON=$(curl "https://omahaproxy.appspot.com/deps.json?version=$CURRENT_BETA_VERSION") - -NODE_SCRIPT=$(cat < "${SCRIPT_FOLDER}/UPSTREAM_CONFIG.sh" -BUILD_NUMBER=$(cat "${SCRIPT_FOLDER}/BUILD_NUMBER") -echo $(( $BUILD_NUMBER + 1 )) > "${SCRIPT_FOLDER}/BUILD_NUMBER" diff --git a/browser_patches/chromium/.gitignore b/browser_patches/chromium/.gitignore deleted file mode 100644 index 2658404cd72839..00000000000000 --- a/browser_patches/chromium/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/output -/depot_tools -/electron-build-tools diff --git a/browser_patches/chromium/BUILD_NUMBER b/browser_patches/chromium/BUILD_NUMBER deleted file mode 100644 index 8463e0903ffa40..00000000000000 --- a/browser_patches/chromium/BUILD_NUMBER +++ /dev/null @@ -1 +0,0 @@ -1021 diff --git a/browser_patches/chromium/EXPECTED_BUILDS b/browser_patches/chromium/EXPECTED_BUILDS deleted file mode 100644 index aa0df7e2ef5aa7..00000000000000 --- a/browser_patches/chromium/EXPECTED_BUILDS +++ /dev/null @@ -1,5 +0,0 @@ -chromium-mac.zip -chromium-mac-arm64.zip -chromium-linux.zip -chromium-linux-arm64.zip -chromium-win64.zip diff --git a/browser_patches/chromium/EXPECTED_BUILDS_WITH_SYMBOLS b/browser_patches/chromium/EXPECTED_BUILDS_WITH_SYMBOLS deleted file mode 100644 index 36a818ac6f2f7b..00000000000000 --- a/browser_patches/chromium/EXPECTED_BUILDS_WITH_SYMBOLS +++ /dev/null @@ -1,5 +0,0 @@ -chromium-with-symbols-mac.zip -chromium-with-symbols-mac-arm64.zip -chromium-with-symbols-linux.zip -chromium-with-symbols-linux-arm64.zip -chromium-with-symbols-win64.zip diff --git a/browser_patches/chromium/UPSTREAM_CONFIG.sh b/browser_patches/chromium/UPSTREAM_CONFIG.sh deleted file mode 100644 index a8d7280576e6df..00000000000000 --- a/browser_patches/chromium/UPSTREAM_CONFIG.sh +++ /dev/null @@ -1,3 +0,0 @@ -# CURRENT_VERSION: 105.0.5195.37 -# BRANCH_BASE_POSITION: 1027018 -BRANCH_COMMIT="9f54e061380e11c611d0c695ab77a94fd2a0afa3" diff --git a/browser_patches/chromium/archive.sh b/browser_patches/chromium/archive.sh deleted file mode 100755 index c9de58258070c9..00000000000000 --- a/browser_patches/chromium/archive.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_PATH=$(pwd -P) -source "${SCRIPT_PATH}/../utils.sh" - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename "$0") [output-absolute-path]" - echo - echo "Generate distributable .zip archive from ./output folder that was previously downloaded." - echo - exit 0 -fi - -ZIP_PATH=$1 - -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname "$ZIP_PATH") ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" -fi -if [[ ! -d "${CR_CHECKOUT_PATH}/src" ]]; then - echo "ERROR: CR_CHECKOUT_PATH does not have src/ subfolder; is this a chromium checkout?" - exit 1 -fi - -CHROMIUM_FOLDER_NAME="" -CHROMIUM_FILES_TO_ARCHIVE=() - -if is_mac; then - CHROMIUM_FOLDER_NAME="chrome-mac" - IFS=$'\n' CHROMIUM_FILES_TO_ARCHIVE=($(node "${SCRIPT_PATH}/compute_files_to_archive.js" "${CR_CHECKOUT_PATH}/src/infra/archive_config/mac-archive-rel.json")) - unset IFS -elif is_linux; then - CHROMIUM_FOLDER_NAME="chrome-linux" - IFS=$'\n' CHROMIUM_FILES_TO_ARCHIVE=($(node "${SCRIPT_PATH}/compute_files_to_archive.js" "${CR_CHECKOUT_PATH}/src/infra/archive_config/linux-archive-rel.json")) - unset IFS -elif is_win; then - CHROMIUM_FOLDER_NAME="chrome-win" - IFS=$'\n\r' CHROMIUM_FILES_TO_ARCHIVE=($(node "${SCRIPT_PATH}/compute_files_to_archive.js" "${CR_CHECKOUT_PATH}/src/infra/archive_config/win-archive-rel.json")) - unset IFS -else - echo "ERROR: unsupported platform - $(uname)" - exit 1 -fi - -# Prepare resulting archive. -cd "$SCRIPT_PATH" -rm -rf output -mkdir -p "output/${CHROMIUM_FOLDER_NAME}" - -# On Mac, use 'ditto' to copy directories instead of 'cp'. -COPY_COMMAND="cp -R" -if is_mac; then - COPY_COMMAND="ditto" -fi - -for ((i = 0; i < ${#CHROMIUM_FILES_TO_ARCHIVE[@]}; i++)) do - file="${CHROMIUM_FILES_TO_ARCHIVE[$i]}" - mkdir -p "output/${CHROMIUM_FOLDER_NAME}/$(dirname "${file}")" - $COPY_COMMAND "${CR_CHECKOUT_PATH}/src/out/Default/${file}" "output/${CHROMIUM_FOLDER_NAME}/${file}" -done - -if is_win; then - $COPY_COMMAND "${CR_CHECKOUT_PATH}/src/out/Default/"*.manifest "output/${CHROMIUM_FOLDER_NAME}/" - mkdir -p "output/${CHROMIUM_FOLDER_NAME}/locales" - $COPY_COMMAND "${CR_CHECKOUT_PATH}/src/out/Default/locales/"*.pak "output/${CHROMIUM_FOLDER_NAME}/locales/" -fi - -cd output -zip --symlinks -r build.zip "${CHROMIUM_FOLDER_NAME}" - -cd "${SCRIPT_PATH}" -cp output/build.zip "$ZIP_PATH" diff --git a/browser_patches/chromium/build.sh b/browser_patches/chromium/build.sh deleted file mode 100755 index 521fb32e702ee9..00000000000000 --- a/browser_patches/chromium/build.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) -source "${SCRIPT_FOLDER}/../utils.sh" - -USAGE=$(cat< - - --arm64 cross-compile for arm64 - --symbols compile with symbols - --full install build dependencies - --goma use goma when compiling. Make sure to pre-start goma client beforehand with './goma.sh start'. - - On Linux & MacOS, it is possible to specify custom compilation targets: - - ./build.sh --goma blink_tests - -EOF -) - -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ $1 == "--help" || $1 == "-h" ]]; then - echo "$USAGE" - exit 0 -fi - -args=("$@") -IS_ARM64="" -IS_SYMBOLS_BUILD="" -IS_FULL="" -USE_GOMA="" -for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --arm64) IS_ARM64="1"; unset args[i]; ;; - --symbols) IS_SYMBOLS_BUILD="1"; unset args[i]; ;; - --full) IS_FULL="1"; unset args[i]; ;; - --goma) USE_GOMA="1"; unset args[i]; ;; - esac -done - -compile_chromium() { - if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" - fi - - if [[ ! -d "${CR_CHECKOUT_PATH}/src" ]]; then - echo "ERROR: CR_CHECKOUT_PATH does not have src/ subfolder; is this a chromium checkout?" - exit 1 - fi - - source "${SCRIPT_FOLDER}/ensure_depot_tools.sh" - - if is_mac; then - selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" chromium) - fi - - cd "${CR_CHECKOUT_PATH}/src" - - # Prepare build folder. - mkdir -p "./out/Default" - echo "is_debug = false" > ./out/Default/args.gn - echo "dcheck_always_on = false" >> ./out/Default/args.gn - if [[ -n "${IS_SYMBOLS_BUILD}" ]]; then - echo "symbol_level = 1" >> ./out/Default/args.gn - else - echo "symbol_level = 0" >> ./out/Default/args.gn - fi - - if [[ -n "${IS_ARM64}" ]]; then - echo 'target_cpu = "arm64"' >> ./out/Default/args.gn - fi - - if [[ ! -z "$USE_GOMA" ]]; then - "${SCRIPT_FOLDER}/goma.sh" args >> ./out/Default/args.gn - fi - echo 'enable_nacl = false' >> ./out/Default/args.gn - - echo "===== args.gn =====" - cat ./out/Default/args.gn - echo "===== ======= =====" - - if [[ -n "$IS_FULL" ]]; then - if is_linux; then - ./build/install-build-deps.sh - if [[ -n "$IS_ARM64" ]]; then - # Install sysroot image, see https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/linux/chromium_arm.md - ./build/linux/sysroot_scripts/install-sysroot.py --arch=arm64 - fi - fi - fi - - TARGETS="${args[@]}" - if is_win; then - if [[ -n "$TARGETS" ]]; then - echo "ERROR: cannot compile custom targets on windows yet." - echo "Requested to compile chromium targets - ${TARGETS}" - exit 1 - fi - if [[ -z "$USE_GOMA" ]]; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w "${SCRIPT_FOLDER}"/buildwin.bat)" - else - /c/Windows/System32/cmd.exe "/c $(cygpath -w "${SCRIPT_FOLDER}"/buildwingoma.bat)" - fi - else - if [[ -z "$TARGETS" ]]; then - if is_linux; then - TARGETS="chrome chrome_sandbox clear_key_cdm" - else - TARGETS="chrome" - fi - fi - echo - echo ">> Compiling Targets: $TARGETS" - echo - - gn gen out/Default - if [[ -z "$USE_GOMA" ]]; then - autoninja -C out/Default $TARGETS - else - ninja -j 200 -C out/Default $TARGETS - fi - fi -} - -compile_chromium "${args[@]}" diff --git a/browser_patches/chromium/buildwin.bat b/browser_patches/chromium/buildwin.bat deleted file mode 100644 index eec9a5c4129cca..00000000000000 --- a/browser_patches/chromium/buildwin.bat +++ /dev/null @@ -1,2 +0,0 @@ -CALL gn gen out/Default -CALL autoninja -C out/Default chrome eventlog_provider diff --git a/browser_patches/chromium/buildwingoma.bat b/browser_patches/chromium/buildwingoma.bat deleted file mode 100644 index d834c5516fa6d7..00000000000000 --- a/browser_patches/chromium/buildwingoma.bat +++ /dev/null @@ -1,2 +0,0 @@ -CALL gn gen out/Default -CALL ninja -j 200 -C out/Default chrome eventlog_provider diff --git a/browser_patches/chromium/clean.sh b/browser_patches/chromium/clean.sh deleted file mode 100755 index e03c7df33b76c0..00000000000000 --- a/browser_patches/chromium/clean.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -rm -rf output -if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" -fi - -if [[ -d "${CR_CHECKOUT_PATH}/src" ]]; then - rm -rf "${CR_CHECKOUT_PATH}/src/out" -fi diff --git a/browser_patches/chromium/compute_files_to_archive.js b/browser_patches/chromium/compute_files_to_archive.js deleted file mode 100644 index 341837bc1c8737..00000000000000 --- a/browser_patches/chromium/compute_files_to_archive.js +++ /dev/null @@ -1,26 +0,0 @@ -// This script is supposed to be run with a path to either of the following configs from chromium checkout: -// - infra/archive_config/mac-archive-rel.json -// - infra/archive_config/linux-archive-rel.json -// - infra/archive_config/win-archive-rel.json - -const fs = require('fs'); - -const configs = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')).archive_datas; -const config = configs.find(config => config.gcs_path.includes('chrome-linux.zip') || config.gcs_path.includes('chrome-win.zip') || config.gcs_path.includes('chrome-mac.zip')); - -const excludeList = new Set([ - // We do not need interactive tests in our archive. - 'interactive_ui_tests.exe', - // We no longer compile nacl with Chromium. - 'nacl_helper_bootstrap', - 'nacl_helper', - 'nacl_irt_x86_64.nexe', -]); - -const entries = [ - ...(config.files || []), - ...(config.dirs || []), -].filter(entry => !excludeList.has(entry)); - -for (const entry of entries) - console.log(entry); diff --git a/browser_patches/chromium/ensure_depot_tools.sh b/browser_patches/chromium/ensure_depot_tools.sh deleted file mode 100644 index c746fe53624715..00000000000000 --- a/browser_patches/chromium/ensure_depot_tools.sh +++ /dev/null @@ -1,32 +0,0 @@ -# Since this script modifies PATH, it cannot be run in a subshell -# and must be sourced. -# Make sure it is sourced. -sourced=0 -(return 0 2>/dev/null) && sourced=1 || sourced=0 - -if [[ $sourced == 0 ]]; then - echo 'ERROR: cannot run this script in a subshell' - echo 'This file modifies $PATH of the current shell, so it must be sourced instead' - echo 'Use `source ensure_depot_tool.sh` instead' - exit 1 -fi - -function ensure_depot_tools() { - # Install depot_tools if they are not in system, and modify $PATH - # to include depot_tools - if ! command -v autoninja >/dev/null; then - if [[ $(uname) == "MINGW"* || "$(uname)" == MSYS* ]]; then - # NOTE: as of Feb 8, 2021, windows requires manual and separate - # installation of depot_tools. - echo "ERROR: cannot automatically install depot_tools on windows. Please, install manually" - exit 1 - fi - local SCRIPT_PATH=$(cd "$(dirname "$BASH_SOURCE")"; pwd -P) - if [[ ! -d "${SCRIPT_PATH}/depot_tools" ]]; then - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git "${SCRIPT_PATH}/depot_tools" - fi - export PATH="${SCRIPT_PATH}/depot_tools:$PATH" - fi -} - -ensure_depot_tools diff --git a/browser_patches/chromium/goma.sh b/browser_patches/chromium/goma.sh deleted file mode 100755 index 8e2ff8649b2264..00000000000000 --- a/browser_patches/chromium/goma.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) -source "${SCRIPT_FOLDER}/../utils.sh" - -ELECTRON_BUILD_TOOLS_REQUIRED_VERSION=2c24fb5c7c938a4e387f355ab64be449604ae5db -if [[ -d ./electron-build-tools ]]; then - cd ./electron-build-tools - # Make sure required commit is part of electron-build-tools. - if ! git merge-base --is-ancestor "${ELECTRON_BUILD_TOOLS_REQUIRED_VERSION}" HEAD; then - cd .. - rm -rf ./electron-build-tools - echo "Updating electron-build-tools" - else - cd .. - fi -fi - -if [[ ! -d ./electron-build-tools ]]; then - git clone --single-branch --branch main https://github.com/electron/build-tools/ electron-build-tools - cd electron-build-tools - npm install - mkdir -p third_party - ./src/e update-goma msftGoma - cd .. -fi - -if ! is_win; then - if command -v python >/dev/null; then - PYTHON=python - elif command -v python3 >/dev/null; then - PYTHON=python3 - else - echo "ERROR: no python or python3 found in PATH" - exit 1 - fi -fi - -cd electron-build-tools/third_party/goma - -export GOMA_START_COMPILER_PROXY=true - -function print_gn_args() { - PLAYWRIGHT_GOMA_PATH="${SCRIPT_FOLDER}/electron-build-tools/third_party/goma" - if is_win; then - PLAYWRIGHT_GOMA_PATH=$(cygpath -w "${PLAYWRIGHT_GOMA_PATH}") - fi - echo 'use_goma = true' - echo "goma_dir = \"${PLAYWRIGHT_GOMA_PATH}\"" -} - -if [[ $1 == "--help" ]]; then - echo "$(basename "$0") [login|start|stop|--help]" - exit 0 -elif [[ $1 == "args" ]]; then - print_gn_args -elif [[ $1 == "login" ]]; then - if is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w $(pwd)/goma_auth.bat) login" - else - $PYTHON ./goma_auth.py login - fi - echo - echo "Congratulation! Goma is logged in!" - echo "run '$(basename "$0") start' to launch goma client" -elif [[ $1 == "start" ]]; then - # We have to prefix ENV with `PLAYWRIGHT` since `GOMA_` env variables - # have special treatment by goma. - if [[ ! -z "$PLAYWRIGHT_GOMA_LOGIN_COOKIE" ]]; then - echo "$PLAYWRIGHT_GOMA_LOGIN_COOKIE" > "$HOME/.goma_oauth2_config" - fi - if [[ ! -f "$HOME/.goma_oauth2_config" ]]; then - echo "ERROR: goma is not logged in!" - echo "run '$(basename "$0") login'" - exit 1 - fi - if is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w $(pwd)/goma_ctl.bat) ensure_start" - else - $PYTHON ./goma_ctl.py ensure_start - fi - set +x - echo - echo "Congratulatons! Goma is running!" - echo - echo "Add the following gn args to use goma:" - echo - echo "===== args.gn =====" - print_gn_args - echo "===== ======= =====" -elif [[ $1 == "stop" ]]; then - if is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w $(pwd)/goma_ctl.bat) stop" - else - $PYTHON ./goma_ctl.py stop - fi -else - echo "ERROR: unknown command - $1" - echo "Use --help to list all available commands" - exit 1 -fi diff --git a/browser_patches/chromium/roll_to_current_beta.sh b/browser_patches/chromium/roll_to_current_beta.sh deleted file mode 100755 index 7b1c7d6e04ea42..00000000000000 --- a/browser_patches/chromium/roll_to_current_beta.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER=$(pwd -P) - -# 1. get current version -CURRENT_BETA_VERSION=$(curl https://omahaproxy.appspot.com/all | grep "win64,beta" | cut -d ',' -f 3) -VERSION_INFO_JSON=$(curl "https://omahaproxy.appspot.com/deps.json?version=$CURRENT_BETA_VERSION") - -NODE_SCRIPT=$(cat < "${SCRIPT_FOLDER}/UPSTREAM_CONFIG.sh" -BUILD_NUMBER=$(cat "${SCRIPT_FOLDER}/BUILD_NUMBER") -echo $(( $BUILD_NUMBER + 1 )) > "${SCRIPT_FOLDER}/BUILD_NUMBER" diff --git a/browser_patches/clean.sh b/browser_patches/clean.sh deleted file mode 100755 index b6a2cfe1da8d91..00000000000000 --- a/browser_patches/clean.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: clean.sh [firefox|webkit|firefox-beta]" - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './clean.sh --help' for more information" - exit 1 -fi - -CMD="$1" -shift -if [[ ("$CMD" == "firefox") || ("$CMD" == "firefox/") || ("$CMD" == "ff") ]]; then - bash ./firefox/clean.sh "$@" -elif [[ ("$CMD" == "firefox-beta") || ("$CMD" == "ff-beta") ]]; then - bash ./firefox-beta/clean.sh "$@" -elif [[ ("$CMD" == "webkit") || ("$CMD" == "webkit/") || ("$CMD" == "wk") ]]; then - bash ./webkit/clean.sh "$@" -elif [[ ("$CMD" == "chromium") || ("$CMD" == "chromium/") || ("$CMD" == "cr") ]]; then - bash ./chromium/clean.sh "$@" -elif [[ ("$CMD" == "winldd") ]]; then - bash ./winldd/clean.sh "$@" -elif [[ ("$CMD" == "ffmpeg") ]]; then - bash ./ffmpeg/clean.sh "$@" -else - echo ERROR: unknown browser to build - "$CMD" - exit 1 -fi - diff --git a/browser_patches/docker/cli.sh b/browser_patches/docker/cli.sh deleted file mode 100755 index 1904ebad7e55f9..00000000000000 --- a/browser_patches/docker/cli.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -# This script is designed to build Firefox & WebKit on various Linux -# distributions inside docker containers. -set -e -set +x -set -o pipefail - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [webkit-ubuntu-20.04|firefox-debian-11|...] [build|test|compile|enter|cleanup]" - echo - echo "Builds Webkit or Firefox browser inside given Linux distribution" - exit 0 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" - -export BUILD_FLAVOR="${1}" -export BROWSER_NAME="" - -DOCKERFILE="" - -if [[ "${BUILD_FLAVOR}" == "firefox-beta-"* ]]; then - DOCKERFILE="${SCRIPT_FOLDER}/firefox-beta/${BUILD_FLAVOR#firefox-beta-}.dockerfile" - BROWSER_NAME="firefox-beta" -elif [[ "${BUILD_FLAVOR}" == "firefox-"* ]]; then - DOCKERFILE="${SCRIPT_FOLDER}/firefox/${BUILD_FLAVOR#firefox-}.dockerfile" - BROWSER_NAME="firefox" -elif [[ "${BUILD_FLAVOR}" == "webkit-"* ]]; then - DOCKERFILE="${SCRIPT_FOLDER}/webkit/${BUILD_FLAVOR#webkit-}.dockerfile" - BROWSER_NAME="webkit" -else - echo "ERROR: unknown build flavor - ${BUILD_FLAVOR}" - exit 1 -fi - -if [[ "${BUILD_FLAVOR}" == *"-arm64" ]]; then - EXPECTED_ARCH="arm64" - DOCKER_PLATFORM="linux/arm64" -else - EXPECTED_ARCH="x86_64" - DOCKER_PLATFORM="linux/amd64" -fi - -if [[ $(arch) != "${EXPECTED_ARCH}" ]]; then - echo "ERROR: host architecture $(arch) does not match expected architecture - ${EXPECTED_ARCH}" - exit 1 -fi - -DOCKER_IMAGE_NAME="${BUILD_FLAVOR}" -DOCKER_CONTAINER_NAME="${BUILD_FLAVOR}" -DOCKER_ARGS=$(echo \ - --env CI \ - --env BUILD_FLAVOR \ - --env BROWSER_NAME \ - --env TELEGRAM_BOT_KEY \ - --env AZ_ACCOUNT_NAME \ - --env AZ_ACCOUNT_KEY \ - --env GITHUB_SERVER_URL \ - --env GITHUB_REPOSITORY \ - --env GITHUB_RUN_ID \ - --env GH_TOKEN \ - --env DEBIAN_FRONTEND=noninteractive \ - --env TZ="America/Los_Angeles" -) - -if [[ "$2" == "build" ]]; then - docker build \ - --build-arg ARG_BUILD_FLAVOR="${BUILD_FLAVOR}" \ - --build-arg ARG_BROWSER_NAME="${BROWSER_NAME}" \ - --no-cache \ - --platform "${DOCKER_PLATFORM}" \ - -t "${DOCKER_IMAGE_NAME}" \ - -f "${DOCKERFILE}" . -elif [[ "$2" == "test" ]]; then - docker run --rm ${DOCKER_ARGS} --init --name "${DOCKER_CONTAINER_NAME}" --platform "${DOCKER_PLATFORM}" -it "${DOCKER_IMAGE_NAME}" /bin/bash -c ' - CI=1 ./browser_patches/prepare_checkout.sh "${BROWSER_NAME}" - ./browser_patches/build.sh "${BROWSER_NAME}" --full - ./browser_patches/${BROWSER_NAME}/archive.sh $PWD/archive.zip - ' -elif [[ "$2" == "compile" ]]; then - docker run --rm ${DOCKER_ARGS} --init --name "${DOCKER_CONTAINER_NAME}" --platform "${DOCKER_PLATFORM}" -t "${DOCKER_IMAGE_NAME}" /bin/bash -c ' - ./browser_patches/checkout_build_archive_upload.sh "${BUILD_FLAVOR}" - ' -elif [[ "$2" == "enter" ]]; then - docker run --rm ${DOCKER_ARGS} --init --name "${DOCKER_CONTAINER_NAME}" --platform "${DOCKER_PLATFORM}" -it "${DOCKER_IMAGE_NAME}" /bin/bash -elif [[ "$2" == "cleanup" ]]; then - docker kill "${DOCKER_CONTAINER_NAME}" || true - # Wait for container to stop - docker wait "${DOCKER_CONTAINER_NAME}" || true - docker rmi "${DOCKER_IMAGE_NAME}" - docker system prune -f -else - echo "ERROR: unknown command - $2" - exit 1 -fi - diff --git a/browser_patches/docker/firefox-beta/debian-11.dockerfile b/browser_patches/docker/firefox-beta/debian-11.dockerfile deleted file mode 100644 index 714e0f3860341a..00000000000000 --- a/browser_patches/docker/firefox-beta/debian-11.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 debian:11 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-18.04.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-18.04.dockerfile deleted file mode 100644 index b329797466893c..00000000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-18.04.dockerfile +++ /dev/null @@ -1,60 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:18.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -# Firefox build on Ubuntu 18.04 requires Python3.8 to run its build scripts. -RUN apt-get install -y python3.8 python3.8-dev python3.8-distutils && \ - # Point python3 to python3.8 - update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2 && \ - curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \ - python3 get-pip.py && \ - rm get-pip.py - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-20.04-arm64.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-20.04-arm64.dockerfile deleted file mode 100644 index 8528f52ac21e09..00000000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-20.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 20.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-20.04.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-20.04.dockerfile deleted file mode 100644 index d6dcbab630bf39..00000000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-20.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-22.04-arm64.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-22.04-arm64.dockerfile deleted file mode 100644 index 768e956b0960f7..00000000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-22.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 22.04 aarch64 specific: default to clang-14. -RUN apt-get install -y clang-14 -ENV CC=/usr/bin/clang-14 -ENV CXX=/usr/bin/clang++-14 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox-beta/ubuntu-22.04.dockerfile b/browser_patches/docker/firefox-beta/ubuntu-22.04.dockerfile deleted file mode 100644 index 348ef04af3e033..00000000000000 --- a/browser_patches/docker/firefox-beta/ubuntu-22.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/debian-11.dockerfile b/browser_patches/docker/firefox/debian-11.dockerfile deleted file mode 100644 index 714e0f3860341a..00000000000000 --- a/browser_patches/docker/firefox/debian-11.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 debian:11 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-18.04.dockerfile b/browser_patches/docker/firefox/ubuntu-18.04.dockerfile deleted file mode 100644 index b329797466893c..00000000000000 --- a/browser_patches/docker/firefox/ubuntu-18.04.dockerfile +++ /dev/null @@ -1,60 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:18.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -# Firefox build on Ubuntu 18.04 requires Python3.8 to run its build scripts. -RUN apt-get install -y python3.8 python3.8-dev python3.8-distutils && \ - # Point python3 to python3.8 - update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2 && \ - curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \ - python3 get-pip.py && \ - rm get-pip.py - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-20.04-arm64.dockerfile b/browser_patches/docker/firefox/ubuntu-20.04-arm64.dockerfile deleted file mode 100644 index 8528f52ac21e09..00000000000000 --- a/browser_patches/docker/firefox/ubuntu-20.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 20.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-20.04.dockerfile b/browser_patches/docker/firefox/ubuntu-20.04.dockerfile deleted file mode 100644 index d6dcbab630bf39..00000000000000 --- a/browser_patches/docker/firefox/ubuntu-20.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-22.04-arm64.dockerfile b/browser_patches/docker/firefox/ubuntu-22.04-arm64.dockerfile deleted file mode 100644 index 768e956b0960f7..00000000000000 --- a/browser_patches/docker/firefox/ubuntu-22.04-arm64.dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 22.04 aarch64 specific: default to clang-14. -RUN apt-get install -y clang-14 -ENV CC=/usr/bin/clang-14 -ENV CXX=/usr/bin/clang++-14 - -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/firefox/ubuntu-22.04.dockerfile b/browser_patches/docker/firefox/ubuntu-22.04.dockerfile deleted file mode 100644 index 348ef04af3e033..00000000000000 --- a/browser_patches/docker/firefox/ubuntu-22.04.dockerfile +++ /dev/null @@ -1,54 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo -# Install Python3 with distutils -RUN apt-get install -y python3 python3-dev python3-pip python3-distutils - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message to pwuser -COPY --chown=pwuser ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser - -# Install Rust -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="${PATH}:/home/pwuser/.cargo/bin" - -RUN mkdir -p /home/pwuser/.mozbuild -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - - diff --git a/browser_patches/docker/pwuser_bashrc b/browser_patches/docker/pwuser_bashrc deleted file mode 100644 index ed78a6e0534061..00000000000000 --- a/browser_patches/docker/pwuser_bashrc +++ /dev/null @@ -1,29 +0,0 @@ -source /etc/os-release -if [[ -z "${BUILD_FLAVOR}" ]]; then - BUILD_FLAVOR='' -fi -if [[ -z "${BROWSER_NAME}" ]]; then - BROWSER_NAME='' -fi - -echo "======================================================================" -echo "Welcome to the ${BUILD_FLAVOR} environment!" -echo "- distro: ${PRETTY_NAME}" -echo "- arch: $(arch)" - -if [[ -n "${CXX}" ]]; then - echo "- CXX: ${CXX}" -fi -if [[ -n "${CC}" ]]; then - echo "- CC: ${CC}" -fi - -echo -echo "NOTE: Playwright clone is shallow (has no git history); to unshallow, run:" -echo " git fetch --unshallow" -echo -echo "To get started, prepare your browser checkout:" -echo " CI=1 ./browser_patches/prepare_checkout.sh ${BROWSER_NAME}" -echo -echo "======================================================================" - diff --git a/browser_patches/docker/webkit/debian-11.dockerfile b/browser_patches/docker/webkit/debian-11.dockerfile deleted file mode 100644 index 34969d74d49fb5..00000000000000 --- a/browser_patches/docker/webkit/debian-11.dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM --platform=linux/amd64 debian:11 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -# Debian 11 specific: add contrib & non-free repositories. -RUN echo "deb http://ftp.us.debian.org/debian bullseye main contrib non-free" >> /etc/apt/sources.list.d/pwbuild.list - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-18.04.dockerfile b/browser_patches/docker/webkit/ubuntu-18.04.dockerfile deleted file mode 100644 index 7cba2be2c832b3..00000000000000 --- a/browser_patches/docker/webkit/ubuntu-18.04.dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:18.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 18.04 specific: update CMake. Default CMake on Ubuntu 18.04 is 3.10, whereas WebKit requires 3.12+. -RUN apt purge --auto-remove cmake && \ - apt-get install -y wget software-properties-common && \ - wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null && \ - apt-add-repository "deb https://apt.kitware.com/ubuntu/ bionic main" && \ - apt-get update && apt-get install -y cmake - -# Ubuntu 18.04 specific: default to gcc-9. -RUN add-apt-repository ppa:ubuntu-toolchain-r/test && \ - apt-get update && \ - apt-get install -y gcc-9 g++-9 -ENV CC=/usr/bin/gcc-9 -ENV CXX=/usr/bin/g++-9 - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-20.04-arm64.dockerfile b/browser_patches/docker/webkit/ubuntu-20.04-arm64.dockerfile deleted file mode 100644 index 5b30404a562a6f..00000000000000 --- a/browser_patches/docker/webkit/ubuntu-20.04-arm64.dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 20.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN apt-get install -y python3 \ - python3-dev \ - python3-pip \ - python3-distutils && \ - pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-20.04.dockerfile b/browser_patches/docker/webkit/ubuntu-20.04.dockerfile deleted file mode 100644 index 260954626583b4..00000000000000 --- a/browser_patches/docker/webkit/ubuntu-20.04.dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:20.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-22.04-arm64.dockerfile b/browser_patches/docker/webkit/ubuntu-22.04-arm64.dockerfile deleted file mode 100644 index 30e86a1f3e7f57..00000000000000 --- a/browser_patches/docker/webkit/ubuntu-22.04-arm64.dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -FROM --platform=linux/arm64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Ubuntu 22.04 aarch64 specific: default to clang-12. -RUN apt-get install -y clang-12 -ENV CC=/usr/bin/clang-12 -ENV CXX=/usr/bin/clang++-12 - -# Install AZ CLI with Python since they do not ship -# aarch64 to APT: https://github.com/Azure/azure-cli/issues/7368 -# Pin so future releases do not break us. -RUN apt-get install -y python3 \ - python3-dev \ - python3-pip \ - python3-distutils && \ - pip3 install azure-cli==2.38.0 - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/docker/webkit/ubuntu-22.04.dockerfile b/browser_patches/docker/webkit/ubuntu-22.04.dockerfile deleted file mode 100644 index 928874b654a8b0..00000000000000 --- a/browser_patches/docker/webkit/ubuntu-22.04.dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM --platform=linux/amd64 ubuntu:22.04 - -# Reexport --build-arg as environment variables -ARG ARG_BUILD_FLAVOR -ARG ARG_BROWSER_NAME -ENV BUILD_FLAVOR="${ARG_BUILD_FLAVOR}" -ENV BROWSER_NAME="${ARG_BROWSER_NAME}" - -# These are needed to auto-install tzdata. See https://serverfault.com/questions/949991/how-to-install-tzdata-on-a-ubuntu-docker-image -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles - -RUN apt-get update && apt-get install -y curl \ - build-essential \ - git-core \ - zip unzip \ - tzdata \ - sudo - -# Install Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - -# Install node16 -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs - -# Create the pwuser and make it passwordless sudoer. -RUN adduser --disabled-password --gecos "" pwuser && \ - echo "ALL ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers - -# mitigate git clone issues on CI -# See https://stdworkflow.com/877/error-rpc-failed-curl-56-gnutls-recv-error-54-error-in-the-pull-function -RUN git config --system user.email "devops@playwright.dev" && \ - git config --system user.name "Playwright DevOps" && \ - git config --system http.postBuffer 524288000 && \ - git config --system http.lowSpeedLimit 0 && \ - git config --system http.lowSpeedTime 999999 - -# Show welcome message -COPY ./pwuser_bashrc /home/pwuser/.bashrc - -USER pwuser -RUN cd /home/pwuser && git clone --depth=1 https://github.com/microsoft/playwright - -WORKDIR /home/pwuser/playwright - diff --git a/browser_patches/export.sh b/browser_patches/export.sh deleted file mode 100755 index 01139737f05372..00000000000000 --- a/browser_patches/export.sh +++ /dev/null @@ -1,177 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -REMOTE_BROWSER_UPSTREAM="browser_upstream" -BUILD_BRANCH="playwright-build" - -# COLORS -RED=$'\e[1;31m' -GRN=$'\e[1;32m' -YEL=$'\e[1;33m' -END=$'\e[0m' - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: export.sh [firefox|webkit] [custom_checkout_path]" - echo - echo "Exports patch from the current branch of the checkout to browser folder." - echo "The checkout has to be 'prepared', meaning that 'prepare_checkout.sh' should be" - echo "run against it first." - echo - echo "You can optionally specify custom_checkout_path if you have browser checkout somewhere else" - echo "and wish to export patches from it." - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './export.sh --help' for more information" - exit 1 -fi - -# FRIENDLY_CHECKOUT_PATH is used only for logging. -FRIENDLY_CHECKOUT_PATH=""; -BUILD_NUMBER_UPSTREAM_URL="" -CHECKOUT_PATH="" -EXPORT_PATH="" -EXTRA_FOLDER_PW_PATH="" -EXTRA_FOLDER_CHECKOUT_RELPATH="" -if [[ ("$1" == "firefox") || ("$1" == "firefox/") || ("$1" == "ff") ]]; then - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - EXTRA_FOLDER_PW_PATH="$PWD/firefox/juggler" - EXTRA_FOLDER_CHECKOUT_RELPATH="juggler" - EXPORT_PATH="$PWD/firefox" - BUILD_NUMBER_UPSTREAM_URL="https://raw.githubusercontent.com/microsoft/playwright/main/browser_patches/firefox/BUILD_NUMBER" - source "./firefox/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "firefox-beta") || ("$1" == "ff-beta") ]]; then - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - EXTRA_FOLDER_PW_PATH="$PWD/firefox-beta/juggler" - EXTRA_FOLDER_CHECKOUT_RELPATH="juggler" - EXPORT_PATH="$PWD/firefox-beta" - BUILD_NUMBER_UPSTREAM_URL="https://raw.githubusercontent.com/microsoft/playwright/main/browser_patches/firefox-beta/BUILD_NUMBER" - source "./firefox-beta/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "webkit") || ("$1" == "webkit/") || ("$1" == "wk") ]]; then - if [[ -z "${WK_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/webkit'; - CHECKOUT_PATH="$HOME/webkit" - else - echo "WARNING: using checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" - CHECKOUT_PATH="${WK_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - EXTRA_FOLDER_PW_PATH="$PWD/webkit/embedder/Playwright" - EXTRA_FOLDER_CHECKOUT_RELPATH="Tools/Playwright" - EXPORT_PATH="$PWD/webkit" - BUILD_NUMBER_UPSTREAM_URL="https://raw.githubusercontent.com/microsoft/playwright/main/browser_patches/webkit/BUILD_NUMBER" - source "./webkit/UPSTREAM_CONFIG.sh" -else - echo ERROR: unknown browser to export - "$1" - exit 1 -fi - -# we will use this just for beauty. -if [[ $# == 2 ]]; then - echo "WARNING: using custom checkout path $2" - CHECKOUT_PATH=$2 - FRIENDLY_CHECKOUT_PATH="" -fi - -# if there's no checkout folder - bail out. -if ! [[ -d $CHECKOUT_PATH ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH is missing - nothing to export." - exit 1; -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH exists - OK" -fi - -# if folder exists but not a git repository - bail out. -if ! [[ -d $CHECKOUT_PATH/.git ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH is not a git repository! Nothing to export." - exit 1 -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH is a git repo - OK" -fi - -# Switch to git repository. -cd "$CHECKOUT_PATH" - -# Setting up |$REMOTE_BROWSER_UPSTREAM| remote and fetch the $BASE_BRANCH -if git remote get-url $REMOTE_BROWSER_UPSTREAM >/dev/null; then - if ! [[ $(git config --get remote.$REMOTE_BROWSER_UPSTREAM.url || echo "") == "$REMOTE_URL" ]]; then - echo "ERROR: remote $REMOTE_BROWSER_UPSTREAM is not pointing to '$REMOTE_URL'! run 'prepare_checkout.sh' first" - exit 1 - fi -else - echo "ERROR: checkout does not have $REMOTE_BROWSER_UPSTREAM; run 'prepare_checkout.sh' first" - exit 1 -fi - -# Check if git repo is dirty. -if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH has dirty GIT state - aborting export." - exit 1 -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH is clean - OK" -fi - -PATCH_NAME=$(ls -1 "$EXPORT_PATH"/patches) -if [[ -z "$PATCH_NAME" ]]; then - PATCH_NAME="bootstrap.diff" - OLD_DIFF="" -else - OLD_DIFF=$(cat "$EXPORT_PATH"/patches/$PATCH_NAME) -fi - -CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -NEW_BASE_REVISION=$(git merge-base $REMOTE_BROWSER_UPSTREAM/"$BASE_BRANCH" "$CURRENT_BRANCH") -NEW_DIFF=$(git diff --diff-algorithm=myers --full-index "$NEW_BASE_REVISION" "$CURRENT_BRANCH" -- . ":!${EXTRA_FOLDER_CHECKOUT_RELPATH}") - -# Increment BUILD_NUMBER -BUILD_NUMBER=$(curl ${BUILD_NUMBER_UPSTREAM_URL} | head -1) -BUILD_NUMBER=$((BUILD_NUMBER+1)) - -echo "REMOTE_URL=\"$REMOTE_URL\" -BASE_BRANCH=\"$BASE_BRANCH\" -BASE_REVISION=\"$NEW_BASE_REVISION\"" > "$EXPORT_PATH"/UPSTREAM_CONFIG.sh -echo "$NEW_DIFF" > "$EXPORT_PATH"/patches/$PATCH_NAME -echo $BUILD_NUMBER > "$EXPORT_PATH"/BUILD_NUMBER -echo "Changed: $(git config user.email) $(date)" >> "$EXPORT_PATH"/BUILD_NUMBER - -echo "-- exporting standalone folder" -rm -rf "${EXTRA_FOLDER_PW_PATH}" -mkdir -p $(dirname "${EXTRA_FOLDER_PW_PATH}") -cp -r "${EXTRA_FOLDER_CHECKOUT_RELPATH}" "${EXTRA_FOLDER_PW_PATH}" - -NEW_BASE_REVISION_TEXT="$NEW_BASE_REVISION (not changed)" -if [[ "$NEW_BASE_REVISION" != "$BASE_REVISION" ]]; then - NEW_BASE_REVISION_TEXT="$YEL$NEW_BASE_REVISION (changed)$END" -fi - -echo "==============================================================" -echo " Repository: $FRIENDLY_CHECKOUT_PATH" -echo " Changes between branches: $REMOTE_BROWSER_UPSTREAM/$BASE_BRANCH..$CURRENT_BRANCH" -echo " BASE_REVISION: $NEW_BASE_REVISION_TEXT" -echo " BUILD_NUMBER: $YEL$BUILD_NUMBER (changed)$END" -echo "==============================================================" -echo diff --git a/browser_patches/ffmpeg/.gitignore b/browser_patches/ffmpeg/.gitignore deleted file mode 100644 index b97a986fa15ea7..00000000000000 --- a/browser_patches/ffmpeg/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -output/ diff --git a/browser_patches/ffmpeg/BUILD_NUMBER b/browser_patches/ffmpeg/BUILD_NUMBER deleted file mode 100644 index fb35a14c027168..00000000000000 --- a/browser_patches/ffmpeg/BUILD_NUMBER +++ /dev/null @@ -1 +0,0 @@ -1007 diff --git a/browser_patches/ffmpeg/CONFIG.sh b/browser_patches/ffmpeg/CONFIG.sh deleted file mode 100644 index 2cb8e6f83642ac..00000000000000 --- a/browser_patches/ffmpeg/CONFIG.sh +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -ZLIB_VERSION="v1.2.11" -ZLIB_CONFIG="--static" - -LIBVPX_VERSION="v1.9.0" -LIBVPX_CONFIG="--enable-static \ - --disable-shared \ - --disable-docs \ - --disable-tools \ - --disable-unit-tests \ - --disable-examples" - -FFMPEG_VERSION="n4.3.1" -FFMPEG_CONFIG="--extra-version=playwright-build-$(cat ./BUILD_NUMBER | head -1) \ - --disable-debug \ - --disable-autodetect \ - --disable-everything \ - --enable-ffmpeg \ - --enable-protocol=pipe \ - --enable-protocol=file \ - --enable-parser=mjpeg \ - --enable-decoder=mjpeg \ - --enable-demuxer=image2pipe \ - --enable-filter=pad \ - --enable-filter=crop \ - --enable-filter=scale \ - --enable-muxer=webm \ - --enable-libvpx \ - --enable-static \ - --enable-encoder=libvpx_vp8 \ - --enable-decoder=libvpx_vp8 \ - --enable-demuxer=matroska \ - --enable-encoder=png \ - --enable-zlib \ - --enable-muxer=image2 \ - --disable-pthreads \ - --disable-iconv \ - --disable-w32threads \ - --disable-bzlib" - diff --git a/browser_patches/ffmpeg/EXPECTED_BUILDS b/browser_patches/ffmpeg/EXPECTED_BUILDS deleted file mode 100644 index ec5ce4f2e01618..00000000000000 --- a/browser_patches/ffmpeg/EXPECTED_BUILDS +++ /dev/null @@ -1,6 +0,0 @@ -ffmpeg-mac.zip -ffmpeg-mac-arm64.zip -ffmpeg-linux.zip -ffmpeg-linux-arm64.zip -ffmpeg-win64.zip - diff --git a/browser_patches/ffmpeg/README.md b/browser_patches/ffmpeg/README.md deleted file mode 100644 index 89ed18d6dc2b9c..00000000000000 --- a/browser_patches/ffmpeg/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Playwright and FFMPEG - -Playwright requires FFMPEG to produce screncast and bundles FFMPEG binaries for Mac , Linux and Windows. - -## Configuration - -We compile `libvpx` and `ffmpeg` only. Their source versions and build -configurations are defined in [`//browser_patches/ffmpeg/CONFIG.sh`](./CONFIG.sh). - -## Building `ffmpeg-linux` - -Compilation scripts are based on: -- https://trac.ffmpeg.org/wiki/CompilationGuide/Generic - -Prerequisites: -- Mac or Linux -- Docker - -Building: - -``` -~/playwright$ ./browser_patches/ffmpeg/build.sh --linux -``` - -## Building `ffmpeg-mac` - -Compilation scripts are based on: -- https://trac.ffmpeg.org/wiki/CompilationGuide/Generic -- https://trac.ffmpeg.org/wiki/CompilationGuide/macOS - -Prerequisites: -- Mac -- xcode command line tools: `xcode-select --install` -- [homebrew](https://brew.sh/) - -Building: - -``` -~/playwright$ ./browser_patches/ffmpeg/build.sh --mac -``` - -## Building `ffmpeg-win*` - -Cross-compilation scripts are based on: -- https://trac.ffmpeg.org/wiki/CompilationGuide/Generic -- https://trac.ffmpeg.org/wiki/CompilationGuide/CrossCompilingForWindows - -Prerequisites: -- Mac or Linux -- [Docker](https://www.docker.com/) - -Building: - -``` -~/playwright$ ./browser_patches/ffmpeg/build.sh --cross-compile-win64 -``` - diff --git a/browser_patches/ffmpeg/archive.sh b/browser_patches/ffmpeg/archive.sh deleted file mode 100755 index ffdf2aba9e0cc0..00000000000000 --- a/browser_patches/ffmpeg/archive.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -set -e -set +x - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename $0) [output-absolute-path]" - echo - echo "Generate distributable .zip archive from ./output folder that was previously built." - echo - exit 0 -fi - -ZIP_PATH=$1 -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname $ZIP_PATH) ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -cp output/ffmpeg.zip $ZIP_PATH diff --git a/browser_patches/ffmpeg/build-linux.sh b/browser_patches/ffmpeg/build-linux.sh deleted file mode 100644 index 5514a07e7c7162..00000000000000 --- a/browser_patches/ffmpeg/build-linux.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -function die() { echo "$@"; exit 1; } - - -PREFIX="${HOME}/prefix" - - -if [[ "$(uname)" != "Linux" ]]; then - echo "ERROR: this script is designed to be run on Linux. Can't run on $(uname)" - exit 1 -fi - -output_path="$1" -if [[ -z "${output_path}" ]]; then - die "ERROR: output path is not specified" -elif [[ "${output_path}" != /* ]]; then - die "ERROR: output path ${output_path} is not absolute" -elif ! [[ -d $(dirname "${output_path}") ]]; then - die "ERROR: folder for output path ${output_path} does not exist." -fi - -function build_zlib { - cd "${HOME}" - git clone https://github.com/madler/zlib - cd zlib - git checkout "${ZLIB_VERSION}" - ./configure --prefix="${PREFIX}" ${ZLIB_CONFIG} - make && make install -} - -function build_libvpx { - cd "${HOME}" - git clone https://chromium.googlesource.com/webm/libvpx - cd libvpx - git checkout "${LIBVPX_VERSION}" - # Cross-compiling libvpx according to the docs: - # - https://chromium.googlesource.com/webm/libvpx/+/main/README - ./configure --prefix="${PREFIX}" ${LIBVPX_CONFIG} - make && make install -} - -function build_ffmpeg { - cd "${HOME}" - git clone git://source.ffmpeg.org/ffmpeg.git - cd ffmpeg - git checkout "${FFMPEG_VERSION}" - export PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig" - # Prohibit pkg-config from using linux system installed libs. - export PKG_CONFIG_LIBDIR= - - ./configure --pkg-config=pkg-config \ - --pkg-config-flags="--static" \ - --extra-cflags="-I/${PREFIX}/include" \ - --extra-ldflags="-L/${PREFIX}/lib -static" \ - --prefix="${PREFIX}" \ - --bindir="${PWD}/bin" \ - ${FFMPEG_CONFIG} - make && make install -} - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -source ./CONFIG.sh - -apt-get update -apt-get install -y git make yasm pkg-config - -build_zlib -build_libvpx -build_ffmpeg - -# put resulting executable where we were asked to -cp "${HOME}/ffmpeg/bin/ffmpeg" "${output_path}" -strip "${output_path}" - diff --git a/browser_patches/ffmpeg/build-mac.sh b/browser_patches/ffmpeg/build-mac.sh deleted file mode 100755 index 91ac05f633bb90..00000000000000 --- a/browser_patches/ffmpeg/build-mac.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e - -function die() { echo "$@"; exit 1; } - -if [[ "$(uname)" != "Darwin" ]]; then - die "ERROR: this script is designed to be run on OSX. Can't run on $(uname)" -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" ffmpeg) - -source ./CONFIG.sh - -BUILDDIR="${PWD}/build" -PREFIX="${BUILDDIR}/osx_prefix" -OUTPUT_PATH="${PWD}/output/ffmpeg-mac" - -function build_zlib { - cd "${BUILDDIR}" - git clone https://github.com/madler/zlib - cd zlib - git checkout "${ZLIB_VERSION}" - ./configure --prefix="${PREFIX}" ${ZLIB_CONFIG} - make && make install -} - -function build_libvpx { - cd "${BUILDDIR}" - git clone https://chromium.googlesource.com/webm/libvpx - cd libvpx - git checkout "${LIBVPX_VERSION}" - # Compile libvpx according to the docs: - # - https://chromium.googlesource.com/webm/libvpx/+/main/README - ./configure --prefix="${PREFIX}" ${LIBVPX_CONFIG} - make && make install -} - -function build_ffmpeg { - cd "${BUILDDIR}" - git clone git://source.ffmpeg.org/ffmpeg.git - cd ffmpeg - git checkout "${FFMPEG_VERSION}" - export PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig" - # Prohibit pkg-config from using system installed libs. - export PKG_CONFIG_LIBDIR= - - ./configure --pkg-config=pkg-config \ - --pkg-config-flags="--static" \ - --extra-cflags="-I/${PREFIX}/include" \ - --extra-ldflags="-L/${PREFIX}/lib" \ - --prefix="${PREFIX}" \ - --bindir="${PWD}/bin" \ - ${FFMPEG_CONFIG} - make && make install -} - -REQUIERED_BUILD_TOOLS=("git" "make" "yasm" "pkg-config") -missing_build_tools=() - -for dependency in ${REQUIERED_BUILD_TOOLS[@]}; do - if ! command -v "${dependency}" >/dev/null; then - missing_build_tools+=("${dependency}") - fi -done - -if [[ ${#missing_build_tools[@]} != 0 ]]; then - if [[ "$1" == "--full" ]]; then - brew install ${missing_build_tools[@]} - else - die "ERROR: missing dependencies! Please run: brew install ${missing_build_tools[@]}" - fi -fi - -# Cleanup -set -x -rm -rf "${BUILDDIR}" -mkdir -p "${BUILDDIR}" - -build_zlib -build_libvpx -build_ffmpeg - -# put resulting executable where we were asked to -mkdir -p $(dirname "${OUTPUT_PATH}") -cp "${BUILDDIR}/ffmpeg/bin/ffmpeg" "${OUTPUT_PATH}" -strip "${OUTPUT_PATH}" diff --git a/browser_patches/ffmpeg/build.sh b/browser_patches/ffmpeg/build.sh deleted file mode 100755 index 929f78823481f8..00000000000000 --- a/browser_patches/ffmpeg/build.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename $0) [--mac|--linux|--cross-compile-win64] [--full]" - echo - echo "Build ffmpeg for the given platform" - echo - exit 0 -fi - -if [[ -z "$1" ]]; then - echo "ERROR: expected build target. Run with --help for more info" - exit 1 -fi - -LICENSE_FILE="COPYING.LGPLv2.1" - -rm -rf ./output -mkdir -p output -cp ffmpeg-license/"${LICENSE_FILE}" output - -dockerflags=""; -# Use |-it| to run docker to support Ctrl-C if we run the script inside interactive terminal. -# Otherwise (e.g. cronjob) - do nothing. -if [[ -t 0 ]]; then - dockerflags="-it" -fi - -function ensure_docker_or_die() { - if ! command -v docker >/dev/null; then - echo "ERROR: docker is required for the script" - exit 1 - fi -} - -if [[ "$1" == "--mac" ]]; then - bash ./build-mac.sh $2 - cd output && zip ffmpeg.zip ffmpeg-mac "${LICENSE_FILE}" -elif [[ "$1" == "--linux" ]]; then - ensure_docker_or_die - - time docker run --init --rm -v"${PWD}":/host ${dockerflags} ubuntu:18.04 bash /host/build-linux.sh /host/output/ffmpeg-linux - cd output && zip ffmpeg.zip ffmpeg-linux "${LICENSE_FILE}" -elif [[ "$1" == --cross-compile-win64 ]]; then - ensure_docker_or_die - - time docker run --init --rm -v"${PWD}":/host ${dockerflags} ubuntu:18.04 bash /host/crosscompile-from-linux.sh --win64 /host/output/ffmpeg-win64.exe - cd output && zip ffmpeg.zip ffmpeg-win64.exe "${LICENSE_FILE}" -elif [[ "$1" == "--cross-compile-linux-arm64" ]]; then - ensure_docker_or_die - - time docker run --init --rm -v"${PWD}":/host ${dockerflags} ubuntu:18.04 bash /host/crosscompile-from-linux.sh --linux-arm64 /host/output/ffmpeg-linux - cd output && zip ffmpeg.zip ffmpeg-linux "${LICENSE_FILE}" -else - echo "ERROR: unsupported platform - $1" - exit 1 -fi - diff --git a/browser_patches/ffmpeg/clean.sh b/browser_patches/ffmpeg/clean.sh deleted file mode 100755 index db4d36c08e7bb5..00000000000000 --- a/browser_patches/ffmpeg/clean.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -rm -rf output - diff --git a/browser_patches/ffmpeg/crosscompile-from-linux.sh b/browser_patches/ffmpeg/crosscompile-from-linux.sh deleted file mode 100644 index caa94843946561..00000000000000 --- a/browser_patches/ffmpeg/crosscompile-from-linux.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/bash - -# Copyright (c) Microsoft Corporation. -# -# Licensed under the Apache License, Version 2.0 (the 'License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -function die() { echo "$@"; exit 1; } - - -PREFIX="${HOME}/prefix" -TOOLCHAIN_PREFIX_64="/usr/bin/x86_64-w64-mingw32-" -TOOLCHAIN_PREFIX_ARM64="/usr/bin/aarch64-linux-gnu-" - -arch="" -toolchain_prefix="" -binary="" - -if [[ "$(uname)" != "Linux" ]]; then - echo "ERROR: this script is designed to be run on Linux. Can't run on $(uname)" - exit 1 -fi - -if [[ "$1" == "--win64" ]]; then - arch="win64"; - toolchain_prefix="${TOOLCHAIN_PREFIX_64}" - binary="ffmpeg.exe" -elif [[ "$1" == "--linux-arm64" ]]; then - arch="linux-arm64"; - toolchain_prefix="${TOOLCHAIN_PREFIX_ARM64}" - binary="ffmpeg" -elif [[ -z "$1" ]]; then - die "ERROR: expect --win64 or --linux-arm64 as the first argument" -else - die "ERROR: unknown arch '$1' - expected --win64 or --linux-arm64" -fi - -output_path="$2" -if [[ -z "${output_path}" ]]; then - die "ERROR: output path is not specified" -elif [[ "${output_path}" != /* ]]; then - die "ERROR: output path ${output_path} is not absolute" -elif ! [[ -d $(dirname "${output_path}") ]]; then - die "ERROR: folder for output path ${output_path} does not exist." -fi - -function build_zlib { - cd "${HOME}" - git clone https://github.com/madler/zlib - cd zlib - git checkout "${ZLIB_VERSION}" - ./configure --prefix="${PREFIX}" ${ZLIB_CONFIG} - make \ - CC="${toolchain_prefix}gcc" \ - CXX="${toolchain_prefix}g++" \ - AR="${toolchain_prefix}ar" \ - PREFIX="$PREFIX" \ - RANLIB="${toolchain_prefix}ranlib" \ - LD="${toolchain_prefix}ld" \ - STRIP="${toolchain_prefix}strip" - make install -} - -function build_libvpx { - cd "${HOME}" - git clone https://chromium.googlesource.com/webm/libvpx - cd libvpx - git checkout "${LIBVPX_VERSION}" - # Cross-compiling libvpx according to the docs: - # - https://chromium.googlesource.com/webm/libvpx/+/main/README - local target="" - if [[ $arch == "win64" ]]; then - target="x86_64-win64-gcc"; - elif [[ $arch == "linux-arm64" ]]; then - target="arm64-linux-gcc"; - else - die "ERROR: unsupported arch to compile libvpx - $arch" - fi - CROSS="${toolchain_prefix}" ./configure --prefix="${PREFIX}" --target="${target}" ${LIBVPX_CONFIG} - CROSS="${toolchain_prefix}" make && make install -} - -function build_ffmpeg { - cd "${HOME}" - git clone git://source.ffmpeg.org/ffmpeg.git - cd ffmpeg - git checkout "${FFMPEG_VERSION}" - export PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig" - # Prohibit pkg-config from using linux system installed libs. - export PKG_CONFIG_LIBDIR= - - local ffmpeg_arch="" - local ffmpeg_target_os="" - if [[ $arch == "win64" ]]; then - ffmpeg_arch="x86_64"; - ffmpeg_target_os="mingw32" - elif [[ $arch == "linux-arm64" ]]; then - ffmpeg_arch="arm64"; - ffmpeg_target_os="linux" - else - die "ERROR: unsupported arch to compile ffmpeg - $arch" - fi - ./configure --arch="${ffmpeg_arch}" \ - --target-os="${ffmpeg_target_os}" \ - --cross-prefix="${toolchain_prefix}" \ - --disable-doc \ - --pkg-config=pkg-config \ - --pkg-config-flags="--static" \ - --extra-cflags="-I/${PREFIX}/include" \ - --extra-ldflags="-L/${PREFIX}/lib -static" \ - --prefix="${PREFIX}" \ - --bindir="${PWD}/bin" \ - ${FFMPEG_CONFIG} - make && make install -} - -trap "cd $(pwd -P)" EXIT -cd "$(dirname $0)" - -source ./CONFIG.sh - -apt-get update -apt-get install -y git make yasm pkg-config -if [[ "${arch}" == "linux-arm64" ]]; then - apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -else - apt-get install -y mingw-w64 -fi - -build_zlib -build_libvpx -build_ffmpeg - -# put resulting executable where we were asked to -cp "${HOME}/ffmpeg/bin/${binary}" "${output_path}" -${toolchain_prefix}strip "${output_path}" diff --git a/browser_patches/ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 b/browser_patches/ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 deleted file mode 100644 index 58af0d3787aec7..00000000000000 --- a/browser_patches/ffmpeg/ffmpeg-license/COPYING.LGPLv2.1 +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/browser_patches/firefox-beta/.gitignore b/browser_patches/firefox-beta/.gitignore deleted file mode 100644 index 5e660dc18ee09d..00000000000000 --- a/browser_patches/firefox-beta/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/checkout diff --git a/browser_patches/firefox-beta/BUILD_NUMBER b/browser_patches/firefox-beta/BUILD_NUMBER deleted file mode 100644 index 3a5b7616276061..00000000000000 --- a/browser_patches/firefox-beta/BUILD_NUMBER +++ /dev/null @@ -1,2 +0,0 @@ -1347 -Changed: aslushnikov@gmail.com Sat Aug 13 14:56:35 MSK 2022 diff --git a/browser_patches/firefox-beta/EXPECTED_BUILDS b/browser_patches/firefox-beta/EXPECTED_BUILDS deleted file mode 100644 index 1ef87929ac3838..00000000000000 --- a/browser_patches/firefox-beta/EXPECTED_BUILDS +++ /dev/null @@ -1,9 +0,0 @@ -firefox-beta-mac-11.zip -firefox-beta-mac-11-arm64.zip -firefox-beta-ubuntu-18.04.zip -firefox-beta-ubuntu-20.04.zip -firefox-beta-ubuntu-20.04-arm64.zip -firefox-beta-ubuntu-22.04.zip -firefox-beta-ubuntu-22.04-arm64.zip -firefox-beta-debian-11.zip -firefox-beta-win64.zip diff --git a/browser_patches/firefox-beta/UPSTREAM_CONFIG.sh b/browser_patches/firefox-beta/UPSTREAM_CONFIG.sh deleted file mode 100644 index 5f19bdfda533d5..00000000000000 --- a/browser_patches/firefox-beta/UPSTREAM_CONFIG.sh +++ /dev/null @@ -1,3 +0,0 @@ -REMOTE_URL="https://github.com/mozilla/gecko-dev" -BASE_BRANCH="beta" -BASE_REVISION="762e3edda145d3196066dcd86f2eb8806a66a9c7" diff --git a/browser_patches/firefox-beta/archive.sh b/browser_patches/firefox-beta/archive.sh deleted file mode 100755 index 99dd2c31cb21fb..00000000000000 --- a/browser_patches/firefox-beta/archive.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -set -e -set +x - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename "$0") [output-absolute-path]" - echo - echo "Generate distributable .zip archive from Firefox checkout folder that was previously built." - echo - exit 0 -fi - -ZIP_PATH=$1 -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname "$ZIP_PATH") ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FF_CHECKOUT_PATH="$HOME/firefox" -fi -OBJ_FOLDER="${FF_CHECKOUT_PATH}/obj-build-playwright" - -cd "${FF_CHECKOUT_PATH}" - -export MH_BRANCH=mozilla-beta -export MOZ_BUILD_DATE=$(date +%Y%m%d%H%M%S) -./mach package -node "${SCRIPT_FOLDER}/install-preferences.js" "${OBJ_FOLDER}/dist/firefox" - -if ! [[ -d "$OBJ_FOLDER/dist/firefox" ]]; then - echo "ERROR: cannot find $OBJ_FOLDER/dist/firefox folder in the firefox checkout. Did you build?" - exit 1; -fi - -if is_win; then - # Bundle vcruntime14_1.dll - see https://github.com/microsoft/playwright/issues/9974 - cd "$(printMSVCRedistDir)" - cp -t "${OBJ_FOLDER}/dist/firefox" vcruntime140_1.dll -fi - -# tar resulting directory and cleanup TMP. -cd "${OBJ_FOLDER}/dist" -zip -r "$ZIP_PATH" firefox diff --git a/browser_patches/firefox-beta/build.sh b/browser_patches/firefox-beta/build.sh deleted file mode 100755 index 4f2e8c1b54917c..00000000000000 --- a/browser_patches/firefox-beta/build.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash -set -e -set +x - -RUST_VERSION="1.59.0" -CBINDGEN_VERSION="0.24.3" - -trap "cd $(pwd -P)" EXIT - -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -args=("$@") -IS_FULL="" -IS_JUGGLER="" -IS_DEBUG="" -for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --full) IS_FULL="1"; unset args[i]; ;; - --juggler) IS_JUGGLER="1"; unset args[i]; ;; - --debug) IS_DEBUG="1"; unset args[i]; ;; - esac -done - -if [[ -n "${IS_JUGGLER}" && -n "${IS_FULL}" ]]; then - echo "ERROR: either --full or --juggler is allowed" - exit 1 -fi - -echo "== BUILD CONFIGURATION ==" -if [[ -n "${IS_FULL}" ]]; then - echo "- build type: FULL" -elif [[ -n "${IS_JUGGLER}" ]]; then - echo "- build type: JUGGLER" -else - echo "- build type: INCREMENTAL" -fi - -if [[ -n "${IS_DEBUG}" ]]; then - echo "- debug: YES" -else - echo "- debug: NO" -fi - -echo "=========================" - -rm -rf .mozconfig - -if is_mac; then - selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" firefox) - echo "-- building on Mac" -elif is_linux; then - echo "-- building on Linux" -elif is_win; then - echo "ac_add_options --disable-update-agent" >> .mozconfig - echo "ac_add_options --disable-default-browser-agent" >> .mozconfig - echo "ac_add_options --disable-maintenance-service" >> .mozconfig - - echo "-- building win64 build on MINGW" - echo "ac_add_options --target=x86_64-pc-mingw32" >> .mozconfig - echo "ac_add_options --host=x86_64-pc-mingw32" >> .mozconfig - DLL_FILE=$("C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -find '**\Redist\MSVC\*\x64\**\vcruntime140.dll') - WIN32_REDIST_DIR=$(dirname "$DLL_FILE" | tail -n 1) - if ! [[ -d $WIN32_REDIST_DIR ]]; then - echo "ERROR: cannot find MS VS C++ redistributable $WIN32_REDIST_DIR" - exit 1; - fi -else - echo "ERROR: cannot upload on this platform!" 1>&2 - exit 1; -fi - -# There's no pre-built wasi sysroot on certain platforms. -echo "ac_add_options --without-wasm-sandboxed-libraries" >> .mozconfig - -OBJ_FOLDER="obj-build-playwright" -echo "mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/${OBJ_FOLDER}" >> .mozconfig -echo "ac_add_options --disable-crashreporter" >> .mozconfig -echo "ac_add_options --disable-backgroundtasks" >> .mozconfig - -if [[ -n "${IS_DEBUG}" ]]; then - echo "ac_add_options --enable-debug" >> .mozconfig - echo "ac_add_options --enable-debug-symbols" >> .mozconfig -else - echo "ac_add_options --enable-release" >> .mozconfig -fi - -if is_mac || is_win; then - # This options is only available on win and mac. - echo "ac_add_options --disable-update-agent" >> .mozconfig -fi - -if [[ -z "${IS_JUGGLER}" ]]; then - # TODO: rustup is not in the PATH on Windows - if command -v rustup >/dev/null; then - # We manage Rust version ourselves. - echo "-- Using rust v${RUST_VERSION}" - rustup install "${RUST_VERSION}" - rustup default "${RUST_VERSION}" - fi - # Firefox on Linux arm64 host does not ship - # cbindgen in their default toolchains - install manually. - if command -v cargo >/dev/null; then - echo "-- Using cbindgen v${CBINDGEN_VERSION}" - cargo install cbindgen --version "${CBINDGEN_VERSION}" - fi -fi - -if [[ -n "${IS_FULL}" ]]; then - # This is a slow but sure way to get all the necessary toolchains. - # However, it will not work if tree is dirty. - # Bail out if git repo is dirty. - if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: dirty GIT state - commit everything and re-run the script." - exit 1 - fi - - # 1. We have a --single-branch checkout, so we have to add a "master" branch and fetch it - git remote set-branches --add browser_upstream master - git fetch --depth 1 browser_upstream master - # 2. Checkout the master branch and run bootstrap from it. - git checkout browser_upstream/master - echo "ac_add_options --enable-bootstrap" >> .mozconfig - SHELL=/bin/sh ./mach --no-interactive bootstrap --application-choice=browser - git checkout - - rm -rf "${OBJ_FOLDER}" - - if [[ -n "${WIN32_REDIST_DIR}" ]]; then - # Having this option in .mozconfig kills incremental compilation. - echo "export WIN32_REDIST_DIR=\"$WIN32_REDIST_DIR\"" >> .mozconfig - fi -fi - -if [[ -n "${IS_JUGGLER}" ]]; then - ./mach build faster -else - ./mach build - if is_mac; then - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist - else - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist/bin - fi -fi - - diff --git a/browser_patches/firefox-beta/clean.sh b/browser_patches/firefox-beta/clean.sh deleted file mode 100755 index d94baf33a30d9d..00000000000000 --- a/browser_patches/firefox-beta/clean.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -OBJ_FOLDER="obj-build-playwright" -if [[ -d $OBJ_FOLDER ]]; then - rm -rf $OBJ_FOLDER -fi - -if [[ -f "mach" ]]; then - ./mach clobber || true -fi diff --git a/browser_patches/firefox-beta/install-preferences.js b/browser_patches/firefox-beta/install-preferences.js deleted file mode 100644 index f82f791d54c053..00000000000000 --- a/browser_patches/firefox-beta/install-preferences.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright 2018 Google Inc. All rights reserved. - * Modifications copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const os = require('os'); -const fs = require('fs'); -const path = require('path'); -const util = require('util'); - -const writeFileAsync = util.promisify(fs.writeFile.bind(fs)); -const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); - -// Install browser preferences after downloading and unpacking -// firefox instances. -// Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Enterprise_deployment_before_60#Configuration -async function installFirefoxPreferences(distpath) { - let executablePath = ''; - if (os.platform() === 'linux') - executablePath = path.join(distpath, 'firefox'); - else if (os.platform() === 'darwin') - executablePath = path.join(distpath, (process.env.FF_DEBUG_BUILD ? 'NightlyDebug.app' : 'Nightly.app'), 'Contents', 'MacOS', 'firefox'); - else if (os.platform() === 'win32') - executablePath = path.join(distpath, 'firefox.exe'); - - const firefoxFolder = path.dirname(executablePath); - - let prefPath = ''; - let configPath = ''; - if (os.platform() === 'darwin') { - prefPath = path.join(firefoxFolder, '..', 'Resources', 'defaults', 'pref'); - configPath = path.join(firefoxFolder, '..', 'Resources'); - } else if (os.platform() === 'linux') { - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults')); - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences')); - prefPath = path.join(firefoxFolder, 'browser', 'defaults', 'preferences'); - configPath = firefoxFolder; - } else if (os.platform() === 'win32') { - prefPath = path.join(firefoxFolder, 'defaults', 'pref'); - configPath = firefoxFolder; - } else { - throw new Error('Unsupported platform: ' + os.platform()); - } - - await Promise.all([ - copyFile({ - from: path.join(__dirname, 'preferences', '00-playwright-prefs.js'), - to: path.join(prefPath, '00-playwright-prefs.js'), - }), - copyFile({ - from: path.join(__dirname, 'preferences', 'playwright.cfg'), - to: path.join(configPath, 'playwright.cfg'), - }), - ]); -} - -function copyFile({from, to}) { - const rd = fs.createReadStream(from); - const wr = fs.createWriteStream(to); - return new Promise(function(resolve, reject) { - rd.on('error', reject); - wr.on('error', reject); - wr.on('finish', resolve); - rd.pipe(wr); - }).catch(function(error) { - rd.destroy(); - wr.end(); - throw error; - }); -} - -module.exports = { installFirefoxPreferences }; - -if (require.main === module) { - if (process.argv.length !== 3) { - console.log('ERROR: expected a path to the directory with browser build'); - process.exit(1); - return; - } - - installFirefoxPreferences(process.argv[2]).catch(error => { - console.error('ERROR: failed to put preferences!'); - console.error(error); - process.exit(1); - }); -} diff --git a/browser_patches/firefox-beta/juggler/Helper.js b/browser_patches/firefox-beta/juggler/Helper.js deleted file mode 100644 index 70d8aef0d37c43..00000000000000 --- a/browser_patches/firefox-beta/juggler/Helper.js +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); - -class Helper { - - addObserver(handler, topic) { - Services.obs.addObserver(handler, topic); - return () => Services.obs.removeObserver(handler, topic); - } - - addMessageListener(receiver, eventName, handler) { - receiver.addMessageListener(eventName, handler); - return () => receiver.removeMessageListener(eventName, handler); - } - - addEventListener(receiver, eventName, handler) { - receiver.addEventListener(eventName, handler); - return () => receiver.removeEventListener(eventName, handler); - } - - awaitEvent(receiver, eventName) { - return new Promise(resolve => { - receiver.addEventListener(eventName, function listener() { - receiver.removeEventListener(eventName, listener); - resolve(); - }); - }); - } - - on(receiver, eventName, handler) { - // The toolkit/modules/EventEmitter.jsm dispatches event name as a first argument. - // Fire event listeners without it for convenience. - const handlerWrapper = (_, ...args) => handler(...args); - receiver.on(eventName, handlerWrapper); - return () => receiver.off(eventName, handlerWrapper); - } - - addProgressListener(progress, listener, flags) { - progress.addProgressListener(listener, flags); - return () => progress.removeProgressListener(listener); - } - - removeListeners(listeners) { - for (const tearDown of listeners) - tearDown.call(null); - listeners.splice(0, listeners.length); - } - - generateId() { - const string = uuidGen.generateUUID().toString(); - return string.substring(1, string.length - 1); - } - - getLoadContext(channel) { - let loadContext = null; - try { - if (channel.notificationCallbacks) - loadContext = channel.notificationCallbacks.getInterface(Ci.nsILoadContext); - } catch (e) {} - try { - if (!loadContext && channel.loadGroup) - loadContext = channel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext); - } catch (e) { } - return loadContext; - } - - getNetworkErrorStatusText(status) { - if (!status) - return null; - for (const key of Object.keys(Cr)) { - if (Cr[key] === status) - return key; - } - // Security module. The following is taken from - // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL - if ((status & 0xff0000) === 0x5a0000) { - // NSS_SEC errors (happen below the base value because of negative vals) - if ((status & 0xffff) < Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)) { - // The bases are actually negative, so in our positive numeric space, we - // need to subtract the base off our value. - const nssErr = Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff); - switch (nssErr) { - case 11: - return 'SEC_ERROR_EXPIRED_CERTIFICATE'; - case 12: - return 'SEC_ERROR_REVOKED_CERTIFICATE'; - case 13: - return 'SEC_ERROR_UNKNOWN_ISSUER'; - case 20: - return 'SEC_ERROR_UNTRUSTED_ISSUER'; - case 21: - return 'SEC_ERROR_UNTRUSTED_CERT'; - case 36: - return 'SEC_ERROR_CA_CERT_INVALID'; - case 90: - return 'SEC_ERROR_INADEQUATE_KEY_USAGE'; - case 176: - return 'SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED'; - default: - return 'SEC_ERROR_UNKNOWN'; - } - } - const sslErr = Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff); - switch (sslErr) { - case 3: - return 'SSL_ERROR_NO_CERTIFICATE'; - case 4: - return 'SSL_ERROR_BAD_CERTIFICATE'; - case 8: - return 'SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE'; - case 9: - return 'SSL_ERROR_UNSUPPORTED_VERSION'; - case 12: - return 'SSL_ERROR_BAD_CERT_DOMAIN'; - default: - return 'SSL_ERROR_UNKNOWN'; - } - } - return ''; - } - - browsingContextToFrameId(browsingContext) { - if (!browsingContext) - return undefined; - return 'frame-' + browsingContext.id; - } -} - -var EXPORTED_SYMBOLS = [ "Helper" ]; -this.Helper = Helper; - diff --git a/browser_patches/firefox-beta/juggler/NetworkObserver.js b/browser_patches/firefox-beta/juggler/NetworkObserver.js deleted file mode 100644 index 340f756f6cfef0..00000000000000 --- a/browser_patches/firefox-beta/juggler/NetworkObserver.js +++ /dev/null @@ -1,947 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); -const { ChannelEventSinkFactory } = ChromeUtils.import("chrome://remote/content/cdp/observers/ChannelEventSink.jsm"); - - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cr = Components.results; -const Cm = Components.manager; -const CC = Components.Constructor; -const helper = new Helper(); - -const UINT32_MAX = Math.pow(2, 32)-1; - -const BinaryInputStream = CC('@mozilla.org/binaryinputstream;1', 'nsIBinaryInputStream', 'setInputStream'); -const BinaryOutputStream = CC('@mozilla.org/binaryoutputstream;1', 'nsIBinaryOutputStream', 'setOutputStream'); -const StorageStream = CC('@mozilla.org/storagestream;1', 'nsIStorageStream', 'init'); - -// Cap response storage with 100Mb per tracked tab. -const MAX_RESPONSE_STORAGE_SIZE = 100 * 1024 * 1024; - -const pageNetworkSymbol = Symbol('PageNetwork'); - -class PageNetwork { - static forPageTarget(target) { - let result = target[pageNetworkSymbol]; - if (!result) { - result = new PageNetwork(target); - target[pageNetworkSymbol] = result; - } - return result; - } - - constructor(target) { - EventEmitter.decorate(this); - this._target = target; - this._extraHTTPHeaders = null; - this._responseStorage = new ResponseStorage(MAX_RESPONSE_STORAGE_SIZE, MAX_RESPONSE_STORAGE_SIZE / 10); - this._requestInterceptionEnabled = false; - // This is requestId => NetworkRequest map, only contains requests that are - // awaiting interception action (abort, resume, fulfill) over the protocol. - this._interceptedRequests = new Map(); - } - - setExtraHTTPHeaders(headers) { - this._extraHTTPHeaders = headers; - } - - combinedExtraHTTPHeaders() { - return [ - ...(this._target.browserContext().extraHTTPHeaders || []), - ...(this._extraHTTPHeaders || []), - ]; - } - - enableRequestInterception() { - this._requestInterceptionEnabled = true; - } - - disableRequestInterception() { - this._requestInterceptionEnabled = false; - for (const intercepted of this._interceptedRequests.values()) - intercepted.resume(); - this._interceptedRequests.clear(); - } - - resumeInterceptedRequest(requestId, url, method, headers, postData) { - this._takeIntercepted(requestId).resume(url, method, headers, postData); - } - - fulfillInterceptedRequest(requestId, status, statusText, headers, base64body) { - this._takeIntercepted(requestId).fulfill(status, statusText, headers, base64body); - } - - abortInterceptedRequest(requestId, errorCode) { - this._takeIntercepted(requestId).abort(errorCode); - } - - getResponseBody(requestId) { - if (!this._responseStorage) - throw new Error('Responses are not tracked for the given browser'); - return this._responseStorage.getBase64EncodedResponse(requestId); - } - - _takeIntercepted(requestId) { - const intercepted = this._interceptedRequests.get(requestId); - if (!intercepted) - throw new Error(`Cannot find request "${requestId}"`); - this._interceptedRequests.delete(requestId); - return intercepted; - } -} - -class NetworkRequest { - constructor(networkObserver, httpChannel, redirectedFrom) { - this._networkObserver = networkObserver; - this.httpChannel = httpChannel; - - const loadInfo = this.httpChannel.loadInfo; - let browsingContext = loadInfo?.frameBrowsingContext || loadInfo?.browsingContext; - // TODO: Unfortunately, requests from web workers don't have frameBrowsingContext or - // browsingContext. - // - // We fail to attribute them to the original frames on the browser side, but we - // can use load context top frame to attribute them to the top frame at least. - if (!browsingContext) { - const loadContext = helper.getLoadContext(this.httpChannel); - browsingContext = loadContext?.topFrameElement?.browsingContext; - } - - this._frameId = helper.browsingContextToFrameId(browsingContext); - - this.requestId = httpChannel.channelId + ''; - this.navigationId = httpChannel.isMainDocumentChannel ? this.requestId : undefined; - - this._redirectedIndex = 0; - if (redirectedFrom) { - this.redirectedFromId = redirectedFrom.requestId; - this._redirectedIndex = redirectedFrom._redirectedIndex + 1; - this.requestId = this.requestId + '-redirect' + this._redirectedIndex; - this.navigationId = redirectedFrom.navigationId; - // Finish previous request now. Since we inherit the listener, we could in theory - // use onStopRequest, but that will only happen after the last redirect has finished. - redirectedFrom._sendOnRequestFinished(); - } - // In case of proxy auth, we get two requests with the same channel: - // - one is pre-auth - // - second is with auth header. - // - // In this case, we create this NetworkRequest object with a `redirectedFrom` - // object, and they both share the same httpChannel. - // - // Since we want to maintain _channelToRequest map without clashes, - // we must call `_sendOnRequestFinished` **before** we update it with a new object - // here. - if (this._networkObserver._channelToRequest.has(this.httpChannel)) - throw new Error(`Internal Error: invariant is broken for _channelToRequest map`); - this._networkObserver._channelToRequest.set(this.httpChannel, this); - - this._pageNetwork = redirectedFrom ? redirectedFrom._pageNetwork : networkObserver._findPageNetwork(httpChannel); - this._expectingInterception = false; - this._expectingResumedRequest = undefined; // { method, headers, postData } - this._sentOnResponse = false; - - if (this._pageNetwork) - appendExtraHTTPHeaders(httpChannel, this._pageNetwork.combinedExtraHTTPHeaders()); - - this._responseBodyChunks = []; - - httpChannel.QueryInterface(Ci.nsITraceableChannel); - this._originalListener = httpChannel.setNewListener(this); - if (redirectedFrom) { - // Listener is inherited for regular redirects, so we'd like to avoid - // calling into previous NetworkRequest. - this._originalListener = redirectedFrom._originalListener; - } - - this._previousCallbacks = httpChannel.notificationCallbacks; - httpChannel.notificationCallbacks = this; - - this.QueryInterface = ChromeUtils.generateQI([ - Ci.nsIAuthPrompt2, - Ci.nsIAuthPromptProvider, - Ci.nsIInterfaceRequestor, - Ci.nsINetworkInterceptController, - Ci.nsIStreamListener, - ]); - - if (this.redirectedFromId) { - // Redirects are not interceptable. - this._sendOnRequest(false); - } - } - - // Public interception API. - resume(url, method, headers, postData) { - this._expectingResumedRequest = { method, headers, postData }; - const newUri = url ? Services.io.newURI(url) : null; - this._interceptedChannel.resetInterceptionWithURI(newUri); - this._interceptedChannel = undefined; - } - - // Public interception API. - abort(errorCode) { - const error = errorMap[errorCode] || Cr.NS_ERROR_FAILURE; - this._interceptedChannel.cancelInterception(error); - this._interceptedChannel = undefined; - } - - // Public interception API. - fulfill(status, statusText, headers, base64body) { - this._interceptedChannel.synthesizeStatus(status, statusText); - for (const header of headers) { - this._interceptedChannel.synthesizeHeader(header.name, header.value); - if (header.name.toLowerCase() === 'set-cookie') { - Services.cookies.QueryInterface(Ci.nsICookieService); - Services.cookies.setCookieStringFromHttp(this.httpChannel.URI, header.value, this.httpChannel); - } - } - const synthesized = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream); - synthesized.data = base64body ? atob(base64body) : ''; - this._interceptedChannel.startSynthesizedResponse(synthesized, null, null, '', false); - this._interceptedChannel.finishSynthesizedResponse(); - this._interceptedChannel = undefined; - } - - // Instrumentation called by NetworkObserver. - _onInternalRedirect(newChannel) { - // Intercepted requests produce "internal redirects" - this is both for our own - // interception and service workers. - // An internal redirect has the same channelId, inherits notificationCallbacks and - // listener, and should be used instead of an old channel. - this._networkObserver._channelToRequest.delete(this.httpChannel); - this.httpChannel = newChannel; - this._networkObserver._channelToRequest.set(this.httpChannel, this); - } - - // Instrumentation called by NetworkObserver. - _onInternalRedirectReady() { - // Resumed request is first internally redirected to a new request, - // and then the new request is ready to be updated. - if (!this._expectingResumedRequest) - return; - const { method, headers, postData } = this._expectingResumedRequest; - this._expectingResumedRequest = undefined; - - if (headers) { - for (const header of requestHeaders(this.httpChannel)) - this.httpChannel.setRequestHeader(header.name, '', false /* merge */); - for (const header of headers) - this.httpChannel.setRequestHeader(header.name, header.value, false /* merge */); - } else if (this._pageNetwork) { - appendExtraHTTPHeaders(this.httpChannel, this._pageNetwork.combinedExtraHTTPHeaders()); - } - if (method) - this.httpChannel.requestMethod = method; - if (postData !== undefined) - setPostData(this.httpChannel, postData, headers); - } - - // nsIInterfaceRequestor - getInterface(iid) { - if (iid.equals(Ci.nsIAuthPrompt2) || iid.equals(Ci.nsIAuthPromptProvider) || iid.equals(Ci.nsINetworkInterceptController)) - return this; - if (iid.equals(Ci.nsIAuthPrompt)) // Block nsIAuthPrompt - we want nsIAuthPrompt2 to be used instead. - throw Cr.NS_ERROR_NO_INTERFACE; - if (this._previousCallbacks) - return this._previousCallbacks.getInterface(iid); - throw Cr.NS_ERROR_NO_INTERFACE; - } - - // nsIAuthPromptProvider - getAuthPrompt(aPromptReason, iid) { - return this; - } - - // nsIAuthPrompt2 - asyncPromptAuth(aChannel, aCallback, aContext, level, authInfo) { - let canceled = false; - Promise.resolve().then(() => { - if (canceled) - return; - const hasAuth = this.promptAuth(aChannel, level, authInfo); - if (hasAuth) - aCallback.onAuthAvailable(aContext, authInfo); - else - aCallback.onAuthCancelled(aContext, true); - }); - return { - QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]), - cancel: () => { - aCallback.onAuthCancelled(aContext, false); - canceled = true; - } - }; - } - - // nsIAuthPrompt2 - promptAuth(aChannel, level, authInfo) { - if (authInfo.flags & Ci.nsIAuthInformation.PREVIOUS_FAILED) - return false; - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return false; - let credentials = null; - if (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) { - const proxy = this._networkObserver._targetRegistry.getProxyInfo(aChannel); - credentials = proxy ? {username: proxy.username, password: proxy.password} : null; - } else { - credentials = pageNetwork._target.browserContext().httpCredentials; - } - if (!credentials) - return false; - authInfo.username = credentials.username; - authInfo.password = credentials.password; - // This will produce a new request with respective auth header set. - // It will have the same id as ours. We expect it to arrive as new request and - // will treat it as our own redirect. - this._networkObserver._expectRedirect(this.httpChannel.channelId + '', this); - return true; - } - - // nsINetworkInterceptController - shouldPrepareForIntercept(aURI, channel) { - const interceptController = this._fallThroughInterceptController(); - if (interceptController && interceptController.shouldPrepareForIntercept(aURI, channel)) { - // We assume that interceptController is a service worker if there is one, - // and yield interception to it. We are not going to intercept ourselves, - // so we send onRequest now. - this._sendOnRequest(false); - return true; - } - - if (channel !== this.httpChannel) { - // Not our channel? Just in case this happens, don't do anything. - return false; - } - - // We do not want to intercept any redirects, because we are not able - // to intercept subresource redirects, and it's unreliable for main requests. - // We do not sendOnRequest here, because redirects do that in constructor. - if (this.redirectedFromId) - return false; - - const shouldIntercept = this._shouldIntercept(); - if (!shouldIntercept) { - // We are not intercepting - ready to issue onRequest. - this._sendOnRequest(false); - return false; - } - - this._expectingInterception = true; - return true; - } - - // nsINetworkInterceptController - channelIntercepted(intercepted) { - if (!this._expectingInterception) { - // We are not intercepting, fall-through. - const interceptController = this._fallThroughInterceptController(); - if (interceptController) - interceptController.channelIntercepted(intercepted); - return; - } - - this._expectingInterception = false; - this._interceptedChannel = intercepted.QueryInterface(Ci.nsIInterceptedChannel); - - const pageNetwork = this._pageNetwork; - if (!pageNetwork) { - // Just in case we disabled instrumentation while intercepting, resume and forget. - this.resume(); - return; - } - - const browserContext = pageNetwork._target.browserContext(); - if (browserContext.settings.onlineOverride === 'offline') { - // Implement offline. - this.abort(Cr.NS_ERROR_OFFLINE); - return; - } - - // Ok, so now we have intercepted the request, let's issue onRequest. - // If interception has been disabled while we were intercepting, resume and forget. - const interceptionEnabled = this._shouldIntercept(); - this._sendOnRequest(!!interceptionEnabled); - if (interceptionEnabled) - pageNetwork._interceptedRequests.set(this.requestId, this); - else - this.resume(); - } - - // nsIStreamListener - onDataAvailable(aRequest, aInputStream, aOffset, aCount) { - // Turns out webcompat shims might redirect to - // SimpleChannel, so we get requests from a different channel. - // See https://github.com/microsoft/playwright/issues/9418#issuecomment-944836244 - if (aRequest !== this.httpChannel) - return; - // For requests with internal redirect (e.g. intercepted by Service Worker), - // we do not get onResponse normally, but we do get nsIStreamListener notifications. - this._sendOnResponse(false); - - const iStream = new BinaryInputStream(aInputStream); - const sStream = new StorageStream(8192, aCount, null); - const oStream = new BinaryOutputStream(sStream.getOutputStream(0)); - - // Copy received data as they come. - const data = iStream.readBytes(aCount); - this._responseBodyChunks.push(data); - - oStream.writeBytes(data, aCount); - try { - this._originalListener.onDataAvailable(aRequest, sStream.newInputStream(0), aOffset, aCount); - } catch (e) { - // Be ready to original listener exceptions. - } - } - - // nsIStreamListener - onStartRequest(aRequest) { - // Turns out webcompat shims might redirect to - // SimpleChannel, so we get requests from a different channel. - // See https://github.com/microsoft/playwright/issues/9418#issuecomment-944836244 - if (aRequest !== this.httpChannel) - return; - try { - this._originalListener.onStartRequest(aRequest); - } catch (e) { - // Be ready to original listener exceptions. - } - } - - // nsIStreamListener - onStopRequest(aRequest, aStatusCode) { - // Turns out webcompat shims might redirect to - // SimpleChannel, so we get requests from a different channel. - // See https://github.com/microsoft/playwright/issues/9418#issuecomment-944836244 - if (aRequest !== this.httpChannel) - return; - try { - this._originalListener.onStopRequest(aRequest, aStatusCode); - } catch (e) { - // Be ready to original listener exceptions. - } - - if (aStatusCode === 0) { - // For requests with internal redirect (e.g. intercepted by Service Worker), - // we do not get onResponse normally, but we do get nsIRequestObserver notifications. - this._sendOnResponse(false); - const body = this._responseBodyChunks.join(''); - const pageNetwork = this._pageNetwork; - if (pageNetwork) - pageNetwork._responseStorage.addResponseBody(this, body); - this._sendOnRequestFinished(); - } else { - this._sendOnRequestFailed(aStatusCode); - } - - delete this._responseBodyChunks; - } - - _shouldIntercept() { - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return false; - if (pageNetwork._requestInterceptionEnabled) - return true; - const browserContext = pageNetwork._target.browserContext(); - if (browserContext.requestInterceptionEnabled) - return true; - if (browserContext.settings.onlineOverride === 'offline') - return true; - return false; - } - - _fallThroughInterceptController() { - if (!this._previousCallbacks || !(this._previousCallbacks instanceof Ci.nsINetworkInterceptController)) - return undefined; - return this._previousCallbacks.getInterface(Ci.nsINetworkInterceptController); - } - - _sendOnRequest(isIntercepted) { - // Note: we call _sendOnRequest either after we intercepted the request, - // or at the first moment we know that we are not going to intercept. - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return; - const loadInfo = this.httpChannel.loadInfo; - const causeType = loadInfo?.externalContentPolicyType || Ci.nsIContentPolicy.TYPE_OTHER; - const internalCauseType = loadInfo?.internalContentPolicyType || Ci.nsIContentPolicy.TYPE_OTHER; - pageNetwork.emit(PageNetwork.Events.Request, { - url: this.httpChannel.URI.spec, - frameId: this._frameId, - isIntercepted, - requestId: this.requestId, - redirectedFrom: this.redirectedFromId, - postData: readRequestPostData(this.httpChannel), - headers: requestHeaders(this.httpChannel), - method: this.httpChannel.requestMethod, - navigationId: this.navigationId, - cause: causeTypeToString(causeType), - internalCause: causeTypeToString(internalCauseType), - }, this._frameId); - } - - _sendOnResponse(fromCache, opt_statusCode, opt_statusText) { - if (this._sentOnResponse) { - // We can come here twice because of internal redirects, e.g. service workers. - return; - } - this._sentOnResponse = true; - const pageNetwork = this._pageNetwork; - if (!pageNetwork) - return; - - this.httpChannel.QueryInterface(Ci.nsIHttpChannelInternal); - this.httpChannel.QueryInterface(Ci.nsITimedChannel); - const timing = { - startTime: this.httpChannel.channelCreationTime, - domainLookupStart: this.httpChannel.domainLookupStartTime, - domainLookupEnd: this.httpChannel.domainLookupEndTime, - connectStart: this.httpChannel.connectStartTime, - secureConnectionStart: this.httpChannel.secureConnectionStartTime, - connectEnd: this.httpChannel.connectEndTime, - requestStart: this.httpChannel.requestStartTime, - responseStart: this.httpChannel.responseStartTime, - }; - - const { status, statusText, headers } = responseHead(this.httpChannel, opt_statusCode, opt_statusText); - let remoteIPAddress = undefined; - let remotePort = undefined; - try { - remoteIPAddress = this.httpChannel.remoteAddress; - remotePort = this.httpChannel.remotePort; - } catch (e) { - // remoteAddress is not defined for cached requests. - } - - const fromServiceWorker = this._networkObserver._channelIdsFulfilledByServiceWorker.has(this.requestId); - this._networkObserver._channelIdsFulfilledByServiceWorker.delete(this.requestId); - - pageNetwork.emit(PageNetwork.Events.Response, { - requestId: this.requestId, - securityDetails: getSecurityDetails(this.httpChannel), - fromCache, - headers, - remoteIPAddress, - remotePort, - status, - statusText, - timing, - fromServiceWorker, - }, this._frameId); - } - - _sendOnRequestFailed(error) { - const pageNetwork = this._pageNetwork; - if (pageNetwork) { - pageNetwork.emit(PageNetwork.Events.RequestFailed, { - requestId: this.requestId, - errorCode: helper.getNetworkErrorStatusText(error), - }, this._frameId); - } - this._networkObserver._channelToRequest.delete(this.httpChannel); - } - - _sendOnRequestFinished() { - const pageNetwork = this._pageNetwork; - if (pageNetwork) { - let protocolVersion = undefined; - try { - protocolVersion = this.httpChannel.protocolVersion; - } catch (e) { - // protocolVersion is unavailable in certain cases. - }; - pageNetwork.emit(PageNetwork.Events.RequestFinished, { - requestId: this.requestId, - responseEndTime: this.httpChannel.responseEndTime, - transferSize: this.httpChannel.transferSize, - encodedBodySize: this.httpChannel.encodedBodySize, - protocolVersion, - }, this._frameId); - } - this._networkObserver._channelToRequest.delete(this.httpChannel); - } -} - -class NetworkObserver { - static instance() { - return NetworkObserver._instance || null; - } - - constructor(targetRegistry) { - EventEmitter.decorate(this); - NetworkObserver._instance = this; - - this._targetRegistry = targetRegistry; - - this._channelToRequest = new Map(); // http channel -> network request - this._expectedRedirect = new Map(); // expected redirect channel id (string) -> network request - this._channelIdsFulfilledByServiceWorker = new Set(); // http channel ids that were fulfilled by service worker - - const protocolProxyService = Cc['@mozilla.org/network/protocol-proxy-service;1'].getService(); - this._channelProxyFilter = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIProtocolProxyChannelFilter]), - applyFilter: (channel, defaultProxyInfo, proxyFilter) => { - const proxy = this._targetRegistry.getProxyInfo(channel); - if (!proxy) { - proxyFilter.onProxyFilterResult(defaultProxyInfo); - return; - } - proxyFilter.onProxyFilterResult(protocolProxyService.newProxyInfo( - proxy.type, - proxy.host, - proxy.port, - '', /* aProxyAuthorizationHeader */ - '', /* aConnectionIsolationKey */ - Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST, /* aFlags */ - UINT32_MAX, /* aFailoverTimeout */ - null, /* failover proxy */ - )); - }, - }; - protocolProxyService.registerChannelFilter(this._channelProxyFilter, 0 /* position */); - - // Register self as ChannelEventSink to track redirects. - ChannelEventSinkFactory.getService().registerCollector({ - _onChannelRedirect: this._onRedirect.bind(this), - }); - - this._eventListeners = [ - helper.addObserver(this._onRequest.bind(this), 'http-on-modify-request'), - helper.addObserver(this._onResponse.bind(this, false /* fromCache */), 'http-on-examine-response'), - helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-cached-response'), - helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-merged-response'), - helper.addObserver(this._onServiceWorkerResponse.bind(this), 'service-worker-synthesized-response'), - ]; - } - - _expectRedirect(channelId, previous) { - this._expectedRedirect.set(channelId, previous); - } - - _onRedirect(oldChannel, newChannel, flags) { - if (!(oldChannel instanceof Ci.nsIHttpChannel) || !(newChannel instanceof Ci.nsIHttpChannel)) - return; - const oldHttpChannel = oldChannel.QueryInterface(Ci.nsIHttpChannel); - const newHttpChannel = newChannel.QueryInterface(Ci.nsIHttpChannel); - const request = this._channelToRequest.get(oldHttpChannel); - if (flags & Ci.nsIChannelEventSink.REDIRECT_INTERNAL) { - if (request) - request._onInternalRedirect(newHttpChannel); - } else if (flags & Ci.nsIChannelEventSink.REDIRECT_STS_UPGRADE) { - if (request) { - // This is an internal HSTS upgrade. The original http request is canceled, and a new - // equivalent https request is sent. We forge 307 redirect to follow Chromium here: - // https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_http_job.cc;l=211 - request._sendOnResponse(false, 307, 'Temporary Redirect'); - this._expectRedirect(newHttpChannel.channelId + '', request); - } - } else { - if (request) - this._expectRedirect(newHttpChannel.channelId + '', request); - } - } - - _findPageNetwork(httpChannel) { - let loadContext = helper.getLoadContext(httpChannel); - if (!loadContext) - return; - const target = this._targetRegistry.targetForBrowser(loadContext.topFrameElement); - if (!target) - return; - return PageNetwork.forPageTarget(target); - } - - _onRequest(channel, topic) { - if (!(channel instanceof Ci.nsIHttpChannel)) - return; - const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); - const channelId = httpChannel.channelId + ''; - const redirectedFrom = this._expectedRedirect.get(channelId); - if (redirectedFrom) { - this._expectedRedirect.delete(channelId); - new NetworkRequest(this, httpChannel, redirectedFrom); - } else { - const redirectedRequest = this._channelToRequest.get(httpChannel); - if (redirectedRequest) - redirectedRequest._onInternalRedirectReady(); - else - new NetworkRequest(this, httpChannel); - } - } - - _onResponse(fromCache, httpChannel, topic) { - const request = this._channelToRequest.get(httpChannel); - if (request) - request._sendOnResponse(fromCache); - } - - _onServiceWorkerResponse(channel, topic) { - if (!(channel instanceof Ci.nsIHttpChannel)) - return; - const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); - const channelId = httpChannel.channelId + ''; - this._channelIdsFulfilledByServiceWorker.add(channelId); - } - - dispose() { - this._activityDistributor.removeObserver(this); - ChannelEventSinkFactory.unregister(); - helper.removeListeners(this._eventListeners); - } -} - -const protocolVersionNames = { - [Ci.nsITransportSecurityInfo.TLS_VERSION_1]: 'TLS 1', - [Ci.nsITransportSecurityInfo.TLS_VERSION_1_1]: 'TLS 1.1', - [Ci.nsITransportSecurityInfo.TLS_VERSION_1_2]: 'TLS 1.2', - [Ci.nsITransportSecurityInfo.TLS_VERSION_1_3]: 'TLS 1.3', -}; - -function getSecurityDetails(httpChannel) { - const securityInfo = httpChannel.securityInfo; - if (!securityInfo) - return null; - securityInfo.QueryInterface(Ci.nsITransportSecurityInfo); - if (!securityInfo.serverCert) - return null; - return { - protocol: protocolVersionNames[securityInfo.protocolVersion] || '', - subjectName: securityInfo.serverCert.commonName, - issuer: securityInfo.serverCert.issuerCommonName, - // Convert to seconds. - validFrom: securityInfo.serverCert.validity.notBefore / 1000 / 1000, - validTo: securityInfo.serverCert.validity.notAfter / 1000 / 1000, - }; -} - -function readRequestPostData(httpChannel) { - if (!(httpChannel instanceof Ci.nsIUploadChannel)) - return undefined; - let iStream = httpChannel.uploadStream; - if (!iStream) - return undefined; - const isSeekableStream = iStream instanceof Ci.nsISeekableStream; - - // For some reason, we cannot rewind back big streams, - // so instead we should clone them. - const isCloneable = iStream instanceof Ci.nsICloneableInputStream; - if (isCloneable) - iStream = iStream.clone(); - - let prevOffset; - if (isSeekableStream) { - prevOffset = iStream.tell(); - iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); - } - - // Read data from the stream. - let result = undefined; - try { - const maxLen = iStream.available(); - // Cap at 10Mb. - if (maxLen <= 10 * 1024 * 1024) { - const buffer = NetUtil.readInputStreamToString(iStream, maxLen); - result = btoa(buffer); - } - } catch (err) { - } - - // Seek locks the file, so seek to the beginning only if necko hasn't - // read it yet, since necko doesn't seek to 0 before reading (at lest - // not till 459384 is fixed). - if (isSeekableStream && prevOffset == 0 && !isCloneable) - iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); - return result; -} - -function requestHeaders(httpChannel) { - const headers = []; - httpChannel.visitRequestHeaders({ - visitHeader: (name, value) => headers.push({name, value}), - }); - return headers; -} - -function causeTypeToString(causeType) { - for (let key in Ci.nsIContentPolicy) { - if (Ci.nsIContentPolicy[key] === causeType) - return key; - } - return 'TYPE_OTHER'; -} - -function appendExtraHTTPHeaders(httpChannel, headers) { - if (!headers) - return; - for (const header of headers) - httpChannel.setRequestHeader(header.name, header.value, false /* merge */); -} - -class ResponseStorage { - constructor(maxTotalSize, maxResponseSize) { - this._totalSize = 0; - this._maxResponseSize = maxResponseSize; - this._maxTotalSize = maxTotalSize; - this._responses = new Map(); - } - - addResponseBody(request, body) { - if (body.length > this._maxResponseSize) { - this._responses.set(request.requestId, { - evicted: true, - body: '', - }); - return; - } - let encodings = []; - if ((request.httpChannel instanceof Ci.nsIEncodedChannel) && request.httpChannel.contentEncodings && !request.httpChannel.applyConversion) { - const encodingHeader = request.httpChannel.getResponseHeader("Content-Encoding"); - encodings = encodingHeader.split(/\s*\t*,\s*\t*/); - } - this._responses.set(request.requestId, {body, encodings}); - this._totalSize += body.length; - if (this._totalSize > this._maxTotalSize) { - for (let [requestId, response] of this._responses) { - this._totalSize -= response.body.length; - response.body = ''; - response.evicted = true; - if (this._totalSize < this._maxTotalSize) - break; - } - } - } - - getBase64EncodedResponse(requestId) { - const response = this._responses.get(requestId); - if (!response) - throw new Error(`Request "${requestId}" is not found`); - if (response.evicted) - return {base64body: '', evicted: true}; - let result = response.body; - if (response.encodings && response.encodings.length) { - for (const encoding of response.encodings) - result = convertString(result, encoding, 'uncompressed'); - } - return {base64body: btoa(result)}; - } -} - -function responseHead(httpChannel, opt_statusCode, opt_statusText) { - const headers = []; - let status = opt_statusCode || 0; - let statusText = opt_statusText || ''; - try { - status = httpChannel.responseStatus; - statusText = httpChannel.responseStatusText; - httpChannel.visitResponseHeaders({ - visitHeader: (name, value) => headers.push({name, value}), - }); - } catch (e) { - // Response headers, status and/or statusText are not available - // when redirect did not actually hit the network. - } - return { status, statusText, headers }; -} - -function setPostData(httpChannel, postData, headers) { - if (!(httpChannel instanceof Ci.nsIUploadChannel2)) - return; - const synthesized = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream); - const body = atob(postData); - synthesized.setData(body, body.length); - - const overriddenHeader = (lowerCaseName, defaultValue) => { - if (headers) { - for (const header of headers) { - if (header.name.toLowerCase() === lowerCaseName) { - return header.value; - } - } - } - return defaultValue; - } - // Clear content-length, so that upload stream resets it. - httpChannel.setRequestHeader('content-length', '', false /* merge */); - httpChannel.explicitSetUploadStream(synthesized, overriddenHeader('content-type', 'application/octet-stream'), -1, httpChannel.requestMethod, false); -} - -function convertString(s, source, dest) { - const is = Cc["@mozilla.org/io/string-input-stream;1"].createInstance( - Ci.nsIStringInputStream - ); - is.setData(s, s.length); - const listener = Cc["@mozilla.org/network/stream-loader;1"].createInstance( - Ci.nsIStreamLoader - ); - let result = []; - listener.init({ - onStreamComplete: function onStreamComplete( - loader, - context, - status, - length, - data - ) { - const array = Array.from(data); - const kChunk = 100000; - for (let i = 0; i < length; i += kChunk) { - const len = Math.min(kChunk, length - i); - const chunk = String.fromCharCode.apply(this, array.slice(i, i + len)); - result.push(chunk); - } - }, - }); - const converter = Cc["@mozilla.org/streamConverters;1"].getService( - Ci.nsIStreamConverterService - ).asyncConvertData( - source, - dest, - listener, - null - ); - converter.onStartRequest(null, null); - converter.onDataAvailable(null, is, 0, s.length); - converter.onStopRequest(null, null, null); - return result.join(''); -} - -const errorMap = { - 'aborted': Cr.NS_ERROR_ABORT, - 'accessdenied': Cr.NS_ERROR_PORT_ACCESS_NOT_ALLOWED, - 'addressunreachable': Cr.NS_ERROR_UNKNOWN_HOST, - 'blockedbyclient': Cr.NS_ERROR_FAILURE, - 'blockedbyresponse': Cr.NS_ERROR_FAILURE, - 'connectionaborted': Cr.NS_ERROR_NET_INTERRUPT, - 'connectionclosed': Cr.NS_ERROR_FAILURE, - 'connectionfailed': Cr.NS_ERROR_FAILURE, - 'connectionrefused': Cr.NS_ERROR_CONNECTION_REFUSED, - 'connectionreset': Cr.NS_ERROR_NET_RESET, - 'internetdisconnected': Cr.NS_ERROR_OFFLINE, - 'namenotresolved': Cr.NS_ERROR_UNKNOWN_HOST, - 'timedout': Cr.NS_ERROR_NET_TIMEOUT, - 'failed': Cr.NS_ERROR_FAILURE, -}; - -PageNetwork.Events = { - Request: Symbol('PageNetwork.Events.Request'), - Response: Symbol('PageNetwork.Events.Response'), - RequestFinished: Symbol('PageNetwork.Events.RequestFinished'), - RequestFailed: Symbol('PageNetwork.Events.RequestFailed'), -}; - -var EXPORTED_SYMBOLS = ['NetworkObserver', 'PageNetwork']; -this.NetworkObserver = NetworkObserver; -this.PageNetwork = PageNetwork; diff --git a/browser_patches/firefox-beta/juggler/SimpleChannel.js b/browser_patches/firefox-beta/juggler/SimpleChannel.js deleted file mode 100644 index 59b29532ab1fd2..00000000000000 --- a/browser_patches/firefox-beta/juggler/SimpleChannel.js +++ /dev/null @@ -1,180 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -// Note: this file should be loadabale with eval() into worker environment. -// Avoid Components.*, ChromeUtils and global const variables. - -const SIMPLE_CHANNEL_MESSAGE_NAME = 'juggler:simplechannel'; - -class SimpleChannel { - static createForMessageManager(name, mm) { - const channel = new SimpleChannel(name); - - const messageListener = { - receiveMessage: message => channel._onMessage(message.data) - }; - mm.addMessageListener(SIMPLE_CHANNEL_MESSAGE_NAME, messageListener); - - channel.setTransport({ - sendMessage: obj => mm.sendAsyncMessage(SIMPLE_CHANNEL_MESSAGE_NAME, obj), - dispose: () => mm.removeMessageListener(SIMPLE_CHANNEL_MESSAGE_NAME, messageListener), - }); - - return channel; - } - - constructor(name) { - this._name = name; - this._messageId = 0; - this._connectorId = 0; - this._pendingMessages = new Map(); - this._handlers = new Map(); - this._bufferedIncomingMessages = []; - this._bufferedOutgoingMessages = []; - this.transport = { - sendMessage: null, - dispose: null, - }; - this._ready = false; - this._disposed = false; - } - - setTransport(transport) { - this.transport = transport; - // connection handshake: - // 1. There are two channel ends in different processes. - // 2. Both ends start in the `ready = false` state, meaning that they will - // not send any messages over transport. - // 3. Once channel end is created, it sends `READY` message to the other end. - // 4. Eventually, at least one of the ends receives `READY` message and responds with - // `READY_ACK`. We assume at least one of the ends will receive "READY" event from the other, since - // channel ends have a "parent-child" relation, i.e. one end is always created before the other one. - // 5. Once channel end receives either `READY` or `READY_ACK`, it transitions to `ready` state. - this.transport.sendMessage('READY'); - } - - _markAsReady() { - if (this._ready) - return; - this._ready = true; - for (const msg of this._bufferedOutgoingMessages) - this.transport.sendMessage(msg); - this._bufferedOutgoingMessages = []; - } - - dispose() { - if (this._disposed) - return; - this._disposed = true; - for (const {resolve, reject, methodName} of this._pendingMessages.values()) - reject(new Error(`Failed "${methodName}": ${this._name} is disposed.`)); - this._pendingMessages.clear(); - this._handlers.clear(); - this.transport.dispose(); - } - - _rejectCallbacksFromConnector(connectorId) { - for (const [messageId, callback] of this._pendingMessages) { - if (callback.connectorId === connectorId) { - callback.reject(new Error(`Failed "${callback.methodName}": connector for namespace "${callback.namespace}" in channel "${this._name}" is disposed.`)); - this._pendingMessages.delete(messageId); - } - } - } - - connect(namespace) { - const connectorId = ++this._connectorId; - return { - send: (...args) => this._send(namespace, connectorId, ...args), - emit: (...args) => void this._send(namespace, connectorId, ...args).catch(e => {}), - dispose: () => this._rejectCallbacksFromConnector(connectorId), - }; - } - - register(namespace, handler) { - if (this._handlers.has(namespace)) - throw new Error('ERROR: double-register for namespace ' + namespace); - this._handlers.set(namespace, handler); - // Try to re-deliver all pending messages. - const bufferedRequests = this._bufferedIncomingMessages; - this._bufferedIncomingMessages = []; - for (const data of bufferedRequests) { - this._onMessage(data); - } - return () => this.unregister(namespace); - } - - unregister(namespace) { - this._handlers.delete(namespace); - } - - /** - * @param {string} namespace - * @param {number} connectorId - * @param {string} methodName - * @param {...*} params - * @return {!Promise<*>} - */ - async _send(namespace, connectorId, methodName, ...params) { - if (this._disposed) - throw new Error(`ERROR: channel ${this._name} is already disposed! Cannot send "${methodName}" to "${namespace}"`); - const id = ++this._messageId; - const promise = new Promise((resolve, reject) => { - this._pendingMessages.set(id, {connectorId, resolve, reject, methodName, namespace}); - }); - const message = {requestId: id, methodName, params, namespace}; - if (this._ready) - this.transport.sendMessage(message); - else - this._bufferedOutgoingMessages.push(message); - return promise; - } - - async _onMessage(data) { - if (data === 'READY') { - this.transport.sendMessage('READY_ACK'); - this._markAsReady(); - return; - } - if (data === 'READY_ACK') { - this._markAsReady(); - return; - } - if (data.responseId) { - const {resolve, reject} = this._pendingMessages.get(data.responseId); - this._pendingMessages.delete(data.responseId); - if (data.error) - reject(new Error(data.error)); - else - resolve(data.result); - } else if (data.requestId) { - const namespace = data.namespace; - const handler = this._handlers.get(namespace); - if (!handler) { - this._bufferedIncomingMessages.push(data); - return; - } - const method = handler[data.methodName]; - if (!method) { - this.transport.sendMessage({responseId: data.requestId, error: `error in channel "${this._name}": No method "${data.methodName}" in namespace "${namespace}"`}); - return; - } - try { - const result = await method.call(handler, ...data.params); - this.transport.sendMessage({responseId: data.requestId, result}); - } catch (error) { - this.transport.sendMessage({responseId: data.requestId, error: `error in channel "${this._name}": exception while running method "${data.methodName}" in namespace "${namespace}": ${error.message} ${error.stack}`}); - return; - } - } else { - dump(` - ERROR: unknown message in channel "${this._name}": ${JSON.stringify(data)} - `); - } - } -} - -var EXPORTED_SYMBOLS = ['SimpleChannel']; -this.SimpleChannel = SimpleChannel; diff --git a/browser_patches/firefox-beta/juggler/TargetRegistry.js b/browser_patches/firefox-beta/juggler/TargetRegistry.js deleted file mode 100644 index b222ba98bba847..00000000000000 --- a/browser_patches/firefox-beta/juggler/TargetRegistry.js +++ /dev/null @@ -1,1065 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm"); -const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm"); -const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); -const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); -const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); - -const Cr = Components.results; - -const helper = new Helper(); - -const IDENTITY_NAME = 'JUGGLER '; -const HUNDRED_YEARS = 60 * 60 * 24 * 365 * 100; - -const ALL_PERMISSIONS = [ - 'geo', - 'desktop-notification', -]; - -class DownloadInterceptor { - constructor(registry) { - this._registry = registry - this._handlerToUuid = new Map(); - this._uuidToHandler = new Map(); - } - - // - // nsIDownloadInterceptor implementation. - // - interceptDownloadRequest(externalAppHandler, request, browsingContext, outFile) { - if (!(request instanceof Ci.nsIChannel)) - return false; - const channel = request.QueryInterface(Ci.nsIChannel); - let pageTarget = this._registry._browserBrowsingContextToTarget.get(channel.loadInfo.browsingContext.top); - if (!pageTarget) - return false; - - const browserContext = pageTarget.browserContext(); - const options = browserContext.downloadOptions; - if (!options) - return false; - - const uuid = helper.generateId(); - let file = null; - if (options.behavior === 'saveToDisk') { - file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - file.initWithPath(options.downloadsDir); - file.append(uuid); - - try { - file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); - } catch (e) { - dump(`interceptDownloadRequest failed to create file: ${e}\n`); - return false; - } - } - outFile.value = file; - this._handlerToUuid.set(externalAppHandler, uuid); - this._uuidToHandler.set(uuid, externalAppHandler); - const downloadInfo = { - uuid, - browserContextId: browserContext.browserContextId, - pageTargetId: pageTarget.id(), - url: request.name, - suggestedFileName: externalAppHandler.suggestedFileName, - }; - this._registry.emit(TargetRegistry.Events.DownloadCreated, downloadInfo); - return true; - } - - onDownloadComplete(externalAppHandler, canceled, errorName) { - const uuid = this._handlerToUuid.get(externalAppHandler); - if (!uuid) - return; - this._handlerToUuid.delete(externalAppHandler); - this._uuidToHandler.delete(uuid); - const downloadInfo = { - uuid, - error: errorName, - }; - if (canceled === 'NS_BINDING_ABORTED') { - downloadInfo.canceled = true; - } - this._registry.emit(TargetRegistry.Events.DownloadFinished, downloadInfo); - } - - async cancelDownload(uuid) { - const externalAppHandler = this._uuidToHandler.get(uuid); - if (!externalAppHandler) { - return; - } - await externalAppHandler.cancel(Cr.NS_BINDING_ABORTED); - } -} - -const screencastService = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); - -class TargetRegistry { - constructor() { - EventEmitter.decorate(this); - - this._browserContextIdToBrowserContext = new Map(); - this._userContextIdToBrowserContext = new Map(); - this._browserToTarget = new Map(); - this._browserBrowsingContextToTarget = new Map(); - - this._browserProxy = null; - - // Cleanup containers from previous runs (if any) - for (const identity of ContextualIdentityService.getPublicIdentities()) { - if (identity.name && identity.name.startsWith(IDENTITY_NAME)) { - ContextualIdentityService.remove(identity.userContextId); - ContextualIdentityService.closeContainerTabs(identity.userContextId); - } - } - - this._defaultContext = new BrowserContext(this, undefined, undefined); - - Services.obs.addObserver({ - observe: (subject, topic, data) => { - const browser = subject.ownerElement; - if (!browser) - return; - const target = this._browserToTarget.get(browser); - if (!target) - return; - target.emit(PageTarget.Events.Crashed); - target.dispose(); - } - }, 'oop-frameloader-crashed'); - - Services.mm.addMessageListener('juggler:content-ready', { - receiveMessage: message => { - const linkedBrowser = message.target; - const target = this._browserToTarget.get(linkedBrowser); - if (!target) - return; - - return { - initScripts: target.browserContext().initScripts, - bindings: target.browserContext().bindings, - settings: target.browserContext().settings, - }; - }, - }); - - const onTabOpenListener = (appWindow, window, event) => { - const tab = event.target; - const userContextId = tab.userContextId; - const browserContext = this._userContextIdToBrowserContext.get(userContextId); - const hasExplicitSize = appWindow && (appWindow.chromeFlags & Ci.nsIWebBrowserChrome.JUGGLER_WINDOW_EXPLICIT_SIZE) !== 0; - const openerContext = tab.linkedBrowser.browsingContext.opener; - let openerTarget; - if (openerContext) { - // Popups usually have opener context. Get top context for the case when opener is - // an iframe. - openerTarget = this._browserBrowsingContextToTarget.get(openerContext.top); - } else if (tab.openerTab) { - // Noopener popups from the same window have opener tab instead. - openerTarget = this._browserToTarget.get(tab.openerTab.linkedBrowser); - } - if (!browserContext) - throw new Error(`Internal error: cannot find context for userContextId=${userContextId}`); - const target = new PageTarget(this, window, tab, browserContext, openerTarget); - target.updateUserAgent(); - target.updatePlatform(); - target.updateJavaScriptDisabled(); - target.updateTouchOverride(); - target.updateColorSchemeOverride(); - target.updateReducedMotionOverride(); - target.updateForcedColorsOverride(); - if (!hasExplicitSize) - target.updateViewportSize(); - if (browserContext.videoRecordingOptions) - target._startVideoRecording(browserContext.videoRecordingOptions); - }; - - const onTabCloseListener = event => { - const tab = event.target; - const linkedBrowser = tab.linkedBrowser; - const target = this._browserToTarget.get(linkedBrowser); - if (target) - target.dispose(); - }; - - const domWindowTabListeners = new Map(); - - const onOpenWindow = async (appWindow) => { - - let domWindow; - if (appWindow instanceof Ci.nsIAppWindow) { - domWindow = appWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); - } else { - domWindow = appWindow; - appWindow = null; - } - if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) - return; - // In persistent mode, window might be opened long ago and might be - // already initialized. - // - // In this case, we want to keep this callback synchronous so that we will call - // `onTabOpenListener` synchronously and before the sync IPc message `juggler:content-ready`. - if (domWindow.document.readyState === 'uninitialized' || domWindow.document.readyState === 'loading') { - // For non-initialized windows, DOMContentLoaded initializes gBrowser - // and starts tab loading (see //browser/base/content/browser.js), so we - // are guaranteed to call `onTabOpenListener` before the sync IPC message - // `juggler:content-ready`. - await helper.awaitEvent(domWindow, 'DOMContentLoaded'); - } - - if (!domWindow.gBrowser) - return; - const tabContainer = domWindow.gBrowser.tabContainer; - domWindowTabListeners.set(domWindow, [ - helper.addEventListener(tabContainer, 'TabOpen', event => onTabOpenListener(appWindow, domWindow, event)), - helper.addEventListener(tabContainer, 'TabClose', onTabCloseListener), - ]); - for (const tab of domWindow.gBrowser.tabs) - onTabOpenListener(appWindow, domWindow, { target: tab }); - }; - - const onCloseWindow = window => { - const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); - if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) - return; - if (!domWindow.gBrowser) - return; - - const listeners = domWindowTabListeners.get(domWindow) || []; - domWindowTabListeners.delete(domWindow); - helper.removeListeners(listeners); - for (const tab of domWindow.gBrowser.tabs) - onTabCloseListener({ target: tab }); - }; - - const extHelperAppSvc = Cc["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Ci.nsIExternalHelperAppService); - this._downloadInterceptor = new DownloadInterceptor(this); - extHelperAppSvc.setDownloadInterceptor(this._downloadInterceptor); - - Services.wm.addListener({ onOpenWindow, onCloseWindow }); - for (const win of Services.wm.getEnumerator(null)) - onOpenWindow(win); - } - - async cancelDownload(options) { - this._downloadInterceptor.cancelDownload(options.uuid); - } - - setBrowserProxy(proxy) { - this._browserProxy = proxy; - } - - getProxyInfo(channel) { - const originAttributes = channel.loadInfo && channel.loadInfo.originAttributes; - const browserContext = originAttributes ? this.browserContextForUserContextId(originAttributes.userContextId) : null; - // Prefer context proxy and fallback to browser-level proxy. - const proxyInfo = (browserContext && browserContext._proxy) || this._browserProxy; - if (!proxyInfo || proxyInfo.bypass.some(domainSuffix => channel.URI.host.endsWith(domainSuffix))) - return null; - return proxyInfo; - } - - defaultContext() { - return this._defaultContext; - } - - createBrowserContext(removeOnDetach) { - return new BrowserContext(this, helper.generateId(), removeOnDetach); - } - - browserContextForId(browserContextId) { - return this._browserContextIdToBrowserContext.get(browserContextId); - } - - browserContextForUserContextId(userContextId) { - return this._userContextIdToBrowserContext.get(userContextId); - } - - async newPage({browserContextId}) { - const browserContext = this.browserContextForId(browserContextId); - const features = "chrome,dialog=no,all"; - // See _callWithURIToLoad in browser.js for the structure of window.arguments - // window.arguments[1]: unused (bug 871161) - // [2]: referrerInfo (nsIReferrerInfo) - // [3]: postData (nsIInputStream) - // [4]: allowThirdPartyFixup (bool) - // [5]: userContextId (int) - // [6]: originPrincipal (nsIPrincipal) - // [7]: originStoragePrincipal (nsIPrincipal) - // [8]: triggeringPrincipal (nsIPrincipal) - // [9]: allowInheritPrincipal (bool) - // [10]: csp (nsIContentSecurityPolicy) - // [11]: nsOpenWindowInfo - const args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - const urlSupports = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - urlSupports.data = 'about:blank'; - args.appendElement(urlSupports); // 0 - args.appendElement(undefined); // 1 - args.appendElement(undefined); // 2 - args.appendElement(undefined); // 3 - args.appendElement(undefined); // 4 - const userContextIdSupports = Cc[ - "@mozilla.org/supports-PRUint32;1" - ].createInstance(Ci.nsISupportsPRUint32); - userContextIdSupports.data = browserContext.userContextId; - args.appendElement(userContextIdSupports); // 5 - args.appendElement(undefined); // 6 - args.appendElement(undefined); // 7 - args.appendElement(Services.scriptSecurityManager.getSystemPrincipal()); // 8 - - const window = Services.ww.openWindow(null, AppConstants.BROWSER_CHROME_URL, '_blank', features, args); - await waitForWindowReady(window); - if (window.gBrowser.browsers.length !== 1) - throw new Error(`Unexpected number of tabs in the new window: ${window.gBrowser.browsers.length}`); - const browser = window.gBrowser.browsers[0]; - let target = this._browserToTarget.get(browser); - while (!target) { - await helper.awaitEvent(this, TargetRegistry.Events.TargetCreated); - target = this._browserToTarget.get(browser); - } - browser.focus(); - if (browserContext.settings.timezoneId) { - if (await target.hasFailedToOverrideTimezone()) - throw new Error('Failed to override timezone'); - } - return target.id(); - } - - targets() { - return Array.from(this._browserToTarget.values()); - } - - targetForBrowser(browser) { - return this._browserToTarget.get(browser); - } -} - -class PageTarget { - constructor(registry, win, tab, browserContext, opener) { - EventEmitter.decorate(this); - - this._targetId = helper.generateId(); - this._registry = registry; - this._window = win; - this._gBrowser = win.gBrowser; - this._tab = tab; - this._linkedBrowser = tab.linkedBrowser; - this._browserContext = browserContext; - this._viewportSize = undefined; - this._initialDPPX = this._linkedBrowser.browsingContext.overrideDPPX; - this._url = 'about:blank'; - this._openerId = opener ? opener.id() : undefined; - this._channel = SimpleChannel.createForMessageManager(`browser::page[${this._targetId}]`, this._linkedBrowser.messageManager); - this._videoRecordingInfo = undefined; - this._screencastRecordingInfo = undefined; - this._dialogs = new Map(); - this.forcedColors = 'no-override'; - this._pageInitScripts = []; - - const navigationListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), - onLocationChange: (aWebProgress, aRequest, aLocation) => this._onNavigated(aLocation), - }; - this._eventListeners = [ - helper.addObserver(this._updateModalDialogs.bind(this), 'tabmodal-dialog-loaded'), - helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION), - helper.addEventListener(this._linkedBrowser, 'DOMModalDialogClosed', event => this._updateModalDialogs()), - ]; - - this._disposed = false; - browserContext.pages.add(this); - this._registry._browserToTarget.set(this._linkedBrowser, this); - this._registry._browserBrowsingContextToTarget.set(this._linkedBrowser.browsingContext, this); - - this._registry.emit(TargetRegistry.Events.TargetCreated, this); - } - - dialog(dialogId) { - return this._dialogs.get(dialogId); - } - - dialogs() { - return [...this._dialogs.values()]; - } - - async windowReady() { - await waitForWindowReady(this._window); - } - - linkedBrowser() { - return this._linkedBrowser; - } - - browserContext() { - return this._browserContext; - } - - updateTouchOverride() { - this._linkedBrowser.browsingContext.touchEventsOverride = this._browserContext.touchOverride ? 'enabled' : 'none'; - } - - updateUserAgent() { - this._linkedBrowser.browsingContext.customUserAgent = this._browserContext.defaultUserAgent; - } - - updatePlatform() { - this._linkedBrowser.browsingContext.customPlatform = this._browserContext.defaultPlatform; - } - - updateJavaScriptDisabled() { - this._linkedBrowser.browsingContext.allowJavascript = !this._browserContext.javaScriptDisabled; - } - - _updateModalDialogs() { - const prompts = new Set(this._linkedBrowser.tabModalPromptBox ? this._linkedBrowser.tabModalPromptBox.listPrompts() : []); - for (const dialog of this._dialogs.values()) { - if (!prompts.has(dialog.prompt())) { - this._dialogs.delete(dialog.id()); - this.emit(PageTarget.Events.DialogClosed, dialog); - } else { - prompts.delete(dialog.prompt()); - } - } - for (const prompt of prompts) { - const dialog = Dialog.createIfSupported(prompt); - if (!dialog) - continue; - this._dialogs.set(dialog.id(), dialog); - this.emit(PageTarget.Events.DialogOpened, dialog); - } - } - - async updateViewportSize() { - // Viewport size is defined by three arguments: - // 1. default size. Could be explicit if set as part of `window.open` call, e.g. - // `window.open(url, title, 'width=400,height=400')` - // 2. page viewport size - // 3. browserContext viewport size - // - // The "default size" (1) is only respected when the page is opened. - // Otherwise, explicitly set page viewport prevales over browser context - // default viewport. - const viewportSize = this._viewportSize || this._browserContext.defaultViewportSize; - const actualSize = await setViewportSizeForBrowser(viewportSize, this._linkedBrowser, this._window); - this._linkedBrowser.browsingContext.overrideDPPX = this._browserContext.deviceScaleFactor || this._initialDPPX; - await this._channel.connect('').send('awaitViewportDimensions', { - width: actualSize.width, - height: actualSize.height, - deviceSizeIsPageSize: !!this._browserContext.deviceScaleFactor, - }); - } - - setEmulatedMedia(mediumOverride) { - this._linkedBrowser.browsingContext.mediumOverride = mediumOverride || ''; - } - - setColorScheme(colorScheme) { - this.colorScheme = fromProtocolColorScheme(colorScheme); - this.updateColorSchemeOverride(); - } - - updateColorSchemeOverride() { - this._linkedBrowser.browsingContext.prefersColorSchemeOverride = this.colorScheme || this._browserContext.colorScheme || 'none'; - } - - setReducedMotion(reducedMotion) { - this.reducedMotion = fromProtocolReducedMotion(reducedMotion); - this.updateReducedMotionOverride(); - } - - updateReducedMotionOverride() { - this._linkedBrowser.browsingContext.prefersReducedMotionOverride = this.reducedMotion || this._browserContext.reducedMotion || 'none'; - } - - setForcedColors(forcedColors) { - this.forcedColors = fromProtocolForcedColors(forcedColors); - this.updateForcedColorsOverride(); - } - - updateForcedColorsOverride() { - this._linkedBrowser.browsingContext.forcedColorsOverride = (this.forcedColors !== 'no-override' ? this.forcedColors : this._browserContext.forcedColors) || 'no-override'; - } - - async setViewportSize(viewportSize) { - this._viewportSize = viewportSize; - await this.updateViewportSize(); - } - - close(runBeforeUnload = false) { - this._gBrowser.removeTab(this._tab, { - skipPermitUnload: !runBeforeUnload, - }); - } - - channel() { - return this._channel; - } - - id() { - return this._targetId; - } - - info() { - return { - targetId: this.id(), - type: 'page', - browserContextId: this._browserContext.browserContextId, - openerId: this._openerId, - }; - } - - _onNavigated(aLocation) { - this._url = aLocation.spec; - this._browserContext.grantPermissionsToOrigin(this._url); - } - - async ensurePermissions() { - await this._channel.connect('').send('ensurePermissions', {}).catch(e => void e); - } - - async setInitScripts(scripts) { - this._pageInitScripts = scripts; - await this.pushInitScripts(); - } - - async pushInitScripts() { - await this._channel.connect('').send('setInitScripts', [...this._browserContext.initScripts, ...this._pageInitScripts]).catch(e => void e); - } - - async addBinding(worldName, name, script) { - await this._channel.connect('').send('addBinding', { worldName, name, script }).catch(e => void e); - } - - async applyContextSetting(name, value) { - await this._channel.connect('').send('applyContextSetting', { name, value }).catch(e => void e); - } - - async hasFailedToOverrideTimezone() { - return await this._channel.connect('').send('hasFailedToOverrideTimezone').catch(e => true); - } - - async _startVideoRecording({width, height, dir}) { - // On Mac the window may not yet be visible when TargetCreated and its - // NSWindow.windowNumber may be -1, so we wait until the window is known - // to be initialized and visible. - await this.windowReady(); - const file = OS.Path.join(dir, helper.generateId() + '.webm'); - if (width < 10 || width > 10000 || height < 10 || height > 10000) - throw new Error("Invalid size"); - - const docShell = this._gBrowser.ownerGlobal.docShell; - // Exclude address bar and navigation control from the video. - const rect = this.linkedBrowser().getBoundingClientRect(); - const devicePixelRatio = this._window.devicePixelRatio; - let sessionId; - const registry = this._registry; - const screencastClient = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), - screencastFrame(data, deviceWidth, deviceHeight) { - }, - screencastStopped() { - registry.emit(TargetRegistry.Events.ScreencastStopped, sessionId); - }, - }; - const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; - sessionId = screencastService.startVideoRecording(screencastClient, docShell, true, file, width, height, 0, viewport.width, viewport.height, devicePixelRatio * rect.top); - this._videoRecordingInfo = { sessionId, file }; - this.emit(PageTarget.Events.ScreencastStarted); - } - - _stopVideoRecording() { - if (!this._videoRecordingInfo) - throw new Error('No video recording in progress'); - const videoRecordingInfo = this._videoRecordingInfo; - this._videoRecordingInfo = undefined; - screencastService.stopVideoRecording(videoRecordingInfo.sessionId); - } - - videoRecordingInfo() { - return this._videoRecordingInfo; - } - - async startScreencast({ width, height, quality }) { - // On Mac the window may not yet be visible when TargetCreated and its - // NSWindow.windowNumber may be -1, so we wait until the window is known - // to be initialized and visible. - await this.windowReady(); - if (width < 10 || width > 10000 || height < 10 || height > 10000) - throw new Error("Invalid size"); - - const docShell = this._gBrowser.ownerGlobal.docShell; - // Exclude address bar and navigation control from the video. - const rect = this.linkedBrowser().getBoundingClientRect(); - const devicePixelRatio = this._window.devicePixelRatio; - - const self = this; - const screencastClient = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIScreencastServiceClient]), - screencastFrame(data, deviceWidth, deviceHeight) { - if (self._screencastRecordingInfo) - self.emit(PageTarget.Events.ScreencastFrame, { data, deviceWidth, deviceHeight }); - }, - screencastStopped() { - }, - }; - const viewport = this._viewportSize || this._browserContext.defaultViewportSize || { width: 0, height: 0 }; - const screencastId = screencastService.startVideoRecording(screencastClient, docShell, false, '', width, height, quality || 90, viewport.width, viewport.height, devicePixelRatio * rect.top); - this._screencastRecordingInfo = { screencastId }; - return { screencastId }; - } - - screencastFrameAck({ screencastId }) { - if (!this._screencastRecordingInfo || this._screencastRecordingInfo.screencastId !== screencastId) - return; - screencastService.screencastFrameAck(screencastId); - } - - stopScreencast() { - if (!this._screencastRecordingInfo) - throw new Error('No screencast in progress'); - const { screencastId } = this._screencastRecordingInfo; - this._screencastRecordingInfo = undefined; - screencastService.stopVideoRecording(screencastId); - } - - dispose() { - this._disposed = true; - if (this._videoRecordingInfo) - this._stopVideoRecording(); - if (this._screencastRecordingInfo) - this.stopScreencast(); - this._browserContext.pages.delete(this); - this._registry._browserToTarget.delete(this._linkedBrowser); - this._registry._browserBrowsingContextToTarget.delete(this._linkedBrowser.browsingContext); - try { - helper.removeListeners(this._eventListeners); - } catch (e) { - // In some cases, removing listeners from this._linkedBrowser fails - // because it is already half-destroyed. - if (e) - dump(e.message + '\n' + e.stack + '\n'); - } - this._registry.emit(TargetRegistry.Events.TargetDestroyed, this); - } -} - -PageTarget.Events = { - ScreencastStarted: Symbol('PageTarget.ScreencastStarted'), - ScreencastFrame: Symbol('PageTarget.ScreencastFrame'), - Crashed: Symbol('PageTarget.Crashed'), - DialogOpened: Symbol('PageTarget.DialogOpened'), - DialogClosed: Symbol('PageTarget.DialogClosed'), -}; - -function fromProtocolColorScheme(colorScheme) { - if (colorScheme === 'light' || colorScheme === 'dark') - return colorScheme; - if (colorScheme === null || colorScheme === 'no-preference') - return undefined; - throw new Error('Unknown color scheme: ' + colorScheme); -} - -function fromProtocolReducedMotion(reducedMotion) { - if (reducedMotion === 'reduce' || reducedMotion === 'no-preference') - return reducedMotion; - if (reducedMotion === null) - return undefined; - throw new Error('Unknown reduced motion: ' + reducedMotion); -} - -function fromProtocolForcedColors(forcedColors) { - if (forcedColors === 'active' || forcedColors === 'none') - return forcedColors; - if (forcedColors === null) - return undefined; - throw new Error('Unknown forced colors: ' + forcedColors); -} - -class BrowserContext { - constructor(registry, browserContextId, removeOnDetach) { - this._registry = registry; - this.browserContextId = browserContextId; - // Default context has userContextId === 0, but we pass undefined to many APIs just in case. - this.userContextId = 0; - if (browserContextId !== undefined) { - const identity = ContextualIdentityService.create(IDENTITY_NAME + browserContextId); - this.userContextId = identity.userContextId; - } - this._principals = []; - // Maps origins to the permission lists. - this._permissions = new Map(); - this._registry._browserContextIdToBrowserContext.set(this.browserContextId, this); - this._registry._userContextIdToBrowserContext.set(this.userContextId, this); - this._proxy = null; - this.removeOnDetach = removeOnDetach; - this.extraHTTPHeaders = undefined; - this.httpCredentials = undefined; - this.requestInterceptionEnabled = undefined; - this.ignoreHTTPSErrors = undefined; - this.downloadOptions = undefined; - this.defaultViewportSize = undefined; - this.deviceScaleFactor = undefined; - this.defaultUserAgent = null; - this.defaultPlatform = null; - this.javaScriptDisabled = false; - this.touchOverride = false; - this.colorScheme = 'none'; - this.forcedColors = 'no-override'; - this.reducedMotion = 'none'; - this.videoRecordingOptions = undefined; - this.initScripts = []; - this.bindings = []; - this.settings = {}; - this.pages = new Set(); - } - - setColorScheme(colorScheme) { - this.colorScheme = fromProtocolColorScheme(colorScheme); - for (const page of this.pages) - page.updateColorSchemeOverride(); - } - - setReducedMotion(reducedMotion) { - this.reducedMotion = fromProtocolReducedMotion(reducedMotion); - for (const page of this.pages) - page.updateReducedMotionOverride(); - } - - setForcedColors(forcedColors) { - this.forcedColors = fromProtocolForcedColors(forcedColors); - for (const page of this.pages) - page.updateForcedColorsOverride(); - } - - async destroy() { - if (this.userContextId !== 0) { - ContextualIdentityService.remove(this.userContextId); - for (const page of this.pages) - page.close(); - if (this.pages.size) { - await new Promise(f => { - const listener = helper.on(this._registry, TargetRegistry.Events.TargetDestroyed, () => { - if (!this.pages.size) { - helper.removeListeners([listener]); - f(); - } - }); - }); - } - } - this._registry._browserContextIdToBrowserContext.delete(this.browserContextId); - this._registry._userContextIdToBrowserContext.delete(this.userContextId); - } - - setProxy(proxy) { - // Clear AuthCache. - Services.obs.notifyObservers(null, "net:clear-active-logins"); - this._proxy = proxy; - } - - setIgnoreHTTPSErrors(ignoreHTTPSErrors) { - if (this.ignoreHTTPSErrors === ignoreHTTPSErrors) - return; - this.ignoreHTTPSErrors = ignoreHTTPSErrors; - const certOverrideService = Cc[ - "@mozilla.org/security/certoverride;1" - ].getService(Ci.nsICertOverrideService); - if (ignoreHTTPSErrors) { - Preferences.set("network.stricttransportsecurity.preloadlist", false); - Preferences.set("security.cert_pinning.enforcement_level", 0); - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(true, this.userContextId); - } else { - certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(false, this.userContextId); - } - } - - setDefaultUserAgent(userAgent) { - this.defaultUserAgent = userAgent; - for (const page of this.pages) - page.updateUserAgent(); - } - - setDefaultPlatform(platform) { - this.defaultPlatform = platform; - for (const page of this.pages) - page.updatePlatform(); - } - - setJavaScriptDisabled(javaScriptDisabled) { - this.javaScriptDisabled = javaScriptDisabled; - for (const page of this.pages) - page.updateJavaScriptDisabled(); - } - - setTouchOverride(touchOverride) { - this.touchOverride = touchOverride; - for (const page of this.pages) - page.updateTouchOverride(); - } - - async setDefaultViewport(viewport) { - this.defaultViewportSize = viewport ? viewport.viewportSize : undefined; - this.deviceScaleFactor = viewport ? viewport.deviceScaleFactor : undefined; - await Promise.all(Array.from(this.pages).map(page => page.updateViewportSize())); - } - - async setInitScripts(scripts) { - this.initScripts = scripts; - await Promise.all(Array.from(this.pages).map(page => page.pushInitScripts())); - } - - async addBinding(worldName, name, script) { - this.bindings.push({ worldName, name, script }); - await Promise.all(Array.from(this.pages).map(page => page.addBinding(worldName, name, script))); - } - - async applySetting(name, value) { - this.settings[name] = value; - await Promise.all(Array.from(this.pages).map(page => page.applyContextSetting(name, value))); - } - - async grantPermissions(origin, permissions) { - this._permissions.set(origin, permissions); - const promises = []; - for (const page of this.pages) { - if (origin === '*' || page._url.startsWith(origin)) { - this.grantPermissionsToOrigin(page._url); - promises.push(page.ensurePermissions()); - } - } - await Promise.all(promises); - } - - resetPermissions() { - for (const principal of this._principals) { - for (const permission of ALL_PERMISSIONS) - Services.perms.removeFromPrincipal(principal, permission); - } - this._principals = []; - this._permissions.clear(); - } - - grantPermissionsToOrigin(url) { - let origin = Array.from(this._permissions.keys()).find(key => url.startsWith(key)); - if (!origin) - origin = '*'; - - const permissions = this._permissions.get(origin); - if (!permissions) - return; - - const attrs = { userContextId: this.userContextId || undefined }; - const principal = Services.scriptSecurityManager.createContentPrincipal(NetUtil.newURI(url), attrs); - this._principals.push(principal); - for (const permission of ALL_PERMISSIONS) { - const action = permissions.includes(permission) ? Ci.nsIPermissionManager.ALLOW_ACTION : Ci.nsIPermissionManager.DENY_ACTION; - Services.perms.addFromPrincipal(principal, permission, action, Ci.nsIPermissionManager.EXPIRE_NEVER, 0 /* expireTime */); - } - } - - setCookies(cookies) { - const protocolToSameSite = { - [undefined]: Ci.nsICookie.SAMESITE_NONE, - 'Lax': Ci.nsICookie.SAMESITE_LAX, - 'Strict': Ci.nsICookie.SAMESITE_STRICT, - }; - for (const cookie of cookies) { - const uri = cookie.url ? NetUtil.newURI(cookie.url) : null; - let domain = cookie.domain; - if (!domain) { - if (!uri) - throw new Error('At least one of the url and domain needs to be specified'); - domain = uri.host; - } - let path = cookie.path; - if (!path) - path = uri ? dirPath(uri.filePath) : '/'; - let secure = false; - if (cookie.secure !== undefined) - secure = cookie.secure; - else if (uri && uri.scheme === 'https') - secure = true; - Services.cookies.add( - domain, - path, - cookie.name, - cookie.value, - secure, - cookie.httpOnly || false, - cookie.expires === undefined || cookie.expires === -1 /* isSession */, - cookie.expires === undefined ? Date.now() + HUNDRED_YEARS : cookie.expires, - { userContextId: this.userContextId || undefined } /* originAttributes */, - protocolToSameSite[cookie.sameSite], - Ci.nsICookie.SCHEME_UNSET - ); - } - } - - clearCookies() { - Services.cookies.removeCookiesWithOriginAttributes(JSON.stringify({ userContextId: this.userContextId || undefined })); - } - - getCookies() { - const result = []; - const sameSiteToProtocol = { - [Ci.nsICookie.SAMESITE_NONE]: 'None', - [Ci.nsICookie.SAMESITE_LAX]: 'Lax', - [Ci.nsICookie.SAMESITE_STRICT]: 'Strict', - }; - for (let cookie of Services.cookies.cookies) { - if (cookie.originAttributes.userContextId !== this.userContextId) - continue; - if (cookie.host === 'addons.mozilla.org') - continue; - result.push({ - name: cookie.name, - value: cookie.value, - domain: cookie.host, - path: cookie.path, - expires: cookie.isSession ? -1 : cookie.expiry, - size: cookie.name.length + cookie.value.length, - httpOnly: cookie.isHttpOnly, - secure: cookie.isSecure, - session: cookie.isSession, - sameSite: sameSiteToProtocol[cookie.sameSite], - }); - } - return result; - } - - async setVideoRecordingOptions(options) { - this.videoRecordingOptions = options; - const promises = []; - for (const page of this.pages) { - if (options) - promises.push(page._startVideoRecording(options)); - else if (page._videoRecordingInfo) - promises.push(page._stopVideoRecording()); - } - await Promise.all(promises); - } -} - -class Dialog { - static createIfSupported(prompt) { - const type = prompt.args.promptType; - switch (type) { - case 'alert': - case 'alertCheck': - return new Dialog(prompt, 'alert'); - case 'prompt': - return new Dialog(prompt, 'prompt'); - case 'confirm': - case 'confirmCheck': - return new Dialog(prompt, 'confirm'); - case 'confirmEx': - return new Dialog(prompt, 'beforeunload'); - default: - return null; - }; - } - - constructor(prompt, type) { - this._id = helper.generateId(); - this._type = type; - this._prompt = prompt; - } - - id() { - return this._id; - } - - message() { - return this._prompt.ui.infoBody.textContent; - } - - type() { - return this._type; - } - - prompt() { - return this._prompt; - } - - dismiss() { - if (this._prompt.ui.button1) - this._prompt.ui.button1.click(); - else - this._prompt.ui.button0.click(); - } - - defaultValue() { - return this._prompt.ui.loginTextbox.value; - } - - accept(promptValue) { - if (typeof promptValue === 'string' && this._type === 'prompt') - this._prompt.ui.loginTextbox.value = promptValue; - this._prompt.ui.button0.click(); - } -} - - -function dirPath(path) { - return path.substring(0, path.lastIndexOf('/') + 1); -} - -async function waitForWindowReady(window) { - if (window.delayedStartupPromise) { - await window.delayedStartupPromise; - } else { - await new Promise((resolve => { - Services.obs.addObserver(function observer(aSubject, aTopic) { - if (window == aSubject) { - Services.obs.removeObserver(observer, aTopic); - resolve(); - } - }, "browser-delayed-startup-finished"); - })); - } - if (window.document.readyState !== 'complete') - await helper.awaitEvent(window, 'load'); -} - -async function setViewportSizeForBrowser(viewportSize, browser, window) { - await waitForWindowReady(window); - if (viewportSize) { - const {width, height} = viewportSize; - const rect = browser.getBoundingClientRect(); - window.resizeBy(width - rect.width, height - rect.height); - browser.style.setProperty('min-width', width + 'px'); - browser.style.setProperty('min-height', height + 'px'); - browser.style.setProperty('max-width', width + 'px'); - browser.style.setProperty('max-height', height + 'px'); - } else { - browser.style.removeProperty('min-width'); - browser.style.removeProperty('min-height'); - browser.style.removeProperty('max-width'); - browser.style.removeProperty('max-height'); - } - const rect = browser.getBoundingClientRect(); - return { width: rect.width, height: rect.height }; -} - -TargetRegistry.Events = { - TargetCreated: Symbol('TargetRegistry.Events.TargetCreated'), - TargetDestroyed: Symbol('TargetRegistry.Events.TargetDestroyed'), - DownloadCreated: Symbol('TargetRegistry.Events.DownloadCreated'), - DownloadFinished: Symbol('TargetRegistry.Events.DownloadFinished'), - ScreencastStopped: Symbol('TargetRegistry.ScreencastStopped'), -}; - -var EXPORTED_SYMBOLS = ['TargetRegistry', 'PageTarget']; -this.TargetRegistry = TargetRegistry; -this.PageTarget = PageTarget; diff --git a/browser_patches/firefox-beta/juggler/components/moz.build b/browser_patches/firefox-beta/juggler/components/moz.build deleted file mode 100644 index bab81f83fcb290..00000000000000 --- a/browser_patches/firefox-beta/juggler/components/moz.build +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPCOM_MANIFESTS += ["components.conf"] - diff --git a/browser_patches/firefox-beta/juggler/content/FrameTree.js b/browser_patches/firefox-beta/juggler/content/FrameTree.js deleted file mode 100644 index 61ff889e755fb9..00000000000000 --- a/browser_patches/firefox-beta/juggler/content/FrameTree.js +++ /dev/null @@ -1,634 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); -const {Runtime} = ChromeUtils.import('chrome://juggler/content/content/Runtime.js'); - -const helper = new Helper(); - -class FrameTree { - constructor(rootDocShell) { - EventEmitter.decorate(this); - - this._browsingContextGroup = rootDocShell.browsingContext.group; - if (!this._browsingContextGroup.__jugglerFrameTrees) - this._browsingContextGroup.__jugglerFrameTrees = new Set(); - this._browsingContextGroup.__jugglerFrameTrees.add(this); - this._isolatedWorlds = new Map(); - - this._webSocketEventService = Cc[ - "@mozilla.org/websocketevent/service;1" - ].getService(Ci.nsIWebSocketEventService); - - this._runtime = new Runtime(false /* isWorker */); - this._workers = new Map(); - this._docShellToFrame = new Map(); - this._frameIdToFrame = new Map(); - this._pageReady = false; - this._mainFrame = this._createFrame(rootDocShell); - const webProgress = rootDocShell.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebProgress); - this.QueryInterface = ChromeUtils.generateQI([ - Ci.nsIWebProgressListener, - Ci.nsIWebProgressListener2, - Ci.nsISupportsWeakReference, - ]); - - this._addedScrollbarsStylesheetSymbol = Symbol('_addedScrollbarsStylesheetSymbol'); - - this._wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].createInstance(Ci.nsIWorkerDebuggerManager); - this._wdmListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerManagerListener]), - onRegister: this._onWorkerCreated.bind(this), - onUnregister: this._onWorkerDestroyed.bind(this), - }; - this._wdm.addListener(this._wdmListener); - for (const workerDebugger of this._wdm.getWorkerDebuggerEnumerator()) - this._onWorkerCreated(workerDebugger); - - const flags = Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT | - Ci.nsIWebProgress.NOTIFY_LOCATION; - this._eventListeners = [ - helper.addObserver(this._onDOMWindowCreated.bind(this), 'content-document-global-created'), - helper.addObserver(this._onDOMWindowCreated.bind(this), 'juggler-dom-window-reused'), - helper.addObserver(subject => this._onDocShellCreated(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-create'), - helper.addObserver(subject => this._onDocShellDestroyed(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-destroy'), - helper.addProgressListener(webProgress, this, flags), - ]; - } - - workers() { - return [...this._workers.values()]; - } - - runtime() { - return this._runtime; - } - - setInitScripts(scripts) { - for (const world of this._isolatedWorlds.values()) - world._scriptsToEvaluateOnNewDocument = []; - - for (let { worldName, script } of scripts) { - worldName = worldName || ''; - const existing = this._isolatedWorlds.has(worldName); - const world = this._ensureWorld(worldName); - world._scriptsToEvaluateOnNewDocument.push(script); - // FIXME: 'should inherit http credentials from browser context' fails without this - if (worldName && !existing) { - for (const frame of this.frames()) - frame._createIsolatedContext(worldName); - } - } - } - - _ensureWorld(worldName) { - worldName = worldName || ''; - let world = this._isolatedWorlds.get(worldName); - if (!world) { - world = new IsolatedWorld(worldName); - this._isolatedWorlds.set(worldName, world); - } - return world; - } - - _frameForWorker(workerDebugger) { - if (workerDebugger.type !== Ci.nsIWorkerDebugger.TYPE_DEDICATED) - return null; - if (!workerDebugger.window) - return null; - const docShell = workerDebugger.window.docShell; - return this._docShellToFrame.get(docShell) || null; - } - - _onDOMWindowCreated(window) { - if (!window[this._addedScrollbarsStylesheetSymbol] && this.scrollbarsHidden) { - const styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService); - const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); - const uri = ioService.newURI('chrome://juggler/content/content/hidden-scrollbars.css', null, null); - const sheet = styleSheetService.preloadSheet(uri, styleSheetService.AGENT_SHEET); - window.windowUtils.addSheet(sheet, styleSheetService.AGENT_SHEET); - window[this._addedScrollbarsStylesheetSymbol] = true; - } - const frame = this._docShellToFrame.get(window.docShell) || null; - if (!frame) - return; - frame._onGlobalObjectCleared(); - } - - setScrollbarsHidden(hidden) { - this.scrollbarsHidden = hidden; - } - - _onWorkerCreated(workerDebugger) { - // Note: we do not interoperate with firefox devtools. - if (workerDebugger.isInitialized) - return; - const frame = this._frameForWorker(workerDebugger); - if (!frame) - return; - const worker = new Worker(frame, workerDebugger); - this._workers.set(workerDebugger, worker); - this.emit(FrameTree.Events.WorkerCreated, worker); - } - - _onWorkerDestroyed(workerDebugger) { - const worker = this._workers.get(workerDebugger); - if (!worker) - return; - worker.dispose(); - this._workers.delete(workerDebugger); - this.emit(FrameTree.Events.WorkerDestroyed, worker); - } - - allFramesInBrowsingContextGroup(group) { - const frames = []; - for (const frameTree of (group.__jugglerFrameTrees || [])) - frames.push(...frameTree.frames()); - return frames; - } - - isPageReady() { - return this._pageReady; - } - - forcePageReady() { - if (this._pageReady) - return false; - this._pageReady = true; - this.emit(FrameTree.Events.PageReady); - return true; - } - - addBinding(worldName, name, script) { - worldName = worldName || ''; - const world = this._ensureWorld(worldName); - world._bindings.set(name, script); - for (const frame of this.frames()) - frame._addBinding(worldName, name, script); - } - - frameForDocShell(docShell) { - return this._docShellToFrame.get(docShell) || null; - } - - frame(frameId) { - return this._frameIdToFrame.get(frameId) || null; - } - - frames() { - let result = []; - collect(this._mainFrame); - return result; - - function collect(frame) { - result.push(frame); - for (const subframe of frame._children) - collect(subframe); - } - } - - mainFrame() { - return this._mainFrame; - } - - dispose() { - this._browsingContextGroup.__jugglerFrameTrees.delete(this); - this._wdm.removeListener(this._wdmListener); - this._runtime.dispose(); - helper.removeListeners(this._eventListeners); - } - - onStateChange(progress, request, flag, status) { - if (!(request instanceof Ci.nsIChannel)) - return; - const channel = request.QueryInterface(Ci.nsIChannel); - const docShell = progress.DOMWindow.docShell; - const frame = this._docShellToFrame.get(docShell); - if (!frame) { - dump(`ERROR: got a state changed event for un-tracked docshell!\n`); - return; - } - - if (!channel.isDocument) { - // Somehow, we can get worker requests here, - // while we are only interested in frame documents. - return; - } - - const isStart = flag & Ci.nsIWebProgressListener.STATE_START; - const isTransferring = flag & Ci.nsIWebProgressListener.STATE_TRANSFERRING; - const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP; - const isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT; - - if (isStart) { - // Starting a new navigation. - frame._pendingNavigationId = channelId(channel); - frame._pendingNavigationURL = channel.URI.spec; - this.emit(FrameTree.Events.NavigationStarted, frame); - } else if (isTransferring || (isStop && frame._pendingNavigationId && !status)) { - // Navigation is committed. - for (const subframe of frame._children) - this._detachFrame(subframe); - const navigationId = frame._pendingNavigationId; - frame._pendingNavigationId = null; - frame._pendingNavigationURL = null; - frame._lastCommittedNavigationId = navigationId; - frame._url = channel.URI.spec; - this.emit(FrameTree.Events.NavigationCommitted, frame); - if (frame === this._mainFrame) - this.forcePageReady(); - } else if (isStop && frame._pendingNavigationId && status) { - // Navigation is aborted. - const navigationId = frame._pendingNavigationId; - frame._pendingNavigationId = null; - frame._pendingNavigationURL = null; - // Always report download navigation as failure to match other browsers. - const errorText = helper.getNetworkErrorStatusText(status); - this.emit(FrameTree.Events.NavigationAborted, frame, navigationId, errorText); - if (frame === this._mainFrame && status !== Cr.NS_BINDING_ABORTED) - this.forcePageReady(); - } - - if (isStop && isDocument) - this.emit(FrameTree.Events.Load, frame); - } - - onLocationChange(progress, request, location, flags) { - const docShell = progress.DOMWindow.docShell; - const frame = this._docShellToFrame.get(docShell); - const sameDocumentNavigation = !!(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT); - if (frame && sameDocumentNavigation) { - frame._url = location.spec; - this.emit(FrameTree.Events.SameDocumentNavigation, frame); - } - } - - _onDocShellCreated(docShell) { - // Bug 1142752: sometimes, the docshell appears to be immediately - // destroyed, bailout early to prevent random exceptions. - if (docShell.isBeingDestroyed()) - return; - // If this docShell doesn't belong to our frame tree - do nothing. - let root = docShell; - while (root.parent) - root = root.parent; - if (root === this._mainFrame._docShell) - this._createFrame(docShell); - } - - _createFrame(docShell) { - const parentFrame = this._docShellToFrame.get(docShell.parent) || null; - const frame = new Frame(this, this._runtime, docShell, parentFrame); - this._docShellToFrame.set(docShell, frame); - this._frameIdToFrame.set(frame.id(), frame); - this.emit(FrameTree.Events.FrameAttached, frame); - // Create execution context **after** reporting frame. - // This is our protocol contract. - if (frame.domWindow()) - frame._onGlobalObjectCleared(); - return frame; - } - - _onDocShellDestroyed(docShell) { - const frame = this._docShellToFrame.get(docShell); - if (frame) - this._detachFrame(frame); - } - - _detachFrame(frame) { - // Detach all children first - for (const subframe of frame._children) - this._detachFrame(subframe); - this._docShellToFrame.delete(frame._docShell); - this._frameIdToFrame.delete(frame.id()); - if (frame._parentFrame) - frame._parentFrame._children.delete(frame); - frame._parentFrame = null; - frame.dispose(); - this.emit(FrameTree.Events.FrameDetached, frame); - } -} - -FrameTree.Events = { - FrameAttached: 'frameattached', - FrameDetached: 'framedetached', - WorkerCreated: 'workercreated', - WorkerDestroyed: 'workerdestroyed', - WebSocketCreated: 'websocketcreated', - WebSocketOpened: 'websocketopened', - WebSocketClosed: 'websocketclosed', - WebSocketFrameReceived: 'websocketframereceived', - WebSocketFrameSent: 'websocketframesent', - NavigationStarted: 'navigationstarted', - NavigationCommitted: 'navigationcommitted', - NavigationAborted: 'navigationaborted', - SameDocumentNavigation: 'samedocumentnavigation', - PageReady: 'pageready', - Load: 'load', -}; - -class IsolatedWorld { - constructor(name) { - this._name = name; - this._scriptsToEvaluateOnNewDocument = []; - this._bindings = new Map(); - } -} - -class Frame { - constructor(frameTree, runtime, docShell, parentFrame) { - this._frameTree = frameTree; - this._runtime = runtime; - this._docShell = docShell; - this._children = new Set(); - this._frameId = helper.browsingContextToFrameId(this._docShell.browsingContext); - this._parentFrame = null; - this._url = ''; - if (docShell.domWindow && docShell.domWindow.location) - this._url = docShell.domWindow.location.href; - if (parentFrame) { - this._parentFrame = parentFrame; - parentFrame._children.add(this); - } - - this._lastCommittedNavigationId = null; - this._pendingNavigationId = null; - this._pendingNavigationURL = null; - - this._textInputProcessor = null; - - this._worldNameToContext = new Map(); - this._initialNavigationDone = false; - - this._webSocketListenerInnerWindowId = 0; - // WebSocketListener calls frameReceived event before webSocketOpened. - // To avoid this, serialize event reporting. - this._webSocketInfos = new Map(); - - const dispatchWebSocketFrameReceived = (webSocketSerialID, frame) => this._frameTree.emit(FrameTree.Events.WebSocketFrameReceived, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - opcode: frame.opCode, - data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload, - }); - this._webSocketListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWebSocketEventListener, ]), - - webSocketCreated: (webSocketSerialID, uri, protocols) => { - this._frameTree.emit(FrameTree.Events.WebSocketCreated, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - requestURL: uri, - }); - this._webSocketInfos.set(webSocketSerialID, { - opened: false, - pendingIncomingFrames: [], - }); - }, - - webSocketOpened: (webSocketSerialID, effectiveURI, protocols, extensions, httpChannelId) => { - this._frameTree.emit(FrameTree.Events.WebSocketOpened, { - frameId: this._frameId, - requestId: httpChannelId + '', - wsid: webSocketSerialID + '', - effectiveURL: effectiveURI, - }); - const info = this._webSocketInfos.get(webSocketSerialID); - info.opened = true; - for (const frame of info.pendingIncomingFrames) - dispatchWebSocketFrameReceived(webSocketSerialID, frame); - }, - - webSocketMessageAvailable: (webSocketSerialID, data, messageType) => { - // We don't use this event. - }, - - webSocketClosed: (webSocketSerialID, wasClean, code, reason) => { - this._webSocketInfos.delete(webSocketSerialID); - let error = ''; - if (!wasClean) { - const keys = Object.keys(Ci.nsIWebSocketChannel); - for (const key of keys) { - if (Ci.nsIWebSocketChannel[key] === code) - error = key; - } - } - this._frameTree.emit(FrameTree.Events.WebSocketClosed, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - error, - }); - }, - - frameReceived: (webSocketSerialID, frame) => { - // Report only text and binary frames. - if (frame.opCode !== 1 && frame.opCode !== 2) - return; - const info = this._webSocketInfos.get(webSocketSerialID); - if (info.opened) - dispatchWebSocketFrameReceived(webSocketSerialID, frame); - else - info.pendingIncomingFrames.push(frame); - }, - - frameSent: (webSocketSerialID, frame) => { - // Report only text and binary frames. - if (frame.opCode !== 1 && frame.opCode !== 2) - return; - this._frameTree.emit(FrameTree.Events.WebSocketFrameSent, { - frameId: this._frameId, - wsid: webSocketSerialID + '', - opcode: frame.opCode, - data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload, - }); - }, - }; - } - - _createIsolatedContext(name) { - const principal = [this.domWindow()]; // extended principal - const sandbox = Cu.Sandbox(principal, { - sandboxPrototype: this.domWindow(), - wantComponents: false, - wantExportHelpers: false, - wantXrays: true, - }); - const world = this._runtime.createExecutionContext(this.domWindow(), sandbox, { - frameId: this.id(), - name, - }); - this._worldNameToContext.set(name, world); - return world; - } - - unsafeObject(objectId) { - for (const context of this._worldNameToContext.values()) { - const result = context.unsafeObject(objectId); - if (result) - return result.object; - } - throw new Error('Cannot find object with id = ' + objectId); - } - - dispose() { - for (const context of this._worldNameToContext.values()) - this._runtime.destroyExecutionContext(context); - this._worldNameToContext.clear(); - } - - _addBinding(worldName, name, script) { - let executionContext = this._worldNameToContext.get(worldName); - if (worldName && !executionContext) - executionContext = this._createIsolatedContext(worldName); - if (executionContext) - executionContext.addBinding(name, script); - } - - _onGlobalObjectCleared() { - const webSocketService = this._frameTree._webSocketEventService; - if (this._webSocketListenerInnerWindowId) - webSocketService.removeListener(this._webSocketListenerInnerWindowId, this._webSocketListener); - this._webSocketListenerInnerWindowId = this.domWindow().windowGlobalChild.innerWindowId; - webSocketService.addListener(this._webSocketListenerInnerWindowId, this._webSocketListener); - - for (const context of this._worldNameToContext.values()) - this._runtime.destroyExecutionContext(context); - this._worldNameToContext.clear(); - - this._worldNameToContext.set('', this._runtime.createExecutionContext(this.domWindow(), this.domWindow(), { - frameId: this._frameId, - name: '', - })); - for (const [name, world] of this._frameTree._isolatedWorlds) { - if (name) - this._createIsolatedContext(name); - const executionContext = this._worldNameToContext.get(name); - // Add bindings before evaluating scripts. - for (const [name, script] of world._bindings) - executionContext.addBinding(name, script); - for (const script of world._scriptsToEvaluateOnNewDocument) - executionContext.evaluateScriptSafely(script); - } - } - - mainExecutionContext() { - return this._worldNameToContext.get(''); - } - - textInputProcessor() { - if (!this._textInputProcessor) { - this._textInputProcessor = Cc["@mozilla.org/text-input-processor;1"].createInstance(Ci.nsITextInputProcessor); - } - this._textInputProcessor.beginInputTransactionForTests(this._docShell.DOMWindow); - return this._textInputProcessor; - } - - pendingNavigationId() { - return this._pendingNavigationId; - } - - pendingNavigationURL() { - return this._pendingNavigationURL; - } - - lastCommittedNavigationId() { - return this._lastCommittedNavigationId; - } - - docShell() { - return this._docShell; - } - - domWindow() { - return this._docShell.domWindow; - } - - name() { - const frameElement = this._docShell.domWindow.frameElement; - let name = ''; - if (frameElement) - name = frameElement.getAttribute('name') || frameElement.getAttribute('id') || ''; - return name; - } - - parentFrame() { - return this._parentFrame; - } - - id() { - return this._frameId; - } - - url() { - return this._url; - } - -} - -class Worker { - constructor(frame, workerDebugger) { - this._frame = frame; - this._workerId = helper.generateId(); - this._workerDebugger = workerDebugger; - - workerDebugger.initialize('chrome://juggler/content/content/WorkerMain.js'); - - this._channel = new SimpleChannel(`content::worker[${this._workerId}]`); - this._channel.setTransport({ - sendMessage: obj => workerDebugger.postMessage(JSON.stringify(obj)), - dispose: () => {}, - }); - this._workerDebuggerListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerListener]), - onMessage: msg => void this._channel._onMessage(JSON.parse(msg)), - onClose: () => void this._channel.dispose(), - onError: (filename, lineno, message) => { - dump(`Error in worker: ${message} @${filename}:${lineno}\n`); - }, - }; - workerDebugger.addListener(this._workerDebuggerListener); - } - - channel() { - return this._channel; - } - - frame() { - return this._frame; - } - - id() { - return this._workerId; - } - - url() { - return this._workerDebugger.url; - } - - dispose() { - this._channel.dispose(); - this._workerDebugger.removeListener(this._workerDebuggerListener); - } -} - -function channelId(channel) { - if (channel instanceof Ci.nsIIdentChannel) { - const identChannel = channel.QueryInterface(Ci.nsIIdentChannel); - return String(identChannel.channelId); - } - return helper.generateId(); -} - - -var EXPORTED_SYMBOLS = ['FrameTree']; -this.FrameTree = FrameTree; - diff --git a/browser_patches/firefox-beta/juggler/content/PageAgent.js b/browser_patches/firefox-beta/juggler/content/PageAgent.js deleted file mode 100644 index 63a1807e4db1c8..00000000000000 --- a/browser_patches/firefox-beta/juggler/content/PageAgent.js +++ /dev/null @@ -1,894 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); -const dragService = Cc["@mozilla.org/widget/dragservice;1"].getService( - Ci.nsIDragService -); -const obs = Cc["@mozilla.org/observer-service;1"].getService( - Ci.nsIObserverService -); - -const helper = new Helper(); - -class WorkerData { - constructor(pageAgent, browserChannel, worker) { - this._workerRuntime = worker.channel().connect('runtime'); - this._browserWorker = browserChannel.connect(worker.id()); - this._worker = worker; - const emit = name => { - return (...args) => this._browserWorker.emit(name, ...args); - }; - this._eventListeners = [ - worker.channel().register('runtime', { - runtimeConsole: emit('runtimeConsole'), - runtimeExecutionContextCreated: emit('runtimeExecutionContextCreated'), - runtimeExecutionContextDestroyed: emit('runtimeExecutionContextDestroyed'), - }), - browserChannel.register(worker.id(), { - evaluate: (options) => this._workerRuntime.send('evaluate', options), - callFunction: (options) => this._workerRuntime.send('callFunction', options), - getObjectProperties: (options) => this._workerRuntime.send('getObjectProperties', options), - disposeObject: (options) => this._workerRuntime.send('disposeObject', options), - }), - ]; - } - - dispose() { - this._workerRuntime.dispose(); - this._browserWorker.dispose(); - helper.removeListeners(this._eventListeners); - } -} - -class PageAgent { - constructor(messageManager, browserChannel, frameTree) { - this._messageManager = messageManager; - this._browserChannel = browserChannel; - this._browserPage = browserChannel.connect('page'); - this._frameTree = frameTree; - this._runtime = frameTree.runtime(); - - this._workerData = new Map(); - - const docShell = frameTree.mainFrame().docShell(); - this._docShell = docShell; - this._initialDPPX = docShell.contentViewer.overrideDPPX; - this._dragging = false; - - // Dispatch frameAttached events for all initial frames - for (const frame of this._frameTree.frames()) { - this._onFrameAttached(frame); - if (frame.url()) - this._onNavigationCommitted(frame); - if (frame.pendingNavigationId()) - this._onNavigationStarted(frame); - } - - // Report created workers. - for (const worker of this._frameTree.workers()) - this._onWorkerCreated(worker); - - // Report execution contexts. - for (const context of this._runtime.executionContexts()) - this._onExecutionContextCreated(context); - - if (this._frameTree.isPageReady()) { - this._browserPage.emit('pageReady', {}); - const mainFrame = this._frameTree.mainFrame(); - const domWindow = mainFrame.domWindow(); - const document = domWindow ? domWindow.document : null; - const readyState = document ? document.readyState : null; - // Sometimes we initialize later than the first about:blank page is opened. - // In this case, the page might've been loaded already, and we need to issue - // the `DOMContentLoaded` and `load` events. - if (mainFrame.url() === 'about:blank' && readyState === 'complete') - this._emitAllEvents(this._frameTree.mainFrame()); - } - - this._eventListeners = [ - helper.addObserver(this._linkClicked.bind(this, false), 'juggler-link-click'), - helper.addObserver(this._linkClicked.bind(this, true), 'juggler-link-click-sync'), - helper.addObserver(this._onWindowOpenInNewContext.bind(this), 'juggler-window-open-in-new-context'), - helper.addObserver(this._filePickerShown.bind(this), 'juggler-file-picker-shown'), - helper.addEventListener(this._messageManager, 'DOMContentLoaded', this._onDOMContentLoaded.bind(this)), - helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'), - helper.on(this._frameTree, 'load', this._onLoad.bind(this)), - helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)), - helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)), - helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)), - helper.on(this._frameTree, 'navigationcommitted', this._onNavigationCommitted.bind(this)), - helper.on(this._frameTree, 'navigationaborted', this._onNavigationAborted.bind(this)), - helper.on(this._frameTree, 'samedocumentnavigation', this._onSameDocumentNavigation.bind(this)), - helper.on(this._frameTree, 'pageready', () => this._browserPage.emit('pageReady', {})), - helper.on(this._frameTree, 'workercreated', this._onWorkerCreated.bind(this)), - helper.on(this._frameTree, 'workerdestroyed', this._onWorkerDestroyed.bind(this)), - helper.on(this._frameTree, 'websocketcreated', event => this._browserPage.emit('webSocketCreated', event)), - helper.on(this._frameTree, 'websocketopened', event => this._browserPage.emit('webSocketOpened', event)), - helper.on(this._frameTree, 'websocketframesent', event => this._browserPage.emit('webSocketFrameSent', event)), - helper.on(this._frameTree, 'websocketframereceived', event => this._browserPage.emit('webSocketFrameReceived', event)), - helper.on(this._frameTree, 'websocketclosed', event => this._browserPage.emit('webSocketClosed', event)), - helper.addObserver(this._onWindowOpen.bind(this), 'webNavigation-createdNavigationTarget-from-js'), - this._runtime.events.onErrorFromWorker((domWindow, message, stack) => { - const frame = this._frameTree.frameForDocShell(domWindow.docShell); - if (!frame) - return; - this._browserPage.emit('pageUncaughtError', { - frameId: frame.id(), - message, - stack, - }); - }), - this._runtime.events.onConsoleMessage(msg => this._browserPage.emit('runtimeConsole', msg)), - this._runtime.events.onRuntimeError(this._onRuntimeError.bind(this)), - this._runtime.events.onExecutionContextCreated(this._onExecutionContextCreated.bind(this)), - this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)), - this._runtime.events.onBindingCalled(this._onBindingCalled.bind(this)), - browserChannel.register('page', { - addBinding: ({ worldName, name, script }) => this._frameTree.addBinding(worldName, name, script), - adoptNode: this._adoptNode.bind(this), - crash: this._crash.bind(this), - describeNode: this._describeNode.bind(this), - dispatchKeyEvent: this._dispatchKeyEvent.bind(this), - dispatchMouseEvent: this._dispatchMouseEvent.bind(this), - dispatchTouchEvent: this._dispatchTouchEvent.bind(this), - dispatchTapEvent: this._dispatchTapEvent.bind(this), - getContentQuads: this._getContentQuads.bind(this), - getFullAXTree: this._getFullAXTree.bind(this), - goBack: this._goBack.bind(this), - goForward: this._goForward.bind(this), - insertText: this._insertText.bind(this), - navigate: this._navigate.bind(this), - reload: this._reload.bind(this), - scrollIntoViewIfNeeded: this._scrollIntoViewIfNeeded.bind(this), - setCacheDisabled: this._setCacheDisabled.bind(this), - setFileInputFiles: this._setFileInputFiles.bind(this), - setInterceptFileChooserDialog: this._setInterceptFileChooserDialog.bind(this), - evaluate: this._runtime.evaluate.bind(this._runtime), - callFunction: this._runtime.callFunction.bind(this._runtime), - getObjectProperties: this._runtime.getObjectProperties.bind(this._runtime), - disposeObject: this._runtime.disposeObject.bind(this._runtime), - }), - ]; - } - - _setCacheDisabled({cacheDisabled}) { - const enable = Ci.nsIRequest.LOAD_NORMAL; - const disable = Ci.nsIRequest.LOAD_BYPASS_CACHE | - Ci.nsIRequest.INHIBIT_CACHING; - - const docShell = this._frameTree.mainFrame().docShell(); - docShell.defaultLoadFlags = cacheDisabled ? disable : enable; - } - - _emitAllEvents(frame) { - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'DOMContentLoaded', - }); - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'load', - }); - } - - _onExecutionContextCreated(executionContext) { - this._browserPage.emit('runtimeExecutionContextCreated', { - executionContextId: executionContext.id(), - auxData: executionContext.auxData(), - }); - } - - _onExecutionContextDestroyed(executionContext) { - this._browserPage.emit('runtimeExecutionContextDestroyed', { - executionContextId: executionContext.id(), - }); - } - - _onWorkerCreated(worker) { - const workerData = new WorkerData(this, this._browserChannel, worker); - this._workerData.set(worker.id(), workerData); - this._browserPage.emit('pageWorkerCreated', { - workerId: worker.id(), - frameId: worker.frame().id(), - url: worker.url(), - }); - } - - _onWorkerDestroyed(worker) { - const workerData = this._workerData.get(worker.id()); - if (!workerData) - return; - this._workerData.delete(worker.id()); - workerData.dispose(); - this._browserPage.emit('pageWorkerDestroyed', { - workerId: worker.id(), - }); - } - - _onWindowOpen(subject) { - if (!(subject instanceof Ci.nsIPropertyBag2)) - return; - const props = subject.QueryInterface(Ci.nsIPropertyBag2); - const hasUrl = props.hasKey('url'); - const createdDocShell = props.getPropertyAsInterface('createdTabDocShell', Ci.nsIDocShell); - if (!hasUrl && createdDocShell === this._docShell && this._frameTree.forcePageReady()) - this._emitAllEvents(this._frameTree.mainFrame()); - } - - _setInterceptFileChooserDialog({enabled}) { - this._docShell.fileInputInterceptionEnabled = !!enabled; - } - - _linkClicked(sync, anchorElement) { - if (anchorElement.ownerGlobal.docShell !== this._docShell) - return; - this._browserPage.emit('pageLinkClicked', { phase: sync ? 'after' : 'before' }); - } - - _onWindowOpenInNewContext(docShell) { - // TODO: unify this with _onWindowOpen if possible. - const frame = this._frameTree.frameForDocShell(docShell); - if (!frame) - return; - this._browserPage.emit('pageWillOpenNewWindowAsynchronously'); - } - - _filePickerShown(inputElement) { - const frame = this._findFrameForNode(inputElement); - if (!frame) - return; - this._browserPage.emit('pageFileChooserOpened', { - executionContextId: frame.mainExecutionContext().id(), - element: frame.mainExecutionContext().rawValueToRemoteObject(inputElement) - }); - } - - _findFrameForNode(node) { - return this._frameTree.frames().find(frame => { - const doc = frame.domWindow().document; - return node === doc || node.ownerDocument === doc; - }); - } - - _onDOMContentLoaded(event) { - if (!event.target.ownerGlobal) - return; - const docShell = event.target.ownerGlobal.docShell; - const frame = this._frameTree.frameForDocShell(docShell); - if (!frame) - return; - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'DOMContentLoaded', - }); - } - - _onRuntimeError({ executionContext, message, stack }) { - this._browserPage.emit('pageUncaughtError', { - frameId: executionContext.auxData().frameId, - message: message.toString(), - stack: stack.toString(), - }); - } - - _onDocumentOpenLoad(document) { - const docShell = document.ownerGlobal.docShell; - const frame = this._frameTree.frameForDocShell(docShell); - if (!frame) - return; - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'load' - }); - } - - _onLoad(frame) { - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'load' - }); - } - - _onNavigationStarted(frame) { - this._browserPage.emit('pageNavigationStarted', { - frameId: frame.id(), - navigationId: frame.pendingNavigationId(), - url: frame.pendingNavigationURL(), - }); - } - - _onNavigationAborted(frame, navigationId, errorText) { - this._browserPage.emit('pageNavigationAborted', { - frameId: frame.id(), - navigationId, - errorText, - }); - if (!frame._initialNavigationDone && frame !== this._frameTree.mainFrame()) - this._emitAllEvents(frame); - frame._initialNavigationDone = true; - } - - _onSameDocumentNavigation(frame) { - this._browserPage.emit('pageSameDocumentNavigation', { - frameId: frame.id(), - url: frame.url(), - }); - } - - _onNavigationCommitted(frame) { - this._browserPage.emit('pageNavigationCommitted', { - frameId: frame.id(), - navigationId: frame.lastCommittedNavigationId() || undefined, - url: frame.url(), - name: frame.name(), - }); - frame._initialNavigationDone = true; - } - - _onFrameAttached(frame) { - this._browserPage.emit('pageFrameAttached', { - frameId: frame.id(), - parentFrameId: frame.parentFrame() ? frame.parentFrame().id() : undefined, - }); - } - - _onFrameDetached(frame) { - this._browserPage.emit('pageFrameDetached', { - frameId: frame.id(), - }); - } - - _onBindingCalled({executionContextId, name, payload}) { - this._browserPage.emit('pageBindingCalled', { - executionContextId, - name, - payload - }); - } - - dispose() { - for (const workerData of this._workerData.values()) - workerData.dispose(); - this._workerData.clear(); - helper.removeListeners(this._eventListeners); - } - - async _navigate({frameId, url, referer}) { - try { - const uri = NetUtil.newURI(url); - } catch (e) { - throw new Error(`Invalid url: "${url}"`); - } - let referrerURI = null; - let referrerInfo = null; - if (referer) { - try { - referrerURI = NetUtil.newURI(referer); - const ReferrerInfo = Components.Constructor( - '@mozilla.org/referrer-info;1', - 'nsIReferrerInfo', - 'init' - ); - referrerInfo = new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, referrerURI); - } catch (e) { - throw new Error(`Invalid referer: "${referer}"`); - } - } - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell().QueryInterface(Ci.nsIWebNavigation); - docShell.loadURI(url, { - triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), - flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE, - referrerInfo, - postData: null, - headers: null, - }); - return {navigationId: frame.pendingNavigationId(), navigationURL: frame.pendingNavigationURL()}; - } - - async _reload({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell().QueryInterface(Ci.nsIWebNavigation); - docShell.reload(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); - } - - async _goBack({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell(); - if (!docShell.canGoBack) - return {success: false}; - docShell.goBack(); - return {success: true}; - } - - async _goForward({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell(); - if (!docShell.canGoForward) - return {success: false}; - docShell.goForward(); - return {success: true}; - } - - async _adoptNode({frameId, objectId, executionContextId}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - const context = this._runtime.findExecutionContext(executionContextId); - const fromPrincipal = unsafeObject.nodePrincipal; - const toFrame = this._frameTree.frame(context.auxData().frameId); - const toPrincipal = toFrame.domWindow().document.nodePrincipal; - if (!toPrincipal.subsumes(fromPrincipal)) - return { remoteObject: null }; - return { remoteObject: context.rawValueToRemoteObject(unsafeObject) }; - } - - async _setFileInputFiles({objectId, frameId, files}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - if (!unsafeObject) - throw new Error('Object is not input!'); - const nsFiles = await Promise.all(files.map(filePath => File.createFromFileName(filePath))); - unsafeObject.mozSetFileArray(nsFiles); - } - - _getContentQuads({objectId, frameId}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - if (!unsafeObject.getBoxQuads) - throw new Error('RemoteObject is not a node'); - const quads = unsafeObject.getBoxQuads({relativeTo: this._frameTree.mainFrame().domWindow().document, recurseWhenNoFrame: true}).map(quad => { - return { - p1: {x: quad.p1.x, y: quad.p1.y}, - p2: {x: quad.p2.x, y: quad.p2.y}, - p3: {x: quad.p3.x, y: quad.p3.y}, - p4: {x: quad.p4.x, y: quad.p4.y}, - }; - }); - return {quads}; - } - - _describeNode({objectId, frameId}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - const browsingContextGroup = frame.docShell().browsingContext.group; - const frames = this._frameTree.allFramesInBrowsingContextGroup(browsingContextGroup); - let contentFrame; - let ownerFrame; - for (const frame of frames) { - if (unsafeObject.contentWindow && frame.docShell() === unsafeObject.contentWindow.docShell) - contentFrame = frame; - const document = frame.domWindow().document; - if (unsafeObject === document || unsafeObject.ownerDocument === document) - ownerFrame = frame; - } - return { - contentFrameId: contentFrame ? contentFrame.id() : undefined, - ownerFrameId: ownerFrame ? ownerFrame.id() : undefined, - }; - } - - async _scrollIntoViewIfNeeded({objectId, frameId, rect}) { - const frame = this._frameTree.frame(frameId); - if (!frame) - throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); - if (!unsafeObject.isConnected) - throw new Error('Node is detached from document'); - if (!rect) - rect = { x: -1, y: -1, width: -1, height: -1}; - if (unsafeObject.scrollRectIntoViewIfNeeded) - unsafeObject.scrollRectIntoViewIfNeeded(rect.x, rect.y, rect.width, rect.height); - else - throw new Error('Node does not have a layout object'); - } - - _getNodeBoundingBox(unsafeObject) { - if (!unsafeObject.getBoxQuads) - throw new Error('RemoteObject is not a node'); - const quads = unsafeObject.getBoxQuads({relativeTo: this._frameTree.mainFrame().domWindow().document}); - if (!quads.length) - return; - let x1 = Infinity; - let y1 = Infinity; - let x2 = -Infinity; - let y2 = -Infinity; - for (const quad of quads) { - const boundingBox = quad.getBounds(); - x1 = Math.min(boundingBox.x, x1); - y1 = Math.min(boundingBox.y, y1); - x2 = Math.max(boundingBox.x + boundingBox.width, x2); - y2 = Math.max(boundingBox.y + boundingBox.height, y2); - } - return {x: x1, y: y1, width: x2 - x1, height: y2 - y1}; - } - - async _dispatchKeyEvent({type, keyCode, code, key, repeat, location, text}) { - // key events don't fire if we are dragging. - if (this._dragging) { - if (type === 'keydown' && key === 'Escape') - this._cancelDragIfNeeded(); - return; - } - const frame = this._frameTree.mainFrame(); - const tip = frame.textInputProcessor(); - if (key === 'Meta' && Services.appinfo.OS !== 'Darwin') - key = 'OS'; - else if (key === 'OS' && Services.appinfo.OS === 'Darwin') - key = 'Meta'; - let keyEvent = new (frame.domWindow().KeyboardEvent)("", { - key, - code, - location, - repeat, - keyCode - }); - if (type === 'keydown') { - if (text && text !== key) { - tip.commitCompositionWith(text, keyEvent); - } else { - const flags = 0; - tip.keydown(keyEvent, flags); - } - } else if (type === 'keyup') { - if (text) - throw new Error(`keyup does not support text option`); - const flags = 0; - tip.keyup(keyEvent, flags); - } else { - throw new Error(`Unknown type ${type}`); - } - } - - async _dispatchTouchEvent({type, touchPoints, modifiers}) { - const frame = this._frameTree.mainFrame(); - const defaultPrevented = frame.domWindow().windowUtils.sendTouchEvent( - type.toLowerCase(), - touchPoints.map((point, id) => id), - touchPoints.map(point => point.x), - touchPoints.map(point => point.y), - touchPoints.map(point => point.radiusX === undefined ? 1.0 : point.radiusX), - touchPoints.map(point => point.radiusY === undefined ? 1.0 : point.radiusY), - touchPoints.map(point => point.rotationAngle === undefined ? 0.0 : point.rotationAngle), - touchPoints.map(point => point.force === undefined ? 1.0 : point.force), - touchPoints.length, - modifiers); - return {defaultPrevented}; - } - - async _dispatchTapEvent({x, y, modifiers}) { - // Force a layout at the point in question, because touch events - // do not seem to trigger one like mouse events. - this._frameTree.mainFrame().domWindow().windowUtils.elementFromPoint( - x, - y, - false /* aIgnoreRootScrollFrame */, - true /* aFlushLayout */); - - const {defaultPrevented: startPrevented} = await this._dispatchTouchEvent({ - type: 'touchstart', - modifiers, - touchPoints: [{x, y}] - }); - const {defaultPrevented: endPrevented} = await this._dispatchTouchEvent({ - type: 'touchend', - modifiers, - touchPoints: [{x, y}] - }); - if (startPrevented || endPrevented) - return; - - const frame = this._frameTree.mainFrame(); - frame.domWindow().windowUtils.sendMouseEvent( - 'mousemove', - x, - y, - 0 /*button*/, - 0 /*clickCount*/, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - 0 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); - - frame.domWindow().windowUtils.sendMouseEvent( - 'mousedown', - x, - y, - 0 /*button*/, - 1 /*clickCount*/, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - 1 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); - - frame.domWindow().windowUtils.sendMouseEvent( - 'mouseup', - x, - y, - 0 /*button*/, - 1 /*clickCount*/, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - 0 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); - } - - _startDragSessionIfNeeded() { - const sess = dragService.getCurrentSession(); - if (sess) return; - dragService.startDragSessionForTests( - Ci.nsIDragService.DRAGDROP_ACTION_MOVE | - Ci.nsIDragService.DRAGDROP_ACTION_COPY | - Ci.nsIDragService.DRAGDROP_ACTION_LINK - ); - } - - _simulateDragEvent(type, x, y, modifiers) { - const window = this._frameTree.mainFrame().domWindow(); - const element = window.windowUtils.elementFromPoint(x, y, false, false); - const event = window.document.createEvent('DragEvent'); - - event.initDragEvent( - type, - true /* bubble */, - true /* cancelable */, - window, - 0 /* clickCount */, - window.mozInnerScreenX + x, - window.mozInnerScreenY + y, - x, - y, - modifiers & 2 /* ctrlkey */, - modifiers & 1 /* altKey */, - modifiers & 4 /* shiftKey */, - modifiers & 8 /* metaKey */, - 0 /* button */, // firefox always has the button as 0 on drops, regardless of which was pressed - null /* relatedTarget */, - null, - ); - if (type !== 'drop' || dragService.dragAction) - window.windowUtils.dispatchDOMEventViaPresShellForTesting(element, event); - if (type === 'drop') - this._cancelDragIfNeeded(); - } - - _cancelDragIfNeeded() { - this._dragging = false; - const sess = dragService.getCurrentSession(); - if (sess) - dragService.endDragSession(true); - } - - async _dispatchMouseEvent({type, x, y, button, clickCount, modifiers, buttons}) { - this._startDragSessionIfNeeded(); - const trapDrag = subject => { - this._dragging = true; - } - - // Don't send mouse events if there is an active drag - if (!this._dragging) { - const frame = this._frameTree.mainFrame(); - - obs.addObserver(trapDrag, 'on-datatransfer-available'); - frame.domWindow().windowUtils.sendMouseEvent( - type, - x, - y, - button, - clickCount, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - undefined /*inputSource*/, - true /*isDOMEventSynthesized*/, - false /*isWidgetEventSynthesized*/, - buttons); - obs.removeObserver(trapDrag, 'on-datatransfer-available'); - - if (type === 'mousedown' && button === 2) { - frame.domWindow().windowUtils.sendMouseEvent( - 'contextmenu', - x, - y, - button, - clickCount, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - undefined /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - undefined /*isWidgetEventSynthesized*/, - buttons); - } - } - - // update drag state - if (this._dragging) { - if (type === 'mousemove') - this._simulateDragEvent('dragover', x, y, modifiers); - else if (type === 'mouseup') // firefox will do drops when any mouse button is released - this._simulateDragEvent('drop', x, y, modifiers); - } else { - this._cancelDragIfNeeded(); - } - } - - async _insertText({text}) { - const frame = this._frameTree.mainFrame(); - frame.textInputProcessor().commitCompositionWith(text); - } - - async _crash() { - dump(`Crashing intentionally\n`); - // This is to intentionally crash the frame. - // We crash by using js-ctypes and dereferencing - // a bad pointer. The crash should happen immediately - // upon loading this frame script. - const { ctypes } = ChromeUtils.import('resource://gre/modules/ctypes.jsm'); - ChromeUtils.privateNoteIntentionalCrash(); - const zero = new ctypes.intptr_t(8); - const badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t)); - badptr.contents; - } - - async _getFullAXTree({objectId}) { - let unsafeObject = null; - if (objectId) { - unsafeObject = this._frameTree.mainFrame().unsafeObject(objectId); - if (!unsafeObject) - throw new Error(`No object found for id "${objectId}"`); - } - - const service = Cc["@mozilla.org/accessibilityService;1"] - .getService(Ci.nsIAccessibilityService); - const document = this._frameTree.mainFrame().domWindow().document; - const docAcc = service.getAccessibleFor(document); - - while (docAcc.document.isUpdatePendingForJugglerAccessibility) - await new Promise(x => this._frameTree.mainFrame().domWindow().requestAnimationFrame(x)); - - async function waitForQuiet() { - let state = {}; - docAcc.getState(state, {}); - if ((state.value & Ci.nsIAccessibleStates.STATE_BUSY) == 0) - return; - let resolve, reject; - const promise = new Promise((x, y) => {resolve = x, reject = y}); - let eventObserver = { - observe(subject, topic) { - if (topic !== "accessible-event") { - return; - } - - // If event type does not match expected type, skip the event. - let event = subject.QueryInterface(Ci.nsIAccessibleEvent); - if (event.eventType !== Ci.nsIAccessibleEvent.EVENT_STATE_CHANGE) { - return; - } - - // If event's accessible does not match expected accessible, - // skip the event. - if (event.accessible !== docAcc) { - return; - } - - Services.obs.removeObserver(this, "accessible-event"); - resolve(); - }, - }; - Services.obs.addObserver(eventObserver, "accessible-event"); - return promise; - } - function buildNode(accElement) { - let a = {}, b = {}; - accElement.getState(a, b); - const tree = { - role: service.getStringRole(accElement.role), - name: accElement.name || '', - }; - if (unsafeObject && unsafeObject === accElement.DOMNode) - tree.foundObject = true; - for (const userStringProperty of [ - 'value', - 'description' - ]) { - tree[userStringProperty] = accElement[userStringProperty] || undefined; - } - - const states = {}; - for (const name of service.getStringStates(a.value, b.value)) - states[name] = true; - for (const name of ['selected', - 'focused', - 'pressed', - 'focusable', - 'required', - 'invalid', - 'modal', - 'editable', - 'busy', - 'checked', - 'multiselectable']) { - if (states[name]) - tree[name] = true; - } - - if (states['multi line']) - tree['multiline'] = true; - if (states['editable'] && states['readonly']) - tree['readonly'] = true; - if (states['checked']) - tree['checked'] = true; - if (states['mixed']) - tree['checked'] = 'mixed'; - if (states['expanded']) - tree['expanded'] = true; - else if (states['collapsed']) - tree['expanded'] = false; - if (!states['enabled']) - tree['disabled'] = true; - - const attributes = {}; - if (accElement.attributes) { - for (const { key, value } of accElement.attributes.enumerate()) { - attributes[key] = value; - } - } - for (const numericalProperty of ['level']) { - if (numericalProperty in attributes) - tree[numericalProperty] = parseFloat(attributes[numericalProperty]); - } - for (const stringProperty of ['tag', 'roledescription', 'valuetext', 'orientation', 'autocomplete', 'keyshortcuts', 'haspopup']) { - if (stringProperty in attributes) - tree[stringProperty] = attributes[stringProperty]; - } - const children = []; - - for (let child = accElement.firstChild; child; child = child.nextSibling) { - children.push(buildNode(child)); - } - if (children.length) - tree.children = children; - return tree; - } - await waitForQuiet(); - return { - tree: buildNode(docAcc) - }; - } -} - -var EXPORTED_SYMBOLS = ['PageAgent']; -this.PageAgent = PageAgent; - diff --git a/browser_patches/firefox-beta/juggler/content/Runtime.js b/browser_patches/firefox-beta/juggler/content/Runtime.js deleted file mode 100644 index 20c046a1dbd36c..00000000000000 --- a/browser_patches/firefox-beta/juggler/content/Runtime.js +++ /dev/null @@ -1,596 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -// Note: this file should be loadabale with eval() into worker environment. -// Avoid Components.*, ChromeUtils and global const variables. - -if (!this.Debugger) { - // Worker has a Debugger defined already. - const {addDebuggerToGlobal} = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm", {}); - addDebuggerToGlobal(Components.utils.getGlobalForObject(this)); -} - -let lastId = 0; -function generateId() { - return 'id-' + (++lastId); -} - -const consoleLevelToProtocolType = { - 'dir': 'dir', - 'log': 'log', - 'debug': 'debug', - 'info': 'info', - 'error': 'error', - 'warn': 'warning', - 'dirxml': 'dirxml', - 'table': 'table', - 'trace': 'trace', - 'clear': 'clear', - 'group': 'startGroup', - 'groupCollapsed': 'startGroupCollapsed', - 'groupEnd': 'endGroup', - 'assert': 'assert', - 'profile': 'profile', - 'profileEnd': 'profileEnd', - 'count': 'count', - 'countReset': 'countReset', - 'time': null, - 'timeLog': 'timeLog', - 'timeEnd': 'timeEnd', - 'timeStamp': 'timeStamp', -}; - -const disallowedMessageCategories = new Set([ - 'XPConnect JavaScript', - 'component javascript', - 'chrome javascript', - 'chrome registration', - 'XBL', - 'XBL Prototype Handler', - 'XBL Content Sink', - 'xbl javascript', -]); - -class Runtime { - constructor(isWorker = false) { - this._debugger = new Debugger(); - this._pendingPromises = new Map(); - this._executionContexts = new Map(); - this._windowToExecutionContext = new Map(); - this._eventListeners = []; - if (isWorker) { - this._registerWorkerConsoleHandler(); - } else { - const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); - this._registerConsoleServiceListener(Services); - this._registerConsoleAPIListener(Services); - } - // We can't use event listener here to be compatible with Worker Global Context. - // Use plain callbacks instead. - this.events = { - onConsoleMessage: createEvent(), - onRuntimeError: createEvent(), - onErrorFromWorker: createEvent(), - onExecutionContextCreated: createEvent(), - onExecutionContextDestroyed: createEvent(), - onBindingCalled: createEvent(), - }; - } - - executionContexts() { - return [...this._executionContexts.values()]; - } - - async evaluate({executionContextId, expression, returnByValue}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - const exceptionDetails = {}; - let result = await executionContext.evaluateScript(expression, exceptionDetails); - if (!result) - return {exceptionDetails}; - if (returnByValue) - result = executionContext.ensureSerializedToValue(result); - return {result}; - } - - async callFunction({executionContextId, functionDeclaration, args, returnByValue}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - const exceptionDetails = {}; - let result = await executionContext.evaluateFunction(functionDeclaration, args, exceptionDetails); - if (!result) - return {exceptionDetails}; - if (returnByValue) - result = executionContext.ensureSerializedToValue(result); - return {result}; - } - - async getObjectProperties({executionContextId, objectId}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - return {properties: executionContext.getObjectProperties(objectId)}; - } - - async disposeObject({executionContextId, objectId}) { - const executionContext = this.findExecutionContext(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - return executionContext.disposeObject(objectId); - } - - _registerConsoleServiceListener(Services) { - const Ci = Components.interfaces; - const consoleServiceListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIConsoleListener]), - - observe: message => { - if (!(message instanceof Ci.nsIScriptError) || !message.outerWindowID || - !message.category || disallowedMessageCategories.has(message.category)) { - return; - } - const errorWindow = Services.wm.getOuterWindowWithId(message.outerWindowID); - if (message.category === 'Web Worker' && message.logLevel === Ci.nsIConsoleMessage.error) { - emitEvent(this.events.onErrorFromWorker, errorWindow, message.message, '' + message.stack); - return; - } - const executionContext = this._windowToExecutionContext.get(errorWindow); - if (!executionContext) { - return; - } - const typeNames = { - [Ci.nsIConsoleMessage.debug]: 'debug', - [Ci.nsIConsoleMessage.info]: 'info', - [Ci.nsIConsoleMessage.warn]: 'warn', - [Ci.nsIConsoleMessage.error]: 'error', - }; - if (!message.hasException) { - emitEvent(this.events.onConsoleMessage, { - args: [{ - value: message.message, - }], - type: typeNames[message.logLevel], - executionContextId: executionContext.id(), - location: { - lineNumber: message.lineNumber, - columnNumber: message.columnNumber, - url: message.sourceName, - }, - }); - } else { - emitEvent(this.events.onRuntimeError, { - executionContext, - message: message.errorMessage, - stack: message.stack.toString(), - }); - } - }, - }; - Services.console.registerListener(consoleServiceListener); - this._eventListeners.push(() => Services.console.unregisterListener(consoleServiceListener)); - } - - _registerConsoleAPIListener(Services) { - const Ci = Components.interfaces; - const Cc = Components.classes; - const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage); - const onMessage = ({ wrappedJSObject }) => { - const executionContext = Array.from(this._executionContexts.values()).find(context => { - // There is no easy way to determine isolated world context and we normally don't write - // objects to console from utility worlds so we always return main world context here. - if (context._isIsolatedWorldContext()) - return false; - const domWindow = context._domWindow; - return domWindow && domWindow.windowGlobalChild.innerWindowId === wrappedJSObject.innerID; - }); - if (!executionContext) - return; - this._onConsoleMessage(executionContext, wrappedJSObject); - } - ConsoleAPIStorage.addLogEventListener( - onMessage, - Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal) - ); - this._eventListeners.push(() => ConsoleAPIStorage.removeLogEventListener(onMessage)); - } - - _registerWorkerConsoleHandler() { - setConsoleEventHandler(message => { - const executionContext = Array.from(this._executionContexts.values())[0]; - this._onConsoleMessage(executionContext, message); - }); - this._eventListeners.push(() => setConsoleEventHandler(null)); - } - - _onConsoleMessage(executionContext, message) { - const type = consoleLevelToProtocolType[message.level]; - if (!type) - return; - const args = message.arguments.map(arg => executionContext.rawValueToRemoteObject(arg)); - emitEvent(this.events.onConsoleMessage, { - args, - type, - executionContextId: executionContext.id(), - location: { - lineNumber: message.lineNumber - 1, - columnNumber: message.columnNumber - 1, - url: message.filename, - }, - }); - } - - dispose() { - for (const tearDown of this._eventListeners) - tearDown.call(null); - this._eventListeners = []; - } - - async _awaitPromise(executionContext, obj, exceptionDetails = {}) { - if (obj.promiseState === 'fulfilled') - return {success: true, obj: obj.promiseValue}; - if (obj.promiseState === 'rejected') { - const debuggee = executionContext._debuggee; - exceptionDetails.text = debuggee.executeInGlobalWithBindings('e.message', {e: obj.promiseReason}).return; - exceptionDetails.stack = debuggee.executeInGlobalWithBindings('e.stack', {e: obj.promiseReason}).return; - return {success: false, obj: null}; - } - let resolve, reject; - const promise = new Promise((a, b) => { - resolve = a; - reject = b; - }); - this._pendingPromises.set(obj.promiseID, {resolve, reject, executionContext, exceptionDetails}); - if (this._pendingPromises.size === 1) - this._debugger.onPromiseSettled = this._onPromiseSettled.bind(this); - return await promise; - } - - _onPromiseSettled(obj) { - const pendingPromise = this._pendingPromises.get(obj.promiseID); - if (!pendingPromise) - return; - this._pendingPromises.delete(obj.promiseID); - if (!this._pendingPromises.size) - this._debugger.onPromiseSettled = undefined; - - if (obj.promiseState === 'fulfilled') { - pendingPromise.resolve({success: true, obj: obj.promiseValue}); - return; - }; - const debuggee = pendingPromise.executionContext._debuggee; - pendingPromise.exceptionDetails.text = debuggee.executeInGlobalWithBindings('e.message', {e: obj.promiseReason}).return; - pendingPromise.exceptionDetails.stack = debuggee.executeInGlobalWithBindings('e.stack', {e: obj.promiseReason}).return; - pendingPromise.resolve({success: false, obj: null}); - } - - createExecutionContext(domWindow, contextGlobal, auxData) { - // Note: domWindow is null for workers. - const context = new ExecutionContext(this, domWindow, contextGlobal, auxData); - this._executionContexts.set(context._id, context); - if (domWindow) - this._windowToExecutionContext.set(domWindow, context); - emitEvent(this.events.onExecutionContextCreated, context); - return context; - } - - findExecutionContext(executionContextId) { - const executionContext = this._executionContexts.get(executionContextId); - if (!executionContext) - throw new Error('Failed to find execution context with id = ' + executionContextId); - return executionContext; - } - - destroyExecutionContext(destroyedContext) { - for (const [promiseID, {reject, executionContext}] of this._pendingPromises) { - if (executionContext === destroyedContext) { - reject(new Error('Execution context was destroyed!')); - this._pendingPromises.delete(promiseID); - } - } - if (!this._pendingPromises.size) - this._debugger.onPromiseSettled = undefined; - this._debugger.removeDebuggee(destroyedContext._contextGlobal); - this._executionContexts.delete(destroyedContext._id); - if (destroyedContext._domWindow) - this._windowToExecutionContext.delete(destroyedContext._domWindow); - emitEvent(this.events.onExecutionContextDestroyed, destroyedContext); - } -} - -class ExecutionContext { - constructor(runtime, domWindow, contextGlobal, auxData) { - this._runtime = runtime; - this._domWindow = domWindow; - this._contextGlobal = contextGlobal; - this._debuggee = runtime._debugger.addDebuggee(contextGlobal); - this._remoteObjects = new Map(); - this._id = generateId(); - this._auxData = auxData; - this._jsonStringifyObject = this._debuggee.executeInGlobal(`((stringify, object) => { - const oldToJSON = Date.prototype.toJSON; - Date.prototype.toJSON = undefined; - const oldArrayToJSON = Array.prototype.toJSON; - const oldArrayHadToJSON = Array.prototype.hasOwnProperty('toJSON'); - if (oldArrayHadToJSON) - Array.prototype.toJSON = undefined; - - let hasSymbol = false; - const result = stringify(object, (key, value) => { - if (typeof value === 'symbol') - hasSymbol = true; - return value; - }); - - Date.prototype.toJSON = oldToJSON; - if (oldArrayHadToJSON) - Array.prototype.toJSON = oldArrayToJSON; - - return hasSymbol ? undefined : result; - }).bind(null, JSON.stringify.bind(JSON))`).return; - } - - id() { - return this._id; - } - - auxData() { - return this._auxData; - } - - _isIsolatedWorldContext() { - return !!this._auxData.name; - } - - async evaluateScript(script, exceptionDetails = {}) { - const userInputHelper = this._domWindow ? this._domWindow.windowUtils.setHandlingUserInput(true) : null; - if (this._domWindow && this._domWindow.document) - this._domWindow.document.notifyUserGestureActivation(); - - let {success, obj} = this._getResult(this._debuggee.executeInGlobal(script), exceptionDetails); - userInputHelper && userInputHelper.destruct(); - if (!success) - return null; - if (obj && obj.isPromise) { - const awaitResult = await this._runtime._awaitPromise(this, obj, exceptionDetails); - if (!awaitResult.success) - return null; - obj = awaitResult.obj; - } - return this._createRemoteObject(obj); - } - - evaluateScriptSafely(script) { - try { - this._debuggee.executeInGlobal(script); - } catch (e) { - dump(`ERROR: ${e.message}\n${e.stack}\n`); - } - } - - async evaluateFunction(functionText, args, exceptionDetails = {}) { - const funEvaluation = this._getResult(this._debuggee.executeInGlobal('(' + functionText + ')'), exceptionDetails); - if (!funEvaluation.success) - return null; - if (!funEvaluation.obj.callable) - throw new Error('functionText does not evaluate to a function!'); - args = args.map(arg => { - if (arg.objectId) { - if (!this._remoteObjects.has(arg.objectId)) - throw new Error('Cannot find object with id = ' + arg.objectId); - return this._remoteObjects.get(arg.objectId); - } - switch (arg.unserializableValue) { - case 'Infinity': return Infinity; - case '-Infinity': return -Infinity; - case '-0': return -0; - case 'NaN': return NaN; - default: return this._toDebugger(arg.value); - } - }); - const userInputHelper = this._domWindow ? this._domWindow.windowUtils.setHandlingUserInput(true) : null; - if (this._domWindow && this._domWindow.document) - this._domWindow.document.notifyUserGestureActivation(); - let {success, obj} = this._getResult(funEvaluation.obj.apply(null, args), exceptionDetails); - userInputHelper && userInputHelper.destruct(); - if (!success) - return null; - if (obj && obj.isPromise) { - const awaitResult = await this._runtime._awaitPromise(this, obj, exceptionDetails); - if (!awaitResult.success) - return null; - obj = awaitResult.obj; - } - return this._createRemoteObject(obj); - } - - addBinding(name, script) { - Cu.exportFunction((...args) => { - emitEvent(this._runtime.events.onBindingCalled, { - executionContextId: this._id, - name, - payload: args[0], - }); - }, this._contextGlobal, { - defineAs: name, - }); - this.evaluateScriptSafely(script); - } - - unsafeObject(objectId) { - if (!this._remoteObjects.has(objectId)) - return; - return { object: this._remoteObjects.get(objectId).unsafeDereference() }; - } - - rawValueToRemoteObject(rawValue) { - const debuggerObj = this._debuggee.makeDebuggeeValue(rawValue); - return this._createRemoteObject(debuggerObj); - } - - _instanceOf(debuggerObj, rawObj, className) { - if (this._domWindow) - return rawObj instanceof this._domWindow[className]; - return this._debuggee.executeInGlobalWithBindings('o instanceof this[className]', {o: debuggerObj, className: this._debuggee.makeDebuggeeValue(className)}).return; - } - - _createRemoteObject(debuggerObj) { - if (debuggerObj instanceof Debugger.Object) { - const objectId = generateId(); - this._remoteObjects.set(objectId, debuggerObj); - const rawObj = debuggerObj.unsafeDereference(); - const type = typeof rawObj; - let subtype = undefined; - if (debuggerObj.isProxy) - subtype = 'proxy'; - else if (Array.isArray(rawObj)) - subtype = 'array'; - else if (Object.is(rawObj, null)) - subtype = 'null'; - else if (this._instanceOf(debuggerObj, rawObj, 'Node')) - subtype = 'node'; - else if (this._instanceOf(debuggerObj, rawObj, 'RegExp')) - subtype = 'regexp'; - else if (this._instanceOf(debuggerObj, rawObj, 'Date')) - subtype = 'date'; - else if (this._instanceOf(debuggerObj, rawObj, 'Map')) - subtype = 'map'; - else if (this._instanceOf(debuggerObj, rawObj, 'Set')) - subtype = 'set'; - else if (this._instanceOf(debuggerObj, rawObj, 'WeakMap')) - subtype = 'weakmap'; - else if (this._instanceOf(debuggerObj, rawObj, 'WeakSet')) - subtype = 'weakset'; - else if (this._instanceOf(debuggerObj, rawObj, 'Error')) - subtype = 'error'; - else if (this._instanceOf(debuggerObj, rawObj, 'Promise')) - subtype = 'promise'; - else if ((this._instanceOf(debuggerObj, rawObj, 'Int8Array')) || (this._instanceOf(debuggerObj, rawObj, 'Uint8Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Uint8ClampedArray')) || (this._instanceOf(debuggerObj, rawObj, 'Int16Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Uint16Array')) || (this._instanceOf(debuggerObj, rawObj, 'Int32Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Uint32Array')) || (this._instanceOf(debuggerObj, rawObj, 'Float32Array')) || - (this._instanceOf(debuggerObj, rawObj, 'Float64Array'))) { - subtype = 'typedarray'; - } - return {objectId, type, subtype}; - } - if (typeof debuggerObj === 'symbol') { - const objectId = generateId(); - this._remoteObjects.set(objectId, debuggerObj); - return {objectId, type: 'symbol'}; - } - - let unserializableValue = undefined; - if (Object.is(debuggerObj, NaN)) - unserializableValue = 'NaN'; - else if (Object.is(debuggerObj, -0)) - unserializableValue = '-0'; - else if (Object.is(debuggerObj, Infinity)) - unserializableValue = 'Infinity'; - else if (Object.is(debuggerObj, -Infinity)) - unserializableValue = '-Infinity'; - return unserializableValue ? {unserializableValue} : {value: debuggerObj}; - } - - ensureSerializedToValue(protocolObject) { - if (!protocolObject.objectId) - return protocolObject; - const obj = this._remoteObjects.get(protocolObject.objectId); - this._remoteObjects.delete(protocolObject.objectId); - return {value: this._serialize(obj)}; - } - - _toDebugger(obj) { - if (typeof obj !== 'object') - return obj; - if (obj === null) - return obj; - const properties = {}; - for (let [key, value] of Object.entries(obj)) { - properties[key] = { - configurable: true, - writable: true, - enumerable: true, - value: this._toDebugger(value), - }; - } - const baseObject = Array.isArray(obj) ? '([])' : '({})'; - const debuggerObj = this._debuggee.executeInGlobal(baseObject).return; - debuggerObj.defineProperties(properties); - return debuggerObj; - } - - _serialize(obj) { - const result = this._debuggee.executeInGlobalWithBindings('stringify(e)', {e: obj, stringify: this._jsonStringifyObject}); - if (result.throw) - throw new Error('Object is not serializable'); - return result.return === undefined ? undefined : JSON.parse(result.return); - } - - disposeObject(objectId) { - this._remoteObjects.delete(objectId); - } - - getObjectProperties(objectId) { - if (!this._remoteObjects.has(objectId)) - throw new Error('Cannot find object with id = ' + arg.objectId); - const result = []; - for (let obj = this._remoteObjects.get(objectId); obj; obj = obj.proto) { - for (const propertyName of obj.getOwnPropertyNames()) { - const descriptor = obj.getOwnPropertyDescriptor(propertyName); - if (!descriptor.enumerable) - continue; - result.push({ - name: propertyName, - value: this._createRemoteObject(descriptor.value), - }); - } - } - return result; - } - - _getResult(completionValue, exceptionDetails = {}) { - if (!completionValue) { - exceptionDetails.text = 'Evaluation terminated!'; - exceptionDetails.stack = ''; - return {success: false, obj: null}; - } - if (completionValue.throw) { - if (this._debuggee.executeInGlobalWithBindings('e instanceof Error', {e: completionValue.throw}).return) { - exceptionDetails.text = this._debuggee.executeInGlobalWithBindings('e.message', {e: completionValue.throw}).return; - exceptionDetails.stack = this._debuggee.executeInGlobalWithBindings('e.stack', {e: completionValue.throw}).return; - } else { - exceptionDetails.value = this._serialize(completionValue.throw); - } - return {success: false, obj: null}; - } - return {success: true, obj: completionValue.return}; - } -} - -const listenersSymbol = Symbol('listeners'); - -function createEvent() { - const listeners = new Set(); - const subscribeFunction = listener => { - listeners.add(listener); - return () => listeners.delete(listener); - } - subscribeFunction[listenersSymbol] = listeners; - return subscribeFunction; -} - -function emitEvent(event, ...args) { - let listeners = event[listenersSymbol]; - if (!listeners || !listeners.size) - return; - listeners = new Set(listeners); - for (const listener of listeners) - listener.call(null, ...args); -} - -var EXPORTED_SYMBOLS = ['Runtime']; -this.Runtime = Runtime; diff --git a/browser_patches/firefox-beta/juggler/content/WorkerMain.js b/browser_patches/firefox-beta/juggler/content/WorkerMain.js deleted file mode 100644 index 3d0c1168cb8915..00000000000000 --- a/browser_patches/firefox-beta/juggler/content/WorkerMain.js +++ /dev/null @@ -1,76 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -loadSubScript('chrome://juggler/content/content/Runtime.js'); -loadSubScript('chrome://juggler/content/SimpleChannel.js'); - -const channel = new SimpleChannel('worker::worker'); -const eventListener = event => channel._onMessage(JSON.parse(event.data)); -this.addEventListener('message', eventListener); -channel.setTransport({ - sendMessage: msg => postMessage(JSON.stringify(msg)), - dispose: () => this.removeEventListener('message', eventListener), -}); - -const runtime = new Runtime(true /* isWorker */); - -(() => { - // Create execution context in the runtime only when the script - // source was actually evaluated in it. - const dbg = new Debugger(global); - if (dbg.findScripts({global}).length) { - runtime.createExecutionContext(null /* domWindow */, global, {}); - } else { - dbg.onNewScript = function(s) { - dbg.onNewScript = undefined; - dbg.removeAllDebuggees(); - runtime.createExecutionContext(null /* domWindow */, global, {}); - }; - } -})(); - -class RuntimeAgent { - constructor(runtime, channel) { - this._runtime = runtime; - this._browserRuntime = channel.connect('runtime'); - - for (const context of this._runtime.executionContexts()) - this._onExecutionContextCreated(context); - - this._eventListeners = [ - this._runtime.events.onConsoleMessage(msg => this._browserRuntime.emit('runtimeConsole', msg)), - this._runtime.events.onExecutionContextCreated(this._onExecutionContextCreated.bind(this)), - this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)), - channel.register('runtime', { - evaluate: this._runtime.evaluate.bind(this._runtime), - callFunction: this._runtime.callFunction.bind(this._runtime), - getObjectProperties: this._runtime.getObjectProperties.bind(this._runtime), - disposeObject: this._runtime.disposeObject.bind(this._runtime), - }), - ]; - } - - _onExecutionContextCreated(executionContext) { - this._browserRuntime.emit('runtimeExecutionContextCreated', { - executionContextId: executionContext.id(), - auxData: executionContext.auxData(), - }); - } - - _onExecutionContextDestroyed(executionContext) { - this._browserRuntime.emit('runtimeExecutionContextDestroyed', { - executionContextId: executionContext.id(), - }); - } - - dispose() { - for (const disposer of this._eventListeners) - disposer(); - this._eventListeners = []; - } -} - -new RuntimeAgent(runtime, channel); - diff --git a/browser_patches/firefox-beta/juggler/content/hidden-scrollbars.css b/browser_patches/firefox-beta/juggler/content/hidden-scrollbars.css deleted file mode 100644 index 26fc0db7680db4..00000000000000 --- a/browser_patches/firefox-beta/juggler/content/hidden-scrollbars.css +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -* { - scrollbar-width: none !important; -} diff --git a/browser_patches/firefox-beta/juggler/content/main.js b/browser_patches/firefox-beta/juggler/content/main.js deleted file mode 100644 index d471ab955327d3..00000000000000 --- a/browser_patches/firefox-beta/juggler/content/main.js +++ /dev/null @@ -1,155 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js'); -const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); -const {PageAgent} = ChromeUtils.import('chrome://juggler/content/content/PageAgent.js'); - -let frameTree; -const helper = new Helper(); -const messageManager = this; - -let pageAgent; - -let failedToOverrideTimezone = false; - -const applySetting = { - geolocation: (geolocation) => { - if (geolocation) { - docShell.setGeolocationOverride({ - coords: { - latitude: geolocation.latitude, - longitude: geolocation.longitude, - accuracy: geolocation.accuracy, - altitude: NaN, - altitudeAccuracy: NaN, - heading: NaN, - speed: NaN, - }, - address: null, - timestamp: Date.now() - }); - } else { - docShell.setGeolocationOverride(null); - } - }, - - onlineOverride: (onlineOverride) => { - if (!onlineOverride) { - docShell.onlineOverride = Ci.nsIDocShell.ONLINE_OVERRIDE_NONE; - return; - } - docShell.onlineOverride = onlineOverride === 'online' ? - Ci.nsIDocShell.ONLINE_OVERRIDE_ONLINE : Ci.nsIDocShell.ONLINE_OVERRIDE_OFFLINE; - }, - - bypassCSP: (bypassCSP) => { - docShell.bypassCSPEnabled = bypassCSP; - }, - - timezoneId: (timezoneId) => { - failedToOverrideTimezone = !docShell.overrideTimezone(timezoneId); - }, - - locale: (locale) => { - docShell.languageOverride = locale; - }, - - scrollbarsHidden: (hidden) => { - frameTree.setScrollbarsHidden(hidden); - }, - - colorScheme: (colorScheme) => { - frameTree.setColorScheme(colorScheme); - }, - - reducedMotion: (reducedMotion) => { - frameTree.setReducedMotion(reducedMotion); - }, - - forcedColors: (forcedColors) => { - frameTree.setForcedColors(forcedColors); - }, -}; - -const channel = SimpleChannel.createForMessageManager('content::page', messageManager); - -function initialize() { - const response = sendSyncMessage('juggler:content-ready')[0]; - // If we didn't get a response, then we don't want to do anything - // as a part of this frame script. - if (!response) - return; - const { - initScripts = [], - bindings = [], - settings = {} - } = response || {}; - // Enforce focused state for all top level documents. - docShell.overrideHasFocus = true; - docShell.forceActiveState = true; - frameTree = new FrameTree(docShell); - for (const [name, value] of Object.entries(settings)) { - if (value !== undefined) - applySetting[name](value); - } - for (const { worldName, name, script } of bindings) - frameTree.addBinding(worldName, name, script); - frameTree.setInitScripts(initScripts); - - pageAgent = new PageAgent(messageManager, channel, frameTree); - - channel.register('', { - setInitScripts(scripts) { - frameTree.setInitScripts(scripts); - }, - - addBinding({worldName, name, script}) { - frameTree.addBinding(worldName, name, script); - }, - - applyContextSetting({name, value}) { - applySetting[name](value); - }, - - ensurePermissions() { - // noop, just a rountrip. - }, - - hasFailedToOverrideTimezone() { - return failedToOverrideTimezone; - }, - - async awaitViewportDimensions({width, height, deviceSizeIsPageSize}) { - docShell.deviceSizeIsPageSize = deviceSizeIsPageSize; - const win = docShell.domWindow; - if (win.innerWidth === width && win.innerHeight === height) - return; - await new Promise(resolve => { - const listener = helper.addEventListener(win, 'resize', () => { - if (win.innerWidth === width && win.innerHeight === height) { - helper.removeListeners([listener]); - resolve(); - } - }); - }); - }, - - dispose() { - }, - }); - - const gListeners = [ - helper.addEventListener(messageManager, 'unload', msg => { - helper.removeListeners(gListeners); - pageAgent.dispose(); - frameTree.dispose(); - channel.dispose(); - }), - ]; -} - -initialize(); diff --git a/browser_patches/firefox-beta/juggler/jar.mn b/browser_patches/firefox-beta/juggler/jar.mn deleted file mode 100644 index 8b3d3922c14ab3..00000000000000 --- a/browser_patches/firefox-beta/juggler/jar.mn +++ /dev/null @@ -1,25 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -juggler.jar: -% content juggler %content/ - - content/components/Juggler.js (components/Juggler.js) - - content/Helper.js (Helper.js) - content/NetworkObserver.js (NetworkObserver.js) - content/TargetRegistry.js (TargetRegistry.js) - content/SimpleChannel.js (SimpleChannel.js) - content/protocol/PrimitiveTypes.js (protocol/PrimitiveTypes.js) - content/protocol/Protocol.js (protocol/Protocol.js) - content/protocol/Dispatcher.js (protocol/Dispatcher.js) - content/protocol/PageHandler.js (protocol/PageHandler.js) - content/protocol/BrowserHandler.js (protocol/BrowserHandler.js) - content/content/main.js (content/main.js) - content/content/FrameTree.js (content/FrameTree.js) - content/content/PageAgent.js (content/PageAgent.js) - content/content/Runtime.js (content/Runtime.js) - content/content/WorkerMain.js (content/WorkerMain.js) - content/content/hidden-scrollbars.css (content/hidden-scrollbars.css) - diff --git a/browser_patches/firefox-beta/juggler/moz.build b/browser_patches/firefox-beta/juggler/moz.build deleted file mode 100644 index 905c20cc3139ef..00000000000000 --- a/browser_patches/firefox-beta/juggler/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ["components", "screencast", "pipe"] - -JAR_MANIFESTS += ["jar.mn"] -with Files("**"): - BUG_COMPONENT = ("Testing", "Juggler") - diff --git a/browser_patches/firefox-beta/juggler/pipe/components.conf b/browser_patches/firefox-beta/juggler/pipe/components.conf deleted file mode 100644 index db13a00ba7c979..00000000000000 --- a/browser_patches/firefox-beta/juggler/pipe/components.conf +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -Classes = [ - { - 'cid': '{d69ecefe-3df7-4d11-9dc7-f604edb96da2}', - 'contract_ids': ['@mozilla.org/juggler/remotedebuggingpipe;1'], - 'type': 'nsIRemoteDebuggingPipe', - 'constructor': 'mozilla::nsRemoteDebuggingPipe::GetSingleton', - 'headers': ['/juggler/pipe/nsRemoteDebuggingPipe.h'], - }, -] diff --git a/browser_patches/firefox-beta/juggler/pipe/moz.build b/browser_patches/firefox-beta/juggler/pipe/moz.build deleted file mode 100644 index b56c697881173f..00000000000000 --- a/browser_patches/firefox-beta/juggler/pipe/moz.build +++ /dev/null @@ -1,24 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPIDL_SOURCES += [ - 'nsIRemoteDebuggingPipe.idl', -] - -XPIDL_MODULE = 'jugglerpipe' - -SOURCES += [ - 'nsRemoteDebuggingPipe.cpp', -] - -XPCOM_MANIFESTS += [ - 'components.conf', -] - -LOCAL_INCLUDES += [ -] - -FINAL_LIBRARY = 'xul' diff --git a/browser_patches/firefox-beta/juggler/pipe/nsIRemoteDebuggingPipe.idl b/browser_patches/firefox-beta/juggler/pipe/nsIRemoteDebuggingPipe.idl deleted file mode 100644 index ac91b636155a3e..00000000000000 --- a/browser_patches/firefox-beta/juggler/pipe/nsIRemoteDebuggingPipe.idl +++ /dev/null @@ -1,20 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(7910c231-971a-4653-abdc-a8599a986c4c)] -interface nsIRemoteDebuggingPipeClient : nsISupports -{ - void receiveMessage(in AString message); - void disconnected(); -}; - -[scriptable, uuid(b7bfb66b-fd46-4aa2-b4ad-396177186d94)] -interface nsIRemoteDebuggingPipe : nsISupports -{ - void init(in nsIRemoteDebuggingPipeClient client); - void sendMessage(in AString message); - void stop(); -}; diff --git a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.cpp b/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.cpp deleted file mode 100644 index abcb0a758fac13..00000000000000 --- a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsRemoteDebuggingPipe.h" - -#include -#if defined(_WIN32) -#include -#include -#else -#include -#include -#include -#endif - -#include "mozilla/StaticPtr.h" -#include "nsISupportsPrimitives.h" -#include "nsThreadUtils.h" - -namespace mozilla { - -NS_IMPL_ISUPPORTS(nsRemoteDebuggingPipe, nsIRemoteDebuggingPipe) - -namespace { - -StaticRefPtr gPipe; - -const size_t kWritePacketSize = 1 << 16; - -#if defined(_WIN32) -HANDLE readHandle; -HANDLE writeHandle; -#else -const int readFD = 3; -const int writeFD = 4; -#endif - -size_t ReadBytes(void* buffer, size_t size, bool exact_size) -{ - size_t bytesRead = 0; - while (bytesRead < size) { -#if defined(_WIN32) - DWORD sizeRead = 0; - bool hadError = !ReadFile(readHandle, static_cast(buffer) + bytesRead, - size - bytesRead, &sizeRead, nullptr); -#else - int sizeRead = read(readFD, static_cast(buffer) + bytesRead, - size - bytesRead); - if (sizeRead < 0 && errno == EINTR) - continue; - bool hadError = sizeRead <= 0; -#endif - if (hadError) { - return 0; - } - bytesRead += sizeRead; - if (!exact_size) - break; - } - return bytesRead; -} - -void WriteBytes(const char* bytes, size_t size) -{ - size_t totalWritten = 0; - while (totalWritten < size) { - size_t length = size - totalWritten; - if (length > kWritePacketSize) - length = kWritePacketSize; -#if defined(_WIN32) - DWORD bytesWritten = 0; - bool hadError = !WriteFile(writeHandle, bytes + totalWritten, static_cast(length), &bytesWritten, nullptr); -#else - int bytesWritten = write(writeFD, bytes + totalWritten, length); - if (bytesWritten < 0 && errno == EINTR) - continue; - bool hadError = bytesWritten <= 0; -#endif - if (hadError) - return; - totalWritten += bytesWritten; - } -} - -} // namespace - -// static -already_AddRefed nsRemoteDebuggingPipe::GetSingleton() { - if (!gPipe) { - gPipe = new nsRemoteDebuggingPipe(); - } - return do_AddRef(gPipe); -} - -nsRemoteDebuggingPipe::nsRemoteDebuggingPipe() = default; - -nsRemoteDebuggingPipe::~nsRemoteDebuggingPipe() = default; - -nsresult nsRemoteDebuggingPipe::Init(nsIRemoteDebuggingPipeClient* aClient) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (mClient) { - return NS_ERROR_FAILURE; - } - mClient = aClient; - - MOZ_ALWAYS_SUCCEEDS(NS_NewNamedThread("Pipe Reader", getter_AddRefs(mReaderThread))); - MOZ_ALWAYS_SUCCEEDS(NS_NewNamedThread("Pipe Writer", getter_AddRefs(mWriterThread))); - -#if defined(_WIN32) - CHAR pipeReadStr[20]; - CHAR pipeWriteStr[20]; - GetEnvironmentVariableA("PW_PIPE_READ", pipeReadStr, 20); - GetEnvironmentVariableA("PW_PIPE_WRITE", pipeWriteStr, 20); - readHandle = reinterpret_cast(atoi(pipeReadStr)); - writeHandle = reinterpret_cast(atoi(pipeWriteStr)); -#endif - - MOZ_ALWAYS_SUCCEEDS(mReaderThread->Dispatch(NewRunnableMethod( - "nsRemoteDebuggingPipe::ReaderLoop", - this, &nsRemoteDebuggingPipe::ReaderLoop), nsIThread::DISPATCH_NORMAL)); - return NS_OK; -} - -nsresult nsRemoteDebuggingPipe::Stop() { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (!mClient) { - return NS_ERROR_FAILURE; - } - m_terminated = true; - mClient = nullptr; - // Cancel pending synchronous read. -#if defined(_WIN32) - CancelIoEx(readHandle, nullptr); - CloseHandle(readHandle); - CloseHandle(writeHandle); -#else - shutdown(readFD, SHUT_RDWR); - shutdown(writeFD, SHUT_RDWR); -#endif - mReaderThread->Shutdown(); - mReaderThread = nullptr; - mWriterThread->Shutdown(); - mWriterThread = nullptr; - return NS_OK; -} - -void nsRemoteDebuggingPipe::ReaderLoop() { - const size_t bufSize = 256 * 1024; - std::vector buffer; - buffer.resize(bufSize); - std::vector line; - while (!m_terminated) { - size_t size = ReadBytes(buffer.data(), bufSize, false); - if (!size) { - nsCOMPtr runnable = NewRunnableMethod<>( - "nsRemoteDebuggingPipe::Disconnected", - this, &nsRemoteDebuggingPipe::Disconnected); - NS_DispatchToMainThread(runnable.forget()); - break; - } - size_t start = 0; - size_t end = line.size(); - line.insert(line.end(), buffer.begin(), buffer.begin() + size); - while (true) { - for (; end < line.size(); ++end) { - if (line[end] == '\0') { - break; - } - } - if (end == line.size()) { - break; - } - if (end > start) { - nsCString message; - message.Append(line.data() + start, end - start); - nsCOMPtr runnable = NewRunnableMethod( - "nsRemoteDebuggingPipe::ReceiveMessage", - this, &nsRemoteDebuggingPipe::ReceiveMessage, std::move(message)); - NS_DispatchToMainThread(runnable.forget()); - } - ++end; - start = end; - } - if (start != 0 && start < line.size()) { - memmove(line.data(), line.data() + start, line.size() - start); - } - line.resize(line.size() - start); - } -} - -void nsRemoteDebuggingPipe::ReceiveMessage(const nsCString& aMessage) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (mClient) { - NS_ConvertUTF8toUTF16 utf16(aMessage); - mClient->ReceiveMessage(utf16); - } -} - -void nsRemoteDebuggingPipe::Disconnected() { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (mClient) - mClient->Disconnected(); -} - -nsresult nsRemoteDebuggingPipe::SendMessage(const nsAString& aMessage) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Remote debugging pipe must be used on the Main thread."); - if (!mClient) { - return NS_ERROR_FAILURE; - } - NS_ConvertUTF16toUTF8 utf8(aMessage); - nsCOMPtr runnable = NS_NewRunnableFunction( - "nsRemoteDebuggingPipe::SendMessage", - [message = std::move(utf8)] { - const nsCString& flat = PromiseFlatCString(message); - WriteBytes(flat.Data(), flat.Length()); - WriteBytes("\0", 1); - }); - MOZ_ALWAYS_SUCCEEDS(mWriterThread->Dispatch(runnable.forget(), nsIThread::DISPATCH_NORMAL)); - return NS_OK; -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.h b/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.h deleted file mode 100644 index be4cb2675e7810..00000000000000 --- a/browser_patches/firefox-beta/juggler/pipe/nsRemoteDebuggingPipe.h +++ /dev/null @@ -1,34 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include "nsCOMPtr.h" -#include "nsIRemoteDebuggingPipe.h" -#include "nsThread.h" - -namespace mozilla { - -class nsRemoteDebuggingPipe final : public nsIRemoteDebuggingPipe { - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIREMOTEDEBUGGINGPIPE - - static already_AddRefed GetSingleton(); - nsRemoteDebuggingPipe(); - - private: - void ReaderLoop(); - void ReceiveMessage(const nsCString& aMessage); - void Disconnected(); - ~nsRemoteDebuggingPipe(); - - RefPtr mClient; - nsCOMPtr mReaderThread; - nsCOMPtr mWriterThread; - std::atomic m_terminated { false }; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/protocol/BrowserHandler.js b/browser_patches/firefox-beta/juggler/protocol/BrowserHandler.js deleted file mode 100644 index 623f9cc3312689..00000000000000 --- a/browser_patches/firefox-beta/juggler/protocol/BrowserHandler.js +++ /dev/null @@ -1,296 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {AddonManager} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm"); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {TargetRegistry} = ChromeUtils.import("chrome://juggler/content/TargetRegistry.js"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {PageHandler} = ChromeUtils.import("chrome://juggler/content/protocol/PageHandler.js"); -const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); - -const helper = new Helper(); - -class BrowserHandler { - constructor(session, dispatcher, targetRegistry, onclose, onstart) { - this._session = session; - this._dispatcher = dispatcher; - this._targetRegistry = targetRegistry; - this._enabled = false; - this._attachToDefaultContext = false; - this._eventListeners = []; - this._createdBrowserContextIds = new Set(); - this._attachedSessions = new Map(); - this._onclose = onclose; - this._onstart = onstart; - } - - async ['Browser.enable']({attachToDefaultContext}) { - if (this._enabled) - return; - await this._onstart(); - this._enabled = true; - this._attachToDefaultContext = attachToDefaultContext; - - this._eventListeners = [ - helper.on(this._targetRegistry, TargetRegistry.Events.TargetCreated, this._onTargetCreated.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.TargetDestroyed, this._onTargetDestroyed.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.DownloadCreated, this._onDownloadCreated.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.DownloadFinished, this._onDownloadFinished.bind(this)), - helper.on(this._targetRegistry, TargetRegistry.Events.ScreencastStopped, sessionId => { - this._session.emitEvent('Browser.videoRecordingFinished', {screencastId: '' + sessionId}); - }) - ]; - - for (const target of this._targetRegistry.targets()) - this._onTargetCreated(target); - } - - async ['Browser.createBrowserContext']({removeOnDetach}) { - if (!this._enabled) - throw new Error('Browser domain is not enabled'); - const browserContext = this._targetRegistry.createBrowserContext(removeOnDetach); - this._createdBrowserContextIds.add(browserContext.browserContextId); - return {browserContextId: browserContext.browserContextId}; - } - - async ['Browser.removeBrowserContext']({browserContextId}) { - if (!this._enabled) - throw new Error('Browser domain is not enabled'); - await this._targetRegistry.browserContextForId(browserContextId).destroy(); - this._createdBrowserContextIds.delete(browserContextId); - } - - dispose() { - helper.removeListeners(this._eventListeners); - for (const [target, session] of this._attachedSessions) - this._dispatcher.destroySession(session); - this._attachedSessions.clear(); - for (const browserContextId of this._createdBrowserContextIds) { - const browserContext = this._targetRegistry.browserContextForId(browserContextId); - if (browserContext.removeOnDetach) - browserContext.destroy(); - } - this._createdBrowserContextIds.clear(); - } - - _shouldAttachToTarget(target) { - if (this._createdBrowserContextIds.has(target._browserContext.browserContextId)) - return true; - return this._attachToDefaultContext && target._browserContext === this._targetRegistry.defaultContext(); - } - - _onTargetCreated(target) { - if (!this._shouldAttachToTarget(target)) - return; - const channel = target.channel(); - const session = this._dispatcher.createSession(); - this._attachedSessions.set(target, session); - this._session.emitEvent('Browser.attachedToTarget', { - sessionId: session.sessionId(), - targetInfo: target.info() - }); - session.setHandler(new PageHandler(target, session, channel)); - } - - _onTargetDestroyed(target) { - const session = this._attachedSessions.get(target); - if (!session) - return; - this._attachedSessions.delete(target); - this._dispatcher.destroySession(session); - this._session.emitEvent('Browser.detachedFromTarget', { - sessionId: session.sessionId(), - targetId: target.id(), - }); - } - - _onDownloadCreated(downloadInfo) { - this._session.emitEvent('Browser.downloadCreated', downloadInfo); - } - - _onDownloadFinished(downloadInfo) { - this._session.emitEvent('Browser.downloadFinished', downloadInfo); - } - - async ['Browser.cancelDownload']({uuid}) { - await this._targetRegistry.cancelDownload({uuid}); - } - - async ['Browser.newPage']({browserContextId}) { - const targetId = await this._targetRegistry.newPage({browserContextId}); - return {targetId}; - } - - async ['Browser.close']() { - let browserWindow = Services.wm.getMostRecentWindow( - "navigator:browser" - ); - if (browserWindow && browserWindow.gBrowserInit) { - // idleTasksFinishedPromise does not resolve when the window - // is closed early enough, so we race against window closure. - await Promise.race([ - browserWindow.gBrowserInit.idleTasksFinishedPromise, - waitForWindowClosed(browserWindow), - ]); - } - this._onclose(); - Services.startup.quit(Ci.nsIAppStartup.eForceQuit); - } - - async ['Browser.grantPermissions']({browserContextId, origin, permissions}) { - await this._targetRegistry.browserContextForId(browserContextId).grantPermissions(origin, permissions); - } - - async ['Browser.resetPermissions']({browserContextId}) { - this._targetRegistry.browserContextForId(browserContextId).resetPermissions(); - } - - ['Browser.setExtraHTTPHeaders']({browserContextId, headers}) { - this._targetRegistry.browserContextForId(browserContextId).extraHTTPHeaders = headers; - } - - ['Browser.setHTTPCredentials']({browserContextId, credentials}) { - this._targetRegistry.browserContextForId(browserContextId).httpCredentials = nullToUndefined(credentials); - } - - async ['Browser.setBrowserProxy']({type, host, port, bypass, username, password}) { - this._targetRegistry.setBrowserProxy({ type, host, port, bypass, username, password}); - } - - async ['Browser.setContextProxy']({browserContextId, type, host, port, bypass, username, password}) { - const browserContext = this._targetRegistry.browserContextForId(browserContextId); - browserContext.setProxy({ type, host, port, bypass, username, password }); - } - - ['Browser.setRequestInterception']({browserContextId, enabled}) { - this._targetRegistry.browserContextForId(browserContextId).requestInterceptionEnabled = enabled; - } - - ['Browser.setIgnoreHTTPSErrors']({browserContextId, ignoreHTTPSErrors}) { - this._targetRegistry.browserContextForId(browserContextId).setIgnoreHTTPSErrors(nullToUndefined(ignoreHTTPSErrors)); - } - - ['Browser.setDownloadOptions']({browserContextId, downloadOptions}) { - this._targetRegistry.browserContextForId(browserContextId).downloadOptions = nullToUndefined(downloadOptions); - } - - async ['Browser.setGeolocationOverride']({browserContextId, geolocation}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('geolocation', nullToUndefined(geolocation)); - } - - async ['Browser.setOnlineOverride']({browserContextId, override}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('onlineOverride', nullToUndefined(override)); - } - - async ['Browser.setColorScheme']({browserContextId, colorScheme}) { - await this._targetRegistry.browserContextForId(browserContextId).setColorScheme(nullToUndefined(colorScheme)); - } - - async ['Browser.setReducedMotion']({browserContextId, reducedMotion}) { - await this._targetRegistry.browserContextForId(browserContextId).setReducedMotion(nullToUndefined(reducedMotion)); - } - - async ['Browser.setForcedColors']({browserContextId, forcedColors}) { - await this._targetRegistry.browserContextForId(browserContextId).setForcedColors(nullToUndefined(forcedColors)); - } - - async ['Browser.setVideoRecordingOptions']({browserContextId, options}) { - await this._targetRegistry.browserContextForId(browserContextId).setVideoRecordingOptions(options); - } - - async ['Browser.setUserAgentOverride']({browserContextId, userAgent}) { - await this._targetRegistry.browserContextForId(browserContextId).setDefaultUserAgent(userAgent); - } - - async ['Browser.setPlatformOverride']({browserContextId, platform}) { - await this._targetRegistry.browserContextForId(browserContextId).setDefaultPlatform(platform); - } - - async ['Browser.setBypassCSP']({browserContextId, bypassCSP}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('bypassCSP', nullToUndefined(bypassCSP)); - } - - async ['Browser.setJavaScriptDisabled']({browserContextId, javaScriptDisabled}) { - await this._targetRegistry.browserContextForId(browserContextId).setJavaScriptDisabled(javaScriptDisabled); - } - - async ['Browser.setLocaleOverride']({browserContextId, locale}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('locale', nullToUndefined(locale)); - } - - async ['Browser.setTimezoneOverride']({browserContextId, timezoneId}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('timezoneId', nullToUndefined(timezoneId)); - } - - async ['Browser.setTouchOverride']({browserContextId, hasTouch}) { - await this._targetRegistry.browserContextForId(browserContextId).setTouchOverride(nullToUndefined(hasTouch)); - } - - async ['Browser.setDefaultViewport']({browserContextId, viewport}) { - await this._targetRegistry.browserContextForId(browserContextId).setDefaultViewport(nullToUndefined(viewport)); - } - - async ['Browser.setScrollbarsHidden']({browserContextId, hidden}) { - await this._targetRegistry.browserContextForId(browserContextId).applySetting('scrollbarsHidden', nullToUndefined(hidden)); - } - - async ['Browser.setInitScripts']({browserContextId, scripts}) { - await this._targetRegistry.browserContextForId(browserContextId).setInitScripts(scripts); - } - - async ['Browser.addBinding']({browserContextId, worldName, name, script}) { - await this._targetRegistry.browserContextForId(browserContextId).addBinding(worldName, name, script); - } - - ['Browser.setCookies']({browserContextId, cookies}) { - this._targetRegistry.browserContextForId(browserContextId).setCookies(cookies); - } - - ['Browser.clearCookies']({browserContextId}) { - this._targetRegistry.browserContextForId(browserContextId).clearCookies(); - } - - ['Browser.getCookies']({browserContextId}) { - const cookies = this._targetRegistry.browserContextForId(browserContextId).getCookies(); - return {cookies}; - } - - async ['Browser.getInfo']() { - const version = AppConstants.MOZ_APP_VERSION_DISPLAY; - const userAgent = Components.classes["@mozilla.org/network/protocol;1?name=http"] - .getService(Components.interfaces.nsIHttpProtocolHandler) - .userAgent; - return {version: 'Firefox/' + version, userAgent}; - } -} - -async function waitForWindowClosed(browserWindow) { - if (browserWindow.closed) - return; - await new Promise((resolve => { - const listener = { - onCloseWindow: window => { - let domWindow; - if (window instanceof Ci.nsIAppWindow) - domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); - else - domWindow = window; - if (domWindow === browserWindow) { - Services.wm.removeListener(listener); - resolve(); - } - }, - }; - Services.wm.addListener(listener); - })); -} - -function nullToUndefined(value) { - return value === null ? undefined : value; -} - -var EXPORTED_SYMBOLS = ['BrowserHandler']; -this.BrowserHandler = BrowserHandler; diff --git a/browser_patches/firefox-beta/juggler/protocol/Dispatcher.js b/browser_patches/firefox-beta/juggler/protocol/Dispatcher.js deleted file mode 100644 index af72f307ac4953..00000000000000 --- a/browser_patches/firefox-beta/juggler/protocol/Dispatcher.js +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {protocol, checkScheme} = ChromeUtils.import("chrome://juggler/content/protocol/Protocol.js"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); - -const helper = new Helper(); - -class Dispatcher { - /** - * @param {Connection} connection - */ - constructor(connection) { - this._connection = connection; - this._connection.onmessage = this._dispatch.bind(this); - this._connection.onclose = this._dispose.bind(this); - this._sessions = new Map(); - this._rootSession = new ProtocolSession(this, undefined); - } - - rootSession() { - return this._rootSession; - } - - createSession() { - const session = new ProtocolSession(this, helper.generateId()); - this._sessions.set(session.sessionId(), session); - return session; - } - - destroySession(session) { - this._sessions.delete(session.sessionId()); - session._dispose(); - } - - _dispose() { - this._connection.onmessage = null; - this._connection.onclose = null; - this._rootSession._dispose(); - this._rootSession = null; - this._sessions.clear(); - } - - async _dispatch(event) { - const data = JSON.parse(event.data); - const id = data.id; - const sessionId = data.sessionId; - delete data.sessionId; - try { - const session = sessionId ? this._sessions.get(sessionId) : this._rootSession; - if (!session) - throw new Error(`ERROR: cannot find session with id "${sessionId}"`); - const method = data.method; - const params = data.params || {}; - if (!id) - throw new Error(`ERROR: every message must have an 'id' parameter`); - if (!method) - throw new Error(`ERROR: every message must have a 'method' parameter`); - - const [domain, methodName] = method.split('.'); - const descriptor = protocol.domains[domain] ? protocol.domains[domain].methods[methodName] : null; - if (!descriptor) - throw new Error(`ERROR: method '${method}' is not supported`); - let details = {}; - if (!checkScheme(descriptor.params || {}, params, details)) - throw new Error(`ERROR: failed to call method '${method}' with parameters ${JSON.stringify(params, null, 2)}\n${details.error}`); - - const result = await session.dispatch(method, params); - - details = {}; - if ((descriptor.returns || result) && !checkScheme(descriptor.returns, result, details)) - throw new Error(`ERROR: failed to dispatch method '${method}' result ${JSON.stringify(result, null, 2)}\n${details.error}`); - - this._connection.send(JSON.stringify({id, sessionId, result})); - } catch (e) { - this._connection.send(JSON.stringify({id, sessionId, error: { - message: e.message, - data: e.stack - }})); - } - } - - _emitEvent(sessionId, eventName, params) { - const [domain, eName] = eventName.split('.'); - const scheme = protocol.domains[domain] ? protocol.domains[domain].events[eName] : null; - if (!scheme) - throw new Error(`ERROR: event '${eventName}' is not supported`); - const details = {}; - if (!checkScheme(scheme, params || {}, details)) - throw new Error(`ERROR: failed to emit event '${eventName}' ${JSON.stringify(params, null, 2)}\n${details.error}`); - this._connection.send(JSON.stringify({method: eventName, params, sessionId})); - } -} - -class ProtocolSession { - constructor(dispatcher, sessionId) { - this._sessionId = sessionId; - this._dispatcher = dispatcher; - this._handler = null; - } - - sessionId() { - return this._sessionId; - } - - setHandler(handler) { - this._handler = handler; - } - - _dispose() { - if (this._handler) - this._handler.dispose(); - this._handler = null; - this._dispatcher = null; - } - - emitEvent(eventName, params) { - if (!this._dispatcher) - throw new Error(`Session has been disposed.`); - this._dispatcher._emitEvent(this._sessionId, eventName, params); - } - - async dispatch(method, params) { - if (!this._handler) - throw new Error(`Session does not have a handler!`); - if (!this._handler[method]) - throw new Error(`Handler for does not implement method "${method}"`); - return await this._handler[method](params); - } -} - -this.EXPORTED_SYMBOLS = ['Dispatcher']; -this.Dispatcher = Dispatcher; - diff --git a/browser_patches/firefox-beta/juggler/protocol/PageHandler.js b/browser_patches/firefox-beta/juggler/protocol/PageHandler.js deleted file mode 100644 index 415f395aaf048f..00000000000000 --- a/browser_patches/firefox-beta/juggler/protocol/PageHandler.js +++ /dev/null @@ -1,466 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {NetworkObserver, PageNetwork} = ChromeUtils.import('chrome://juggler/content/NetworkObserver.js'); -const {PageTarget} = ChromeUtils.import('chrome://juggler/content/TargetRegistry.js'); -const {setTimeout} = ChromeUtils.import('resource://gre/modules/Timer.jsm'); - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; -const helper = new Helper(); - -function hashConsoleMessage(params) { - return params.location.lineNumber + ':' + params.location.columnNumber + ':' + params.location.url; -} - -class WorkerHandler { - constructor(session, contentChannel, workerId) { - this._session = session; - this._contentWorker = contentChannel.connect(workerId); - this._workerConsoleMessages = new Set(); - this._workerId = workerId; - - const emitWrappedProtocolEvent = eventName => { - return params => { - this._session.emitEvent('Page.dispatchMessageFromWorker', { - workerId, - message: JSON.stringify({method: eventName, params}), - }); - } - } - - this._eventListeners = [ - contentChannel.register(workerId, { - runtimeConsole: (params) => { - this._workerConsoleMessages.add(hashConsoleMessage(params)); - emitWrappedProtocolEvent('Runtime.console')(params); - }, - runtimeExecutionContextCreated: emitWrappedProtocolEvent('Runtime.executionContextCreated'), - runtimeExecutionContextDestroyed: emitWrappedProtocolEvent('Runtime.executionContextDestroyed'), - }), - ]; - } - - async sendMessage(message) { - const [domain, method] = message.method.split('.'); - if (domain !== 'Runtime') - throw new Error('ERROR: can only dispatch to Runtime domain inside worker'); - const result = await this._contentWorker.send(method, message.params); - this._session.emitEvent('Page.dispatchMessageFromWorker', { - workerId: this._workerId, - message: JSON.stringify({result, id: message.id}), - }); - } - - dispose() { - this._contentWorker.dispose(); - helper.removeListeners(this._eventListeners); - } -} - -class PageHandler { - constructor(target, session, contentChannel) { - this._session = session; - this._contentChannel = contentChannel; - this._contentPage = contentChannel.connect('page'); - this._workers = new Map(); - - this._pageTarget = target; - this._pageNetwork = PageNetwork.forPageTarget(target); - - const emitProtocolEvent = eventName => { - return (...args) => this._session.emitEvent(eventName, ...args); - } - - this._reportedFrameIds = new Set(); - this._networkEventsForUnreportedFrameIds = new Map(); - - // `Page.ready` protocol event is emitted whenever page has completed initialization, e.g. - // finished all the transient navigations to the `about:blank`. - // - // We'd like to avoid reporting meaningful events before the `Page.ready` since they are likely - // to be ignored by the protocol clients. - this._isPageReady = false; - - if (this._pageTarget.videoRecordingInfo()) - this._onVideoRecordingStarted(); - - this._eventListeners = [ - helper.on(this._pageTarget, PageTarget.Events.DialogOpened, this._onDialogOpened.bind(this)), - helper.on(this._pageTarget, PageTarget.Events.DialogClosed, this._onDialogClosed.bind(this)), - helper.on(this._pageTarget, PageTarget.Events.Crashed, () => { - this._session.emitEvent('Page.crashed', {}); - }), - helper.on(this._pageTarget, PageTarget.Events.ScreencastStarted, this._onVideoRecordingStarted.bind(this)), - helper.on(this._pageTarget, PageTarget.Events.ScreencastFrame, this._onScreencastFrame.bind(this)), - helper.on(this._pageNetwork, PageNetwork.Events.Request, this._handleNetworkEvent.bind(this, 'Network.requestWillBeSent')), - helper.on(this._pageNetwork, PageNetwork.Events.Response, this._handleNetworkEvent.bind(this, 'Network.responseReceived')), - helper.on(this._pageNetwork, PageNetwork.Events.RequestFinished, this._handleNetworkEvent.bind(this, 'Network.requestFinished')), - helper.on(this._pageNetwork, PageNetwork.Events.RequestFailed, this._handleNetworkEvent.bind(this, 'Network.requestFailed')), - contentChannel.register('page', { - pageBindingCalled: emitProtocolEvent('Page.bindingCalled'), - pageDispatchMessageFromWorker: emitProtocolEvent('Page.dispatchMessageFromWorker'), - pageEventFired: emitProtocolEvent('Page.eventFired'), - pageFileChooserOpened: emitProtocolEvent('Page.fileChooserOpened'), - pageFrameAttached: this._onFrameAttached.bind(this), - pageFrameDetached: emitProtocolEvent('Page.frameDetached'), - pageLinkClicked: emitProtocolEvent('Page.linkClicked'), - pageWillOpenNewWindowAsynchronously: emitProtocolEvent('Page.willOpenNewWindowAsynchronously'), - pageNavigationAborted: emitProtocolEvent('Page.navigationAborted'), - pageNavigationCommitted: emitProtocolEvent('Page.navigationCommitted'), - pageNavigationStarted: emitProtocolEvent('Page.navigationStarted'), - pageReady: this._onPageReady.bind(this), - pageSameDocumentNavigation: emitProtocolEvent('Page.sameDocumentNavigation'), - pageUncaughtError: emitProtocolEvent('Page.uncaughtError'), - pageWorkerCreated: this._onWorkerCreated.bind(this), - pageWorkerDestroyed: this._onWorkerDestroyed.bind(this), - runtimeConsole: params => { - const consoleMessageHash = hashConsoleMessage(params); - for (const worker of this._workers.values()) { - if (worker._workerConsoleMessages.has(consoleMessageHash)) { - worker._workerConsoleMessages.delete(consoleMessageHash); - return; - } - } - emitProtocolEvent('Runtime.console')(params); - }, - runtimeExecutionContextCreated: emitProtocolEvent('Runtime.executionContextCreated'), - runtimeExecutionContextDestroyed: emitProtocolEvent('Runtime.executionContextDestroyed'), - - webSocketCreated: emitProtocolEvent('Page.webSocketCreated'), - webSocketOpened: emitProtocolEvent('Page.webSocketOpened'), - webSocketClosed: emitProtocolEvent('Page.webSocketClosed'), - webSocketFrameReceived: emitProtocolEvent('Page.webSocketFrameReceived'), - webSocketFrameSent: emitProtocolEvent('Page.webSocketFrameSent'), - }), - ]; - } - - async dispose() { - this._contentPage.dispose(); - helper.removeListeners(this._eventListeners); - } - - _onVideoRecordingStarted() { - const info = this._pageTarget.videoRecordingInfo(); - this._session.emitEvent('Page.videoRecordingStarted', { screencastId: info.sessionId, file: info.file }); - } - - _onScreencastFrame(params) { - this._session.emitEvent('Page.screencastFrame', params); - } - - _onPageReady(event) { - this._isPageReady = true; - this._session.emitEvent('Page.ready'); - for (const dialog of this._pageTarget.dialogs()) - this._onDialogOpened(dialog); - } - - _onDialogOpened(dialog) { - if (!this._isPageReady) - return; - this._session.emitEvent('Page.dialogOpened', { - dialogId: dialog.id(), - type: dialog.type(), - message: dialog.message(), - defaultValue: dialog.defaultValue(), - }); - } - - _onDialogClosed(dialog) { - if (!this._isPageReady) - return; - this._session.emitEvent('Page.dialogClosed', { dialogId: dialog.id(), }); - } - - _onWorkerCreated({workerId, frameId, url}) { - const worker = new WorkerHandler(this._session, this._contentChannel, workerId); - this._workers.set(workerId, worker); - this._session.emitEvent('Page.workerCreated', {workerId, frameId, url}); - } - - _onWorkerDestroyed({workerId}) { - const worker = this._workers.get(workerId); - if (!worker) - return; - this._workers.delete(workerId); - worker.dispose(); - this._session.emitEvent('Page.workerDestroyed', {workerId}); - } - - _handleNetworkEvent(protocolEventName, eventDetails, frameId) { - if (!this._reportedFrameIds.has(frameId)) { - let events = this._networkEventsForUnreportedFrameIds.get(frameId); - if (!events) { - events = []; - this._networkEventsForUnreportedFrameIds.set(frameId, events); - } - events.push({eventName: protocolEventName, eventDetails}); - } else { - this._session.emitEvent(protocolEventName, eventDetails); - } - } - - _onFrameAttached({frameId, parentFrameId}) { - this._session.emitEvent('Page.frameAttached', {frameId, parentFrameId}); - this._reportedFrameIds.add(frameId); - const events = this._networkEventsForUnreportedFrameIds.get(frameId) || []; - this._networkEventsForUnreportedFrameIds.delete(frameId); - for (const {eventName, eventDetails} of events) - this._session.emitEvent(eventName, eventDetails); - } - - async ['Page.close']({runBeforeUnload}) { - // Postpone target close to deliver response in session. - Services.tm.dispatchToMainThread(() => { - this._pageTarget.close(runBeforeUnload); - }); - } - - async ['Page.setViewportSize']({viewportSize}) { - await this._pageTarget.setViewportSize(viewportSize === null ? undefined : viewportSize); - } - - async ['Runtime.evaluate'](options) { - return await this._contentPage.send('evaluate', options); - } - - async ['Runtime.callFunction'](options) { - return await this._contentPage.send('callFunction', options); - } - - async ['Runtime.getObjectProperties'](options) { - return await this._contentPage.send('getObjectProperties', options); - } - - async ['Runtime.disposeObject'](options) { - return await this._contentPage.send('disposeObject', options); - } - - async ['Network.getResponseBody']({requestId}) { - return this._pageNetwork.getResponseBody(requestId); - } - - async ['Network.setExtraHTTPHeaders']({headers}) { - this._pageNetwork.setExtraHTTPHeaders(headers); - } - - async ['Network.setRequestInterception']({enabled}) { - if (enabled) - this._pageNetwork.enableRequestInterception(); - else - this._pageNetwork.disableRequestInterception(); - } - - async ['Network.resumeInterceptedRequest']({requestId, url, method, headers, postData}) { - this._pageNetwork.resumeInterceptedRequest(requestId, url, method, headers, postData); - } - - async ['Network.abortInterceptedRequest']({requestId, errorCode}) { - this._pageNetwork.abortInterceptedRequest(requestId, errorCode); - } - - async ['Network.fulfillInterceptedRequest']({requestId, status, statusText, headers, base64body}) { - this._pageNetwork.fulfillInterceptedRequest(requestId, status, statusText, headers, base64body); - } - - async ['Accessibility.getFullAXTree'](params) { - return await this._contentPage.send('getFullAXTree', params); - } - - async ['Page.setFileInputFiles'](options) { - return await this._contentPage.send('setFileInputFiles', options); - } - - async ['Page.setEmulatedMedia']({colorScheme, type, reducedMotion, forcedColors}) { - this._pageTarget.setColorScheme(colorScheme || null); - this._pageTarget.setReducedMotion(reducedMotion || null); - this._pageTarget.setForcedColors(forcedColors || null); - this._pageTarget.setEmulatedMedia(type); - } - - async ['Page.bringToFront'](options) { - this._pageTarget._window.focus(); - } - - async ['Page.setCacheDisabled'](options) { - return await this._contentPage.send('setCacheDisabled', options); - } - - async ['Page.addBinding'](options) { - return await this._contentPage.send('addBinding', options); - } - - async ['Page.adoptNode'](options) { - return await this._contentPage.send('adoptNode', options); - } - - async ['Page.screenshot']({ mimeType, clip, omitDeviceScaleFactor }) { - const rect = new DOMRect(clip.x, clip.y, clip.width, clip.height); - - const browsingContext = this._pageTarget.linkedBrowser().browsingContext; - // `win.devicePixelRatio` returns a non-overriden value to priveleged code. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1761032 - // See https://phabricator.services.mozilla.com/D141323 - const devicePixelRatio = browsingContext.overrideDPPX || this._pageTarget._window.devicePixelRatio; - const scale = omitDeviceScaleFactor ? 1 : devicePixelRatio; - const canvasWidth = rect.width * scale; - const canvasHeight = rect.height * scale; - - const MAX_CANVAS_DIMENSIONS = 32767; - const MAX_CANVAS_AREA = 472907776; - if (canvasWidth > MAX_CANVAS_DIMENSIONS || canvasHeight > MAX_CANVAS_DIMENSIONS) - throw new Error('Cannot take screenshot larger than ' + MAX_CANVAS_DIMENSIONS); - if (canvasWidth * canvasHeight > MAX_CANVAS_AREA) - throw new Error('Cannot take screenshot with more than ' + MAX_CANVAS_AREA + ' pixels'); - - let snapshot; - while (!snapshot) { - try { - //TODO(fission): browsingContext will change in case of cross-group navigation. - snapshot = await browsingContext.currentWindowGlobal.drawSnapshot( - rect, - scale, - "rgb(255,255,255)" - ); - } catch (e) { - // The currentWindowGlobal.drawSnapshot might throw - // NS_ERROR_LOSS_OF_SIGNIFICANT_DATA if called during navigation. - // wait a little and re-try. - await new Promise(x => setTimeout(x, 50)); - } - } - - const win = browsingContext.topChromeWindow.ownerGlobal; - const canvas = win.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas'); - canvas.width = canvasWidth; - canvas.height = canvasHeight; - let ctx = canvas.getContext('2d'); - ctx.drawImage(snapshot, 0, 0); - snapshot.close(); - const dataURL = canvas.toDataURL(mimeType); - return { data: dataURL.substring(dataURL.indexOf(',') + 1) }; - } - - async ['Page.getContentQuads'](options) { - return await this._contentPage.send('getContentQuads', options); - } - - async ['Page.navigate'](options) { - return await this._contentPage.send('navigate', options); - } - - async ['Page.goBack'](options) { - return await this._contentPage.send('goBack', options); - } - - async ['Page.goForward'](options) { - return await this._contentPage.send('goForward', options); - } - - async ['Page.reload'](options) { - return await this._contentPage.send('reload', options); - } - - async ['Page.describeNode'](options) { - return await this._contentPage.send('describeNode', options); - } - - async ['Page.scrollIntoViewIfNeeded'](options) { - return await this._contentPage.send('scrollIntoViewIfNeeded', options); - } - - async ['Page.setInitScripts']({ scripts }) { - return await this._pageTarget.setInitScripts(scripts); - } - - async ['Page.dispatchKeyEvent'](options) { - return await this._contentPage.send('dispatchKeyEvent', options); - } - - async ['Page.dispatchTouchEvent'](options) { - return await this._contentPage.send('dispatchTouchEvent', options); - } - - async ['Page.dispatchTapEvent'](options) { - return await this._contentPage.send('dispatchTapEvent', options); - } - - async ['Page.dispatchMouseEvent'](options) { - return await this._contentPage.send('dispatchMouseEvent', options); - } - - async ['Page.dispatchWheelEvent']({x, y, button, deltaX, deltaY, deltaZ, modifiers }) { - const boundingBox = this._pageTarget._linkedBrowser.getBoundingClientRect(); - x += boundingBox.left; - y += boundingBox.top; - const deltaMode = 0; // WheelEvent.DOM_DELTA_PIXEL - const lineOrPageDeltaX = deltaX > 0 ? Math.floor(deltaX) : Math.ceil(deltaX); - const lineOrPageDeltaY = deltaY > 0 ? Math.floor(deltaY) : Math.ceil(deltaY); - - const win = this._pageTarget._window; - win.windowUtils.sendWheelEvent( - x, - y, - deltaX, - deltaY, - deltaZ, - deltaMode, - modifiers, - lineOrPageDeltaX, - lineOrPageDeltaY, - 0 /* options */); - } - - async ['Page.insertText'](options) { - return await this._contentPage.send('insertText', options); - } - - async ['Page.crash'](options) { - return await this._contentPage.send('crash', options); - } - - async ['Page.handleDialog']({dialogId, accept, promptText}) { - const dialog = this._pageTarget.dialog(dialogId); - if (!dialog) - throw new Error('Failed to find dialog with id = ' + dialogId); - if (accept) - dialog.accept(promptText); - else - dialog.dismiss(); - } - - async ['Page.setInterceptFileChooserDialog'](options) { - return await this._contentPage.send('setInterceptFileChooserDialog', options); - } - - async ['Page.startScreencast'](options) { - return await this._pageTarget.startScreencast(options); - } - - async ['Page.screencastFrameAck'](options) { - await this._pageTarget.screencastFrameAck(options); - } - - async ['Page.stopScreencast'](options) { - await this._pageTarget.stopScreencast(options); - } - - async ['Page.sendMessageToWorker']({workerId, message}) { - const worker = this._workers.get(workerId); - if (!worker) - throw new Error('ERROR: cannot find worker with id ' + workerId); - return await worker.sendMessage(JSON.parse(message)); - } -} - -var EXPORTED_SYMBOLS = ['PageHandler']; -this.PageHandler = PageHandler; diff --git a/browser_patches/firefox-beta/juggler/protocol/PrimitiveTypes.js b/browser_patches/firefox-beta/juggler/protocol/PrimitiveTypes.js deleted file mode 100644 index 5799038f19cbca..00000000000000 --- a/browser_patches/firefox-beta/juggler/protocol/PrimitiveTypes.js +++ /dev/null @@ -1,147 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const t = {}; - -t.String = function(x, details = {}, path = ['']) { - if (typeof x === 'string' || typeof x === 'String') - return true; - details.error = `Expected "${path.join('.')}" to be |string|; found |${typeof x}| \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Number = function(x, details = {}, path = ['']) { - if (typeof x === 'number') - return true; - details.error = `Expected "${path.join('.')}" to be |number|; found |${typeof x}| \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Boolean = function(x, details = {}, path = ['']) { - if (typeof x === 'boolean') - return true; - details.error = `Expected "${path.join('.')}" to be |boolean|; found |${typeof x}| \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Null = function(x, details = {}, path = ['']) { - if (Object.is(x, null)) - return true; - details.error = `Expected "${path.join('.')}" to be \`null\`; found \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Undefined = function(x, details = {}, path = ['']) { - if (Object.is(x, undefined)) - return true; - details.error = `Expected "${path.join('.')}" to be \`undefined\`; found \`${JSON.stringify(x)}\` instead.`; - return false; -} - -t.Any = x => true, - -t.Enum = function(values) { - return function(x, details = {}, path = ['']) { - if (values.indexOf(x) !== -1) - return true; - details.error = `Expected "${path.join('.')}" to be one of [${values.join(', ')}]; found \`${JSON.stringify(x)}\` (${typeof x}) instead.`; - return false; - } -} - -t.Nullable = function(scheme) { - return function(x, details = {}, path = ['']) { - if (Object.is(x, null)) - return true; - return checkScheme(scheme, x, details, path); - } -} - -t.Optional = function(scheme) { - return function(x, details = {}, path = ['']) { - if (Object.is(x, undefined)) - return true; - return checkScheme(scheme, x, details, path); - } -} - -t.Array = function(scheme) { - return function(x, details = {}, path = ['']) { - if (!Array.isArray(x)) { - details.error = `Expected "${path.join('.')}" to be an array; found \`${JSON.stringify(x)}\` (${typeof x}) instead.`; - return false; - } - const lastPathElement = path[path.length - 1]; - for (let i = 0; i < x.length; ++i) { - path[path.length - 1] = lastPathElement + `[${i}]`; - if (!checkScheme(scheme, x[i], details, path)) - return false; - } - path[path.length - 1] = lastPathElement; - return true; - } -} - -t.Recursive = function(types, schemeName) { - return function(x, details = {}, path = ['']) { - const scheme = types[schemeName]; - return checkScheme(scheme, x, details, path); - } -} - -function beauty(path, obj) { - if (path.length === 1) - return `object ${JSON.stringify(obj, null, 2)}`; - return `property "${path.join('.')}" - ${JSON.stringify(obj, null, 2)}`; -} - -function checkScheme(scheme, x, details = {}, path = ['']) { - if (!scheme) - throw new Error(`ILLDEFINED SCHEME: ${path.join('.')}`); - if (typeof scheme === 'object') { - if (!x) { - details.error = `Object "${path.join('.')}" is undefined, but has some scheme`; - return false; - } - for (const [propertyName, aScheme] of Object.entries(scheme)) { - path.push(propertyName); - const result = checkScheme(aScheme, x[propertyName], details, path); - path.pop(); - if (!result) - return false; - } - for (const propertyName of Object.keys(x)) { - if (!scheme[propertyName]) { - path.push(propertyName); - details.error = `Found ${beauty(path, x[propertyName])} which is not described in this scheme`; - return false; - } - } - return true; - } - return scheme(x, details, path); -} - -/* - -function test(scheme, obj) { - const details = {}; - if (!checkScheme(scheme, obj, details)) { - dump(`FAILED: ${JSON.stringify(obj)} - details.error: ${details.error} - `); - } else { - dump(`SUCCESS: ${JSON.stringify(obj)} -`); - } -} - -test(t.Array(t.String), ['a', 'b', 2, 'c']); -test(t.Either(t.String, t.Number), {}); - -*/ - -this.t = t; -this.checkScheme = checkScheme; -this.EXPORTED_SYMBOLS = ['t', 'checkScheme']; diff --git a/browser_patches/firefox-beta/juggler/protocol/Protocol.js b/browser_patches/firefox-beta/juggler/protocol/Protocol.js deleted file mode 100644 index be0f15af0d5a74..00000000000000 --- a/browser_patches/firefox-beta/juggler/protocol/Protocol.js +++ /dev/null @@ -1,993 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {t, checkScheme} = ChromeUtils.import('chrome://juggler/content/protocol/PrimitiveTypes.js'); - -// Protocol-specific types. -const browserTypes = {}; - -browserTypes.TargetInfo = { - type: t.Enum(['page']), - targetId: t.String, - browserContextId: t.Optional(t.String), - // PageId of parent tab, if any. - openerId: t.Optional(t.String), -}; - -browserTypes.CookieOptions = { - name: t.String, - value: t.String, - url: t.Optional(t.String), - domain: t.Optional(t.String), - path: t.Optional(t.String), - secure: t.Optional(t.Boolean), - httpOnly: t.Optional(t.Boolean), - sameSite: t.Optional(t.Enum(['Strict', 'Lax', 'None'])), - expires: t.Optional(t.Number), -}; - -browserTypes.Cookie = { - name: t.String, - domain: t.String, - path: t.String, - value: t.String, - expires: t.Number, - size: t.Number, - httpOnly: t.Boolean, - secure: t.Boolean, - session: t.Boolean, - sameSite: t.Enum(['Strict', 'Lax', 'None']), -}; - -browserTypes.Geolocation = { - latitude: t.Number, - longitude: t.Number, - accuracy: t.Optional(t.Number), -}; - -browserTypes.DownloadOptions = { - behavior: t.Optional(t.Enum(['saveToDisk', 'cancel'])), - downloadsDir: t.Optional(t.String), -}; - -const pageTypes = {}; -pageTypes.DOMPoint = { - x: t.Number, - y: t.Number, -}; - -pageTypes.Rect = { - x: t.Number, - y: t.Number, - width: t.Number, - height: t.Number, -}; - -pageTypes.Size = { - width: t.Number, - height: t.Number, -}; - -pageTypes.Viewport = { - viewportSize: pageTypes.Size, - deviceScaleFactor: t.Optional(t.Number), -}; - -pageTypes.DOMQuad = { - p1: pageTypes.DOMPoint, - p2: pageTypes.DOMPoint, - p3: pageTypes.DOMPoint, - p4: pageTypes.DOMPoint, -}; - -pageTypes.TouchPoint = { - x: t.Number, - y: t.Number, - radiusX: t.Optional(t.Number), - radiusY: t.Optional(t.Number), - rotationAngle: t.Optional(t.Number), - force: t.Optional(t.Number), -}; - -pageTypes.Clip = { - x: t.Number, - y: t.Number, - width: t.Number, - height: t.Number, -}; - -pageTypes.InitScript = { - script: t.String, - worldName: t.Optional(t.String), -}; - -const runtimeTypes = {}; -runtimeTypes.RemoteObject = { - type: t.Optional(t.Enum(['object', 'function', 'undefined', 'string', 'number', 'boolean', 'symbol', 'bigint'])), - subtype: t.Optional(t.Enum(['array', 'null', 'node', 'regexp', 'date', 'map', 'set', 'weakmap', 'weakset', 'error', 'proxy', 'promise', 'typedarray'])), - objectId: t.Optional(t.String), - unserializableValue: t.Optional(t.Enum(['Infinity', '-Infinity', '-0', 'NaN'])), - value: t.Any -}; - -runtimeTypes.ObjectProperty = { - name: t.String, - value: runtimeTypes.RemoteObject, -}; - -runtimeTypes.ScriptLocation = { - columnNumber: t.Number, - lineNumber: t.Number, - url: t.String, -}; - -runtimeTypes.ExceptionDetails = { - text: t.Optional(t.String), - stack: t.Optional(t.String), - value: t.Optional(t.Any), -}; - -runtimeTypes.CallFunctionArgument = { - objectId: t.Optional(t.String), - unserializableValue: t.Optional(t.Enum(['Infinity', '-Infinity', '-0', 'NaN'])), - value: t.Any, -}; - -runtimeTypes.AuxData = { - frameId: t.Optional(t.String), - name: t.Optional(t.String), -}; - -const axTypes = {}; -axTypes.AXTree = { - role: t.String, - name: t.String, - children: t.Optional(t.Array(t.Recursive(axTypes, 'AXTree'))), - - selected: t.Optional(t.Boolean), - focused: t.Optional(t.Boolean), - pressed: t.Optional(t.Boolean), - focusable: t.Optional(t.Boolean), - haspopup: t.Optional(t.String), - required: t.Optional(t.Boolean), - invalid: t.Optional(t.Boolean), - modal: t.Optional(t.Boolean), - editable: t.Optional(t.Boolean), - busy: t.Optional(t.Boolean), - multiline: t.Optional(t.Boolean), - readonly: t.Optional(t.Boolean), - checked: t.Optional(t.Enum(['mixed', true])), - expanded: t.Optional(t.Boolean), - disabled: t.Optional(t.Boolean), - multiselectable: t.Optional(t.Boolean), - - value: t.Optional(t.String), - description: t.Optional(t.String), - - roledescription: t.Optional(t.String), - valuetext: t.Optional(t.String), - orientation: t.Optional(t.String), - autocomplete: t.Optional(t.String), - keyshortcuts: t.Optional(t.String), - - level: t.Optional(t.Number), - - tag: t.Optional(t.String), - - foundObject: t.Optional(t.Boolean), -} - -const networkTypes = {}; - -networkTypes.HTTPHeader = { - name: t.String, - value: t.String, -}; - -networkTypes.HTTPCredentials = { - username: t.String, - password: t.String, -}; - -networkTypes.SecurityDetails = { - protocol: t.String, - subjectName: t.String, - issuer: t.String, - validFrom: t.Number, - validTo: t.Number, -}; - -networkTypes.ResourceTiming = { - startTime: t.Number, - domainLookupStart: t.Number, - domainLookupEnd: t.Number, - connectStart: t.Number, - secureConnectionStart: t.Number, - connectEnd: t.Number, - requestStart: t.Number, - responseStart: t.Number, -}; - -const Browser = { - targets: ['browser'], - - types: browserTypes, - - events: { - 'attachedToTarget': { - sessionId: t.String, - targetInfo: browserTypes.TargetInfo, - }, - 'detachedFromTarget': { - sessionId: t.String, - targetId: t.String, - }, - 'downloadCreated': { - uuid: t.String, - browserContextId: t.Optional(t.String), - pageTargetId: t.String, - url: t.String, - suggestedFileName: t.String, - }, - 'downloadFinished': { - uuid: t.String, - canceled: t.Optional(t.Boolean), - error: t.Optional(t.String), - }, - 'videoRecordingFinished': { - screencastId: t.String, - }, - }, - - methods: { - 'enable': { - params: { - attachToDefaultContext: t.Boolean, - }, - }, - 'createBrowserContext': { - params: { - removeOnDetach: t.Optional(t.Boolean), - }, - returns: { - browserContextId: t.String, - }, - }, - 'removeBrowserContext': { - params: { - browserContextId: t.String, - }, - }, - 'newPage': { - params: { - browserContextId: t.Optional(t.String), - }, - returns: { - targetId: t.String, - } - }, - 'close': {}, - 'getInfo': { - returns: { - userAgent: t.String, - version: t.String, - }, - }, - 'setExtraHTTPHeaders': { - params: { - browserContextId: t.Optional(t.String), - headers: t.Array(networkTypes.HTTPHeader), - }, - }, - 'setBrowserProxy': { - params: { - type: t.Enum(['http', 'https', 'socks', 'socks4']), - bypass: t.Array(t.String), - host: t.String, - port: t.Number, - username: t.Optional(t.String), - password: t.Optional(t.String), - }, - }, - 'setContextProxy': { - params: { - browserContextId: t.Optional(t.String), - type: t.Enum(['http', 'https', 'socks', 'socks4']), - bypass: t.Array(t.String), - host: t.String, - port: t.Number, - username: t.Optional(t.String), - password: t.Optional(t.String), - }, - }, - 'setHTTPCredentials': { - params: { - browserContextId: t.Optional(t.String), - credentials: t.Nullable(networkTypes.HTTPCredentials), - }, - }, - 'setRequestInterception': { - params: { - browserContextId: t.Optional(t.String), - enabled: t.Boolean, - }, - }, - 'setGeolocationOverride': { - params: { - browserContextId: t.Optional(t.String), - geolocation: t.Nullable(browserTypes.Geolocation), - } - }, - 'setUserAgentOverride': { - params: { - browserContextId: t.Optional(t.String), - userAgent: t.Nullable(t.String), - } - }, - 'setPlatformOverride': { - params: { - browserContextId: t.Optional(t.String), - platform: t.Nullable(t.String), - } - }, - 'setBypassCSP': { - params: { - browserContextId: t.Optional(t.String), - bypassCSP: t.Nullable(t.Boolean), - } - }, - 'setIgnoreHTTPSErrors': { - params: { - browserContextId: t.Optional(t.String), - ignoreHTTPSErrors: t.Nullable(t.Boolean), - } - }, - 'setJavaScriptDisabled': { - params: { - browserContextId: t.Optional(t.String), - javaScriptDisabled: t.Boolean, - } - }, - 'setLocaleOverride': { - params: { - browserContextId: t.Optional(t.String), - locale: t.Nullable(t.String), - } - }, - 'setTimezoneOverride': { - params: { - browserContextId: t.Optional(t.String), - timezoneId: t.Nullable(t.String), - } - }, - 'setDownloadOptions': { - params: { - browserContextId: t.Optional(t.String), - downloadOptions: t.Nullable(browserTypes.DownloadOptions), - } - }, - 'setTouchOverride': { - params: { - browserContextId: t.Optional(t.String), - hasTouch: t.Nullable(t.Boolean), - } - }, - 'setDefaultViewport': { - params: { - browserContextId: t.Optional(t.String), - viewport: t.Nullable(pageTypes.Viewport), - } - }, - 'setScrollbarsHidden': { - params: { - browserContextId: t.Optional(t.String), - hidden: t.Boolean, - } - }, - 'setInitScripts': { - params: { - browserContextId: t.Optional(t.String), - scripts: t.Array(pageTypes.InitScript), - } - }, - 'addBinding': { - params: { - browserContextId: t.Optional(t.String), - worldName: t.Optional(t.String), - name: t.String, - script: t.String, - }, - }, - 'grantPermissions': { - params: { - origin: t.String, - browserContextId: t.Optional(t.String), - permissions: t.Array(t.String), - }, - }, - 'resetPermissions': { - params: { - browserContextId: t.Optional(t.String), - } - }, - 'setCookies': { - params: { - browserContextId: t.Optional(t.String), - cookies: t.Array(browserTypes.CookieOptions), - } - }, - 'clearCookies': { - params: { - browserContextId: t.Optional(t.String), - } - }, - 'getCookies': { - params: { - browserContextId: t.Optional(t.String) - }, - returns: { - cookies: t.Array(browserTypes.Cookie), - }, - }, - 'setOnlineOverride': { - params: { - browserContextId: t.Optional(t.String), - override: t.Nullable(t.Enum(['online', 'offline'])), - } - }, - 'setColorScheme': { - params: { - browserContextId: t.Optional(t.String), - colorScheme: t.Nullable(t.Enum(['dark', 'light', 'no-preference'])), - }, - }, - 'setReducedMotion': { - params: { - browserContextId: t.Optional(t.String), - reducedMotion: t.Nullable(t.Enum(['reduce', 'no-preference'])), - }, - }, - 'setForcedColors': { - params: { - browserContextId: t.Optional(t.String), - forcedColors: t.Nullable(t.Enum(['active', 'none'])), - }, - }, - 'setVideoRecordingOptions': { - params: { - browserContextId: t.Optional(t.String), - options: t.Optional({ - dir: t.String, - width: t.Number, - height: t.Number, - }), - }, - }, - 'cancelDownload': { - params: { - uuid: t.Optional(t.String), - } - } - }, -}; - -const Network = { - targets: ['page'], - types: networkTypes, - events: { - 'requestWillBeSent': { - // frameId may be absent for redirected requests. - frameId: t.Optional(t.String), - requestId: t.String, - // RequestID of redirected request. - redirectedFrom: t.Optional(t.String), - postData: t.Optional(t.String), - headers: t.Array(networkTypes.HTTPHeader), - isIntercepted: t.Boolean, - url: t.String, - method: t.String, - navigationId: t.Optional(t.String), - cause: t.String, - internalCause: t.String, - }, - 'responseReceived': { - securityDetails: t.Nullable(networkTypes.SecurityDetails), - requestId: t.String, - fromCache: t.Boolean, - remoteIPAddress: t.Optional(t.String), - remotePort: t.Optional(t.Number), - status: t.Number, - statusText: t.String, - headers: t.Array(networkTypes.HTTPHeader), - timing: networkTypes.ResourceTiming, - fromServiceWorker: t.Boolean, - }, - 'requestFinished': { - requestId: t.String, - responseEndTime: t.Number, - transferSize: t.Number, - encodedBodySize: t.Number, - protocolVersion: t.Optional(t.String), - }, - 'requestFailed': { - requestId: t.String, - errorCode: t.String, - }, - }, - methods: { - 'setRequestInterception': { - params: { - enabled: t.Boolean, - }, - }, - 'setExtraHTTPHeaders': { - params: { - headers: t.Array(networkTypes.HTTPHeader), - }, - }, - 'abortInterceptedRequest': { - params: { - requestId: t.String, - errorCode: t.String, - }, - }, - 'resumeInterceptedRequest': { - params: { - requestId: t.String, - url: t.Optional(t.String), - method: t.Optional(t.String), - headers: t.Optional(t.Array(networkTypes.HTTPHeader)), - postData: t.Optional(t.String), - }, - }, - 'fulfillInterceptedRequest': { - params: { - requestId: t.String, - status: t.Number, - statusText: t.String, - headers: t.Array(networkTypes.HTTPHeader), - base64body: t.Optional(t.String), // base64-encoded - }, - }, - 'getResponseBody': { - params: { - requestId: t.String, - }, - returns: { - base64body: t.String, - evicted: t.Optional(t.Boolean), - }, - }, - }, -}; - -const Runtime = { - targets: ['page'], - types: runtimeTypes, - events: { - 'executionContextCreated': { - executionContextId: t.String, - auxData: runtimeTypes.AuxData, - }, - 'executionContextDestroyed': { - executionContextId: t.String, - }, - 'console': { - executionContextId: t.String, - args: t.Array(runtimeTypes.RemoteObject), - type: t.String, - location: runtimeTypes.ScriptLocation, - }, - }, - methods: { - 'evaluate': { - params: { - // Pass frameId here. - executionContextId: t.String, - expression: t.String, - returnByValue: t.Optional(t.Boolean), - }, - - returns: { - result: t.Optional(runtimeTypes.RemoteObject), - exceptionDetails: t.Optional(runtimeTypes.ExceptionDetails), - } - }, - 'callFunction': { - params: { - // Pass frameId here. - executionContextId: t.String, - functionDeclaration: t.String, - returnByValue: t.Optional(t.Boolean), - args: t.Array(runtimeTypes.CallFunctionArgument), - }, - - returns: { - result: t.Optional(runtimeTypes.RemoteObject), - exceptionDetails: t.Optional(runtimeTypes.ExceptionDetails), - } - }, - 'disposeObject': { - params: { - executionContextId: t.String, - objectId: t.String, - }, - }, - - 'getObjectProperties': { - params: { - executionContextId: t.String, - objectId: t.String, - }, - - returns: { - properties: t.Array(runtimeTypes.ObjectProperty), - } - }, - }, -}; - -const Page = { - targets: ['page'], - - types: pageTypes, - events: { - 'ready': { - }, - 'crashed': { - }, - 'eventFired': { - frameId: t.String, - name: t.Enum(['load', 'DOMContentLoaded']), - }, - 'uncaughtError': { - frameId: t.String, - message: t.String, - stack: t.String, - }, - 'frameAttached': { - frameId: t.String, - parentFrameId: t.Optional(t.String), - }, - 'frameDetached': { - frameId: t.String, - }, - 'navigationStarted': { - frameId: t.String, - navigationId: t.String, - url: t.String, - }, - 'navigationCommitted': { - frameId: t.String, - // |navigationId| can only be null in response to enable. - navigationId: t.Optional(t.String), - url: t.String, - // frame.id or frame.name - name: t.String, - }, - 'navigationAborted': { - frameId: t.String, - navigationId: t.String, - errorText: t.String, - }, - 'sameDocumentNavigation': { - frameId: t.String, - url: t.String, - }, - 'dialogOpened': { - dialogId: t.String, - type: t.Enum(['prompt', 'alert', 'confirm', 'beforeunload']), - message: t.String, - defaultValue: t.Optional(t.String), - }, - 'dialogClosed': { - dialogId: t.String, - }, - 'bindingCalled': { - executionContextId: t.String, - name: t.String, - payload: t.Any, - }, - 'linkClicked': { - phase: t.Enum(['before', 'after']), - }, - 'willOpenNewWindowAsynchronously': {}, - 'fileChooserOpened': { - executionContextId: t.String, - element: runtimeTypes.RemoteObject - }, - 'workerCreated': { - workerId: t.String, - frameId: t.String, - url: t.String, - }, - 'workerDestroyed': { - workerId: t.String, - }, - 'dispatchMessageFromWorker': { - workerId: t.String, - message: t.String, - }, - 'videoRecordingStarted': { - screencastId: t.String, - file: t.String, - }, - 'webSocketCreated': { - frameId: t.String, - wsid: t.String, - requestURL: t.String, - }, - 'webSocketOpened': { - frameId: t.String, - requestId: t.String, - wsid: t.String, - effectiveURL: t.String, - }, - 'webSocketClosed': { - frameId: t.String, - wsid: t.String, - error: t.String, - }, - 'webSocketFrameSent': { - frameId: t.String, - wsid: t.String, - opcode: t.Number, - data: t.String, - }, - 'webSocketFrameReceived': { - frameId: t.String, - wsid: t.String, - opcode: t.Number, - data: t.String, - }, - 'screencastFrame': { - data: t.String, - deviceWidth: t.Number, - deviceHeight: t.Number, - }, - }, - - methods: { - 'close': { - params: { - runBeforeUnload: t.Optional(t.Boolean), - }, - }, - 'setFileInputFiles': { - params: { - frameId: t.String, - objectId: t.String, - files: t.Array(t.String), - }, - }, - 'addBinding': { - params: { - worldName: t.Optional(t.String), - name: t.String, - script: t.String, - }, - }, - 'setViewportSize': { - params: { - viewportSize: t.Nullable(pageTypes.Size), - }, - }, - 'bringToFront': { - params: { - }, - }, - 'setEmulatedMedia': { - params: { - type: t.Optional(t.Enum(['screen', 'print', ''])), - colorScheme: t.Optional(t.Enum(['dark', 'light', 'no-preference'])), - reducedMotion: t.Optional(t.Enum(['reduce', 'no-preference'])), - forcedColors: t.Optional(t.Enum(['active', 'none'])), - }, - }, - 'setCacheDisabled': { - params: { - cacheDisabled: t.Boolean, - }, - }, - 'describeNode': { - params: { - frameId: t.String, - objectId: t.String, - }, - returns: { - contentFrameId: t.Optional(t.String), - ownerFrameId: t.Optional(t.String), - }, - }, - 'scrollIntoViewIfNeeded': { - params: { - frameId: t.String, - objectId: t.String, - rect: t.Optional(pageTypes.Rect), - }, - }, - 'setInitScripts': { - params: { - scripts: t.Array(pageTypes.InitScript) - } - }, - 'navigate': { - params: { - frameId: t.String, - url: t.String, - referer: t.Optional(t.String), - }, - returns: { - navigationId: t.Nullable(t.String), - navigationURL: t.Nullable(t.String), - } - }, - 'goBack': { - params: { - frameId: t.String, - }, - returns: { - success: t.Boolean, - }, - }, - 'goForward': { - params: { - frameId: t.String, - }, - returns: { - success: t.Boolean, - }, - }, - 'reload': { - params: { - frameId: t.String, - }, - }, - 'adoptNode': { - params: { - frameId: t.String, - objectId: t.String, - executionContextId: t.String, - }, - returns: { - remoteObject: t.Nullable(runtimeTypes.RemoteObject), - }, - }, - 'screenshot': { - params: { - mimeType: t.Enum(['image/png', 'image/jpeg']), - clip: pageTypes.Clip, - omitDeviceScaleFactor: t.Optional(t.Boolean), - }, - returns: { - data: t.String, - } - }, - 'getContentQuads': { - params: { - frameId: t.String, - objectId: t.String, - }, - returns: { - quads: t.Array(pageTypes.DOMQuad), - }, - }, - 'dispatchKeyEvent': { - params: { - type: t.String, - key: t.String, - keyCode: t.Number, - location: t.Number, - code: t.String, - repeat: t.Boolean, - text: t.Optional(t.String), - } - }, - 'dispatchTouchEvent': { - params: { - type: t.Enum(['touchStart', 'touchEnd', 'touchMove', 'touchCancel']), - touchPoints: t.Array(pageTypes.TouchPoint), - modifiers: t.Number, - }, - returns: { - defaultPrevented: t.Boolean, - } - }, - 'dispatchTapEvent': { - params: { - x: t.Number, - y: t.Number, - modifiers: t.Number, - } - }, - 'dispatchMouseEvent': { - params: { - type: t.String, - button: t.Number, - x: t.Number, - y: t.Number, - modifiers: t.Number, - clickCount: t.Optional(t.Number), - buttons: t.Number, - } - }, - 'dispatchWheelEvent': { - params: { - x: t.Number, - y: t.Number, - deltaX: t.Number, - deltaY: t.Number, - deltaZ: t.Number, - modifiers: t.Number, - } - }, - 'insertText': { - params: { - text: t.String, - } - }, - 'crash': { - params: {} - }, - 'handleDialog': { - params: { - dialogId: t.String, - accept: t.Boolean, - promptText: t.Optional(t.String), - }, - }, - 'setInterceptFileChooserDialog': { - params: { - enabled: t.Boolean, - }, - }, - 'sendMessageToWorker': { - params: { - frameId: t.String, - workerId: t.String, - message: t.String, - }, - }, - 'startScreencast': { - params: { - width: t.Number, - height: t.Number, - quality: t.Number, - }, - returns: { - screencastId: t.String, - }, - }, - 'screencastFrameAck': { - params: { - screencastId: t.String, - }, - }, - 'stopScreencast': { - }, - }, -}; - - -const Accessibility = { - targets: ['page'], - types: axTypes, - events: {}, - methods: { - 'getFullAXTree': { - params: { - objectId: t.Optional(t.String), - }, - returns: { - tree: axTypes.AXTree - }, - } - } -} - -this.protocol = { - domains: {Browser, Page, Runtime, Network, Accessibility}, -}; -this.checkScheme = checkScheme; -this.EXPORTED_SYMBOLS = ['protocol', 'checkScheme']; diff --git a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.cpp b/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.cpp deleted file mode 100644 index 88d1791dde449b..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "HeadlessWindowCapturer.h" - -#include "api/video/i420_buffer.h" -#include "HeadlessWidget.h" -#include "libyuv.h" -#include "mozilla/EndianUtils.h" -#include "mozilla/gfx/DataSurfaceHelpers.h" -#include "rtc_base/ref_counted_object.h" -#include "rtc_base/time_utils.h" -#include "api/scoped_refptr.h" - -using namespace mozilla::widget; -using namespace webrtc; - -namespace mozilla { - -rtc::scoped_refptr HeadlessWindowCapturer::Create(HeadlessWidget* headlessWindow) { - return new rtc::RefCountedObject(headlessWindow); -} - -HeadlessWindowCapturer::HeadlessWindowCapturer(mozilla::widget::HeadlessWidget* window) - : mWindow(window) { -} -HeadlessWindowCapturer::~HeadlessWindowCapturer() { - StopCapture(); -} - - -void HeadlessWindowCapturer::RegisterCaptureDataCallback(rtc::VideoSinkInterface* dataCallback) { - rtc::CritScope lock2(&_callBackCs); - _dataCallBacks.insert(dataCallback); -} -void HeadlessWindowCapturer::DeRegisterCaptureDataCallback(rtc::VideoSinkInterface* dataCallback) { - rtc::CritScope lock2(&_callBackCs); - auto it = _dataCallBacks.find(dataCallback); - if (it != _dataCallBacks.end()) { - _dataCallBacks.erase(it); - } -} - -void HeadlessWindowCapturer::RegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) { - rtc::CritScope lock2(&_callBackCs); - _rawFrameCallbacks.insert(rawFrameCallback); -} - -void HeadlessWindowCapturer::DeRegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) { - rtc::CritScope lock2(&_callBackCs); - auto it = _rawFrameCallbacks.find(rawFrameCallback); - if (it != _rawFrameCallbacks.end()) { - _rawFrameCallbacks.erase(it); - } -} - -void HeadlessWindowCapturer::NotifyFrameCaptured(const webrtc::VideoFrame& frame) { - rtc::CritScope lock2(&_callBackCs); - for (auto dataCallBack : _dataCallBacks) - dataCallBack->OnFrame(frame); -} - -int32_t HeadlessWindowCapturer::StopCaptureIfAllClientsClose() { - if (_dataCallBacks.empty()) { - return StopCapture(); - } else { - return 0; - } -} - -int32_t HeadlessWindowCapturer::StartCapture(const webrtc::VideoCaptureCapability& capability) { - mWindow->SetSnapshotListener([this] (RefPtr&& dataSurface){ - if (!NS_IsInCompositorThread()) { - fprintf(stderr, "SnapshotListener is called not on the Compositor thread!\n"); - return; - } - - if (dataSurface->GetFormat() != gfx::SurfaceFormat::B8G8R8A8) { - fprintf(stderr, "Unexpected snapshot surface format: %hhd\n", dataSurface->GetFormat()); - return; - } - - webrtc::VideoCaptureCapability frameInfo; - frameInfo.width = dataSurface->GetSize().width; - frameInfo.height = dataSurface->GetSize().height; -#if MOZ_LITTLE_ENDIAN() - frameInfo.videoType = VideoType::kARGB; -#else - frameInfo.videoType = VideoType::kBGRA; -#endif - - { - rtc::CritScope lock2(&_callBackCs); - for (auto rawFrameCallback : _rawFrameCallbacks) { - rawFrameCallback->OnRawFrame(dataSurface->GetData(), dataSurface->Stride(), frameInfo); - } - if (!_dataCallBacks.size()) - return; - } - - int width = dataSurface->GetSize().width; - int height = dataSurface->GetSize().height; - rtc::scoped_refptr buffer = I420Buffer::Create(width, height); - - gfx::DataSourceSurface::ScopedMap map(dataSurface.get(), gfx::DataSourceSurface::MapType::READ); - if (!map.IsMapped()) { - fprintf(stderr, "Failed to map snapshot bytes!\n"); - return; - } - -#if MOZ_LITTLE_ENDIAN() - const int conversionResult = libyuv::ARGBToI420( -#else - const int conversionResult = libyuv::BGRAToI420( -#endif - map.GetData(), map.GetStride(), - buffer->MutableDataY(), buffer->StrideY(), - buffer->MutableDataU(), buffer->StrideU(), - buffer->MutableDataV(), buffer->StrideV(), - width, height); - if (conversionResult != 0) { - fprintf(stderr, "Failed to convert capture frame to I420: %d\n", conversionResult); - return; - } - - VideoFrame captureFrame(buffer, 0, rtc::TimeMillis(), kVideoRotation_0); - NotifyFrameCaptured(captureFrame); - }); - return 0; -} - -int32_t HeadlessWindowCapturer::StopCapture() { - if (!CaptureStarted()) - return 0; - mWindow->SetSnapshotListener(nullptr); - return 0; -} - -bool HeadlessWindowCapturer::CaptureStarted() { - return true; -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.h b/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.h deleted file mode 100644 index 9f67565c04d418..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/HeadlessWindowCapturer.h +++ /dev/null @@ -1,64 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include "api/video/video_frame.h" -#include "api/video/video_sink_interface.h" -#include "modules/video_capture/video_capture.h" -#include "rtc_base/deprecated/recursive_critical_section.h" -#include "video_engine/desktop_capture_impl.h" - -class nsIWidget; - -namespace mozilla { - -namespace widget { -class HeadlessWidget; -} - -class HeadlessWindowCapturer : public webrtc::VideoCaptureModuleEx { - public: - static rtc::scoped_refptr Create(mozilla::widget::HeadlessWidget*); - - void RegisterCaptureDataCallback( - rtc::VideoSinkInterface* dataCallback) override; - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* dataCallback) override; - int32_t StopCaptureIfAllClientsClose() override; - - void RegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) override; - void DeRegisterRawFrameCallback(webrtc::RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(webrtc::VideoRotation) override { return -1; } - bool SetApplyRotation(bool) override { return false; } - bool GetApplyRotation() override { return true; } - - const char* CurrentDeviceName() const override { return "Headless window"; } - - // Platform dependent - int32_t StartCapture(const webrtc::VideoCaptureCapability& capability) override; - bool FocusOnSelectedSource() override { return false; } - int32_t StopCapture() override; - bool CaptureStarted() override; - int32_t CaptureSettings(webrtc::VideoCaptureCapability& settings) override { - return -1; - } - - protected: - HeadlessWindowCapturer(mozilla::widget::HeadlessWidget*); - ~HeadlessWindowCapturer() override; - - private: - void NotifyFrameCaptured(const webrtc::VideoFrame& frame); - - RefPtr mWindow; - rtc::RecursiveCriticalSection _callBackCs; - std::set*> _dataCallBacks; - std::set _rawFrameCallbacks; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.cpp b/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.cpp deleted file mode 100644 index 5891953392bb56..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2010, The WebM Project authors. All rights reserved. - * Copyright (c) 2013 The Chromium Authors. All rights reserved. - * Copyright (C) 2020 Microsoft Corporation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "ScreencastEncoder.h" - -#include -#include -#include -#include -#include -#include "nsIThread.h" -#include "nsThreadUtils.h" -#include "WebMFileWriter.h" -#include "api/video/video_frame.h" - -namespace mozilla { - -namespace { - -struct VpxCodecDeleter { - void operator()(vpx_codec_ctx_t* codec) { - if (codec) { - vpx_codec_err_t ret = vpx_codec_destroy(codec); - if (ret != VPX_CODEC_OK) - fprintf(stderr, "Failed to destroy codec: %s\n", vpx_codec_error(codec)); - } - } -}; - -using ScopedVpxCodec = std::unique_ptr; - -// Number of timebase unints per one frame. -constexpr int timeScale = 1000; - -// Defines the dimension of a macro block. This is used to compute the active -// map for the encoder. -const int kMacroBlockSize = 16; - -void createImage(unsigned int width, unsigned int height, - std::unique_ptr& out_image, - std::unique_ptr& out_image_buffer, - int& out_buffer_size) { - std::unique_ptr image(new vpx_image_t()); - memset(image.get(), 0, sizeof(vpx_image_t)); - - // libvpx seems to require both to be assigned. - image->d_w = width; - image->w = width; - image->d_h = height; - image->h = height; - - // I420 - image->fmt = VPX_IMG_FMT_YV12; - image->x_chroma_shift = 1; - image->y_chroma_shift = 1; - - // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad - // the Y, U and V planes' strides to multiples of 16 bytes. - const int y_stride = ((image->w - 1) & ~15) + 16; - const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; - const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; - - // libvpx accesses the source image in macro blocks, and will over-read - // if the image is not padded out to the next macroblock: crbug.com/119633. - // Pad the Y, U and V planes' height out to compensate. - // Assuming macroblocks are 16x16, aligning the planes' strides above also - // macroblock aligned them. - static_assert(kMacroBlockSize == 16, "macroblock_size_not_16"); - const int y_rows = ((image->h - 1) & ~(kMacroBlockSize-1)) + kMacroBlockSize; - const int uv_rows = y_rows >> image->y_chroma_shift; - - // Allocate a YUV buffer large enough for the aligned data & padding. - out_buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows; - std::unique_ptr image_buffer(new uint8_t[out_buffer_size]); - - // Reset image value to 128 so we just need to fill in the y plane. - memset(image_buffer.get(), 128, out_buffer_size); - - // Fill in the information for |image_|. - unsigned char* uchar_buffer = - reinterpret_cast(image_buffer.get()); - image->planes[0] = uchar_buffer; - image->planes[1] = image->planes[0] + y_stride * y_rows; - image->planes[2] = image->planes[1] + uv_stride * uv_rows; - image->stride[0] = y_stride; - image->stride[1] = uv_stride; - image->stride[2] = uv_stride; - - out_image = std::move(image); - out_image_buffer = std::move(image_buffer); -} - -} // namespace - -class ScreencastEncoder::VPXFrame { -public: - VPXFrame(rtc::scoped_refptr&& buffer, const gfx::IntMargin& margin) - : m_frameBuffer(std::move(buffer)) - , m_margin(margin) - { } - - void setDuration(TimeDuration duration) { m_duration = duration; } - TimeDuration duration() const { return m_duration; } - - void convertToVpxImage(vpx_image_t* image) - { - if (m_frameBuffer->type() != webrtc::VideoFrameBuffer::Type::kI420) { - fprintf(stderr, "convertToVpxImage unexpected frame buffer type: %d\n", m_frameBuffer->type()); - return; - } - - auto src = m_frameBuffer->GetI420(); - const int y_stride = image->stride[VPX_PLANE_Y]; - MOZ_ASSERT(image->stride[VPX_PLANE_U] == image->stride[VPX_PLANE_V]); - const int uv_stride = image->stride[1]; - uint8_t* y_data = image->planes[VPX_PLANE_Y]; - uint8_t* u_data = image->planes[VPX_PLANE_U]; - uint8_t* v_data = image->planes[VPX_PLANE_V]; - - double src_width = src->width() - m_margin.LeftRight(); - double src_height = src->height() - m_margin.top; - // YUV offsets must be even. - int yuvTopOffset = m_margin.top & 1 ? m_margin.top + 1 : m_margin.top; - int yuvLeftOffset = m_margin.left & 1 ? m_margin.left + 1 : m_margin.left; - - if (src_width > image->w || src_height > image->h) { - double scale = std::min(image->w / src_width, image->h / src_height); - double dst_width = src_width * scale; - if (dst_width > image->w) { - src_width *= image->w / dst_width; - dst_width = image->w; - } - double dst_height = src_height * scale; - if (dst_height > image->h) { - src_height *= image->h / dst_height; - dst_height = image->h; - } - libyuv::I420Scale(src->DataY() + yuvTopOffset * src->StrideY() + yuvLeftOffset, src->StrideY(), - src->DataU() + (yuvTopOffset * src->StrideU() + yuvLeftOffset) / 2, src->StrideU(), - src->DataV() + (yuvTopOffset * src->StrideV() + yuvLeftOffset) / 2, src->StrideV(), - src_width, src_height, - y_data, y_stride, - u_data, uv_stride, - v_data, uv_stride, - dst_width, dst_height, - libyuv::kFilterBilinear); - } else { - int width = std::min(image->w, src_width); - int height = std::min(image->h, src_height); - - libyuv::I420Copy(src->DataY() + yuvTopOffset * src->StrideY() + yuvLeftOffset, src->StrideY(), - src->DataU() + (yuvTopOffset * src->StrideU() + yuvLeftOffset) / 2, src->StrideU(), - src->DataV() + (yuvTopOffset * src->StrideV() + yuvLeftOffset) / 2, src->StrideV(), - y_data, y_stride, - u_data, uv_stride, - v_data, uv_stride, - width, height); - } - } - -private: - rtc::scoped_refptr m_frameBuffer; - gfx::IntMargin m_margin; - TimeDuration m_duration; -}; - - -class ScreencastEncoder::VPXCodec { -public: - VPXCodec(ScopedVpxCodec codec, vpx_codec_enc_cfg_t cfg, FILE* file) - : m_codec(std::move(codec)) - , m_cfg(cfg) - , m_file(file) - , m_writer(new WebMFileWriter(file, &m_cfg)) - { - nsresult rv = NS_NewNamedThread("Screencast enc", getter_AddRefs(m_encoderQueue)); - if (rv != NS_OK) { - fprintf(stderr, "ScreencastEncoder::VPXCodec failed to spawn thread %d\n", rv); - return; - } - - createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer, m_imageBufferSize); - } - - ~VPXCodec() { - m_encoderQueue->Shutdown(); - m_encoderQueue = nullptr; - } - - void encodeFrameAsync(std::unique_ptr&& frame) - { - m_encoderQueue->Dispatch(NS_NewRunnableFunction("VPXCodec::encodeFrameAsync", [this, frame = std::move(frame)] { - memset(m_imageBuffer.get(), 128, m_imageBufferSize); - frame->convertToVpxImage(m_image.get()); - - double frameCount = frame->duration().ToSeconds() * fps; - // For long duration repeat frame at 1 fps to ensure last frame duration is short enough. - // TODO: figure out why simply passing duration doesn't work well. - for (;frameCount > 1.5; frameCount -= 1) { - encodeFrame(m_image.get(), timeScale); - } - encodeFrame(m_image.get(), std::max(1, frameCount * timeScale)); - })); - } - - void finishAsync(std::function&& callback) - { - m_encoderQueue->Dispatch(NS_NewRunnableFunction("VPXCodec::finishAsync", [this, callback = std::move(callback)] { - finish(); - callback(); - })); - } - -private: - bool encodeFrame(vpx_image_t *img, int duration) - { - vpx_codec_iter_t iter = nullptr; - const vpx_codec_cx_pkt_t *pkt = nullptr; - int flags = 0; - const vpx_codec_err_t res = vpx_codec_encode(m_codec.get(), img, m_pts, duration, flags, VPX_DL_REALTIME); - if (res != VPX_CODEC_OK) { - fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(m_codec.get())); - return false; - } - - bool gotPkts = false; - while ((pkt = vpx_codec_get_cx_data(m_codec.get(), &iter)) != nullptr) { - gotPkts = true; - - if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { - m_writer->writeFrame(pkt); - ++m_frameCount; - // fprintf(stderr, " #%03d %spts=%" PRId64 " sz=%zd\n", m_frameCount, (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0 ? "[K] " : "", pkt->data.frame.pts, pkt->data.frame.sz); - m_pts += pkt->data.frame.duration; - } - } - - return gotPkts; - } - - void finish() - { - // Flush encoder. - while (encodeFrame(nullptr, 1)) - ++m_frameCount; - - m_writer->finish(); - fclose(m_file); - // fprintf(stderr, "ScreencastEncoder::finish %d frames\n", m_frameCount); - } - - RefPtr m_encoderQueue; - ScopedVpxCodec m_codec; - vpx_codec_enc_cfg_t m_cfg; - FILE* m_file { nullptr }; - std::unique_ptr m_writer; - int m_frameCount { 0 }; - int64_t m_pts { 0 }; - std::unique_ptr m_imageBuffer; - int m_imageBufferSize { 0 }; - std::unique_ptr m_image; -}; - -ScreencastEncoder::ScreencastEncoder(std::unique_ptr vpxCodec, const gfx::IntMargin& margin) - : m_vpxCodec(std::move(vpxCodec)) - , m_margin(margin) -{ -} - -ScreencastEncoder::~ScreencastEncoder() -{ -} - -std::unique_ptr ScreencastEncoder::create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin) -{ - vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx(); - if (!codec_interface) { - errorString = "Codec not found."; - return nullptr; - } - - if (width <= 0 || height <= 0 || (width % 2) != 0 || (height % 2) != 0) { - errorString.AppendPrintf("Invalid frame size: %dx%d", width, height); - return nullptr; - } - - vpx_codec_enc_cfg_t cfg; - memset(&cfg, 0, sizeof(cfg)); - vpx_codec_err_t error = vpx_codec_enc_config_default(codec_interface, &cfg, 0); - if (error) { - errorString.AppendPrintf("Failed to get default codec config: %s", vpx_codec_err_to_string(error)); - return nullptr; - } - - cfg.g_w = width; - cfg.g_h = height; - cfg.g_timebase.num = 1; - cfg.g_timebase.den = fps * timeScale; - cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; - - ScopedVpxCodec codec(new vpx_codec_ctx_t); - if (vpx_codec_enc_init(codec.get(), codec_interface, &cfg, 0)) { - errorString.AppendPrintf("Failed to initialize encoder: %s", vpx_codec_error(codec.get())); - return nullptr; - } - - FILE* file = fopen(filePath.get(), "wb"); - if (!file) { - errorString.AppendPrintf("Failed to open file '%s' for writing: %s", filePath.get(), strerror(errno)); - return nullptr; - } - - std::unique_ptr vpxCodec(new VPXCodec(std::move(codec), cfg, file)); - // fprintf(stderr, "ScreencastEncoder initialized with: %s\n", vpx_codec_iface_name(codec_interface)); - return std::make_unique(std::move(vpxCodec), margin); -} - -void ScreencastEncoder::flushLastFrame() -{ - TimeStamp now = TimeStamp::Now(); - if (m_lastFrameTimestamp) { - // If previous frame encoding failed for some rason leave the timestampt intact. - if (!m_lastFrame) - return; - - m_lastFrame->setDuration(now - m_lastFrameTimestamp); - m_vpxCodec->encodeFrameAsync(std::move(m_lastFrame)); - } - m_lastFrameTimestamp = now; -} - -void ScreencastEncoder::encodeFrame(const webrtc::VideoFrame& videoFrame) -{ - // fprintf(stderr, "ScreencastEncoder::encodeFrame\n"); - flushLastFrame(); - - m_lastFrame = std::make_unique(videoFrame.video_frame_buffer(), m_margin); -} - -void ScreencastEncoder::finish(std::function&& callback) -{ - if (!m_vpxCodec) { - callback(); - return; - } - - flushLastFrame(); - m_vpxCodec->finishAsync([callback = std::move(callback)] () mutable { - NS_DispatchToMainThread(NS_NewRunnableFunction("ScreencastEncoder::finish callback", std::move(callback))); - }); -} - - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.h b/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.h deleted file mode 100644 index 883ad01011cf6d..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/ScreencastEncoder.h +++ /dev/null @@ -1,45 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include "mozilla/gfx/Rect.h" -#include "mozilla/Maybe.h" -#include "mozilla/TimeStamp.h" -#include "nsISupportsImpl.h" -#include "nsStringFwd.h" - -namespace webrtc { -class VideoFrame; -} - -namespace mozilla { - -class ScreencastEncoder { -public: - static constexpr int fps = 25; - - static std::unique_ptr create(nsCString& errorString, const nsCString& filePath, int width, int height, const gfx::IntMargin& margin); - - class VPXCodec; - ScreencastEncoder(std::unique_ptr, const gfx::IntMargin& margin); - ~ScreencastEncoder(); - - void encodeFrame(const webrtc::VideoFrame& videoFrame); - - void finish(std::function&& callback); - -private: - void flushLastFrame(); - - std::unique_ptr m_vpxCodec; - gfx::IntMargin m_margin; - TimeStamp m_lastFrameTimestamp; - class VPXFrame; - std::unique_ptr m_lastFrame; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.cpp b/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.cpp deleted file mode 100644 index f720b300f25187..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2014 The WebM project authors. All Rights Reserved. - */ - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WebMFileWriter.h" - -#include -#include "mkvmuxer/mkvmuxerutil.h" - -namespace mozilla { - -WebMFileWriter::WebMFileWriter(FILE* file, vpx_codec_enc_cfg_t* cfg) - : m_cfg(cfg) - , m_writer(new mkvmuxer::MkvWriter(file)) - , m_segment(new mkvmuxer::Segment()) { - m_segment->Init(m_writer.get()); - m_segment->set_mode(mkvmuxer::Segment::kFile); - m_segment->OutputCues(true); - - mkvmuxer::SegmentInfo* info = m_segment->GetSegmentInfo(); - std::string version = "Playwright " + std::string(vpx_codec_version_str()); - info->set_writing_app(version.c_str()); - - // Add vp8 track. - m_videoTrackId = m_segment->AddVideoTrack( - static_cast(m_cfg->g_w), static_cast(m_cfg->g_h), 0); - if (!m_videoTrackId) { - fprintf(stderr, "Failed to add video track\n"); - } -} - -WebMFileWriter::~WebMFileWriter() {} - -void WebMFileWriter::writeFrame(const vpx_codec_cx_pkt_t* pkt) { - int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * m_cfg->g_timebase.num / - m_cfg->g_timebase.den; - m_segment->AddFrame(static_cast(pkt->data.frame.buf), - pkt->data.frame.sz, m_videoTrackId, pts_ns, - pkt->data.frame.flags & VPX_FRAME_IS_KEY); -} - -void WebMFileWriter::finish() { - m_segment->Finalize(); -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.h b/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.h deleted file mode 100644 index 4a7fd06e6c3e74..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/WebMFileWriter.h +++ /dev/null @@ -1,32 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include -#include "vpx/vpx_encoder.h" - -#include "mkvmuxer/mkvmuxer.h" -#include "mkvmuxer/mkvwriter.h" - -namespace mozilla { - -class WebMFileWriter { -public: - WebMFileWriter(FILE*, vpx_codec_enc_cfg_t* cfg); - ~WebMFileWriter(); - - void writeFrame(const vpx_codec_cx_pkt_t* pkt); - void finish(); - -private: - vpx_codec_enc_cfg_t* m_cfg = nullptr; - std::unique_ptr m_writer; - std::unique_ptr m_segment; - uint64_t m_videoTrackId = 0; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/components.conf b/browser_patches/firefox-beta/juggler/screencast/components.conf deleted file mode 100644 index 6298739122ea57..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/components.conf +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -Classes = [ - { - 'cid': '{d8c4d9e0-9462-445e-9e43-68d3872ad1de}', - 'contract_ids': ['@mozilla.org/juggler/screencast;1'], - 'type': 'nsIScreencastService', - 'constructor': 'mozilla::nsScreencastService::GetSingleton', - 'headers': ['/juggler/screencast/nsScreencastService.h'], - }, -] diff --git a/browser_patches/firefox-beta/juggler/screencast/moz.build b/browser_patches/firefox-beta/juggler/screencast/moz.build deleted file mode 100644 index e21b177c3965ce..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/moz.build +++ /dev/null @@ -1,49 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -XPIDL_SOURCES += [ - 'nsIScreencastService.idl', -] - -XPIDL_MODULE = 'jugglerscreencast' - -SOURCES += [ - 'HeadlessWindowCapturer.cpp', - 'nsScreencastService.cpp', - 'ScreencastEncoder.cpp', -] - -XPCOM_MANIFESTS += [ - 'components.conf', -] - -LOCAL_INCLUDES += [ - '/dom/media/systemservices', - '/media/libyuv/libyuv/include', - '/third_party/libwebrtc', - '/third_party/libwebrtc/third_party/abseil-cpp', -] - -LOCAL_INCLUDES += [ - '/widget', - '/widget/headless', -] - -LOCAL_INCLUDES += [ - '/third_party/aom/third_party/libwebm', -] - -SOURCES += [ - '/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxer.cc', - '/third_party/aom/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc', - '/third_party/aom/third_party/libwebm/mkvmuxer/mkvwriter.cc', - 'WebMFileWriter.cpp', -] - -include('/dom/media/webrtc/third_party_build/webrtc.mozbuild') -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' diff --git a/browser_patches/firefox-beta/juggler/screencast/nsIScreencastService.idl b/browser_patches/firefox-beta/juggler/screencast/nsIScreencastService.idl deleted file mode 100644 index 16c94371ba1c53..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/nsIScreencastService.idl +++ /dev/null @@ -1,31 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIDocShell; - -[scriptable, uuid(0b5d32c4-aeeb-11eb-8529-0242ac130003)] -interface nsIScreencastServiceClient : nsISupports -{ - void screencastFrame(in AString frame, in uint32_t deviceWidth, in uint32_t deviceHeight); - - void screencastStopped(); -}; - -/** - * Service for recording window video. - */ -[scriptable, uuid(d8c4d9e0-9462-445e-9e43-68d3872ad1de)] -interface nsIScreencastService : nsISupports -{ - AString startVideoRecording(in nsIScreencastServiceClient client, in nsIDocShell docShell, in boolean isVideo, in ACString fileName, in uint32_t width, in uint32_t height, in uint32_t quality, in uint32_t viewportWidth, in uint32_t viewportHeight, in uint32_t offset_top); - - /** - * Will emit 'juggler-screencast-stopped' when the video file is saved. - */ - void stopVideoRecording(in AString sessionId); - - void screencastFrameAck(in AString sessionId); -}; diff --git a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.cpp b/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.cpp deleted file mode 100644 index 20a766dc3735de..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsScreencastService.h" - -#include "ScreencastEncoder.h" -#include "HeadlessWidget.h" -#include "HeadlessWindowCapturer.h" -#include "mozilla/Base64.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/PresShell.h" -#include "mozilla/StaticPtr.h" -#include "nsIDocShell.h" -#include "nsIObserverService.h" -#include "nsIRandomGenerator.h" -#include "nsISupportsPrimitives.h" -#include "nsThreadManager.h" -#include "nsView.h" -#include "nsViewManager.h" -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/desktop_capture/desktop_frame.h" -#include "modules/video_capture/video_capture.h" -#include "mozilla/widget/PlatformWidgetTypes.h" -#include "video_engine/desktop_capture_impl.h" -extern "C" { -#include "jpeglib.h" -} -#include - -using namespace mozilla::widget; - -namespace mozilla { - -NS_IMPL_ISUPPORTS(nsScreencastService, nsIScreencastService) - -namespace { - -const int kMaxFramesInFlight = 1; - -StaticRefPtr gScreencastService; - -rtc::scoped_refptr CreateWindowCapturer(nsIWidget* widget) { - if (gfxPlatform::IsHeadless()) { - HeadlessWidget* headlessWidget = static_cast(widget); - return HeadlessWindowCapturer::Create(headlessWidget); - } - uintptr_t rawWindowId = reinterpret_cast(widget->GetNativeData(NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID)); - if (!rawWindowId) { - fprintf(stderr, "Failed to get native window id\n"); - return nullptr; - } - nsCString windowId; - windowId.AppendPrintf("%" PRIuPTR, rawWindowId); - bool captureCursor = false; - static int moduleId = 0; - return webrtc::DesktopCaptureImpl::Create(++moduleId, windowId.get(), CaptureDeviceType::Window, captureCursor); -} - -nsresult generateUid(nsString& uid) { - nsresult rv = NS_OK; - nsCOMPtr rg = do_GetService("@mozilla.org/security/random-generator;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - uint8_t* buffer; - const int kLen = 16; - rv = rg->GenerateRandomBytes(kLen, &buffer); - NS_ENSURE_SUCCESS(rv, rv); - - for (int i = 0; i < kLen; i++) { - uid.AppendPrintf("%02x", buffer[i]); - } - free(buffer); - return rv; -} -} - -class nsScreencastService::Session : public rtc::VideoSinkInterface, - public webrtc::RawFrameCallback { - Session( - nsIScreencastServiceClient* client, - rtc::scoped_refptr&& capturer, - std::unique_ptr encoder, - int width, int height, - int viewportWidth, int viewportHeight, - gfx::IntMargin margin, - uint32_t jpegQuality) - : mClient(client) - , mCaptureModule(std::move(capturer)) - , mEncoder(std::move(encoder)) - , mJpegQuality(jpegQuality) - , mWidth(width) - , mHeight(height) - , mViewportWidth(viewportWidth) - , mViewportHeight(viewportHeight) - , mMargin(margin) { - } - ~Session() override = default; - - public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Session) - static RefPtr Create( - nsIScreencastServiceClient* client, - rtc::scoped_refptr&& capturer, - std::unique_ptr encoder, - int width, int height, - int viewportWidth, int viewportHeight, - gfx::IntMargin margin, - uint32_t jpegQuality) { - return do_AddRef(new Session(client, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, jpegQuality)); - } - - bool Start() { - webrtc::VideoCaptureCapability capability; - // The size is ignored in fact. - capability.width = 1280; - capability.height = 960; - capability.maxFPS = ScreencastEncoder::fps; - capability.videoType = webrtc::VideoType::kI420; - int error = mCaptureModule->StartCapture(capability); - if (error) { - fprintf(stderr, "StartCapture error %d\n", error); - return false; - } - - if (mEncoder) - mCaptureModule->RegisterCaptureDataCallback(this); - else - mCaptureModule->RegisterRawFrameCallback(this); - return true; - } - - void Stop() { - if (mStopped) { - fprintf(stderr, "Screencast session has already been stopped\n"); - return; - } - mStopped = true; - if (mEncoder) - mCaptureModule->DeRegisterCaptureDataCallback(this); - else - mCaptureModule->DeRegisterRawFrameCallback(this); - int error = mCaptureModule->StopCapture(); - if (error) { - fprintf(stderr, "StopCapture error %d\n", error); - } - if (mEncoder) { - mEncoder->finish([this, protect = RefPtr{this}] { - NS_DispatchToMainThread(NS_NewRunnableFunction( - "NotifyScreencastStopped", [this, protect = std::move(protect)]() -> void { - mClient->ScreencastStopped(); - })); - }); - } else { - mClient->ScreencastStopped(); - } - } - - void ScreencastFrameAck() { - if (mFramesInFlight.load() == 0) { - fprintf(stderr, "ScreencastFrameAck is called while there are no inflight frames\n"); - return; - } - mFramesInFlight.fetch_sub(1); - } - - // These callbacks end up running on the VideoCapture thread. - void OnFrame(const webrtc::VideoFrame& videoFrame) override { - if (!mEncoder) - return; - mEncoder->encodeFrame(videoFrame); - } - - // These callbacks end up running on the VideoCapture thread. - void OnRawFrame(uint8_t* videoFrame, size_t videoFrameStride, const webrtc::VideoCaptureCapability& frameInfo) override { - int pageWidth = frameInfo.width - mMargin.LeftRight(); - int pageHeight = frameInfo.height - mMargin.TopBottom(); - // Frame size is 1x1 when browser window is minimized. - if (pageWidth <= 1 || pageHeight <= 1) - return; - // Headed Firefox brings sizes in sync slowly. - if (mViewportWidth && pageWidth > mViewportWidth) - pageWidth = mViewportWidth; - if (mViewportHeight && pageHeight > mViewportHeight) - pageHeight = mViewportHeight; - - if (mFramesInFlight.load() >= kMaxFramesInFlight) - return; - - int screenshotWidth = pageWidth; - int screenshotHeight = pageHeight; - int screenshotTopMargin = mMargin.TopBottom(); - std::unique_ptr canvas; - uint8_t* canvasPtr = videoFrame; - int canvasStride = videoFrameStride; - - if (mWidth < pageWidth || mHeight < pageHeight) { - double scale = std::min(1., std::min((double)mWidth / pageWidth, (double)mHeight / pageHeight)); - int canvasWidth = frameInfo.width * scale; - int canvasHeight = frameInfo.height * scale; - canvasStride = canvasWidth * 4; - - screenshotWidth *= scale; - screenshotHeight *= scale; - screenshotTopMargin *= scale; - - canvas.reset(new uint8_t[canvasWidth * canvasHeight * 4]); - canvasPtr = canvas.get(); - libyuv::ARGBScale(videoFrame, - videoFrameStride, - frameInfo.width, - frameInfo.height, - canvasPtr, - canvasStride, - canvasWidth, - canvasHeight, - libyuv::kFilterBilinear); - } - - jpeg_compress_struct info; - jpeg_error_mgr error; - info.err = jpeg_std_error(&error); - jpeg_create_compress(&info); - - unsigned char* bufferPtr = nullptr; - unsigned long bufferSize; - jpeg_mem_dest(&info, &bufferPtr, &bufferSize); - - info.image_width = screenshotWidth; - info.image_height = screenshotHeight; - -#if MOZ_LITTLE_ENDIAN() - if (frameInfo.videoType == webrtc::VideoType::kARGB) - info.in_color_space = JCS_EXT_BGRA; - if (frameInfo.videoType == webrtc::VideoType::kBGRA) - info.in_color_space = JCS_EXT_ARGB; -#else - if (frameInfo.videoType == webrtc::VideoType::kARGB) - info.in_color_space = JCS_EXT_ARGB; - if (frameInfo.videoType == webrtc::VideoType::kBGRA) - info.in_color_space = JCS_EXT_BGRA; -#endif - - // # of color components in input image - info.input_components = 4; - - jpeg_set_defaults(&info); - jpeg_set_quality(&info, mJpegQuality, true); - - jpeg_start_compress(&info, true); - while (info.next_scanline < info.image_height) { - JSAMPROW row = canvasPtr + (screenshotTopMargin + info.next_scanline) * canvasStride; - if (jpeg_write_scanlines(&info, &row, 1) != 1) { - fprintf(stderr, "JPEG library failed to encode line\n"); - break; - } - } - - jpeg_finish_compress(&info); - jpeg_destroy_compress(&info); - - nsCString base64; - nsresult rv = mozilla::Base64Encode(reinterpret_cast(bufferPtr), bufferSize, base64); - free(bufferPtr); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - mFramesInFlight.fetch_add(1); - NS_DispatchToMainThread(NS_NewRunnableFunction( - "NotifyScreencastFrame", [this, protect = RefPtr{this}, base64, pageWidth, pageHeight]() -> void { - if (mStopped) - return; - NS_ConvertUTF8toUTF16 utf16(base64); - mClient->ScreencastFrame(utf16, pageWidth, pageHeight); - })); - } - - private: - RefPtr mClient; - rtc::scoped_refptr mCaptureModule; - std::unique_ptr mEncoder; - uint32_t mJpegQuality; - bool mStopped = false; - std::atomic mFramesInFlight = 0; - int mWidth; - int mHeight; - int mViewportWidth; - int mViewportHeight; - gfx::IntMargin mMargin; -}; - - -// static -already_AddRefed nsScreencastService::GetSingleton() { - if (gScreencastService) { - return do_AddRef(gScreencastService); - } - - gScreencastService = new nsScreencastService(); - // ClearOnShutdown(&gScreencastService); - return do_AddRef(gScreencastService); -} - -nsScreencastService::nsScreencastService() = default; - -nsScreencastService::~nsScreencastService() { -} - -nsresult nsScreencastService::StartVideoRecording(nsIScreencastServiceClient* aClient, nsIDocShell* aDocShell, bool isVideo, const nsACString& aVideoFileName, uint32_t width, uint32_t height, uint32_t quality, uint32_t viewportWidth, uint32_t viewportHeight, uint32_t offsetTop, nsAString& sessionId) { - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Screencast service must be started on the Main thread."); - - PresShell* presShell = aDocShell->GetPresShell(); - if (!presShell) - return NS_ERROR_UNEXPECTED; - nsViewManager* viewManager = presShell->GetViewManager(); - if (!viewManager) - return NS_ERROR_UNEXPECTED; - nsView* view = viewManager->GetRootView(); - if (!view) - return NS_ERROR_UNEXPECTED; - nsIWidget* widget = view->GetWidget(); - - rtc::scoped_refptr capturer = CreateWindowCapturer(widget); - if (!capturer) - return NS_ERROR_FAILURE; - - gfx::IntMargin margin; - auto bounds = widget->GetScreenBounds().ToUnknownRect(); - auto clientBounds = widget->GetClientBounds().ToUnknownRect(); - // Crop the image to exclude frame (if any). - margin = bounds - clientBounds; - // Crop the image to exclude controls. - margin.top += offsetTop; - - nsCString error; - std::unique_ptr encoder; - if (isVideo) { - encoder = ScreencastEncoder::create(error, PromiseFlatCString(aVideoFileName), width, height, margin); - if (!encoder) { - fprintf(stderr, "Failed to create ScreencastEncoder: %s\n", error.get()); - return NS_ERROR_FAILURE; - } - } - - nsString uid; - nsresult rv = generateUid(uid); - NS_ENSURE_SUCCESS(rv, rv); - sessionId = uid; - - auto session = Session::Create(aClient, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, isVideo ? 0 : quality); - if (!session->Start()) - return NS_ERROR_FAILURE; - mIdToSession.emplace(sessionId, std::move(session)); - return NS_OK; -} - -nsresult nsScreencastService::StopVideoRecording(const nsAString& aSessionId) { - nsString sessionId(aSessionId); - auto it = mIdToSession.find(sessionId); - if (it == mIdToSession.end()) - return NS_ERROR_INVALID_ARG; - it->second->Stop(); - mIdToSession.erase(it); - return NS_OK; -} - -nsresult nsScreencastService::ScreencastFrameAck(const nsAString& aSessionId) { - nsString sessionId(aSessionId); - auto it = mIdToSession.find(sessionId); - if (it == mIdToSession.end()) - return NS_ERROR_INVALID_ARG; - it->second->ScreencastFrameAck(); - return NS_OK; -} - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.h b/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.h deleted file mode 100644 index 419603e0e69b0a..00000000000000 --- a/browser_patches/firefox-beta/juggler/screencast/nsScreencastService.h +++ /dev/null @@ -1,29 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#pragma once - -#include -#include -#include "nsIScreencastService.h" - -namespace mozilla { - -class nsScreencastService final : public nsIScreencastService { - public: - NS_DECL_ISUPPORTS - NS_DECL_NSISCREENCASTSERVICE - - static already_AddRefed GetSingleton(); - - nsScreencastService(); - - private: - ~nsScreencastService(); - - class Session; - std::map> mIdToSession; -}; - -} // namespace mozilla diff --git a/browser_patches/firefox-beta/patches/bootstrap.diff b/browser_patches/firefox-beta/patches/bootstrap.diff deleted file mode 100644 index 90ea0ed347d241..00000000000000 --- a/browser_patches/firefox-beta/patches/bootstrap.diff +++ /dev/null @@ -1,2920 +0,0 @@ -diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h -index afb6230bb613ecde4a5e3271478a682d0396dc3b..a3a7d9786f9d18bad6afc292264b9dbc62c14cf2 100644 ---- a/accessible/base/NotificationController.h -+++ b/accessible/base/NotificationController.h -@@ -276,6 +276,8 @@ class NotificationController final : public EventQueue, - } - #endif - -+ bool IsUpdatePendingForJugglerAccessibility() { return IsUpdatePending(); } -+ - protected: - virtual ~NotificationController(); - -diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl -index a91df31c96afda66f478a5a38eaa4352039c2a0b..ee777c1746284027fb3aa2f1686f8082af9d89ee 100644 ---- a/accessible/interfaces/nsIAccessibleDocument.idl -+++ b/accessible/interfaces/nsIAccessibleDocument.idl -@@ -72,4 +72,9 @@ interface nsIAccessibleDocument : nsISupports - * Return the child document accessible at the given index. - */ - nsIAccessibleDocument getChildDocumentAt(in unsigned long index); -+ -+ /** -+ * Return whether it is updating. -+ */ -+ readonly attribute boolean isUpdatePendingForJugglerAccessibility; - }; -diff --git a/accessible/xpcom/xpcAccessibleDocument.cpp b/accessible/xpcom/xpcAccessibleDocument.cpp -index 1ddd5c8372c2742a8dc4e7a8156c084aaf2442fc..7e3aa30c20d8b2fcae5c12d293ca7772ecd28657 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.cpp -+++ b/accessible/xpcom/xpcAccessibleDocument.cpp -@@ -143,6 +143,15 @@ xpcAccessibleDocument::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) { - return NS_OK; - } - -+ -+NS_IMETHODIMP -+xpcAccessibleDocument::GetIsUpdatePendingForJugglerAccessibility(bool* updating) { -+ NS_ENSURE_ARG_POINTER(updating); -+ *updating = Intl()->Controller()->IsUpdatePendingForJugglerAccessibility(); -+ return NS_OK; -+} -+ -+ - //////////////////////////////////////////////////////////////////////////////// - // xpcAccessibleDocument - -diff --git a/accessible/xpcom/xpcAccessibleDocument.h b/accessible/xpcom/xpcAccessibleDocument.h -index 416a1c5497c97ed80cc0f37d72545e36f7e36b4c..b81983cf7153378260a21f6af225e3493f8f30dc 100644 ---- a/accessible/xpcom/xpcAccessibleDocument.h -+++ b/accessible/xpcom/xpcAccessibleDocument.h -@@ -48,6 +48,8 @@ class xpcAccessibleDocument : public xpcAccessibleHyperText, - nsIAccessibleDocument** aDocument) final; - NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) final; - -+ NS_IMETHOD GetIsUpdatePendingForJugglerAccessibility(bool* aUpdating) final; -+ - /** - * Return XPCOM wrapper for the internal accessible. - */ -diff --git a/browser/app/winlauncher/LauncherProcessWin.cpp b/browser/app/winlauncher/LauncherProcessWin.cpp -index 4460774865769609b66c0710f7c83f4d5c02b6fa..2ca95607b9b093218d48f83adc95c514cebe661b 100644 ---- a/browser/app/winlauncher/LauncherProcessWin.cpp -+++ b/browser/app/winlauncher/LauncherProcessWin.cpp -@@ -23,6 +23,7 @@ - #include "mozilla/WinHeaderOnlyUtils.h" - #include "nsWindowsHelpers.h" - -+#include - #include - #include - -@@ -359,8 +360,19 @@ Maybe LauncherMain(int& argc, wchar_t* argv[], - HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE), - ::GetStdHandle(STD_OUTPUT_HANDLE), - ::GetStdHandle(STD_ERROR_HANDLE)}; -- - attrs.AddInheritableHandles(stdHandles); -+ // Playwright pipe installation. -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, L"juggler-pipe", -+ static_cast(nullptr), -+ mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; -+ if (hasJugglerPipe) { -+ intptr_t stdio3 = _get_osfhandle(3); -+ intptr_t stdio4 = _get_osfhandle(4); -+ HANDLE pipeHandles[] = {reinterpret_cast(stdio3), -+ reinterpret_cast(stdio4)}; -+ attrs.AddInheritableHandles(pipeHandles); -+ } - - DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; - -diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn -index b59fe4b1854fec7cb329139f9c6773498fb9de51..29973af04902848808e850b40bf85e5f694d349a 100644 ---- a/browser/installer/allowed-dupes.mn -+++ b/browser/installer/allowed-dupes.mn -@@ -71,6 +71,12 @@ browser/features/webcompat@mozilla.org/shims/empty-shim.txt - removed-files - #endif - -+# Juggler/marionette files -+chrome/juggler/content/content/floating-scrollbars.css -+browser/chrome/devtools/skin/floating-scrollbars-responsive-design.css -+chrome/juggler/content/server/stream-utils.js -+chrome/marionette/content/stream-utils.js -+ - #ifdef MOZ_EME_WIN32_ARTIFACT - gmp-clearkey/0.1/manifest.json - i686/gmp-clearkey/0.1/manifest.json -diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 14e582fc61be808d5b6f3ae7801f43c7b0b743d4..80e400b5c3e316afe2bff1bac16808bad16dc4bd 100644 ---- a/browser/installer/package-manifest.in -+++ b/browser/installer/package-manifest.in -@@ -192,6 +192,9 @@ - @RESPATH@/chrome/remote.manifest - #endif - -+@RESPATH@/chrome/juggler@JAREXT@ -+@RESPATH@/chrome/juggler.manifest -+ - ; [Extensions] - @RESPATH@/components/extensions-toolkit.manifest - @RESPATH@/browser/components/extensions-browser.manifest -diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c2835307f88 100644 ---- a/devtools/server/socket/websocket-server.js -+++ b/devtools/server/socket/websocket-server.js -@@ -133,13 +133,12 @@ function writeHttpResponse(output, response) { - * Process the WebSocket handshake headers and return the key to be sent in - * Sec-WebSocket-Accept response header. - */ --function processRequest({ requestLine, headers }) { -+function processRequest({ requestLine, headers }, expectedPath) { - const [method, path] = requestLine.split(" "); - if (method !== "GET") { - throw new Error("The handshake request must use GET method"); - } -- -- if (path !== "/") { -+ if (path !== expectedPath) { - throw new Error("The handshake request has unknown path"); - } - -@@ -189,13 +188,13 @@ function computeKey(key) { - /** - * Perform the server part of a WebSocket opening handshake on an incoming connection. - */ --const serverHandshake = async function(input, output) { -+const serverHandshake = async function(input, output, expectedPath) { - // Read the request - const request = await readHttpRequest(input); - - try { - // Check and extract info from the request -- const { acceptKey } = processRequest(request); -+ const { acceptKey } = processRequest(request, expectedPath); - - // Send response headers - await writeHttpResponse(output, [ -@@ -217,8 +216,8 @@ const serverHandshake = async function(input, output) { - * Performs the WebSocket handshake and waits for the WebSocket to open. - * Returns Promise with a WebSocket ready to send and receive messages. - */ --const accept = async function(transport, input, output) { -- await serverHandshake(input, output); -+const accept = async function(transport, input, output, expectedPath) { -+ await serverHandshake(input, output, expectedPath || "/"); - - const transportProvider = { - setListener(upgradeListener) { -diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp -index 4b4c20d5d04e51e5eeb08027c4b48068ee21d703..5529185d2a39e041b7e5021a5f5de63269644a4b 100644 ---- a/docshell/base/BrowsingContext.cpp -+++ b/docshell/base/BrowsingContext.cpp -@@ -111,6 +111,20 @@ struct ParamTraits - mozilla::dom::PrefersColorSchemeOverride::None, - mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {}; - -+template <> -+struct ParamTraits -+ : public ContiguousEnumSerializer< -+ mozilla::dom::PrefersReducedMotionOverride, -+ mozilla::dom::PrefersReducedMotionOverride::None, -+ mozilla::dom::PrefersReducedMotionOverride::EndGuard_> {}; -+ -+template <> -+struct ParamTraits -+ : public ContiguousEnumSerializer< -+ mozilla::dom::ForcedColorsOverride, -+ mozilla::dom::ForcedColorsOverride::None, -+ mozilla::dom::ForcedColorsOverride::EndGuard_> {}; -+ - template <> - struct ParamTraits - : public ContiguousEnumSerializer< -@@ -2782,6 +2796,40 @@ void BrowsingContext::DidSet(FieldIndex, - PresContextAffectingFieldChanged(); - } - -+void BrowsingContext::DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (PrefersReducedMotionOverride() == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (nsIDocShell* shell = aContext->GetDocShell()) { -+ if (nsPresContext* pc = shell->GetPresContext()) { -+ pc->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ } -+ }); -+} -+ -+void BrowsingContext::DidSet(FieldIndex, -+ dom::ForcedColorsOverride aOldValue) { -+ MOZ_ASSERT(IsTop()); -+ if (ForcedColorsOverride() == aOldValue) { -+ return; -+ } -+ PreOrderWalk([&](BrowsingContext* aContext) { -+ if (nsIDocShell* shell = aContext->GetDocShell()) { -+ if (nsPresContext* pc = shell->GetPresContext()) { -+ pc->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ } -+ }); -+} -+ - void BrowsingContext::DidSet(FieldIndex, - nsString&& aOldValue) { - MOZ_ASSERT(IsTop()); -diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index e0b091feba6ce38e57681c62c386d3b70234de1f..4fae381a8bded7ae004ccb25187b3ace559fea41 100644 ---- a/docshell/base/BrowsingContext.h -+++ b/docshell/base/BrowsingContext.h -@@ -176,10 +176,10 @@ enum class ExplicitActiveStatus : uint8_t { - FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ - /* ScreenOrientation-related APIs */ \ - FIELD(CurrentOrientationAngle, float) \ -- FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \ -+ FIELD(CurrentOrientationType, dom::OrientationType) \ - FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \ - FIELD(UserAgentOverride, nsString) \ -- FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \ -+ FIELD(TouchEventsOverrideInternal, dom::TouchEventsOverride) \ - FIELD(EmbedderElementType, Maybe) \ - FIELD(MessageManagerGroup, nsString) \ - FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -217,6 +217,10 @@ enum class ExplicitActiveStatus : uint8_t { - * embedder element. */ \ - FIELD(EmbedderColorScheme, dom::PrefersColorSchemeOverride) \ - FIELD(DisplayMode, dom::DisplayMode) \ -+ /* playwright addition */ \ -+ FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ -+ /* playwright addition */ \ -+ FIELD(ForcedColorsOverride, dom::ForcedColorsOverride) \ - /* The number of entries added to the session history because of this \ - * browsing context. */ \ - FIELD(HistoryEntryCount, uint32_t) \ -@@ -893,6 +897,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - return GetPrefersColorSchemeOverride(); - } - -+ dom::PrefersReducedMotionOverride PrefersReducedMotionOverride() const { -+ return GetPrefersReducedMotionOverride(); -+ } -+ -+ dom::ForcedColorsOverride ForcedColorsOverride() const { -+ return GetForcedColorsOverride(); -+ } -+ - bool IsInBFCache() const; - - bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1047,6 +1059,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - - void PresContextAffectingFieldChanged(); - -+ bool CanSet(FieldIndex, -+ dom::PrefersReducedMotionOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::PrefersReducedMotionOverride aOldValue); -+ -+ -+ bool CanSet(FieldIndex, -+ dom::ForcedColorsOverride, ContentParent*) { -+ return IsTop(); -+ } -+ -+ void DidSet(FieldIndex, -+ dom::ForcedColorsOverride aOldValue); -+ - void DidSet(FieldIndex, nsString&& aOldValue); - - bool CanSet(FieldIndex, bool, ContentParent*) { -diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index e7f3305fae1c6754974b2a53995080f487d559cf..eaa173262e6cfec0765153fb890588fef768d74c 100644 ---- a/docshell/base/nsDocShell.cpp -+++ b/docshell/base/nsDocShell.cpp -@@ -15,6 +15,12 @@ - # include // for getpid() - #endif - -+#if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU -+# include "unicode/locid.h" -+#endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */ -+ -+#include "js/LocaleSensitive.h" -+ - #include "mozilla/ArrayUtils.h" - #include "mozilla/Attributes.h" - #include "mozilla/AutoRestore.h" -@@ -65,6 +71,7 @@ - #include "mozilla/dom/ContentFrameMessageManager.h" - #include "mozilla/dom/DocGroup.h" - #include "mozilla/dom/Element.h" -+#include "mozilla/dom/Geolocation.h" - #include "mozilla/dom/HTMLAnchorElement.h" - #include "mozilla/dom/HTMLIFrameElement.h" - #include "mozilla/dom/PerformanceNavigation.h" -@@ -90,6 +97,7 @@ - #include "mozilla/dom/JSWindowActorChild.h" - #include "mozilla/dom/DocumentBinding.h" - #include "mozilla/ipc/ProtocolUtils.h" -+#include "mozilla/dom/WorkerCommon.h" - #include "mozilla/net/DocumentChannel.h" - #include "mozilla/net/DocumentChannelChild.h" - #include "mozilla/net/ParentChannelWrapper.h" -@@ -114,6 +122,7 @@ - #include "nsIDocShellTreeOwner.h" - #include "mozilla/dom/Document.h" - #include "nsHTMLDocument.h" -+#include "mozilla/dom/Element.h" - #include "nsIDocumentLoaderFactory.h" - #include "nsIDOMWindow.h" - #include "nsIEditingSession.h" -@@ -208,6 +217,7 @@ - #include "nsFocusManager.h" - #include "nsGlobalWindow.h" - #include "nsJSEnvironment.h" -+#include "nsJSUtils.h" - #include "nsNetCID.h" - #include "nsNetUtil.h" - #include "nsObjectLoadingContent.h" -@@ -371,6 +381,13 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, - mAllowDNSPrefetch(true), - mAllowWindowControl(true), - mCSSErrorReportingEnabled(false), -+ mFileInputInterceptionEnabled(false), -+ mOverrideHasFocus(false), -+ mBypassCSPEnabled(false), -+ mForceActiveState(false), -+ mOnlineOverride(nsIDocShell::ONLINE_OVERRIDE_NONE), -+ mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), -+ mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), - mAllowAuth(mItemType == typeContent), - mAllowKeywordFixup(false), - mDisableMetaRefreshWhenInactive(false), -@@ -3256,6 +3273,221 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { - return NS_OK; - } - -+// =============== Juggler Begin ======================= -+ -+nsDocShell* nsDocShell::GetRootDocShell() { -+ nsCOMPtr rootAsItem; -+ GetInProcessSameTypeRootTreeItem(getter_AddRefs(rootAsItem)); -+ nsCOMPtr rootShell = do_QueryInterface(rootAsItem); -+ return nsDocShell::Cast(rootShell); -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetBypassCSPEnabled(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mBypassCSPEnabled; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetBypassCSPEnabled(bool aEnabled) { -+ mBypassCSPEnabled = aEnabled; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetForceActiveState(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mForceActiveState; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetForceActiveState(bool aEnabled) { -+ mForceActiveState = aEnabled; -+ ActivenessMaybeChanged(); -+ return NS_OK; -+} -+ -+bool nsDocShell::IsBypassCSPEnabled() { -+ return GetRootDocShell()->mBypassCSPEnabled; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetOverrideHasFocus(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = mOverrideHasFocus; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetOverrideHasFocus(bool aEnabled) { -+ mOverrideHasFocus = aEnabled; -+ return NS_OK; -+} -+ -+bool nsDocShell::ShouldOverrideHasFocus() const { -+ return mOverrideHasFocus; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetLanguageOverride(nsAString& aLanguageOverride) { -+ aLanguageOverride = GetRootDocShell()->mLanguageOverride; -+ return NS_OK; -+} -+ -+ -+static void SetIcuLocale(const nsAString& aLanguageOverride) { -+ icu::Locale locale(NS_LossyConvertUTF16toASCII(aLanguageOverride).get()); -+ if (icu::Locale::getDefault() == locale) -+ return; -+ UErrorCode error_code = U_ZERO_ERROR; -+ const char* lang = locale.getLanguage(); -+ if (lang != nullptr && *lang != '\0') { -+ icu::Locale::setDefault(locale, error_code); -+ } else { -+ fprintf(stderr, "SetIcuLocale Failed to set the ICU default locale to %s\n", NS_LossyConvertUTF16toASCII(aLanguageOverride).get()); -+ } -+ -+ AutoJSAPI jsapi; -+ jsapi.Init(); -+ JSContext* cx = jsapi.cx(); -+ JS_ResetDefaultLocale(JS_GetRuntime(cx)); -+ -+ ResetDefaultLocaleInAllWorkers(); -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetLanguageOverride(const nsAString& aLanguageOverride) { -+ mLanguageOverride = aLanguageOverride; -+ SetIcuLocale(aLanguageOverride); -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride, -+ bool* aSuccess) { -+ NS_ENSURE_ARG(aSuccess); -+ NS_LossyConvertUTF16toASCII timeZoneId(aTimezoneOverride); -+ *aSuccess = nsJSUtils::SetTimeZoneOverride(timeZoneId.get()); -+ -+ // Set TZ which affects localtime_s(). -+ auto setTimeZoneEnv = [](const char* value) { -+#if defined(_WIN32) -+ return _putenv_s("TZ", value) == 0; -+#else -+ return setenv("TZ", value, true) == 0; -+#endif /* _WIN32 */ -+ }; -+ if (*aSuccess) { -+ *aSuccess = setTimeZoneEnv(timeZoneId.get()); -+ if (!*aSuccess) { -+ fprintf(stderr, "Failed to set 'TZ' to '%s'\n", timeZoneId.get()); -+ } -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetFileInputInterceptionEnabled(bool* aEnabled) { -+ MOZ_ASSERT(aEnabled); -+ *aEnabled = GetRootDocShell()->mFileInputInterceptionEnabled; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetFileInputInterceptionEnabled(bool aEnabled) { -+ mFileInputInterceptionEnabled = aEnabled; -+ return NS_OK; -+} -+ -+bool nsDocShell::IsFileInputInterceptionEnabled() { -+ return GetRootDocShell()->mFileInputInterceptionEnabled; -+} -+ -+void nsDocShell::FilePickerShown(mozilla::dom::Element* element) { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ observerService->NotifyObservers( -+ ToSupports(element), "juggler-file-picker-shown", nullptr); -+} -+ -+RefPtr nsDocShell::GetGeolocationServiceOverride() { -+ return GetRootDocShell()->mGeolocationServiceOverride; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetGeolocationOverride(nsIDOMGeoPosition* aGeolocationOverride) { -+ if (aGeolocationOverride) { -+ if (!mGeolocationServiceOverride) { -+ mGeolocationServiceOverride = new nsGeolocationService(); -+ mGeolocationServiceOverride->Init(); -+ } -+ mGeolocationServiceOverride->Update(aGeolocationOverride); -+ } else { -+ mGeolocationServiceOverride = nullptr; -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetOnlineOverride(OnlineOverride* aOnlineOverride) { -+ *aOnlineOverride = GetRootDocShell()->mOnlineOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetOnlineOverride(OnlineOverride aOnlineOverride) { -+ // We don't have a way to verify this coming from Javascript, so this check is -+ // still needed. -+ if (!(aOnlineOverride == ONLINE_OVERRIDE_NONE || -+ aOnlineOverride == ONLINE_OVERRIDE_ONLINE || -+ aOnlineOverride == ONLINE_OVERRIDE_OFFLINE)) { -+ return NS_ERROR_INVALID_ARG; -+ } -+ -+ mOnlineOverride = aOnlineOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetReducedMotionOverride(ReducedMotionOverride* aReducedMotionOverride) { -+ *aReducedMotionOverride = GetRootDocShell()->mReducedMotionOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetReducedMotionOverride(ReducedMotionOverride aReducedMotionOverride) { -+ mReducedMotionOverride = aReducedMotionOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::GetForcedColorsOverride(ForcedColorsOverride* aForcedColorsOverride) { -+ *aForcedColorsOverride = GetRootDocShell()->mForcedColorsOverride; -+ return NS_OK; -+} -+ -+NS_IMETHODIMP -+nsDocShell::SetForcedColorsOverride(ForcedColorsOverride aForcedColorsOverride) { -+ mForcedColorsOverride = aForcedColorsOverride; -+ RefPtr presContext = GetPresContext(); -+ if (presContext) { -+ presContext->MediaFeatureValuesChanged( -+ {MediaFeatureChangeReason::SystemMetricsChange}, -+ MediaFeatureChangePropagation::JustThisDocument); -+ } -+ return NS_OK; -+} -+ -+// =============== Juggler End ======================= -+ - NS_IMETHODIMP - nsDocShell::GetIsNavigating(bool* aOut) { - *aOut = mIsNavigating; -@@ -4886,7 +5118,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { - } - - void nsDocShell::ActivenessMaybeChanged() { -- const bool isActive = mBrowsingContext->IsActive(); -+ const bool isActive = mForceActiveState || mBrowsingContext->IsActive(); - if (RefPtr presShell = GetPresShell()) { - presShell->ActivenessMaybeChanged(); - } -@@ -8624,6 +8856,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { - true, // aForceNoOpener - getter_AddRefs(newBC)); - MOZ_ASSERT(!newBC); -+ if (rv == NS_OK) { -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ if (observerService) { -+ observerService->NotifyObservers(GetAsSupports(this), "juggler-window-open-in-new-context", nullptr); -+ } -+ } - return rv; - } - -@@ -12780,6 +13018,9 @@ class OnLinkClickEvent : public Runnable { - mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, - mTriggeringPrincipal); - } -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(mContent), "juggler-link-click-sync", nullptr); -+ - return NS_OK; - } - -@@ -12859,6 +13100,8 @@ nsresult nsDocShell::OnLinkClick( - nsCOMPtr ev = - new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied, - aIsTrusted, aTriggeringPrincipal); -+ nsCOMPtr observerService = mozilla::services::GetObserverService(); -+ observerService->NotifyObservers(ToSupports(aContent), "juggler-link-click", nullptr); - return Dispatch(TaskCategory::UI, ev.forget()); - } - -diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 61998bf661a2c765411280e03d0726b227c31a3f..5ba8e2ac8e13ae9d18591fd477e5c9414843e3cc 100644 ---- a/docshell/base/nsDocShell.h -+++ b/docshell/base/nsDocShell.h -@@ -16,6 +16,7 @@ - #include "mozilla/UniquePtr.h" - #include "mozilla/WeakPtr.h" - #include "mozilla/dom/BrowsingContext.h" -+#include "mozilla/dom/Element.h" - #include "mozilla/dom/WindowProxyHolder.h" - #include "nsCOMPtr.h" - #include "nsCharsetSource.h" -@@ -77,6 +78,7 @@ class nsCommandManager; - class nsDocShellEditorData; - class nsDOMNavigationTiming; - class nsDSURIContentListener; -+class nsGeolocationService; - class nsGlobalWindowOuter; - - class FramingChecker; -@@ -409,6 +411,15 @@ class nsDocShell final : public nsDocLoader, - void SetWillChangeProcess() { mWillChangeProcess = true; } - bool WillChangeProcess() { return mWillChangeProcess; } - -+ bool IsFileInputInterceptionEnabled(); -+ void FilePickerShown(mozilla::dom::Element* element); -+ -+ bool ShouldOverrideHasFocus() const; -+ -+ bool IsBypassCSPEnabled(); -+ -+ RefPtr GetGeolocationServiceOverride(); -+ - // Create a content viewer within this nsDocShell for the given - // `WindowGlobalChild` actor. - nsresult CreateContentViewerForActor( -@@ -1028,6 +1039,8 @@ class nsDocShell final : public nsDocLoader, - - bool CSSErrorReportingEnabled() const { return mCSSErrorReportingEnabled; } - -+ nsDocShell* GetRootDocShell(); -+ - // Handles retrieval of subframe session history for nsDocShell::LoadURI. If a - // load is requested in a subframe of the current DocShell, the subframe - // loadType may need to reflect the loadType of the parent document, or in -@@ -1313,6 +1326,16 @@ class nsDocShell final : public nsDocLoader, - bool mAllowDNSPrefetch : 1; - bool mAllowWindowControl : 1; - bool mCSSErrorReportingEnabled : 1; -+ bool mFileInputInterceptionEnabled: 1; -+ bool mOverrideHasFocus : 1; -+ bool mBypassCSPEnabled : 1; -+ bool mForceActiveState : 1; -+ nsString mLanguageOverride; -+ RefPtr mGeolocationServiceOverride; -+ OnlineOverride mOnlineOverride; -+ ReducedMotionOverride mReducedMotionOverride; -+ ForcedColorsOverride mForcedColorsOverride; -+ - bool mAllowAuth : 1; - bool mAllowKeywordFixup : 1; - bool mDisableMetaRefreshWhenInactive : 1; -diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 6b85ddd842a6d2e29f86047017b78b2007b99867..e0b56c4f85544580b9a631619fb06799ad244494 100644 ---- a/docshell/base/nsIDocShell.idl -+++ b/docshell/base/nsIDocShell.idl -@@ -44,6 +44,7 @@ interface nsIURI; - interface nsIChannel; - interface nsIContentViewer; - interface nsIContentSecurityPolicy; -+interface nsIDOMGeoPosition; - interface nsIEditor; - interface nsIEditingSession; - interface nsIInputStream; -@@ -803,6 +804,41 @@ interface nsIDocShell : nsIDocShellTreeItem - */ - void synchronizeLayoutHistoryState(); - -+ attribute boolean fileInputInterceptionEnabled; -+ -+ attribute boolean overrideHasFocus; -+ -+ attribute boolean bypassCSPEnabled; -+ -+ attribute boolean forceActiveState; -+ -+ attribute AString languageOverride; -+ -+ boolean overrideTimezone(in AString timezoneId); -+ -+ cenum OnlineOverride: 8 { -+ ONLINE_OVERRIDE_NONE = 0, -+ ONLINE_OVERRIDE_ONLINE = 1, -+ ONLINE_OVERRIDE_OFFLINE = 2, -+ }; -+ [infallible] attribute nsIDocShell_OnlineOverride onlineOverride; -+ -+ cenum ReducedMotionOverride : 8 { -+ REDUCED_MOTION_OVERRIDE_REDUCE, -+ REDUCED_MOTION_OVERRIDE_NO_PREFERENCE, -+ REDUCED_MOTION_OVERRIDE_NONE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ReducedMotionOverride reducedMotionOverride; -+ -+ cenum ForcedColorsOverride : 8 { -+ FORCED_COLORS_OVERRIDE_ACTIVE, -+ FORCED_COLORS_OVERRIDE_NONE, -+ FORCED_COLORS_OVERRIDE_NO_OVERRIDE, /* This clears the override. */ -+ }; -+ [infallible] attribute nsIDocShell_ForcedColorsOverride forcedColorsOverride; -+ -+ void setGeolocationOverride(in nsIDOMGeoPosition position); -+ - /** - * This attempts to save any applicable layout history state (like - * scroll position) in the nsISHEntry. This is normally done -diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp -index b34ad3970c1ecaefeb756b9c2f4ca44727bd8be9..e1ea4bce868c4385d498305bf7c1bbd4de282415 100644 ---- a/dom/base/Document.cpp -+++ b/dom/base/Document.cpp -@@ -3646,6 +3646,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { - } - - void Document::ApplySettingsFromCSP(bool aSpeculative) { -+ if (mDocumentContainer && mDocumentContainer->IsBypassCSPEnabled()) -+ return; -+ - nsresult rv = NS_OK; - if (!aSpeculative) { - // 1) apply settings from regular CSP -@@ -3703,6 +3706,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { - MOZ_ASSERT(!mScriptGlobalObject, - "CSP must be initialized before mScriptGlobalObject is set!"); - -+ nsCOMPtr shell(mDocumentContainer); -+ if (shell && nsDocShell::Cast(shell)->IsBypassCSPEnabled()) { -+ return NS_OK; -+ } -+ - // If this is a data document - no need to set CSP. - if (mLoadedAsData) { - return NS_OK; -@@ -4509,6 +4517,10 @@ bool Document::HasFocus(ErrorResult& rv) const { - return false; - } - -+ if (IsActive() && mDocumentContainer->ShouldOverrideHasFocus()) { -+ return true; -+ } -+ - if (!fm->IsInActiveWindow(bc)) { - return false; - } -@@ -17974,6 +17986,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { - return LookAndFeel::PreferredColorSchemeForContent(); - } - -+bool Document::PrefersReducedMotion() const { -+ auto* docShell = static_cast(GetDocShell()); -+ nsIDocShell::ReducedMotionOverride reducedMotion; -+ if (docShell && docShell->GetReducedMotionOverride(&reducedMotion) == NS_OK && -+ reducedMotion != nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE) { -+ switch (reducedMotion) { -+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_REDUCE: -+ return true; -+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NO_PREFERENCE: -+ return false; -+ case nsIDocShell::REDUCED_MOTION_OVERRIDE_NONE: -+ break; -+ }; -+ } -+ -+ if (auto* bc = GetBrowsingContext()) { -+ switch (bc->Top()->PrefersReducedMotionOverride()) { -+ case dom::PrefersReducedMotionOverride::Reduce: -+ return true; -+ case dom::PrefersReducedMotionOverride::No_preference: -+ return false; -+ case dom::PrefersReducedMotionOverride::None: -+ case dom::PrefersReducedMotionOverride::EndGuard_: -+ break; -+ } -+ } -+ -+ if (nsContentUtils::ShouldResistFingerprinting(this)) { -+ return false; -+ } -+ return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+} -+ -+bool Document::ForcedColors() const { -+ auto* docShell = static_cast(GetDocShell()); -+ nsIDocShell::ForcedColorsOverride forcedColors; -+ if (docShell && docShell->GetForcedColorsOverride(&forcedColors) == NS_OK) { -+ switch (forcedColors) { -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_ACTIVE: -+ return true; -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NONE: -+ return false; -+ case nsIDocShell::FORCED_COLORS_OVERRIDE_NO_OVERRIDE: -+ break; -+ }; -+ } -+ -+ if (auto* bc = GetBrowsingContext()) { -+ switch (bc->Top()->ForcedColorsOverride()) { -+ case dom::ForcedColorsOverride::Active: -+ return true; -+ case dom::ForcedColorsOverride::None: -+ return false; -+ case dom::ForcedColorsOverride::No_override: -+ case dom::ForcedColorsOverride::EndGuard_: -+ break; -+ } -+ } -+ -+ if (mIsBeingUsedAsImage) { -+ return false; -+ } -+ return !PreferenceSheet::PrefsFor(*this).mUseDocumentColors; -+} -+ - bool Document::HasRecentlyStartedForegroundLoads() { - if (!sLoadingForegroundTopLevelContentDocument) { - return false; -diff --git a/dom/base/Document.h b/dom/base/Document.h -index 422ae0179f660b4ff49f1d7e06173d23d5794628..de74cd1b5a2e8ae214be9304a6346067fb541d29 100644 ---- a/dom/base/Document.h -+++ b/dom/base/Document.h -@@ -4016,6 +4016,9 @@ class Document : public nsINode, - // color-scheme meta tag. - ColorScheme DefaultColorScheme() const; - -+ bool PrefersReducedMotion() const; -+ bool ForcedColors() const; -+ - static bool HasRecentlyStartedForegroundLoads(); - - static bool AutomaticStorageAccessPermissionCanBeGranted( -diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 92081a09b4925e0b687608abd8ad51d02ff2f5cf..b010190d8af0cd1765d91b5bbd7e46e360a6c30f 100644 ---- a/dom/base/Navigator.cpp -+++ b/dom/base/Navigator.cpp -@@ -325,14 +325,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const { - * for more detail. - */ - /* static */ --void Navigator::GetAcceptLanguages(nsTArray& aLanguages) { -+void Navigator::GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages) { - MOZ_ASSERT(NS_IsMainThread()); - - aLanguages.Clear(); - - // E.g. "de-de, en-us,en". - nsAutoString acceptLang; -- Preferences::GetLocalizedString("intl.accept_languages", acceptLang); -+ if (aLanguageOverride && aLanguageOverride->Length()) -+ acceptLang = *aLanguageOverride; -+ else -+ Preferences::GetLocalizedString("intl.accept_languages", acceptLang); -+ - - // Split values on commas. - for (nsDependentSubstring lang : -@@ -384,7 +388,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { - } - - void Navigator::GetLanguages(nsTArray& aLanguages) { -- GetAcceptLanguages(aLanguages); -+ if (mWindow && mWindow->GetDocShell()) { -+ nsString languageOverride; -+ mWindow->GetDocShell()->GetLanguageOverride(languageOverride); -+ GetAcceptLanguages(&languageOverride, aLanguages); -+ } else { -+ GetAcceptLanguages(nullptr, aLanguages); -+ } - - // The returned value is cached by the binding code. The window listens to the - // accept languages change and will clear the cache when needed. It has to -@@ -563,7 +573,13 @@ bool Navigator::CookieEnabled() { - return granted; - } - --bool Navigator::OnLine() { return !NS_IsOffline(); } -+bool Navigator::OnLine() { -+ nsDocShell* docShell = static_cast(GetDocShell()); -+ nsIDocShell::OnlineOverride onlineOverride; -+ if (!docShell || docShell->GetOnlineOverride(&onlineOverride) != NS_OK || onlineOverride == nsIDocShell::ONLINE_OVERRIDE_NONE) -+ return !NS_IsOffline(); -+ return onlineOverride == nsIDocShell::ONLINE_OVERRIDE_ONLINE; -+} - - void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType, - ErrorResult& aRv) const { -diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index cb821086b1ac884ba96ef8874211bff16106b206..3b93388637f9ec7493735e9beb6f02a78e14c6b3 100644 ---- a/dom/base/Navigator.h -+++ b/dom/base/Navigator.h -@@ -215,7 +215,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { - - StorageManager* Storage(); - -- static void GetAcceptLanguages(nsTArray& aLanguages); -+ static void GetAcceptLanguages(const nsString* aLanguageOverride, nsTArray& aLanguages); - - dom::MediaCapabilities* MediaCapabilities(); - dom::MediaSession* MediaSession(); -diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index 25b6994c9a42054f97b18d5c4a3e35a0010ee749..cef7ba95112677f1a41beb66db718126601bd151 100644 ---- a/dom/base/nsContentUtils.cpp -+++ b/dom/base/nsContentUtils.cpp -@@ -8505,7 +8505,8 @@ nsresult nsContentUtils::SendMouseEvent( - bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, - PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized) { -+ bool aIsWidgetEventSynthesized, -+ bool convertToPointer) { - nsPoint offset; - nsCOMPtr widget = GetWidget(aPresShell, &offset); - if (!widget) return NS_ERROR_FAILURE; -@@ -8564,6 +8565,7 @@ nsresult nsContentUtils::SendMouseEvent( - event.mTime = PR_IntervalNow(); - event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; - event.mExitFrom = exitFrom; -+ event.convertToPointer = convertToPointer; - - nsPresContext* presContext = aPresShell->GetPresContext(); - if (!presContext) return NS_ERROR_FAILURE; -diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h -index de038d0832adb4037d2d076011e433412e85cb83..79c59cb6da7a7746df983614d7eff02f97eddfb0 100644 ---- a/dom/base/nsContentUtils.h -+++ b/dom/base/nsContentUtils.h -@@ -2957,7 +2957,8 @@ class nsContentUtils { - int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, - unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, - mozilla::PreventDefaultResult* aPreventDefault, -- bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized); -+ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ bool convertToPointer = true); - - static void FirePageShowEventForFrameLoaderSwap( - nsIDocShellTreeItem* aItem, -diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index 972be59520940e93e703312e42c2ef250d2bb4d6..11faf5ab1ab25449ebfbaf41b1dfad15a43096a9 100644 ---- a/dom/base/nsDOMWindowUtils.cpp -+++ b/dom/base/nsDOMWindowUtils.cpp -@@ -683,7 +683,7 @@ nsDOMWindowUtils::SendMouseEvent( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, - bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -- int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount, -+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, uint8_t aOptionalArgCount, - bool* aPreventDefault) { - return SendMouseEventCommon( - aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, -@@ -691,7 +691,7 @@ nsDOMWindowUtils::SendMouseEvent( - aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false, - aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, - aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, -- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); -+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, !aDisablePointerEvent); - } - - NS_IMETHODIMP -@@ -718,13 +718,13 @@ nsDOMWindowUtils::SendMouseEventCommon( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized, int32_t aButtons) { -+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer) { - RefPtr presShell = GetPresShell(); - PreventDefaultResult preventDefaultResult; - nsresult rv = nsContentUtils::SendMouseEvent( - presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers, - aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow, -- &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized); -+ &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer); - - if (aPreventDefault) { - *aPreventDefault = preventDefaultResult != PreventDefaultResult::No; -diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h -index 30e0fafa77857c33e9871259a6ac0cebac965df8..3d8810abcfac1c220529b4e6163b0159475723ff 100644 ---- a/dom/base/nsDOMWindowUtils.h -+++ b/dom/base/nsDOMWindowUtils.h -@@ -93,7 +93,7 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils, - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, - bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, -- bool aIsWidgetEventSynthesized, int32_t aButtons); -+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true); - - MOZ_CAN_RUN_SCRIPT - nsresult SendTouchEventCommon( -diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index 25c06cd90d552345da4fffbcdb4dfaab02377c97..cc81b234da508405daba42735430dd3f065d2b0c 100644 ---- a/dom/base/nsFocusManager.cpp -+++ b/dom/base/nsFocusManager.cpp -@@ -1610,6 +1610,10 @@ void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags, - (GetActiveBrowsingContext() == newRootBrowsingContext); - } - -+ // In Playwright, we want to send focus events even if the element -+ // isn't actually in the active window. -+ isElementInActiveWindow = true; -+ - // Exit fullscreen if a website focuses another window - if (StaticPrefs::full_screen_api_exit_on_windowRaise() && - !isElementInActiveWindow && (aFlags & FLAG_RAISE) && -@@ -2934,7 +2938,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, - } - } - -- if (sTestMode) { -+ // In Playwright, we still want to execte the embedder functions -+ // to actually show / focus windows. -+ if (false && sTestMode) { - // In test mode, emulate raising the window. WindowRaised takes - // care of lowering the present active window. This happens in - // a separate runnable to avoid touching multiple windows in -diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp -index 02e1ad995ba68d69e4353b89464a0259e22d24a0..bb169f97aff4fe707a4fb2be6c5db5eba7e80c49 100644 ---- a/dom/base/nsGlobalWindowOuter.cpp -+++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2489,7 +2489,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, - &nsGlobalWindowInner::FireOnNewGlobalObject)); - } - -- if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) { -+ if (newInnerWindow && mDoc) { - // We should probably notify. However if this is the, arguably bad, - // situation when we're creating a temporary non-chrome-about-blank - // document in a chrome docshell, don't notify just yet. Instead wait -@@ -2508,10 +2508,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, - }(); - - if (!isContentAboutBlankInChromeDocshell) { -- newInnerWindow->mHasNotifiedGlobalCreated = true; -- nsContentUtils::AddScriptRunner(NewRunnableMethod( -- "nsGlobalWindowOuter::DispatchDOMWindowCreated", this, -- &nsGlobalWindowOuter::DispatchDOMWindowCreated)); -+ if (!newInnerWindow->mHasNotifiedGlobalCreated) { -+ newInnerWindow->mHasNotifiedGlobalCreated = true; -+ nsContentUtils::AddScriptRunner(NewRunnableMethod( -+ "nsGlobalWindowOuter::DispatchDOMWindowCreated", this, -+ &nsGlobalWindowOuter::DispatchDOMWindowCreated)); -+ } else if (!reUseInnerWindow) { -+ nsContentUtils::AddScriptRunner(NewRunnableMethod( -+ "nsGlobalWindowOuter::JugglerDispatchDOMWindowReused", this, -+ &nsGlobalWindowOuter::JugglerDispatchDOMWindowReused)); -+ } - } - } - -@@ -2632,6 +2638,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { - } - } - -+void nsGlobalWindowOuter::JugglerDispatchDOMWindowReused() { -+ nsCOMPtr observerService = -+ mozilla::services::GetObserverService(); -+ if (observerService && mDoc) { -+ nsIPrincipal* principal = mDoc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) { -+ observerService->NotifyObservers(static_cast(this), -+ "juggler-dom-window-reused", -+ nullptr); -+ } -+ } -+} -+ - void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } - - void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { -@@ -3769,6 +3788,14 @@ Maybe nsGlobalWindowOuter::GetRDMDeviceSize( - } - } - } -+ if (topInProcessContentDoc) { -+ nsIDocShell* docShell = topInProcessContentDoc->GetDocShell(); -+ if (docShell && docShell->GetDeviceSizeIsPageSize()) { -+ nsPresContext* presContext = docShell->GetPresContext(); -+ if (presContext) -+ return Some(CSSPixel::FromAppUnitsRounded(presContext->GetVisibleArea().Size())); -+ } -+ } - return Nothing(); - } - -diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index a82771c6d0bf1b5d5547e42fa3dad61537381d4a..0a4e153a11972b305a425ecb4fdb427766174a18 100644 ---- a/dom/base/nsGlobalWindowOuter.h -+++ b/dom/base/nsGlobalWindowOuter.h -@@ -333,6 +333,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, - - // Outer windows only. - void DispatchDOMWindowCreated(); -+ void JugglerDispatchDOMWindowReused(); - - // Outer windows only. - virtual void EnsureSizeAndPositionUpToDate() override; -diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp -index 1088bfc489a067f95bfb84a822a787bdf9463e54..54c4687ff71ec1b82912d9139f061ef5c7d4a426 100644 ---- a/dom/base/nsINode.cpp -+++ b/dom/base/nsINode.cpp -@@ -1324,6 +1324,62 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, - mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); - } - -+static nsIFrame* GetFirstFrame(nsINode* aNode) { -+ if (!aNode->IsContent()) -+ return nullptr; -+ nsIFrame* frame = aNode->AsContent()->GetPrimaryFrame(FlushType::Frames); -+ if (!frame) { -+ FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = child->GetPrimaryFrame(FlushType::Frames); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ -+void nsINode::ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv) { -+ aRv = NS_ERROR_UNEXPECTED; -+ nsCOMPtr document = OwnerDoc(); -+ if (!document) { -+ return aRv.ThrowNotFoundError("Node is detached from document"); -+ } -+ PresShell* presShell = document->GetPresShell(); -+ if (!presShell) { -+ return aRv.ThrowNotFoundError("Node is detached from document"); -+ } -+ nsIFrame* primaryFrame = GetFirstFrame(this); -+ if (!primaryFrame) { -+ return aRv.ThrowNotFoundError("Node does not have a layout object"); -+ } -+ aRv = NS_OK; -+ nsRect rect; -+ if (x == -1 && y == -1 && w == -1 && h == -1) { -+ rect = primaryFrame->GetRectRelativeToSelf(); -+ } else { -+ rect = nsRect(nsPresContext::CSSPixelsToAppUnits(x), -+ nsPresContext::CSSPixelsToAppUnits(y), -+ nsPresContext::CSSPixelsToAppUnits(w), -+ nsPresContext::CSSPixelsToAppUnits(h)); -+ } -+ presShell->ScrollFrameRectIntoView( -+ primaryFrame, rect, -+ nsMargin(), -+ ScrollAxis(kScrollToCenter, WhenToScroll::Always), -+ ScrollAxis(kScrollToCenter, WhenToScroll::Always), -+ ScrollFlags::ScrollOverflowHidden); -+ // If a _visual_ scroll update is pending, cancel it; otherwise, it will -+ // clobber next scroll (e.g. subsequent window.scrollTo(0, 0) wlll break). -+ if (presShell->GetPendingVisualScrollUpdate()) { -+ presShell->AcknowledgePendingVisualScrollUpdate(); -+ presShell->ClearPendingVisualScrollUpdate(); -+ } -+} -+ - already_AddRefed nsINode::ConvertQuadFromNode( - DOMQuad& aQuad, const GeometryNode& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h -index 0c7c5867c4a1f2543b774a1f3371c4ce0807f33f..ae35e4a023297f2f0b9d59eb9a0fa8e5aa649202 100644 ---- a/dom/base/nsINode.h -+++ b/dom/base/nsINode.h -@@ -2130,6 +2130,10 @@ class nsINode : public mozilla::dom::EventTarget { - nsTArray>& aResult, - ErrorResult& aRv); - -+ void ScrollRectIntoViewIfNeeded(int32_t x, int32_t y, -+ int32_t w, int32_t h, -+ ErrorResult& aRv); -+ - already_AddRefed ConvertQuadFromNode( - DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, - const ConvertCoordinateOptions& aOptions, CallerType aCallerType, -diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index 1da84501bf3ce25b932ec3693f247cdb1a4fdf21..2305a1730e18ba7293a41772b9b7495b5aa66210 100644 ---- a/dom/base/nsJSUtils.cpp -+++ b/dom/base/nsJSUtils.cpp -@@ -169,6 +169,11 @@ bool nsJSUtils::GetScopeChainForElement( - return true; - } - -+/* static */ -+bool nsJSUtils::SetTimeZoneOverride(const char* timezoneId) { -+ return JS::SetTimeZoneOverride(timezoneId); -+} -+ - /* static */ - void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } - -diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h -index 85a21e459305f556933f4dc0fa7441d8f9ed95a9..d7cb86479ba2ed06542307349d6d86dfd026d55d 100644 ---- a/dom/base/nsJSUtils.h -+++ b/dom/base/nsJSUtils.h -@@ -78,6 +78,7 @@ class nsJSUtils { - JSContext* aCx, mozilla::dom::Element* aElement, - JS::MutableHandleVector aScopeChain); - -+ static bool SetTimeZoneOverride(const char* timezoneId); - static void ResetTimeZone(); - - static bool DumpEnabled(); -diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl -index 414e8367d19057d3249f07f6590fc84534406bf3..5872741f2e22d500cd3b939e66e730aaac5ad717 100644 ---- a/dom/chrome-webidl/BrowsingContext.webidl -+++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -52,6 +52,24 @@ enum PrefersColorSchemeOverride { - "dark", - }; - -+/** -+ * CSS prefers-reduced-motion values. -+ */ -+enum PrefersReducedMotionOverride { -+ "none", -+ "reduce", -+ "no-preference", -+}; -+ -+/** -+ * CSS forced-colors values. -+ */ -+enum ForcedColorsOverride { -+ "none", -+ "active", -+ "no-override", /* This clears the override. */ -+}; -+ - /** - * Allowed overrides of platform/pref default behaviour for touch events. - */ -@@ -186,6 +204,12 @@ interface BrowsingContext { - // Color-scheme simulation, for DevTools. - [SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride; - -+ // Reduced-Motion simulation, for DevTools. -+ [SetterThrows] attribute PrefersReducedMotionOverride prefersReducedMotionOverride; -+ -+ // Forced-Colors simulation, for DevTools. -+ [SetterThrows] attribute ForcedColorsOverride forcedColorsOverride; -+ - /** - * A unique identifier for the browser element that is hosting this - * BrowsingContext tree. Every BrowsingContext in the element's tree will -diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 5b85084f551faa37ed41a3f7c15482b68b653937..b0886dc9fdd5740d24359aed29d45351599950e1 100644 ---- a/dom/geolocation/Geolocation.cpp -+++ b/dom/geolocation/Geolocation.cpp -@@ -23,6 +23,7 @@ - #include "nsComponentManagerUtils.h" - #include "nsContentPermissionHelper.h" - #include "nsContentUtils.h" -+#include "nsDocShell.h" - #include "nsGlobalWindow.h" - #include "mozilla/dom/Document.h" - #include "nsINamed.h" -@@ -260,10 +261,8 @@ nsGeolocationRequest::Allow(JS::Handle aChoices) { - return NS_OK; - } - -- RefPtr gs = -- nsGeolocationService::GetGeolocationService(); -- -- bool canUseCache = false; -+ nsGeolocationService* gs = mLocator->GetGeolocationService(); -+ bool canUseCache = gs != nsGeolocationService::sService.get(); - CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); - if (lastPosition.position) { - EpochTimeStamp cachedPositionTime_ms; -@@ -436,8 +435,7 @@ void nsGeolocationRequest::Shutdown() { - // If there are no other high accuracy requests, the geolocation service will - // notify the provider to switch to the default accuracy. - if (mOptions && mOptions->mEnableHighAccuracy) { -- RefPtr gs = -- nsGeolocationService::GetGeolocationService(); -+ nsGeolocationService* gs = mLocator ? mLocator->GetGeolocationService() : nullptr; - if (gs) { - gs->UpdateAccuracy(); - } -@@ -727,8 +725,14 @@ void nsGeolocationService::StopDevice() { - StaticRefPtr nsGeolocationService::sService; - - already_AddRefed --nsGeolocationService::GetGeolocationService() { -+nsGeolocationService::GetGeolocationService(nsDocShell* docShell) { - RefPtr result; -+ if (docShell) { -+ result = docShell->GetGeolocationServiceOverride(); -+ if (result) -+ return result.forget(); -+ } -+ - if (nsGeolocationService::sService) { - result = nsGeolocationService::sService; - -@@ -820,7 +824,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { - // If no aContentDom was passed into us, we are being used - // by chrome/c++ and have no mOwner, no mPrincipal, and no need - // to prompt. -- mService = nsGeolocationService::GetGeolocationService(); -+ nsCOMPtr doc = aContentDom ? aContentDom->GetDoc() : nullptr; -+ mService = nsGeolocationService::GetGeolocationService( -+ doc ? static_cast(doc->GetDocShell()) : nullptr); - if (mService) { - mService->AddLocator(this); - } -diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 5c0d2f96a22c6928d6aee5a226032c0944ae7a54..5a7bb1f6cea1946eea143dca4e2f1e19746a04a4 100644 ---- a/dom/geolocation/Geolocation.h -+++ b/dom/geolocation/Geolocation.h -@@ -31,6 +31,7 @@ - - #include "nsIGeolocationProvider.h" - #include "mozilla/Attributes.h" -+#include "nsDocShell.h" - - class nsGeolocationService; - class nsGeolocationRequest; -@@ -48,13 +49,14 @@ struct CachedPositionAndAccuracy { - bool isHighAccuracy; - }; - -+ - /** - * Singleton that manages the geolocation provider - */ - class nsGeolocationService final : public nsIGeolocationUpdate, - public nsIObserver { - public: -- static already_AddRefed GetGeolocationService(); -+ static already_AddRefed GetGeolocationService(nsDocShell* docShell = nullptr); - static mozilla::StaticRefPtr sService; - - NS_DECL_THREADSAFE_ISUPPORTS -@@ -179,6 +181,8 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache { - // null. - static already_AddRefed NonWindowSingleton(); - -+ nsGeolocationService* GetGeolocationService() { return mService; }; -+ - private: - ~Geolocation(); - -diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index d53de983402c9e0fd2d1bd848563efc04edee616..c635674099390cf412a361430517c200fec5796a 100644 ---- a/dom/html/HTMLInputElement.cpp -+++ b/dom/html/HTMLInputElement.cpp -@@ -53,6 +53,7 @@ - #include "nsMappedAttributes.h" - #include "nsIFormControl.h" - #include "mozilla/dom/Document.h" -+#include "nsDocShell.h" - #include "nsIFormControlFrame.h" - #include "nsITextControlFrame.h" - #include "nsIFrame.h" -@@ -746,6 +747,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { - return NS_ERROR_FAILURE; - } - -+ nsDocShell* docShell = static_cast(win->GetDocShell()); -+ if (docShell && docShell->IsFileInputInterceptionEnabled()) { -+ docShell->FilePickerShown(this); -+ return NS_OK; -+ } -+ - if (IsPopupBlocked(doc)) { - return NS_OK; - } -diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index 579043a768c506db54a20d615a3f44a2a55de627..33fdee86da62f1e0cc3caa6e4bc4382be9bf762e 100644 ---- a/dom/interfaces/base/nsIDOMWindowUtils.idl -+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -372,7 +372,8 @@ interface nsIDOMWindowUtils : nsISupports { - [optional] in boolean aIsDOMEventSynthesized, - [optional] in boolean aIsWidgetEventSynthesized, - [optional] in long aButtons, -- [optional] in unsigned long aIdentifier); -+ [optional] in unsigned long aIdentifier, -+ [optional] in boolean aDisablePointerEvent); - - /** Synthesize a touch event. The event types supported are: - * touchstart, touchend, touchmove, and touchcancel -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index 9d4e8fbbfe8d45cc6245c7659423004ad1ceedeb..f955c7bace3cedfe0469e59a5e8c5824158c4d50 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -123,10 +123,11 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8, - return 0; - } - --VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t id, -+VideoCaptureModuleEx* DesktopCaptureImpl::Create(const int32_t id, - const char* uniqueId, -- const CaptureDeviceType type) { -- return new rtc::RefCountedObject(id, uniqueId, type); -+ const CaptureDeviceType type, -+ bool captureCursor) { -+ return new rtc::RefCountedObject(id, uniqueId, type, captureCursor); - } - - int32_t WindowDeviceInfoImpl::Init() { -@@ -358,9 +359,13 @@ int32_t DesktopCaptureImpl::Init() { - DesktopCapturer::SourceId sourceId = atoi(_deviceUniqueId.c_str()); - pWindowCapturer->SelectSource(sourceId); - -- desktop_capturer_cursor_composer_ = -- std::unique_ptr( -- new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); -+ if (capture_cursor_) { -+ desktop_capturer_cursor_composer_ = -+ std::unique_ptr( -+ new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); -+ } else { -+ desktop_capturer_cursor_composer_ = std::move(pWindowCapturer); -+ } - } else if (_deviceType == CaptureDeviceType::Browser) { - // XXX We don't capture cursors, so avoid the extra indirection layer. We - // could also pass null for the pMouseCursorMonitor. -@@ -377,13 +382,15 @@ int32_t DesktopCaptureImpl::Init() { - } - - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type) -+ const CaptureDeviceType type, -+ bool captureCursor) - : _id(id), - _deviceUniqueId(uniqueId), - _deviceType(type), - _requestedCapability(), - _rotateFrame(kVideoRotation_0), - last_capture_time_ms_(rtc::TimeMillis()), -+ capture_cursor_(captureCursor), - time_event_(EventWrapper::Create()), - #if defined(_WIN32) - capturer_thread_( -@@ -428,6 +435,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( - } - } - -+void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&_apiCs); -+ _rawFrameCallbacks.insert(rawFrameCallback); -+} -+ -+void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&_apiCs); -+ auto it = _rawFrameCallbacks.find(rawFrameCallback); -+ if (it != _rawFrameCallbacks.end()) { -+ _rawFrameCallbacks.erase(it); -+ } -+} -+ - int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - if (_dataCallBacks.empty()) { - return StopCapture(); -@@ -636,6 +656,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result result, - frameInfo.height = frame->size().height(); - frameInfo.videoType = VideoType::kARGB; - -+ size_t videoFrameStride = -+ frameInfo.width * DesktopFrame::kBytesPerPixel; -+ { -+ rtc::CritScope cs(&_apiCs); -+ for (auto rawFrameCallback : _rawFrameCallbacks) { -+ rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); -+ } -+ } -+ - size_t videoFrameLength = - frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; - IncomingFrame(videoFrame, videoFrameLength, -diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index b725849dab1d1f898ab988e57a35c27e3eb44700..e2e13b0a0926475fe673fecf5e3c497569d158b3 100644 ---- a/dom/media/systemservices/video_engine/desktop_capture_impl.h -+++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -46,6 +46,21 @@ namespace webrtc { - - class VideoCaptureEncodeInterface; - -+class RawFrameCallback { -+ public: -+ virtual ~RawFrameCallback() {} -+ -+ virtual void OnRawFrame(uint8_t* videoFrame, size_t videoFrameLength, const VideoCaptureCapability& frameInfo) = 0; -+}; -+ -+class VideoCaptureModuleEx : public VideoCaptureModule { -+ public: -+ virtual ~VideoCaptureModuleEx() {} -+ -+ virtual void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; -+ virtual void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) = 0; -+}; -+ - // simulate deviceInfo interface for video engine, bridge screen/application and - // real screen/application device info - -@@ -158,12 +173,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { - // As with video, DesktopCaptureImpl is a proxy for screen sharing - // and follows the video pipeline design - class DesktopCaptureImpl : public DesktopCapturer::Callback, -- public VideoCaptureModule { -+ public VideoCaptureModuleEx { - public: - /* Create a screen capture modules object - */ -- static VideoCaptureModule* Create(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type); -+ static VideoCaptureModuleEx* Create(const int32_t id, const char* uniqueId, -+ const CaptureDeviceType type, -+ bool captureCursor = true); - static VideoCaptureModule::DeviceInfo* CreateDeviceInfo( - const int32_t id, const CaptureDeviceType type); - -@@ -173,6 +189,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* dataCallback) override; - int32_t StopCaptureIfAllClientsClose() override; -+ void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; -+ void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; - - int32_t SetCaptureRotation(VideoRotation rotation) override; - bool SetApplyRotation(bool enable) override; -@@ -193,7 +211,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - - protected: - DesktopCaptureImpl(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type); -+ const CaptureDeviceType type, bool captureCursor); - virtual ~DesktopCaptureImpl(); - int32_t DeliverCapturedFrame(webrtc::VideoFrame& captureFrame); - -@@ -215,6 +233,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - rtc::RecursiveCriticalSection _apiCs; - - std::set*> _dataCallBacks; -+ std::set _rawFrameCallbacks; - - int64_t _incomingFrameTimesNanos - [kFrameRateCountHistorySize]; // timestamp for local captured frames -@@ -237,6 +256,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void ProcessIter(); - - private: -+ bool capture_cursor_ = true; - // This is created on the main thread and accessed on both the main thread - // and the capturer thread. It is created prior to the capturer thread - // starting and is destroyed after it is stopped. -diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index 8c8a5810fd56512cf37635da1f43757719f06113..d2bc58fcd3b05f989f948839d574d00d0409873c 100644 ---- a/dom/script/ScriptSettings.cpp -+++ b/dom/script/ScriptSettings.cpp -@@ -150,6 +150,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() { - MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal()); - } - -+static nsIGlobalObject* UnwrapSandboxGlobal(nsIGlobalObject* global) { -+ if (!global) -+ return global; -+ JSObject* globalObject = global->GetGlobalJSObject(); -+ if (!globalObject) -+ return global; -+ JSContext* cx = nsContentUtils::GetCurrentJSContext(); -+ if (!cx) -+ return global; -+ JS::Rooted proto(cx); -+ JS::RootedObject rootedGlobal(cx, globalObject); -+ if (!JS_GetPrototype(cx, rootedGlobal, &proto)) -+ return global; -+ if (!proto || !xpc::IsSandboxPrototypeProxy(proto)) -+ return global; -+ // If this is a sandbox associated with a DOMWindow via a -+ // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey -+ // and JetPack content scripts. -+ proto = js::CheckedUnwrapDynamic(proto, cx, /* stopAtWindowProxy = */ false); -+ if (!proto) -+ return global; -+ return xpc::WindowGlobalOrNull(proto); -+} -+ - // If the entry or incumbent global ends up being something that the subject - // principal doesn't subsume, we don't want to use it. This never happens on - // the web, but can happen with asymmetric privilege relationships (i.e. -@@ -177,7 +201,7 @@ static nsIGlobalObject* ClampToSubject(nsIGlobalObject* aGlobalOrNull) { - NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal()); - if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller() - ->SubsumesConsideringDomain(globalPrin)) { -- return GetCurrentGlobal(); -+ return UnwrapSandboxGlobal(GetCurrentGlobal()); - } - - return aGlobalOrNull; -diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp -index b31ca1000cb1d7b8ca1af74b9ac0313aba053875..54abd38a35fc2b4906760c370d9f96d7f2ade0e2 100644 ---- a/dom/security/nsCSPUtils.cpp -+++ b/dom/security/nsCSPUtils.cpp -@@ -127,6 +127,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, - return; - } - -+ if (aDoc.GetDocShell() && -+ nsDocShell::Cast(aDoc.GetDocShell())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsAutoString policyStr( - nsContentUtils::TrimWhitespace( - aPolicyStr)); -diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index 2f71b284ee5f7e11f117c447834b48355784448c..ddcc545da1efec5784273b032efa00ad8b89fec0 100644 ---- a/dom/webidl/GeometryUtils.webidl -+++ b/dom/webidl/GeometryUtils.webidl -@@ -16,6 +16,8 @@ dictionary BoxQuadOptions { - GeometryNode relativeTo; - [ChromeOnly] - boolean createFramesForSuppressedWhitespace = true; -+ [ChromeOnly] -+ boolean recurseWhenNoFrame = false; - }; - - dictionary ConvertCoordinateOptions { -@@ -27,6 +29,9 @@ interface mixin GeometryUtils { - [Throws, Func="nsINode::HasBoxQuadsSupport", NeedsCallerType] - sequence getBoxQuads(optional BoxQuadOptions options = {}); - -+ [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] -+ void scrollRectIntoViewIfNeeded(long x, long y, long w, long h); -+ - /* getBoxQuadsFromWindowOrigin is similar to getBoxQuads, but the - * returned quads are further translated relative to the window - * origin -- which is not the layout origin. Further translation -diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp -index 88e55560a914f1661b5302a924de519157c25dd9..b86513356488b48cb788acefaaa9905c38c2b05c 100644 ---- a/dom/workers/RuntimeService.cpp -+++ b/dom/workers/RuntimeService.cpp -@@ -977,7 +977,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { - AssertIsOnMainThread(); - - nsTArray languages; -- Navigator::GetAcceptLanguages(languages); -+ Navigator::GetAcceptLanguages(nullptr, languages); - - RuntimeService* runtime = RuntimeService::GetService(); - if (runtime) { -@@ -1179,8 +1179,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { - } - - // The navigator overridden properties should have already been read. -- -- Navigator::GetAcceptLanguages(mNavigatorProperties.mLanguages); -+ Navigator::GetAcceptLanguages(nullptr, mNavigatorProperties.mLanguages); - mNavigatorPropertiesLoaded = true; - } - -@@ -1778,6 +1777,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( - } - } - -+void RuntimeService::ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ BroadcastAllWorkers([](auto& worker) { -+ worker.ResetDefaultLocale(); -+ }); -+} -+ - template - void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { - AssertIsOnMainThread(); -@@ -2193,6 +2199,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( - } - } - -+void ResetDefaultLocaleInAllWorkers() { -+ AssertIsOnMainThread(); -+ RuntimeService* runtime = RuntimeService::GetService(); -+ if (runtime) { -+ runtime->ResetDefaultLocaleInAllWorkers(); -+ } -+} -+ - WorkerPrivate* GetWorkerPrivateFromContext(JSContext* aCx) { - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ASSERT(aCx); -diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h -index ef32cc847e8b86319830bb93879aaf809fe464d4..5db3be0dc87e50ff75177194ca734313b22509d6 100644 ---- a/dom/workers/RuntimeService.h -+++ b/dom/workers/RuntimeService.h -@@ -110,6 +110,8 @@ class RuntimeService final : public nsIObserver { - void PropagateStorageAccessPermissionGranted( - const nsPIDOMWindowInner& aWindow); - -+ void ResetDefaultLocaleInAllWorkers(); -+ - const NavigatorProperties& GetNavigatorProperties() const { - return mNavigatorProperties; - } -diff --git a/dom/workers/WorkerCommon.h b/dom/workers/WorkerCommon.h -index d10dabb5c5ff8e17851edf2bd2efc08e74584d8e..53c4070c5fde43b27fb8fbfdcf4c23d8af57fba3 100644 ---- a/dom/workers/WorkerCommon.h -+++ b/dom/workers/WorkerCommon.h -@@ -44,6 +44,8 @@ void ResumeWorkersForWindow(const nsPIDOMWindowInner& aWindow); - void PropagateStorageAccessPermissionGrantedToWorkers( - const nsPIDOMWindowInner& aWindow); - -+void ResetDefaultLocaleInAllWorkers(); -+ - // All of these are implemented in WorkerScope.cpp - - bool IsWorkerGlobal(JSObject* global); -diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp -index 96357690e6f056501bef4729291c0c280d43b8e3..6fbcad9a972d61ab1d2de295219c361288ffb381 100644 ---- a/dom/workers/WorkerPrivate.cpp -+++ b/dom/workers/WorkerPrivate.cpp -@@ -699,6 +699,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { - } - }; - -+class ResetDefaultLocaleRunnable final : public WorkerControlRunnable { -+ public: -+ explicit ResetDefaultLocaleRunnable(WorkerPrivate* aWorkerPrivate) -+ : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {} -+ -+ virtual bool WorkerRun(JSContext* aCx, -+ WorkerPrivate* aWorkerPrivate) override { -+ aWorkerPrivate->ResetDefaultLocaleInternal(aCx); -+ return true; -+ } -+}; -+ - class UpdateLanguagesRunnable final : public WorkerRunnable { - nsTArray mLanguages; - -@@ -1951,6 +1963,16 @@ void WorkerPrivate::UpdateContextOptions( - } - } - -+void WorkerPrivate::ResetDefaultLocale() { -+ AssertIsOnParentThread(); -+ -+ RefPtr runnable = -+ new ResetDefaultLocaleRunnable(this); -+ if (!runnable->Dispatch()) { -+ NS_WARNING("Failed to reset default locale in worker!"); -+ } -+} -+ - void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { - AssertIsOnParentThread(); - -@@ -5123,6 +5145,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( - } - } - -+void WorkerPrivate::ResetDefaultLocaleInternal(JSContext* aCx) { -+ JS_ResetDefaultLocale(JS_GetRuntime(aCx)); -+ auto data = mWorkerThreadAccessible.Access(); -+ -+ for (uint32_t index = 0; index < data->mChildWorkers.Length(); index++) { -+ data->mChildWorkers[index]->ResetDefaultLocale(); -+ } -+} -+ - void WorkerPrivate::UpdateLanguagesInternal( - const nsTArray& aLanguages) { - WorkerGlobalScope* globalScope = GlobalScope(); -diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index 1f31c4a6a94491cb6c981655e30e1fd42c4dbfc1..dbfdf4fc27f112e7cadbb768a858323f8ee919d1 100644 ---- a/dom/workers/WorkerPrivate.h -+++ b/dom/workers/WorkerPrivate.h -@@ -330,6 +330,8 @@ class WorkerPrivate final - void UpdateContextOptionsInternal(JSContext* aCx, - const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocaleInternal(JSContext* aCx); -+ - void UpdateLanguagesInternal(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -966,6 +968,8 @@ class WorkerPrivate final - - void UpdateContextOptions(const JS::ContextOptions& aContextOptions); - -+ void ResetDefaultLocale(); -+ - void UpdateLanguages(const nsTArray& aLanguages); - - void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe value); -diff --git a/intl/components/src/TimeZone.cpp b/intl/components/src/TimeZone.cpp -index 145dd3f07112c2390325de50f8eae674484adfe6..8cb3787e1b6bb25c6a58f1d910ae7dbc440d9ace 100644 ---- a/intl/components/src/TimeZone.cpp -+++ b/intl/components/src/TimeZone.cpp -@@ -16,6 +16,7 @@ - - namespace mozilla::intl { - -+ - /* static */ - Result, ICUError> TimeZone::TryCreate( - Maybe> aTimeZoneOverride) { -@@ -239,6 +240,13 @@ static ICUResult SetDefaultTimeZone(TimeZoneIdentifierVector& timeZone) { - } - #endif - -+bool TimeZone::IsValidTimeZoneId(const char* timeZoneId) { -+ // Validate timezone id. -+ mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( -+ icu::UnicodeString(timeZoneId, -1, US_INV))); -+ return timeZone && *timeZone != icu::TimeZone::getUnknown(); -+} -+ - Result TimeZone::SetDefaultTimeZone( - Span aTimeZone) { - #if MOZ_INTL_USE_ICU_CPP_TIMEZONE -diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h -index 180092bd3fc0b70462cc6ba67e72946e4c4c7604..bcaecb9fcd7b630c75289581a887cc6894733168 100644 ---- a/intl/components/src/TimeZone.h -+++ b/intl/components/src/TimeZone.h -@@ -154,6 +154,8 @@ class TimeZone final { - return FillBufferWithICUCall(aBuffer, ucal_getHostTimeZone); - } - -+ static bool IsValidTimeZoneId(const char* timeZoneId); -+ - /** - * Set the default time zone. - */ -diff --git a/js/public/Date.h b/js/public/Date.h -index bb69d58dc96ed7f0b37f73e26abdd0bdfeaaf556..8436d439f72287176a2fe6a1a837d3db73409e67 100644 ---- a/js/public/Date.h -+++ b/js/public/Date.h -@@ -53,6 +53,8 @@ namespace JS { - */ - extern JS_PUBLIC_API void ResetTimeZone(); - -+extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId); -+ - class ClippedTime; - inline ClippedTime TimeClip(double time); - -diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp -index 1c00fed8e0dc84b12c9b1c169d841e27402579a1..ad25cb5f8a0572c9c8622f85551b79dd2ffea819 100644 ---- a/js/src/debugger/Object.cpp -+++ b/js/src/debugger/Object.cpp -@@ -2373,7 +2373,11 @@ Maybe DebuggerObject::call(JSContext* cx, - invokeArgs[i].set(args2[i]); - } - -+ // Disable CSP for the scope of the call. -+ const JSSecurityCallbacks* securityCallbacks = JS_GetSecurityCallbacks(cx); -+ JS_SetSecurityCallbacks(cx, nullptr); - ok = js::Call(cx, calleev, thisv, invokeArgs, &result); -+ JS_SetSecurityCallbacks(cx, securityCallbacks); - } - } - -diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp -index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8eac31718cc 100644 ---- a/js/src/vm/DateTime.cpp -+++ b/js/src/vm/DateTime.cpp -@@ -178,6 +178,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { - } - } - -+void js::DateTimeInfo::internalSetTimeZoneOverride(std::string timeZone) { -+ timeZoneOverride_ = std::move(timeZone); -+ internalResetTimeZone(ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); -+} -+ - void js::DateTimeInfo::updateTimeZone() { - MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid); - -@@ -502,10 +507,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { - js::DateTimeInfo::resetTimeZone(mode); - } - -+void js::SetTimeZoneOverrideInternal(std::string timeZone) { -+ auto guard = js::DateTimeInfo::instance->lock(); -+ guard->internalSetTimeZoneOverride(timeZone); -+} -+ - JS_PUBLIC_API void JS::ResetTimeZone() { - js::ResetTimeZoneInternal(js::ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); - } - -+JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) { -+ if (!mozilla::intl::TimeZone::IsValidTimeZoneId(timeZoneId)) { -+ fprintf(stderr, "Invalid timezone id: %s\n", timeZoneId); -+ return false; -+ } -+ js::SetTimeZoneOverrideInternal(std::string(timeZoneId)); -+ return true; -+} -+ - #if JS_HAS_INTL_API - # if defined(XP_WIN) - static bool IsOlsonCompatibleWindowsTimeZoneId(std::string_view tz) { -@@ -727,9 +746,17 @@ void js::ResyncICUDefaultTimeZone() { - - void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { - #if JS_HAS_INTL_API -+ if (!timeZoneOverride_.empty()) { -+ mozilla::Span tzid = mozilla::Span(timeZoneOverride_.data(), timeZoneOverride_.length()); -+ auto result = mozilla::intl::TimeZone::SetDefaultTimeZone(tzid); -+ if (result.isErr()) { -+ fprintf(stderr, "ERROR: failed to setup default time zone\n"); -+ } -+ return; -+ } -+ - if (const char* tzenv = std::getenv("TZ")) { - std::string_view tz(tzenv); -- - mozilla::Span tzid; - - # if defined(XP_WIN) -diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index 3ce936fe3a4a83f9161eddc9e5289322d6a363e3..6b1c34244d8b2f2102ec423e2d96812fb5d41a9d 100644 ---- a/js/src/vm/DateTime.h -+++ b/js/src/vm/DateTime.h -@@ -63,6 +63,8 @@ enum class ResetTimeZoneMode : bool { - */ - extern void ResetTimeZoneInternal(ResetTimeZoneMode mode); - -+extern void SetTimeZoneOverrideInternal(std::string timeZone); -+ - /** - * ICU's default time zone, used for various date/time formatting operations - * that include the local time in the representation, is allowed to go stale -@@ -202,6 +204,7 @@ class DateTimeInfo { - // and js::ResyncICUDefaultTimeZone(). - friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); - friend void js::ResyncICUDefaultTimeZone(); -+ friend void js::SetTimeZoneOverrideInternal(std::string); - - static void resetTimeZone(ResetTimeZoneMode mode) { - auto guard = instance->lock(); -@@ -293,6 +296,8 @@ class DateTimeInfo { - JS::UniqueChars locale_; - JS::UniqueTwoByteChars standardName_; - JS::UniqueTwoByteChars daylightSavingsName_; -+ -+ std::string timeZoneOverride_; - #else - // Restrict the data-time range to the minimum required time_t range as - // specified in POSIX. Most operating systems support 64-bit time_t -@@ -308,6 +313,8 @@ class DateTimeInfo { - - void internalResetTimeZone(ResetTimeZoneMode mode); - -+ void internalSetTimeZoneOverride(std::string timeZone); -+ - void updateTimeZone(); - - void internalResyncICUDefaultTimeZone(); -diff --git a/layout/base/GeometryUtils.cpp b/layout/base/GeometryUtils.cpp -index dac899f7558b26d6848da8b98ed8a93555c8751a..2a07d67fa1c2840b25085566e84dc3b2d9b789cf 100644 ---- a/layout/base/GeometryUtils.cpp -+++ b/layout/base/GeometryUtils.cpp -@@ -23,6 +23,7 @@ - #include "nsContentUtils.h" - #include "nsCSSFrameConstructor.h" - #include "nsLayoutUtils.h" -+#include "ChildIterator.h" - - using namespace mozilla; - using namespace mozilla::dom; -@@ -261,11 +262,27 @@ static bool CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, - return false; - } - -+static nsIFrame* GetFrameForNode(nsINode* aNode, -+ bool aCreateFramesForSuppressedWhitespace, -+ bool aRecurseWhenNoFrame) { -+ nsIFrame* frame = GetFrameForNode(aNode, aCreateFramesForSuppressedWhitespace); -+ if (!frame && aRecurseWhenNoFrame && aNode->IsContent()) { -+ dom::FlattenedChildIterator iter(aNode->AsContent()); -+ for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { -+ frame = GetFrameForNode(child, aCreateFramesForSuppressedWhitespace, aRecurseWhenNoFrame); -+ if (frame) { -+ break; -+ } -+ } -+ } -+ return frame; -+} -+ - void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - nsTArray >& aResult, CallerType aCallerType, - ErrorResult& aRv) { - nsIFrame* frame = -- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); -+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -@@ -280,7 +297,7 @@ void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions, - // when that happens and re-check it. - if (!weakFrame.IsAlive()) { - frame = -- GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace); -+ GetFrameForNode(aNode, aOptions.mCreateFramesForSuppressedWhitespace, aOptions.mRecurseWhenNoFrame); - if (!frame) { - // No boxes to return - return; -diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 014b655e374af3bf6f346febb76df4f7484e2e8d..cf62af15fd34fbcbb3d2bc3b00065eb5aee21d62 100644 ---- a/layout/base/PresShell.cpp -+++ b/layout/base/PresShell.cpp -@@ -10885,7 +10885,9 @@ auto PresShell::ComputeActiveness() const -> Activeness { - if (!browserChild->IsVisible()) { - MOZ_LOG(gLog, LogLevel::Debug, - (" > BrowserChild %p is not visible", browserChild)); -- return {false, inActiveTab}; -+ bool isActive; -+ root->GetDocShell()->GetForceActiveState(&isActive); -+ return {isActive, inActiveTab}; - } - - // If the browser is visible but just due to be preserving layers -diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 3bc4cd498dc22b7d3db097beb9988c68baf26437..77557e174283e8c151ad540f92ede87f88197c80 100644 ---- a/layout/style/GeckoBindings.h -+++ b/layout/style/GeckoBindings.h -@@ -575,6 +575,7 @@ void Gecko_MediaFeatures_GetDeviceSize(const mozilla::dom::Document*, - - float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); - bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); -+bool Gecko_MediaFeatures_ForcedColors(const mozilla::dom::Document*); - mozilla::StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( - const mozilla::dom::Document*); - mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( -diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp -index 2ef43008df12886ad00485ef743564774850c2ba..bb53b96ae491146d895e1c32d62dc0f2ea00812f 100644 ---- a/layout/style/nsMediaFeatures.cpp -+++ b/layout/style/nsMediaFeatures.cpp -@@ -260,10 +260,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { - } - - bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { -- if (nsContentUtils::ShouldResistFingerprinting(aDocument)) { -- return false; -- } -- return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; -+ return aDocument->PrefersReducedMotion(); -+} -+ -+bool Gecko_MediaFeatures_ForcedColors(const Document* aDocument) { -+ return aDocument->ForcedColors(); - } - - StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( -diff --git a/media/libjpeg/jconfig.h b/media/libjpeg/jconfig.h -index f2723e654098ff27542e1eb16a536c11ad0af617..b0b480551ff7d895dfdeb5a9800874858929c8ba 100644 ---- a/media/libjpeg/jconfig.h -+++ b/media/libjpeg/jconfig.h -@@ -17,6 +17,7 @@ - /* #undef D_ARITH_CODING_SUPPORTED */ - - /* Support in-memory source/destination managers */ -+#define MEM_SRCDST_SUPPORTED 1 - /* #undef MEM_SRCDST_SUPPORTED */ - - /* Use accelerated SIMD routines. */ -diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js -index 4e81c2325b0d4a73f6fe52f10a7a6ad593e806ce..541ac135bb854ecf951d4f4dab0aaed1fe8fc051 100644 ---- a/modules/libpref/init/all.js -+++ b/modules/libpref/init/all.js -@@ -4359,7 +4359,9 @@ pref("devtools.experiment.f12.shortcut_disabled", false); - // doesn't provide a way to lock the pref - pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); - #else --pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false, locked); -+// Playwright: DO NOT make preference locked so that we can overwrite it -+// later in our playwright.cfg file. -+pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); - #endif - - // Whether to start the private browsing mode at application startup -diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index e869cd28d396aa87c522241d3e63d435ee8dbae6..2d307f089209721d88d231b03e8628890b8228ea 100644 ---- a/netwerk/base/nsINetworkInterceptController.idl -+++ b/netwerk/base/nsINetworkInterceptController.idl -@@ -59,6 +59,7 @@ interface nsIInterceptedChannel : nsISupports - * results in the resulting client not being controlled. - */ - void resetInterception(in boolean bypass); -+ void resetInterceptionWithURI(in nsIURI aURI); - - /** - * Set the status and reason for the forthcoming synthesized response. -diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index 56eabba18f021719aa084b5bb616d3602d782a97..1408518cdba2db29e994963c4e21aead2aa573c6 100644 ---- a/netwerk/protocol/http/InterceptedHttpChannel.cpp -+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -662,6 +662,14 @@ void InterceptedHttpChannel::DoAsyncAbort(nsresult aStatus) { - Unused << AsyncAbort(aStatus); - } - -+NS_IMETHODIMP -+InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) { -+ if (aURI) { -+ mURI = aURI; -+ } -+ return ResetInterception(true); -+} -+ - NS_IMETHODIMP - InterceptedHttpChannel::ResetInterception(bool aBypass) { - if (mCanceled) { -diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index d956b3b5c6ecf6a983689d09e491193519f34ceb..826aabb5b794a2d4028950066ca3036223a35e0c 100644 ---- a/parser/html/nsHtml5TreeOpExecutor.cpp -+++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1330,6 +1330,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( - void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - -+ if (mDocShell && static_cast(mDocShell.get())->IsBypassCSPEnabled()) { -+ return; -+ } -+ - nsresult rv = NS_OK; - nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); - if (!preloadCsp) { -diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 153722c33b9db6475aa5134ad5b665051ac68658..74324d95f7088c65c3d52ab2a7c40e89901d9512 100644 ---- a/security/manager/ssl/nsCertOverrideService.cpp -+++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -572,7 +572,12 @@ nsCertOverrideService::HasMatchingOverride( - bool disableAllSecurityCheck = false; - { - MutexAutoLock lock(mMutex); -- disableAllSecurityCheck = mDisableAllSecurityCheck; -+ if (aOriginAttributes.mUserContextId) { -+ disableAllSecurityCheck = mUserContextIdsWithDisabledSecurityChecks.has( -+ aOriginAttributes.mUserContextId); -+ } else { -+ disableAllSecurityCheck = mDisableAllSecurityCheck; -+ } - } - if (disableAllSecurityCheck) { - nsCertOverride::OverrideBits all = nsCertOverride::OverrideBits::Untrusted | -@@ -789,14 +794,24 @@ static bool IsDebugger() { - - NS_IMETHODIMP - nsCertOverrideService:: -- SetDisableAllSecurityChecksAndLetAttackersInterceptMyData(bool aDisable) { -- if (!(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { -+ SetDisableAllSecurityChecksAndLetAttackersInterceptMyData( -+ bool aDisable, uint32_t aUserContextId) { -+ if (false /* juggler hacks */ && !(PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR") || IsDebugger())) { - return NS_ERROR_NOT_AVAILABLE; - } - - { - MutexAutoLock lock(mMutex); -- mDisableAllSecurityCheck = aDisable; -+ if (aUserContextId) { -+ if (aDisable) { -+ mozilla::Unused << mUserContextIdsWithDisabledSecurityChecks.put(aUserContextId); -+ } else { -+ mUserContextIdsWithDisabledSecurityChecks.remove(aUserContextId); -+ } -+ return NS_OK; -+ } else { -+ mDisableAllSecurityCheck = aDisable; -+ } - } - - nsCOMPtr nss(do_GetService(PSM_COMPONENT_CONTRACTID)); -diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h -index e601df1b13d9b2c028bffe6348d052960c80951c..0d782585199479db6218f4c72ed7b6133e3122b3 100644 ---- a/security/manager/ssl/nsCertOverrideService.h -+++ b/security/manager/ssl/nsCertOverrideService.h -@@ -134,6 +134,7 @@ class nsCertOverrideService final : public nsICertOverrideService, - - mozilla::Mutex mMutex; - bool mDisableAllSecurityCheck GUARDED_BY(mMutex); -+ mozilla::HashSet mUserContextIdsWithDisabledSecurityChecks GUARDED_BY(mMutex); - nsCOMPtr mSettingsFile GUARDED_BY(mMutex); - nsTHashtable mSettingsTable GUARDED_BY(mMutex); - -diff --git a/security/manager/ssl/nsICertOverrideService.idl b/security/manager/ssl/nsICertOverrideService.idl -index 3862fe6830874c036592fd217cab7ad5f4cd3e27..3166b37db0e52f7f2972d2bcb7a72ed819805794 100644 ---- a/security/manager/ssl/nsICertOverrideService.idl -+++ b/security/manager/ssl/nsICertOverrideService.idl -@@ -201,7 +201,9 @@ interface nsICertOverrideService : nsISupports { - * @param aDisable If true, disable all security check and make - * hasMatchingOverride always return true. - */ -- void setDisableAllSecurityChecksAndLetAttackersInterceptMyData(in boolean aDisable); -+ void setDisableAllSecurityChecksAndLetAttackersInterceptMyData( -+ in boolean aDisable, -+ [optional] in uint32_t aUserContextId); - - readonly attribute boolean securityCheckDisabled; - }; -diff --git a/services/settings/Utils.jsm b/services/settings/Utils.jsm -index a8b0c67ce19d801d2f032d1b59110871a9859787..9d8d689bc4c4fb6aa00ff6c551cbab0dcda7d85d 100644 ---- a/services/settings/Utils.jsm -+++ b/services/settings/Utils.jsm -@@ -102,7 +102,7 @@ function _isUndefined(value) { - - var Utils = { - get SERVER_URL() { -- return lazy.allowServerURLOverride -+ return true || lazy.allowServerURLOverride - ? lazy.gServerURL - : AppConstants.REMOTE_SETTINGS_SERVER_URL; - }, -diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs -index 8c93dfa24ce7810f004227fc0430338229a0bc3f..09a1f93dd027394345e910e00b765689490ac2a3 100644 ---- a/servo/components/style/gecko/media_features.rs -+++ b/servo/components/style/gecko/media_features.rs -@@ -224,10 +224,15 @@ pub enum ForcedColors { - - /// https://drafts.csswg.org/mediaqueries-5/#forced-colors - fn eval_forced_colors(context: &Context, query_value: Option) -> bool { -- let forced = !context.device().use_document_colors(); -+ let prefers_forced_colors = -+ unsafe { bindings::Gecko_MediaFeatures_ForcedColors(context.device().document()) }; -+ let query_value = match query_value { -+ Some(v) => v, -+ None => return prefers_forced_colors, -+ }; - match query_value { -- Some(query_value) => forced == (query_value == ForcedColors::Active), -- None => forced, -+ ForcedColors::Active => prefers_forced_colors, -+ ForcedColors::None => !prefers_forced_colors, - } - } - -diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 4f7337926efbb086a2be97cdbcb3dca39e27c786..f2005cb726ff153d6b1011d6af0479dbf1af02a5 100644 ---- a/toolkit/components/browser/nsIWebBrowserChrome.idl -+++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -70,6 +70,9 @@ interface nsIWebBrowserChrome : nsISupports - // Whether this window should use out-of-process cross-origin subframes. - const unsigned long CHROME_FISSION_WINDOW = 0x00200000; - -+ // Whether this window has "width" or "height" defined in features -+ const unsigned long JUGGLER_WINDOW_EXPLICIT_SIZE = 0x00400000; -+ - // Prevents new window animations on MacOS and Windows. Currently - // ignored for Linux. - const unsigned long CHROME_SUPPRESS_ANIMATION = 0x01000000; -diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -index 5184d1dcb0618dc15abd28462985040236ddf643..bce45ad2d76098c16e0877fa46f71158c884ea5a 100644 ---- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -@@ -116,6 +116,12 @@ EnterprisePoliciesManager.prototype = { - Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); - } - -+ // Playwright: Disable enterprise policies -+ if (true) { -+ this.status = Ci.nsIEnterprisePolicies.INACTIVE; -+ return; -+ } -+ - let provider = this._chooseProvider(); - - if (provider.failed) { -diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index a76e612bc7149155305468307bebf0e69679897d..ba3c5dc0af69a34fcfbf04a3dbc506ef45833107 100644 ---- a/toolkit/components/startup/nsAppStartup.cpp -+++ b/toolkit/components/startup/nsAppStartup.cpp -@@ -370,7 +370,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { - nsCOMPtr windowEnumerator; - nsCOMPtr mediator( - do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); -- if (mediator) { -+ if (ferocity != eForceQuit && mediator) { - mediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator)); - if (windowEnumerator) { - bool more; -diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -index 3e9672fdfe9ddab8acd0f8b18772aece92bb3b64..83454a9c27c96d72597445653beaa014c38728cd 100644 ---- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -+++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -@@ -174,8 +174,8 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress, - } - - NS_IMETHODIMP --nsBrowserStatusFilter::OnProgressChange(nsIWebProgress* aWebProgress, -- nsIRequest* aRequest, -+nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress, -+ nsIRequest *aRequest, - int32_t aCurSelfProgress, - int32_t aMaxSelfProgress, - int32_t aCurTotalProgress, -diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -index 3983d580cd11a8241481876aaf8a924f4f083ad0..0dd75bab6249a4db25dea3cabefd4f8e3744caad 100644 ---- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp -+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1815,7 +1815,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( - - // Open a minimal popup. - *aIsPopupRequested = true; -- return nsIWebBrowserChrome::CHROME_MINIMAL_POPUP; -+ uint32_t chromeFlags = 0; -+ if (aFeatures.Exists("width") || aFeatures.Exists("height")) { -+ chromeFlags |= nsIWebBrowserChrome::JUGGLER_WINDOW_EXPLICIT_SIZE; -+ } -+ return chromeFlags | nsIWebBrowserChrome::CHROME_MINIMAL_POPUP; - } - - /** -diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm -index 393ff53b8f69aba56d7f4d849e18aaddb0b94f49..f29602b0c7c436dec335bb7d6033750f3499fbbe 100644 ---- a/toolkit/mozapps/update/UpdateService.jsm -+++ b/toolkit/mozapps/update/UpdateService.jsm -@@ -3607,6 +3607,8 @@ UpdateService.prototype = { - }, - - get disabledForTesting() { -+ /* for playwright */ -+ return true; - return ( - (Cu.isInAutomation || - lazy.Marionette.running || -diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index 1241f1b0f94e0965b517898167ca1b52cfb48dc5..39c14eb7c548b81d564bd2a4ed15c70a920e173c 100644 ---- a/toolkit/toolkit.mozbuild -+++ b/toolkit/toolkit.mozbuild -@@ -154,6 +154,7 @@ if CONFIG['ENABLE_WEBDRIVER']: - '/remote', - '/testing/firefox-ui', - '/testing/marionette', -+ '/juggler', - '/toolkit/components/telemetry/tests/marionette', - ] - -diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp -index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..f993e78e02563cada8c131be3d4658bc8f7532b6 100644 ---- a/toolkit/xre/nsWindowsWMain.cpp -+++ b/toolkit/xre/nsWindowsWMain.cpp -@@ -14,9 +14,11 @@ - #endif - - #include "mozilla/Char16.h" -+#include "mozilla/CmdLineAndEnvUtils.h" - #include "nsUTF8Utils.h" - #include "nsWindowsHelpers.h" - -+#include - #include - #include - -@@ -130,6 +132,20 @@ int wmain(int argc, WCHAR** argv) { - - SanitizeEnvironmentVariables(); - SetDllDirectoryW(L""); -+ bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, L"juggler-pipe", -+ static_cast(nullptr), -+ mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; -+ if (hasJugglerPipe && !mozilla::EnvHasValue("PW_PIPE_READ")) { -+ intptr_t stdio3 = _get_osfhandle(3); -+ intptr_t stdio4 = _get_osfhandle(4); -+ CHAR stdio3str[20]; -+ CHAR stdio4str[20]; -+ itoa(stdio3, stdio3str, 10); -+ itoa(stdio4, stdio4str, 10); -+ SetEnvironmentVariableA("PW_PIPE_READ", stdio3str); -+ SetEnvironmentVariableA("PW_PIPE_WRITE", stdio4str); -+ } - - // Only run this code if LauncherProcessWin.h was included beforehand, thus - // signalling that the hosting process should support launcher mode. -diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp -index 9ca3975c99c8bff3829bce1cf49d1235910c3ab8..6606eb02fba53ea8bd401d07460b85b068abd2bd 100644 ---- a/uriloader/base/nsDocLoader.cpp -+++ b/uriloader/base/nsDocLoader.cpp -@@ -827,6 +827,13 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, - ("DocLoader:%p: Firing load event for document.open\n", - this)); - -+ nsCOMPtr os = mozilla::services::GetObserverService(); -+ if (os) { -+ nsIPrincipal* principal = doc->NodePrincipal(); -+ if (!principal->IsSystemPrincipal()) -+ os->NotifyObservers(ToSupports(doc), "juggler-document-open-loaded", nullptr); -+ } -+ - // This is a very cut-down version of - // nsDocumentViewer::LoadComplete that doesn't do various things - // that are not relevant here because this wasn't an actual -diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp -index a66f215e577d29eb1db88899136ccf4eff34a960..67ea697e80608a3d5a3836b01334efe3141e70a1 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.cpp -+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -113,6 +113,7 @@ - - #include "mozilla/Components.h" - #include "mozilla/ClearOnShutdown.h" -+#include "mozilla/ErrorNames.h" - #include "mozilla/Preferences.h" - #include "mozilla/ipc/URIUtils.h" - -@@ -838,6 +839,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( - return NS_OK; - } - -+NS_IMETHODIMP nsExternalHelperAppService::SetDownloadInterceptor( -+ nsIDownloadInterceptor* interceptor) { -+ mInterceptor = interceptor; -+ return NS_OK; -+} -+ - nsresult nsExternalHelperAppService::GetFileTokenForPath( - const char16_t* aPlatformAppPath, nsIFile** aFile) { - nsDependentString platformAppPath(aPlatformAppPath); -@@ -1448,7 +1455,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { - // Strip off the ".part" from mTempLeafName - mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1); - -+ return CreateSaverForTempFile(); -+} -+ -+nsresult nsExternalAppHandler::CreateSaverForTempFile() { - MOZ_ASSERT(!mSaver, "Output file initialization called more than once!"); -+ nsresult rv; - mSaver = - do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); -@@ -1639,7 +1651,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - return NS_OK; - } - -- rv = SetUpTempFile(aChannel); -+ bool isIntercepted = false; -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCOMPtr fileToUse; -+ rv = interceptor->InterceptDownloadRequest(this, request, mBrowsingContext, getter_AddRefs(fileToUse), &isIntercepted); -+ if (!NS_SUCCEEDED(rv)) { -+ LOG((" failed to call nsIDowloadInterceptor.interceptDownloadRequest")); -+ return rv; -+ } -+ if (isIntercepted) { -+ LOG((" request interceped by nsIDowloadInterceptor")); -+ if (fileToUse) { -+ mTempFile = fileToUse; -+ rv = mTempFile->GetLeafName(mTempLeafName); -+ NS_ENSURE_SUCCESS(rv, rv); -+ } else { -+ Cancel(NS_BINDING_ABORTED); -+ return NS_OK; -+ } -+ } -+ } -+ -+ // Temp file is the final destination when download is intercepted. In that -+ // case we only need to create saver (and not create transfer later). Not creating -+ // mTransfer also cuts off all downloads handling logic in the js compoenents and -+ // browser UI. -+ if (isIntercepted) -+ rv = CreateSaverForTempFile(); -+ else -+ rv = SetUpTempFile(aChannel); - if (NS_FAILED(rv)) { - nsresult transferError = rv; - -@@ -1693,6 +1734,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { - - bool alwaysAsk = true; - mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); -+ if (isIntercepted) { -+ return NS_OK; -+ } - if (alwaysAsk) { - // But we *don't* ask if this mimeInfo didn't come from - // our user configuration datastore and the user has said -@@ -2259,6 +2303,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, - NotifyTransfer(aStatus); - } - -+ if (!mCanceled) { -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCString noError; -+ nsresult rv = interceptor->OnDownloadComplete(this, noError); -+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to call nsIDowloadInterceptor.OnDownloadComplete"); -+ Unused << rv; -+ } -+ } -+ - return NS_OK; - } - -@@ -2744,6 +2798,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { - } - } - -+ nsCOMPtr interceptor = mExtProtSvc->mInterceptor; -+ if (interceptor) { -+ nsCString errorName; -+ GetErrorName(aReason, errorName); -+ nsresult rv = interceptor->OnDownloadComplete(this, errorName); -+ MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed notify nsIDowloadInterceptor about cancel"); -+ Unused << rv; -+ } -+ - // Break our reference cycle with the helper app dialog (set up in - // OnStartRequest) - mDialog = nullptr; -diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h -index 2a1d67ffe2650d0d5f3e00bcb7f23deee8e76d0f..9e9731bc18de04fef382d0951a03793d83d14e14 100644 ---- a/uriloader/exthandler/nsExternalHelperAppService.h -+++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -244,6 +244,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, - mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, - nsIInterfaceRequestor* aWindowContext, - nsIStreamListener** aStreamListener); -+ -+ nsCOMPtr mInterceptor; - }; - - /** -@@ -446,6 +448,9 @@ class nsExternalAppHandler final : public nsIStreamListener, - * Upon successful return, both mTempFile and mSaver will be valid. - */ - nsresult SetUpTempFile(nsIChannel* aChannel); -+ -+ nsresult CreateSaverForTempFile(); -+ - /** - * When we download a helper app, we are going to retarget all load - * notifications into our own docloader and load group instead of -diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl -index 307e6196a89df52d0bccc3ebd1359f58e32de75d..c3692d0f76178ac3aeb1c77a0e973bfa22359346 100644 ---- a/uriloader/exthandler/nsIExternalHelperAppService.idl -+++ b/uriloader/exthandler/nsIExternalHelperAppService.idl -@@ -6,6 +6,8 @@ - - #include "nsICancelable.idl" - -+webidl BrowsingContext; -+interface nsIHelperAppLauncher; - interface nsIURI; - interface nsIRequest; - interface nsIStreamListener; -@@ -15,6 +17,17 @@ interface nsIWebProgressListener2; - interface nsIInterfaceRequestor; - webidl BrowsingContext; - -+/** -+ * Interceptor interface used by Juggler. -+ */ -+[scriptable, uuid(9a20e9b0-75d0-11ea-bc55-0242ac130003)] -+interface nsIDownloadInterceptor : nsISupports -+{ -+ bool interceptDownloadRequest(in nsIHelperAppLauncher aHandler, in nsIRequest aRequest, in BrowsingContext aBrowsingContext, out nsIFile file); -+ -+ void onDownloadComplete(in nsIHelperAppLauncher aHandler, in ACString aErrorName); -+}; -+ - /** - * The external helper app service is used for finding and launching - * platform specific external applications for a given mime content type. -@@ -76,6 +89,7 @@ interface nsIExternalHelperAppService : nsISupports - boolean applyDecodingForExtension(in AUTF8String aExtension, - in ACString aEncodingType); - -+ void setDownloadInterceptor(in nsIDownloadInterceptor interceptor); - }; - - /** -diff --git a/widget/InProcessCompositorWidget.cpp b/widget/InProcessCompositorWidget.cpp -index 1c25e9d9a101233f71e92288a0f93125b81ac1c5..22cf67b0f6e3ddd2b3ed725a314ba6a9896abd1c 100644 ---- a/widget/InProcessCompositorWidget.cpp -+++ b/widget/InProcessCompositorWidget.cpp -@@ -4,7 +4,10 @@ - - #include "InProcessCompositorWidget.h" - -+#include "HeadlessCompositorWidget.h" -+#include "HeadlessWidget.h" - #include "mozilla/VsyncDispatcher.h" -+#include "mozilla/widget/PlatformWidgetTypes.h" - #include "nsBaseWidget.h" - - namespace mozilla { -@@ -23,6 +26,12 @@ RefPtr CompositorWidget::CreateLocal( - // do it after the static_cast. - nsBaseWidget* widget = static_cast(aWidget); - MOZ_RELEASE_ASSERT(widget); -+ if (aInitData.type() == -+ CompositorWidgetInitData::THeadlessCompositorWidgetInitData) { -+ return new HeadlessCompositorWidget( -+ aInitData.get_HeadlessCompositorWidgetInitData(), aOptions, -+ static_cast(aWidget)); -+ } - return new InProcessCompositorWidget(aOptions, widget); - } - #endif -diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm -index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c62b016eec 100644 ---- a/widget/cocoa/NativeKeyBindings.mm -+++ b/widget/cocoa/NativeKeyBindings.mm -@@ -492,6 +492,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowLeft: - if (aEvent.IsAlt()) { -+ if (aEvent.IsMeta() || aEvent.IsControl()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ !aEvent.IsShift() -+ ? ToObjcSelectorPtr(@selector(moveWordLeft:)) -+ : ToObjcSelectorPtr(@selector(moveWordLeftAndModifySelection:)), -+ aCommands); - break; - } - if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -512,6 +519,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowRight: - if (aEvent.IsAlt()) { -+ if (aEvent.IsMeta() || aEvent.IsControl()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ !aEvent.IsShift() -+ ? ToObjcSelectorPtr(@selector(moveWordRight:)) -+ : ToObjcSelectorPtr(@selector(moveWordRightAndModifySelection:)), -+ aCommands); - break; - } - if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -532,6 +546,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowUp: - if (aEvent.IsControl()) { -+ if (aEvent.IsMeta() || aEvent.IsAlt()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ ToObjcSelectorPtr(@selector(scrollPageUp:)), aCommands); - break; - } - if (aEvent.IsMeta()) { -@@ -541,7 +559,7 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - instance->AppendEditCommandsForSelector( - !aEvent.IsShift() - ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) -- : ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)), -+ : ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)), - aCommands); - break; - } -@@ -564,6 +582,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, - break; - case KEY_NAME_INDEX_ArrowDown: - if (aEvent.IsControl()) { -+ if (aEvent.IsMeta() || aEvent.IsAlt()) -+ break; -+ instance->AppendEditCommandsForSelector( -+ ToObjcSelectorPtr(@selector(scrollPageDown:)), aCommands); - break; - } - if (aEvent.IsMeta()) { -diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6dfcbc2ab 100644 ---- a/widget/headless/HeadlessCompositorWidget.cpp -+++ b/widget/headless/HeadlessCompositorWidget.cpp -@@ -3,6 +3,7 @@ - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -+#include "mozilla/layers/CompositorThread.h" - #include "mozilla/widget/PlatformWidgetTypes.h" - #include "HeadlessCompositorWidget.h" - #include "VsyncDispatcher.h" -@@ -13,10 +14,32 @@ namespace widget { - HeadlessCompositorWidget::HeadlessCompositorWidget( - const HeadlessCompositorWidgetInitData& aInitData, - const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) -- : CompositorWidget(aOptions), mWidget(aWindow) { -+ : CompositorWidget(aOptions), mWidget(aWindow), mMon("snapshotListener") { - mClientSize = aInitData.InitialClientSize(); - } - -+void HeadlessCompositorWidget::SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener) { -+ MOZ_ASSERT(NS_IsMainThread()); -+ -+ ReentrantMonitorAutoEnter lock(mMon); -+ mSnapshotListener = std::move(listener); -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::PeriodicSnapshot", this, -+ &HeadlessCompositorWidget::PeriodicSnapshot -+ )); -+} -+ -+already_AddRefed HeadlessCompositorWidget::StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion, -+ layers::BufferMode* aBufferMode) { -+ if (!mDrawTarget) -+ return nullptr; -+ -+ *aBufferMode = layers::BufferMode::BUFFER_NONE; -+ RefPtr result = mDrawTarget; -+ return result.forget(); -+} -+ - void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - if (RefPtr cvd = - mWidget->GetCompositorVsyncDispatcher()) { -@@ -29,6 +52,59 @@ nsIWidget* HeadlessCompositorWidget::RealWidget() { return mWidget; } - void HeadlessCompositorWidget::NotifyClientSizeChanged( - const LayoutDeviceIntSize& aClientSize) { - mClientSize = aClientSize; -+ layers::CompositorThread()->Dispatch(NewRunnableMethod( -+ "HeadlessCompositorWidget::UpdateDrawTarget", this, -+ &HeadlessCompositorWidget::UpdateDrawTarget, -+ aClientSize)); -+} -+ -+void HeadlessCompositorWidget::UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize) { -+ MOZ_ASSERT(NS_IsInCompositorThread()); -+ if (aClientSize.IsEmpty()) { -+ mDrawTarget = nullptr; -+ return; -+ } -+ -+ RefPtr old = std::move(mDrawTarget); -+ gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8; -+ gfx::IntSize size = aClientSize.ToUnknownSize(); -+ mDrawTarget = mozilla::gfx::Factory::CreateDrawTarget( -+ mozilla::gfx::BackendType::SKIA, size, format); -+ if (old) { -+ RefPtr snapshot = old->Snapshot(); -+ if (snapshot) -+ mDrawTarget->CopySurface(snapshot.get(), old->GetRect(), gfx::IntPoint(0, 0)); -+ } -+} -+ -+void HeadlessCompositorWidget::PeriodicSnapshot() { -+ ReentrantMonitorAutoEnter lock(mMon); -+ if (!mSnapshotListener) -+ return; -+ -+ TakeSnapshot(); -+ NS_DelayedDispatchToCurrentThread(NewRunnableMethod( -+ "HeadlessCompositorWidget::PeriodicSnapshot", this, -+ &HeadlessCompositorWidget::PeriodicSnapshot), 40); -+} -+ -+void HeadlessCompositorWidget::TakeSnapshot() { -+ if (!mDrawTarget) -+ return; -+ -+ RefPtr snapshot = mDrawTarget->Snapshot(); -+ if (!snapshot) { -+ fprintf(stderr, "Failed to get snapshot of draw target\n"); -+ return; -+ } -+ -+ RefPtr dataSurface = snapshot->GetDataSurface(); -+ if (!dataSurface) { -+ fprintf(stderr, "Failed to get data surface from snapshot\n"); -+ return; -+ } -+ -+ mSnapshotListener(std::move(dataSurface)); - } - - LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() { -diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h -index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e65c24835 100644 ---- a/widget/headless/HeadlessCompositorWidget.h -+++ b/widget/headless/HeadlessCompositorWidget.h -@@ -6,6 +6,7 @@ - #ifndef widget_headless_HeadlessCompositorWidget_h - #define widget_headless_HeadlessCompositorWidget_h - -+#include "mozilla/ReentrantMonitor.h" - #include "mozilla/widget/CompositorWidget.h" - - #include "HeadlessWidget.h" -@@ -23,8 +24,12 @@ class HeadlessCompositorWidget final : public CompositorWidget, - HeadlessWidget* aWindow); - - void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize); -+ void SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener); - - // CompositorWidget Overrides -+ already_AddRefed StartRemoteDrawingInRegion( -+ const LayoutDeviceIntRegion& aInvalidRegion, -+ layers::BufferMode* aBufferMode) override; - - uintptr_t GetWidgetKey() override; - -@@ -42,9 +47,17 @@ class HeadlessCompositorWidget final : public CompositorWidget, - } - - private: -+ void UpdateDrawTarget(const LayoutDeviceIntSize& aClientSize); -+ void PeriodicSnapshot(); -+ void TakeSnapshot(); -+ - HeadlessWidget* mWidget; -+ mozilla::ReentrantMonitor mMon; - - LayoutDeviceIntSize mClientSize; -+ -+ HeadlessWidget::SnapshotListener mSnapshotListener; -+ RefPtr mDrawTarget; - }; - - } // namespace widget -diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index c1fbcccc93d9a6876aa82893cdf9c09b72087751..7a8073e3b746aec3a894957e87975189c06782d3 100644 ---- a/widget/headless/HeadlessWidget.cpp -+++ b/widget/headless/HeadlessWidget.cpp -@@ -109,6 +109,8 @@ void HeadlessWidget::Destroy() { - } - } - -+ SetSnapshotListener(nullptr); -+ - nsBaseWidget::OnDestroy(); - - nsBaseWidget::Destroy(); -@@ -564,5 +566,15 @@ nsresult HeadlessWidget::SynthesizeNativeTouchPadPinch( - DispatchPinchGestureInput(inputToDispatch); - return NS_OK; - } -+ -+void HeadlessWidget::SetSnapshotListener(SnapshotListener&& listener) { -+ if (!mCompositorWidget) { -+ if (listener) -+ fprintf(stderr, "Trying to set SnapshotListener without compositor widget\n"); -+ return; -+ } -+ mCompositorWidget->SetSnapshotListener(std::move(listener)); -+} -+ - } // namespace widget - } // namespace mozilla -diff --git a/widget/headless/HeadlessWidget.h b/widget/headless/HeadlessWidget.h -index 2b80eea70e58dd53c34edd9c5fa4415c42bcd632..72ecda7d8ddc7a9f87a954b547f8411e67ef1570 100644 ---- a/widget/headless/HeadlessWidget.h -+++ b/widget/headless/HeadlessWidget.h -@@ -135,6 +135,9 @@ class HeadlessWidget : public nsBaseWidget { - TouchpadGesturePhase aEventPhase, float aScale, - LayoutDeviceIntPoint aPoint, int32_t aModifierFlags) override; - -+ using SnapshotListener = std::function&&)>; -+ void SetSnapshotListener(SnapshotListener&& listener); -+ - private: - ~HeadlessWidget(); - bool mEnabled; -diff --git a/widget/windows/nsAppShell.cpp b/widget/windows/nsAppShell.cpp -index e2cf83f3d6ee0b120bb22f46aa873d3bd6436cd0..8ea269c8de520d3a9eed42f99f66ad28f5e63fbc 100644 ---- a/widget/windows/nsAppShell.cpp -+++ b/widget/windows/nsAppShell.cpp -@@ -17,7 +17,9 @@ - #include "WinIMEHandler.h" - #include "mozilla/widget/AudioSession.h" - #include "mozilla/BackgroundHangMonitor.h" --#include "mozilla/BackgroundTasks.h" -+#ifdef MOZ_BACKGROUNDTASKS -+# include "mozilla/BackgroundTasks.h" -+#endif - #include "mozilla/Hal.h" - #include "nsIDOMWakeLockListener.h" - #include "nsIPowerManagerService.h" -diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h -index 2456c2c2b58b27cd595880b547ed20fb687a1835..e967c089b2331c7cd36d34e511543fbc84320b7d 100644 ---- a/xpcom/reflect/xptinfo/xptinfo.h -+++ b/xpcom/reflect/xptinfo/xptinfo.h -@@ -514,7 +514,7 @@ static_assert(sizeof(nsXPTMethodInfo) == 8, "wrong size"); - #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) - # define PARAM_BUFFER_COUNT 18 - #else --# define PARAM_BUFFER_COUNT 14 -+# define PARAM_BUFFER_COUNT 15 - #endif - - /** diff --git a/browser_patches/firefox-beta/preferences/00-playwright-prefs.js b/browser_patches/firefox-beta/preferences/00-playwright-prefs.js deleted file mode 100644 index 1895d2d1b74c54..00000000000000 --- a/browser_patches/firefox-beta/preferences/00-playwright-prefs.js +++ /dev/null @@ -1,3 +0,0 @@ -// Any comment. You must start the file with a single-line comment! -pref("general.config.filename", "playwright.cfg"); -pref("general.config.obscure_value", 0); diff --git a/browser_patches/firefox-beta/preferences/playwright.cfg b/browser_patches/firefox-beta/preferences/playwright.cfg deleted file mode 100644 index f58a6d10d43e94..00000000000000 --- a/browser_patches/firefox-beta/preferences/playwright.cfg +++ /dev/null @@ -1,291 +0,0 @@ -// Any comment. You must start the file with a comment! - -// ================================================================= -// THESE ARE THE PROPERTIES THAT MUST BE ENABLED FOR JUGGLER TO WORK -// ================================================================= - -pref("datareporting.policy.dataSubmissionEnabled", false); -pref("datareporting.policy.dataSubmissionPolicyAccepted", false); -pref("datareporting.policy.dataSubmissionPolicyBypassNotification", true); - -// @see https://github.com/microsoft/playwright/issues/4297 -pref("browser.tabs.remote.useCrossOriginEmbedderPolicy", false); -pref("browser.tabs.remote.useCrossOriginOpenerPolicy", false); - -pref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false); - -pref("pdfjs.disabled", true); - -// Disable all kinds of cross-process navigations until we are ready. -pref("fission.autostart", false); -pref("fission.webContentIsolationStrategy", 0); -pref("fission.bfcacheInParent", false); -// Avoid about:blank loading cross-process until we are ready. -pref("browser.tabs.remote.systemTriggeredAboutBlankAnywhere", true); - -// ================================================================= -// ================================================================= - -// @see https://github.com/microsoft/playwright/issues/8178 -pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", true); - -// Use light theme by default. -pref("ui.systemUsesDarkTheme", 0); - -// Only allow the old modal dialogs. This should be removed when there is -// support for the new modal UI (see Bug 1686743). -pref("prompts.contentPromptSubDialog", false); - -// Increase max number of child web processes so that new pages -// get a new process by default and we have a process isolation -// between pages from different contexts. If this becomes a performance -// issue we can povide custom '@mozilla.org/ipc/processselector;1' -// -pref("dom.ipc.processCount", 60000); - -// Never reuse processes as they may keep previously overridden values -// (locale, timezone etc.). -pref("dom.ipc.processPrelaunch.enabled", false); - -// Do not use system colors - they are affected by themes. -pref("ui.use_standins_for_native_colors", true); - -// Isolate permissions by user context. -pref("permissions.isolateBy.userContext", true); - -pref("dom.push.serverURL", ""); -// This setting breaks settings loading. -pref("services.settings.server", ""); -pref("browser.safebrowsing.provider.mozilla.updateURL", ""); -pref("browser.library.activity-stream.enabled", false); -pref("browser.search.geoSpecificDefaults", false); -pref("browser.search.geoSpecificDefaults.url", ""); -pref("captivedetect.canonicalURL", ""); -pref("network.captive-portal-service.enabled", false); -pref("network.connectivity-service.enabled", false); -pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", ""); - -// Make sure Shield doesn't hit the network. -pref("app.normandy.api_url", ""); -pref("app.normandy.enabled", false); - -// Disable updater -pref("app.update.enabled", false); -// Disable Firefox old build background check -pref("app.update.checkInstallTime", false); -// Disable automatically upgrading Firefox -pref("app.update.disabledForTesting", true); - -// make absolutely sure it is really off -pref("app.update.auto", false); -pref("app.update.mode", 0); -pref("app.update.service.enabled", false); -// Dislabe newtabpage -pref("browser.startup.homepage", "about:blank"); -pref("browser.startup.page", 0); -pref("browser.newtabpage.enabled", false); -// Do not redirect user when a milstone upgrade of Firefox is detected -pref("browser.startup.homepage_override.mstone", "ignore"); - -pref("browser.tabs.remote.separateFileUriProcess", false); -pref("security.sandbox.content.level", 2); - -// Disable topstories -pref("browser.newtabpage.activity-stream.feeds.section.topstories", false); -// DevTools JSONViewer sometimes fails to load dependencies with its require.js. -// This doesn't affect Puppeteer operations, but spams console with a lot of -// unpleasant errors. -// (bug 1424372) -pref("devtools.jsonview.enabled", false); - -// Increase the APZ content response timeout in tests to 1 minute. -// This is to accommodate the fact that test environments tends to be -// slower than production environments (with the b2g emulator being -// the slowest of them all), resulting in the production timeout value -// sometimes being exceeded and causing false-positive test failures. -// -// (bug 1176798, bug 1177018, bug 1210465) -pref("apz.content_response_timeout", 60000); - -// Allow creating files in content process - required for -// |Page.setFileInputFiles| protocol method. -pref("dom.file.createInChild", true); - -// Indicate that the download panel has been shown once so that -// whichever download test runs first doesn't show the popup -// inconsistently. -pref("browser.download.panel.shown", true); -// Background thumbnails in particular cause grief, and disabling -// thumbnails in general cannot hurt -pref("browser.pagethumbnails.capturing_disabled", true); -// Disable safebrowsing components. -pref("browser.safebrowsing.blockedURIs.enabled", false); -pref("browser.safebrowsing.downloads.enabled", false); -pref("browser.safebrowsing.passwords.enabled", false); -pref("browser.safebrowsing.malware.enabled", false); -pref("browser.safebrowsing.phishing.enabled", false); -// Disable updates to search engines. -pref("browser.search.update", false); -// Do not restore the last open set of tabs if the browser has crashed -pref("browser.sessionstore.resume_from_crash", false); -// Don't check for the default web browser during startup. -pref("browser.shell.checkDefaultBrowser", false); - -// Disable browser animations (tabs, fullscreen, sliding alerts) -pref("toolkit.cosmeticAnimations.enabled", false); - -// Close the window when the last tab gets closed -pref("browser.tabs.closeWindowWithLastTab", true); - -// Do not allow background tabs to be zombified on Android, otherwise for -// tests that open additional tabs, the test harness tab itself might get -// unloaded -pref("browser.tabs.disableBackgroundZombification", false); - -// Do not warn when closing all open tabs -pref("browser.tabs.warnOnClose", false); - -// Do not warn when closing all other open tabs -pref("browser.tabs.warnOnCloseOtherTabs", false); - -// Do not warn when multiple tabs will be opened -pref("browser.tabs.warnOnOpen", false); - -// Disable first run splash page on Windows 10 -pref("browser.usedOnWindows10.introURL", ""); - -// Disable the UI tour. -// -// Should be set in profile. -pref("browser.uitour.enabled", false); - -// Turn off search suggestions in the location bar so as not to trigger -// network connections. -pref("browser.urlbar.suggest.searches", false); - -// Do not warn on quitting Firefox -pref("browser.warnOnQuit", false); - -// Do not show datareporting policy notifications which can -// interfere with tests -pref("datareporting.healthreport.documentServerURI", ""); -pref("datareporting.healthreport.about.reportUrl", ""); -pref("datareporting.healthreport.logging.consoleEnabled", false); -pref("datareporting.healthreport.service.enabled", false); -pref("datareporting.healthreport.service.firstRun", false); -pref("datareporting.healthreport.uploadEnabled", false); - -// Automatically unload beforeunload alerts -pref("dom.disable_beforeunload", false); - -// Disable popup-blocker -pref("dom.disable_open_during_load", false); - -// Disable the ProcessHangMonitor -pref("dom.ipc.reportProcessHangs", false); -pref("hangmonitor.timeout", 0); - -// Disable slow script dialogues -pref("dom.max_chrome_script_run_time", 0); -pref("dom.max_script_run_time", 0); - -// Only load extensions from the application and user profile -// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION -pref("extensions.autoDisableScopes", 0); -pref("extensions.enabledScopes", 5); - -// Disable metadata caching for installed add-ons by default -pref("extensions.getAddons.cache.enabled", false); - -// Disable installing any distribution extensions or add-ons. -pref("extensions.installDistroAddons", false); - -// Turn off extension updates so they do not bother tests -pref("extensions.update.enabled", false); -pref("extensions.update.notifyUser", false); - -// Make sure opening about:addons will not hit the network -pref("extensions.webservice.discoverURL", ""); - -pref("extensions.screenshots.disabled", true); -pref("extensions.screenshots.upload-disabled", true); - -// Allow the application to have focus even it runs in the background -pref("focusmanager.testmode", true); - -// Disable useragent updates -pref("general.useragent.updates.enabled", false); - -// No ICC color correction. -// See https://developer.mozilla.org/en/docs/Mozilla/Firefox/Releases/3.5/ICC_color_correction_in_Firefox. -pref("gfx.color_management.mode", 0); -pref("gfx.color_management.rendering_intent", 3); - -// Always use network provider for geolocation tests so we bypass the -// macOS dialog raised by the corelocation provider -pref("geo.provider.testing", true); - -// Do not scan Wifi -pref("geo.wifi.scan", false); - -// Show chrome errors and warnings in the error console -pref("javascript.options.showInConsole", true); - -// Disable download and usage of OpenH264: and Widevine plugins -pref("media.gmp-manager.updateEnabled", false); - -// Do not prompt with long usernames or passwords in URLs -pref("network.http.phishy-userpass-length", 255); - -// Do not prompt for temporary redirects -pref("network.http.prompt-temp-redirect", false); - -// Disable speculative connections so they are not reported as leaking -// when they are hanging around -pref("network.http.speculative-parallel-limit", 0); - -// Do not automatically switch between offline and online -pref("network.manage-offline-status", false); - -// Make sure SNTP requests do not hit the network -pref("network.sntp.pools", ""); - -// Disable Flash -pref("plugin.state.flash", 0); - -pref("privacy.trackingprotection.enabled", false); - -pref("security.certerrors.mitm.priming.enabled", false); - -// Local documents have access to all other local documents, -// including directory listings -pref("security.fileuri.strict_origin_policy", false); - -// Tests do not wait for the notification button security delay -pref("security.notification_enable_delay", 0); - -// Do not automatically fill sign-in forms with known usernames and -// passwords -pref("signon.autofillForms", false); - -// Disable password capture, so that tests that include forms are not -// influenced by the presence of the persistent doorhanger notification -pref("signon.rememberSignons", false); - -// Disable first-run welcome page -pref("startup.homepage_welcome_url", "about:blank"); -pref("startup.homepage_welcome_url.additional", ""); - -// Prevent starting into safe mode after application crashes -pref("toolkit.startup.max_resumed_crashes", -1); -lockPref("toolkit.crashreporter.enabled", false); - -pref("toolkit.telemetry.enabled", false); -pref("toolkit.telemetry.server", ""); - -// Disable downloading the list of blocked extensions. -pref("extensions.blocklist.enabled", false); - -// Force Firefox Devtools to open in a separate window. -pref("devtools.toolbox.host", "window"); - diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER deleted file mode 100644 index 167b11029d32f1..00000000000000 --- a/browser_patches/firefox/BUILD_NUMBER +++ /dev/null @@ -1,2 +0,0 @@ -1345 -Changed: aslushnikov@gmail.com Sat Aug 13 14:45:35 MSK 2022 diff --git a/browser_patches/firefox/EXPECTED_BUILDS b/browser_patches/firefox/EXPECTED_BUILDS deleted file mode 100644 index d2bf4c2ace24d8..00000000000000 --- a/browser_patches/firefox/EXPECTED_BUILDS +++ /dev/null @@ -1,9 +0,0 @@ -firefox-mac-11.zip -firefox-mac-11-arm64.zip -firefox-ubuntu-18.04.zip -firefox-ubuntu-20.04.zip -firefox-ubuntu-20.04-arm64.zip -firefox-ubuntu-22.04.zip -firefox-ubuntu-22.04-arm64.zip -firefox-debian-11.zip -firefox-win64.zip diff --git a/browser_patches/firefox/UPSTREAM_CONFIG.sh b/browser_patches/firefox/UPSTREAM_CONFIG.sh index 37f825fa642181..d68e6b9ec00ce5 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/gecko-dev" BASE_BRANCH="release" -BASE_REVISION="f532fa26bc150add9f8ba42e5fbfdbeffa23662f" +BASE_REVISION="7177c1fee2d0ae258241aa9f0f332aae8daf87e7" diff --git a/browser_patches/firefox/archive.sh b/browser_patches/firefox/archive.sh deleted file mode 100755 index 1c34d8fb06e040..00000000000000 --- a/browser_patches/firefox/archive.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -set -e -set +x - -if [[ ("$1" == "-h") || ("$1" == "--help") ]]; then - echo "usage: $(basename "$0") [output-absolute-path]" - echo - echo "Generate distributable .zip archive from Firefox checkout folder that was previously built." - echo - exit 0 -fi - -ZIP_PATH=$1 -if [[ $ZIP_PATH != /* ]]; then - echo "ERROR: path $ZIP_PATH is not absolute" - exit 1 -fi -if [[ $ZIP_PATH != *.zip ]]; then - echo "ERROR: path $ZIP_PATH must have .zip extension" - exit 1 -fi -if [[ -f $ZIP_PATH ]]; then - echo "ERROR: path $ZIP_PATH exists; can't do anything." - exit 1 -fi -if ! [[ -d $(dirname "$ZIP_PATH") ]]; then - echo "ERROR: folder for path $($ZIP_PATH) does not exist." - exit 1 -fi - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FF_CHECKOUT_PATH="$HOME/firefox" -fi -OBJ_FOLDER="${FF_CHECKOUT_PATH}/obj-build-playwright" - -cd "${FF_CHECKOUT_PATH}" - -export MH_BRANCH=mozilla-release -export MOZ_BUILD_DATE=$(date +%Y%m%d%H%M%S) -./mach package -node "${SCRIPT_FOLDER}/install-preferences.js" "${OBJ_FOLDER}/dist/firefox" - -if ! [[ -d "$OBJ_FOLDER/dist/firefox" ]]; then - echo "ERROR: cannot find $OBJ_FOLDER/dist/firefox folder in the firefox checkout. Did you build?" - exit 1; -fi - -if is_win; then - # Bundle vcruntime14_1.dll - see https://github.com/microsoft/playwright/issues/9974 - cd "$(printMSVCRedistDir)" - cp -t "${OBJ_FOLDER}/dist/firefox" vcruntime140_1.dll -fi - -# tar resulting directory and cleanup TMP. -cd "${OBJ_FOLDER}/dist" -zip -r "$ZIP_PATH" firefox diff --git a/browser_patches/firefox/build.sh b/browser_patches/firefox/build.sh deleted file mode 100755 index 4f2e8c1b54917c..00000000000000 --- a/browser_patches/firefox/build.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash -set -e -set +x - -RUST_VERSION="1.59.0" -CBINDGEN_VERSION="0.24.3" - -trap "cd $(pwd -P)" EXIT - -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -args=("$@") -IS_FULL="" -IS_JUGGLER="" -IS_DEBUG="" -for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --full) IS_FULL="1"; unset args[i]; ;; - --juggler) IS_JUGGLER="1"; unset args[i]; ;; - --debug) IS_DEBUG="1"; unset args[i]; ;; - esac -done - -if [[ -n "${IS_JUGGLER}" && -n "${IS_FULL}" ]]; then - echo "ERROR: either --full or --juggler is allowed" - exit 1 -fi - -echo "== BUILD CONFIGURATION ==" -if [[ -n "${IS_FULL}" ]]; then - echo "- build type: FULL" -elif [[ -n "${IS_JUGGLER}" ]]; then - echo "- build type: JUGGLER" -else - echo "- build type: INCREMENTAL" -fi - -if [[ -n "${IS_DEBUG}" ]]; then - echo "- debug: YES" -else - echo "- debug: NO" -fi - -echo "=========================" - -rm -rf .mozconfig - -if is_mac; then - selectXcodeVersionOrDie $(node "${SCRIPT_FOLDER}/../get_xcode_version.js" firefox) - echo "-- building on Mac" -elif is_linux; then - echo "-- building on Linux" -elif is_win; then - echo "ac_add_options --disable-update-agent" >> .mozconfig - echo "ac_add_options --disable-default-browser-agent" >> .mozconfig - echo "ac_add_options --disable-maintenance-service" >> .mozconfig - - echo "-- building win64 build on MINGW" - echo "ac_add_options --target=x86_64-pc-mingw32" >> .mozconfig - echo "ac_add_options --host=x86_64-pc-mingw32" >> .mozconfig - DLL_FILE=$("C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -find '**\Redist\MSVC\*\x64\**\vcruntime140.dll') - WIN32_REDIST_DIR=$(dirname "$DLL_FILE" | tail -n 1) - if ! [[ -d $WIN32_REDIST_DIR ]]; then - echo "ERROR: cannot find MS VS C++ redistributable $WIN32_REDIST_DIR" - exit 1; - fi -else - echo "ERROR: cannot upload on this platform!" 1>&2 - exit 1; -fi - -# There's no pre-built wasi sysroot on certain platforms. -echo "ac_add_options --without-wasm-sandboxed-libraries" >> .mozconfig - -OBJ_FOLDER="obj-build-playwright" -echo "mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/${OBJ_FOLDER}" >> .mozconfig -echo "ac_add_options --disable-crashreporter" >> .mozconfig -echo "ac_add_options --disable-backgroundtasks" >> .mozconfig - -if [[ -n "${IS_DEBUG}" ]]; then - echo "ac_add_options --enable-debug" >> .mozconfig - echo "ac_add_options --enable-debug-symbols" >> .mozconfig -else - echo "ac_add_options --enable-release" >> .mozconfig -fi - -if is_mac || is_win; then - # This options is only available on win and mac. - echo "ac_add_options --disable-update-agent" >> .mozconfig -fi - -if [[ -z "${IS_JUGGLER}" ]]; then - # TODO: rustup is not in the PATH on Windows - if command -v rustup >/dev/null; then - # We manage Rust version ourselves. - echo "-- Using rust v${RUST_VERSION}" - rustup install "${RUST_VERSION}" - rustup default "${RUST_VERSION}" - fi - # Firefox on Linux arm64 host does not ship - # cbindgen in their default toolchains - install manually. - if command -v cargo >/dev/null; then - echo "-- Using cbindgen v${CBINDGEN_VERSION}" - cargo install cbindgen --version "${CBINDGEN_VERSION}" - fi -fi - -if [[ -n "${IS_FULL}" ]]; then - # This is a slow but sure way to get all the necessary toolchains. - # However, it will not work if tree is dirty. - # Bail out if git repo is dirty. - if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: dirty GIT state - commit everything and re-run the script." - exit 1 - fi - - # 1. We have a --single-branch checkout, so we have to add a "master" branch and fetch it - git remote set-branches --add browser_upstream master - git fetch --depth 1 browser_upstream master - # 2. Checkout the master branch and run bootstrap from it. - git checkout browser_upstream/master - echo "ac_add_options --enable-bootstrap" >> .mozconfig - SHELL=/bin/sh ./mach --no-interactive bootstrap --application-choice=browser - git checkout - - rm -rf "${OBJ_FOLDER}" - - if [[ -n "${WIN32_REDIST_DIR}" ]]; then - # Having this option in .mozconfig kills incremental compilation. - echo "export WIN32_REDIST_DIR=\"$WIN32_REDIST_DIR\"" >> .mozconfig - fi -fi - -if [[ -n "${IS_JUGGLER}" ]]; then - ./mach build faster -else - ./mach build - if is_mac; then - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist - else - FF_DEBUG_BUILD="${IS_DEBUG}" node "${SCRIPT_FOLDER}"/install-preferences.js "$PWD"/${OBJ_FOLDER}/dist/bin - fi -fi - - diff --git a/browser_patches/firefox/clean.sh b/browser_patches/firefox/clean.sh deleted file mode 100755 index d94baf33a30d9d..00000000000000 --- a/browser_patches/firefox/clean.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -if [[ ! -z "${FF_CHECKOUT_PATH}" ]]; then - cd "${FF_CHECKOUT_PATH}" - echo "WARNING: checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" -else - cd "$HOME/firefox" -fi - -OBJ_FOLDER="obj-build-playwright" -if [[ -d $OBJ_FOLDER ]]; then - rm -rf $OBJ_FOLDER -fi - -if [[ -f "mach" ]]; then - ./mach clobber || true -fi diff --git a/browser_patches/firefox/install-preferences.js b/browser_patches/firefox/install-preferences.js deleted file mode 100644 index f82f791d54c053..00000000000000 --- a/browser_patches/firefox/install-preferences.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright 2018 Google Inc. All rights reserved. - * Modifications copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const os = require('os'); -const fs = require('fs'); -const path = require('path'); -const util = require('util'); - -const writeFileAsync = util.promisify(fs.writeFile.bind(fs)); -const mkdirAsync = util.promisify(fs.mkdir.bind(fs)); - -// Install browser preferences after downloading and unpacking -// firefox instances. -// Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Enterprise_deployment_before_60#Configuration -async function installFirefoxPreferences(distpath) { - let executablePath = ''; - if (os.platform() === 'linux') - executablePath = path.join(distpath, 'firefox'); - else if (os.platform() === 'darwin') - executablePath = path.join(distpath, (process.env.FF_DEBUG_BUILD ? 'NightlyDebug.app' : 'Nightly.app'), 'Contents', 'MacOS', 'firefox'); - else if (os.platform() === 'win32') - executablePath = path.join(distpath, 'firefox.exe'); - - const firefoxFolder = path.dirname(executablePath); - - let prefPath = ''; - let configPath = ''; - if (os.platform() === 'darwin') { - prefPath = path.join(firefoxFolder, '..', 'Resources', 'defaults', 'pref'); - configPath = path.join(firefoxFolder, '..', 'Resources'); - } else if (os.platform() === 'linux') { - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults')); - if (!fs.existsSync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences'))) - await mkdirAsync(path.join(firefoxFolder, 'browser', 'defaults', 'preferences')); - prefPath = path.join(firefoxFolder, 'browser', 'defaults', 'preferences'); - configPath = firefoxFolder; - } else if (os.platform() === 'win32') { - prefPath = path.join(firefoxFolder, 'defaults', 'pref'); - configPath = firefoxFolder; - } else { - throw new Error('Unsupported platform: ' + os.platform()); - } - - await Promise.all([ - copyFile({ - from: path.join(__dirname, 'preferences', '00-playwright-prefs.js'), - to: path.join(prefPath, '00-playwright-prefs.js'), - }), - copyFile({ - from: path.join(__dirname, 'preferences', 'playwright.cfg'), - to: path.join(configPath, 'playwright.cfg'), - }), - ]); -} - -function copyFile({from, to}) { - const rd = fs.createReadStream(from); - const wr = fs.createWriteStream(to); - return new Promise(function(resolve, reject) { - rd.on('error', reject); - wr.on('error', reject); - wr.on('finish', resolve); - rd.pipe(wr); - }).catch(function(error) { - rd.destroy(); - wr.end(); - throw error; - }); -} - -module.exports = { installFirefoxPreferences }; - -if (require.main === module) { - if (process.argv.length !== 3) { - console.log('ERROR: expected a path to the directory with browser build'); - process.exit(1); - return; - } - - installFirefoxPreferences(process.argv[2]).catch(error => { - console.error('ERROR: failed to put preferences!'); - console.error(error); - process.exit(1); - }); -} diff --git a/browser_patches/firefox/juggler/Helper.js b/browser_patches/firefox/juggler/Helper.js index 70d8aef0d37c43..797acd4627cadc 100644 --- a/browser_patches/firefox/juggler/Helper.js +++ b/browser_patches/firefox/juggler/Helper.js @@ -6,6 +6,27 @@ const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerat const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); class Helper { + decorateAsEventEmitter(objectToDecorate) { + const { EventEmitter } = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); + const emitter = new EventEmitter(); + objectToDecorate.on = emitter.on.bind(emitter); + objectToDecorate.addEventListener = emitter.on.bind(emitter); + objectToDecorate.off = emitter.off.bind(emitter); + objectToDecorate.removeEventListener = emitter.off.bind(emitter); + objectToDecorate.once = emitter.once.bind(emitter); + objectToDecorate.emit = emitter.emit.bind(emitter); + } + + collectAllBrowsingContexts(rootBrowsingContext, allBrowsingContexts = []) { + allBrowsingContexts.push(rootBrowsingContext); + for (const child of rootBrowsingContext.children) + this.collectAllBrowsingContexts(child, allBrowsingContexts); + return allBrowsingContexts; + } + + toProtocolNavigationId(loadIdentifier) { + return `nav-${loadIdentifier}`; + } addObserver(handler, topic) { Services.obs.addObserver(handler, topic); @@ -17,9 +38,17 @@ class Helper { return () => receiver.removeMessageListener(eventName, handler); } - addEventListener(receiver, eventName, handler) { - receiver.addEventListener(eventName, handler); - return () => receiver.removeEventListener(eventName, handler); + addEventListener(receiver, eventName, handler, options) { + receiver.addEventListener(eventName, handler, options); + return () => { + try { + receiver.removeEventListener(eventName, handler, options); + } catch (e) { + // This could fail when window has navigated cross-process + // and we remove the listener from WindowProxy. + // Nothing we can do here - so ignore the error. + } + }; } awaitEvent(receiver, eventName) { @@ -31,11 +60,11 @@ class Helper { }); } - on(receiver, eventName, handler) { + on(receiver, eventName, handler, options) { // The toolkit/modules/EventEmitter.jsm dispatches event name as a first argument. // Fire event listeners without it for convenience. const handlerWrapper = (_, ...args) => handler(...args); - receiver.on(eventName, handlerWrapper); + receiver.on(eventName, handlerWrapper, options); return () => receiver.off(eventName, handlerWrapper); } @@ -126,10 +155,76 @@ class Helper { browsingContextToFrameId(browsingContext) { if (!browsingContext) return undefined; - return 'frame-' + browsingContext.id; + if (!browsingContext.parent) + return 'mainframe-' + browsingContext.browserId; + return 'subframe-' + browsingContext.id; + } +} + +const helper = new Helper(); + +class EventWatcher { + constructor(receiver, eventNames, pendingEventWatchers = new Set()) { + this._pendingEventWatchers = pendingEventWatchers; + this._pendingEventWatchers.add(this); + + this._events = []; + this._pendingPromises = []; + this._eventListeners = eventNames.map(eventName => + helper.on(receiver, eventName, this._onEvent.bind(this, eventName)), + ); + } + + _onEvent(eventName, eventObject) { + this._events.push({eventName, eventObject}); + for (const promise of this._pendingPromises) + promise.resolve(); + this._pendingPromises = []; + } + + async ensureEvent(aEventName, predicate) { + if (typeof aEventName !== 'string') + throw new Error('ERROR: ensureEvent expects a "string" as its first argument'); + while (true) { + const result = this.getEvent(aEventName, predicate); + if (result) + return result; + await new Promise((resolve, reject) => this._pendingPromises.push({resolve, reject})); + } + } + + async ensureEvents(eventNames, predicate) { + if (!Array.isArray(eventNames)) + throw new Error('ERROR: ensureEvents expects an array of event names as its first argument'); + return await Promise.all(eventNames.map(eventName => this.ensureEvent(eventName, predicate))); + } + + async ensureEventsAndDispose(eventNames, predicate) { + if (!Array.isArray(eventNames)) + throw new Error('ERROR: ensureEventsAndDispose expects an array of event names as its first argument'); + const result = await this.ensureEvents(eventNames, predicate); + this.dispose(); + return result; + } + + getEvent(aEventName, predicate = (eventObject) => true) { + return this._events.find(({eventName, eventObject}) => eventName === aEventName && predicate(eventObject))?.eventObject; + } + + hasEvent(aEventName, predicate) { + return !!this.getEvent(aEventName, predicate); + } + + dispose() { + this._pendingEventWatchers.delete(this); + for (const promise of this._pendingPromises) + promise.reject(new Error('EventWatcher is being disposed')); + this._pendingPromises = []; + helper.removeListeners(this._eventListeners); } } -var EXPORTED_SYMBOLS = [ "Helper" ]; +var EXPORTED_SYMBOLS = [ "Helper", "EventWatcher" ]; this.Helper = Helper; +this.EventWatcher = EventWatcher; diff --git a/browser_patches/firefox/juggler/JugglerFrameParent.jsm b/browser_patches/firefox/juggler/JugglerFrameParent.jsm new file mode 100644 index 00000000000000..e621fab2406807 --- /dev/null +++ b/browser_patches/firefox/juggler/JugglerFrameParent.jsm @@ -0,0 +1,42 @@ +"use strict"; + +const { TargetRegistry } = ChromeUtils.import('chrome://juggler/content/TargetRegistry.js'); +const { Helper } = ChromeUtils.import('chrome://juggler/content/Helper.js'); + +const helper = new Helper(); + +var EXPORTED_SYMBOLS = ['JugglerFrameParent']; + +class JugglerFrameParent extends JSWindowActorParent { + constructor() { + super(); + } + + receiveMessage() { } + + async actorCreated() { + // Actors are registered per the WindowGlobalParent / WindowGlobalChild pair. We are only + // interested in those WindowGlobalParent actors that are matching current browsingContext + // window global. + // See https://github.com/mozilla/gecko-dev/blob/cd2121e7d83af1b421c95e8c923db70e692dab5f/testing/mochitest/BrowserTestUtils/BrowserTestUtilsParent.sys.mjs#L15 + 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); + } + + didDestroy() { + if (!this._target) + return; + this._target.removeActor(this); + } +} diff --git a/browser_patches/firefox/juggler/NetworkObserver.js b/browser_patches/firefox/juggler/NetworkObserver.js index 340f756f6cfef0..26791c5e56618d 100644 --- a/browser_patches/firefox/juggler/NetworkObserver.js +++ b/browser_patches/firefox/juggler/NetworkObserver.js @@ -4,7 +4,6 @@ "use strict"; -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); @@ -41,7 +40,7 @@ class PageNetwork { } constructor(target) { - EventEmitter.decorate(this); + helper.decorateAsEventEmitter(this); this._target = target; this._extraHTTPHeaders = null; this._responseStorage = new ResponseStorage(MAX_RESPONSE_STORAGE_SIZE, MAX_RESPONSE_STORAGE_SIZE / 10); @@ -120,7 +119,7 @@ class NetworkRequest { this._frameId = helper.browsingContextToFrameId(browsingContext); this.requestId = httpChannel.channelId + ''; - this.navigationId = httpChannel.isMainDocumentChannel ? this.requestId : undefined; + this.navigationId = httpChannel.isMainDocumentChannel ? helper.toProtocolNavigationId(browsingContext.jugglerCurrentLoadIdentifier) : undefined; this._redirectedIndex = 0; if (redirectedFrom) { @@ -217,8 +216,9 @@ class NetworkRequest { _onInternalRedirect(newChannel) { // Intercepted requests produce "internal redirects" - this is both for our own // interception and service workers. - // An internal redirect has the same channelId, inherits notificationCallbacks and - // listener, and should be used instead of an old channel. + // An internal redirect does not necessarily have the same channelId, + // but inherits notificationCallbacks and the listener, + // and should be used instead of an old channel. this._networkObserver._channelToRequest.delete(this.httpChannel); this.httpChannel = newChannel; this._networkObserver._channelToRequest.set(this.httpChannel, this); @@ -300,6 +300,9 @@ class NetworkRequest { } if (!credentials) return false; + const origin = aChannel.URI.scheme + '://' + aChannel.URI.hostPort; + if (credentials.origin && origin.toLowerCase() !== credentials.origin.toLowerCase()) + return false; authInfo.username = credentials.username; authInfo.password = credentials.password; // This will produce a new request with respective auth header set. @@ -363,7 +366,7 @@ class NetworkRequest { } const browserContext = pageNetwork._target.browserContext(); - if (browserContext.settings.onlineOverride === 'offline') { + if (browserContext.crossProcessCookie.settings.onlineOverride === 'offline') { // Implement offline. this.abort(Cr.NS_ERROR_OFFLINE); return; @@ -458,15 +461,17 @@ class NetworkRequest { const browserContext = pageNetwork._target.browserContext(); if (browserContext.requestInterceptionEnabled) return true; - if (browserContext.settings.onlineOverride === 'offline') + if (browserContext.crossProcessCookie.settings.onlineOverride === 'offline') return true; return false; } _fallThroughInterceptController() { - if (!this._previousCallbacks || !(this._previousCallbacks instanceof Ci.nsINetworkInterceptController)) + try { + return this._previousCallbacks?.getInterface(Ci.nsINetworkInterceptController); + } catch (e) { return undefined; - return this._previousCallbacks.getInterface(Ci.nsINetworkInterceptController); + } } _sendOnRequest(isIntercepted) { @@ -581,7 +586,7 @@ class NetworkObserver { } constructor(targetRegistry) { - EventEmitter.decorate(this); + helper.decorateAsEventEmitter(this); NetworkObserver._instance = this; this._targetRegistry = targetRegistry; @@ -863,7 +868,7 @@ function setPostData(httpChannel, postData, headers) { const body = atob(postData); synthesized.setData(body, body.length); - const overriddenHeader = (lowerCaseName, defaultValue) => { + const overriddenHeader = (lowerCaseName) => { if (headers) { for (const header of headers) { if (header.name.toLowerCase() === lowerCaseName) { @@ -871,11 +876,22 @@ function setPostData(httpChannel, postData, headers) { } } } - return defaultValue; + return undefined; } // Clear content-length, so that upload stream resets it. httpChannel.setRequestHeader('content-length', '', false /* merge */); - httpChannel.explicitSetUploadStream(synthesized, overriddenHeader('content-type', 'application/octet-stream'), -1, httpChannel.requestMethod, false); + let contentType = overriddenHeader('content-type'); + if (contentType === undefined) { + try { + contentType = httpChannel.getRequestHeader('content-type'); + } catch (e) { + if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) + contentType = 'application/octet-stream'; + else + throw e; + } + } + httpChannel.explicitSetUploadStream(synthesized, contentType, -1, httpChannel.requestMethod, false); } function convertString(s, source, dest) { diff --git a/browser_patches/firefox/juggler/SimpleChannel.js b/browser_patches/firefox/juggler/SimpleChannel.js index 59b29532ab1fd2..9abe2146fc7a15 100644 --- a/browser_patches/firefox/juggler/SimpleChannel.js +++ b/browser_patches/firefox/juggler/SimpleChannel.js @@ -9,6 +9,12 @@ const SIMPLE_CHANNEL_MESSAGE_NAME = 'juggler:simplechannel'; class SimpleChannel { + static createForActor(actor) { + const channel = new SimpleChannel(''); + channel.bindToActor(actor); + return channel; + } + static createForMessageManager(name, mm) { const channel = new SimpleChannel(name); @@ -32,15 +38,35 @@ class SimpleChannel { this._pendingMessages = new Map(); this._handlers = new Map(); this._bufferedIncomingMessages = []; - this._bufferedOutgoingMessages = []; this.transport = { sendMessage: null, - dispose: null, + dispose: () => {}, }; this._ready = false; + this._paused = false; this._disposed = false; } + bindToActor(actor) { + this.resetTransport(); + this._name = actor.actorName; + const oldReceiveMessage = actor.receiveMessage; + actor.receiveMessage = message => this._onMessage(message.data); + this.setTransport({ + sendMessage: obj => actor.sendAsyncMessage(SIMPLE_CHANNEL_MESSAGE_NAME, obj), + dispose: () => actor.receiveMessage = oldReceiveMessage, + }); + } + + resetTransport() { + this.transport.dispose(); + this.transport = { + sendMessage: null, + dispose: () => {}, + }; + this._ready = false; + } + setTransport(transport) { this.transport = transport; // connection handshake: @@ -55,13 +81,29 @@ class SimpleChannel { this.transport.sendMessage('READY'); } + pause() { + this._paused = true; + } + + resumeSoon() { + if (!this._paused) + return; + this._paused = false; + this._setTimeout(() => this._deliverBufferedIncomingMessages(), 0); + } + + _setTimeout(cb, timeout) { + // Lazy load on first call. + this._setTimeout = ChromeUtils.import('resource://gre/modules/Timer.jsm').setTimeout; + this._setTimeout(cb, timeout); + } + _markAsReady() { if (this._ready) return; this._ready = true; - for (const msg of this._bufferedOutgoingMessages) - this.transport.sendMessage(msg); - this._bufferedOutgoingMessages = []; + for (const { message } of this._pendingMessages.values()) + this.transport.sendMessage(message); } dispose() { @@ -97,13 +139,16 @@ class SimpleChannel { if (this._handlers.has(namespace)) throw new Error('ERROR: double-register for namespace ' + namespace); this._handlers.set(namespace, handler); - // Try to re-deliver all pending messages. + this._deliverBufferedIncomingMessages(); + return () => this.unregister(namespace); + } + + _deliverBufferedIncomingMessages() { const bufferedRequests = this._bufferedIncomingMessages; this._bufferedIncomingMessages = []; for (const data of bufferedRequests) { this._onMessage(data); } - return () => this.unregister(namespace); } unregister(namespace) { @@ -121,18 +166,16 @@ class SimpleChannel { if (this._disposed) throw new Error(`ERROR: channel ${this._name} is already disposed! Cannot send "${methodName}" to "${namespace}"`); const id = ++this._messageId; + const message = {requestId: id, methodName, params, namespace}; const promise = new Promise((resolve, reject) => { - this._pendingMessages.set(id, {connectorId, resolve, reject, methodName, namespace}); + this._pendingMessages.set(id, {connectorId, resolve, reject, methodName, namespace, message}); }); - const message = {requestId: id, methodName, params, namespace}; if (this._ready) this.transport.sendMessage(message); - else - this._bufferedOutgoingMessages.push(message); return promise; } - async _onMessage(data) { + _onMessage(data) { if (data === 'READY') { this.transport.sendMessage('READY_ACK'); this._markAsReady(); @@ -142,13 +185,27 @@ class SimpleChannel { this._markAsReady(); return; } + if (this._paused) + this._bufferedIncomingMessages.push(data); + else + this._onMessageInternal(data); + } + + async _onMessageInternal(data) { if (data.responseId) { - const {resolve, reject} = this._pendingMessages.get(data.responseId); + const message = this._pendingMessages.get(data.responseId); + if (!message) { + // During corss-process navigation, we might receive a response for + // the message sent by another process. + // TODO: consider events that are marked as "no-response" to avoid + // unneeded responses altogether. + return; + } this._pendingMessages.delete(data.responseId); if (data.error) - reject(new Error(data.error)); + message.reject(new Error(data.error)); else - resolve(data.result); + message.resolve(data.result); } else if (data.requestId) { const namespace = data.namespace; const handler = this._handlers.get(namespace); @@ -169,9 +226,7 @@ class SimpleChannel { return; } } else { - dump(` - ERROR: unknown message in channel "${this._name}": ${JSON.stringify(data)} - `); + dump(`WARNING: unknown message in channel "${this._name}": ${JSON.stringify(data)}\n`); } } } diff --git a/browser_patches/firefox/juggler/TargetRegistry.js b/browser_patches/firefox/juggler/TargetRegistry.js index b222ba98bba847..c739c0d306409b 100644 --- a/browser_patches/firefox/juggler/TargetRegistry.js +++ b/browser_patches/firefox/juggler/TargetRegistry.js @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); @@ -38,7 +37,7 @@ class DownloadInterceptor { if (!(request instanceof Ci.nsIChannel)) return false; const channel = request.QueryInterface(Ci.nsIChannel); - let pageTarget = this._registry._browserBrowsingContextToTarget.get(channel.loadInfo.browsingContext.top); + let pageTarget = this._registry._browserIdToTarget.get(channel.loadInfo.browsingContext.top.browserId); if (!pageTarget) return false; @@ -57,7 +56,7 @@ class DownloadInterceptor { try { file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); } catch (e) { - dump(`interceptDownloadRequest failed to create file: ${e}\n`); + dump(`WARNING: interceptDownloadRequest failed to create file: ${e}\n`); return false; } } @@ -68,6 +67,7 @@ class DownloadInterceptor { uuid, browserContextId: browserContext.browserContextId, pageTargetId: pageTarget.id(), + frameId: helper.browsingContextToFrameId(channel.loadInfo.browsingContext), url: request.name, suggestedFileName: externalAppHandler.suggestedFileName, }; @@ -103,13 +103,18 @@ class DownloadInterceptor { const screencastService = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); class TargetRegistry { + static instance() { + return TargetRegistry._instance || null; + } + constructor() { - EventEmitter.decorate(this); + helper.decorateAsEventEmitter(this); + TargetRegistry._instance = this; this._browserContextIdToBrowserContext = new Map(); this._userContextIdToBrowserContext = new Map(); this._browserToTarget = new Map(); - this._browserBrowsingContextToTarget = new Map(); + this._browserIdToTarget = new Map(); this._browserProxy = null; @@ -136,21 +141,6 @@ class TargetRegistry { } }, 'oop-frameloader-crashed'); - Services.mm.addMessageListener('juggler:content-ready', { - receiveMessage: message => { - const linkedBrowser = message.target; - const target = this._browserToTarget.get(linkedBrowser); - if (!target) - return; - - return { - initScripts: target.browserContext().initScripts, - bindings: target.browserContext().bindings, - settings: target.browserContext().settings, - }; - }, - }); - const onTabOpenListener = (appWindow, window, event) => { const tab = event.target; const userContextId = tab.userContextId; @@ -161,7 +151,7 @@ class TargetRegistry { if (openerContext) { // Popups usually have opener context. Get top context for the case when opener is // an iframe. - openerTarget = this._browserBrowsingContextToTarget.get(openerContext.top); + openerTarget = this._browserIdToTarget.get(openerContext.top.browserId); } else if (tab.openerTab) { // Noopener popups from the same window have opener tab instead. openerTarget = this._browserToTarget.get(tab.openerTab.linkedBrowser); @@ -169,13 +159,7 @@ class TargetRegistry { if (!browserContext) throw new Error(`Internal error: cannot find context for userContextId=${userContextId}`); const target = new PageTarget(this, window, tab, browserContext, openerTarget); - target.updateUserAgent(); - target.updatePlatform(); - target.updateJavaScriptDisabled(); - target.updateTouchOverride(); - target.updateColorSchemeOverride(); - target.updateReducedMotionOverride(); - target.updateForcedColorsOverride(); + target.updateOverridesForBrowsingContext(tab.linkedBrowser.browsingContext); if (!hasExplicitSize) target.updateViewportSize(); if (browserContext.videoRecordingOptions) @@ -329,7 +313,7 @@ class TargetRegistry { target = this._browserToTarget.get(browser); } browser.focus(); - if (browserContext.settings.timezoneId) { + if (browserContext.crossProcessCookie.settings.timezoneId) { if (await target.hasFailedToOverrideTimezone()) throw new Error('Failed to override timezone'); } @@ -343,11 +327,15 @@ class TargetRegistry { targetForBrowser(browser) { return this._browserToTarget.get(browser); } + + targetForBrowserId(browserId) { + return this._browserIdToTarget.get(browserId); + } } class PageTarget { constructor(registry, win, tab, browserContext, opener) { - EventEmitter.decorate(this); + helper.decorateAsEventEmitter(this); this._targetId = helper.generateId(); this._registry = registry; @@ -360,12 +348,19 @@ class PageTarget { this._initialDPPX = this._linkedBrowser.browsingContext.overrideDPPX; this._url = 'about:blank'; this._openerId = opener ? opener.id() : undefined; - this._channel = SimpleChannel.createForMessageManager(`browser::page[${this._targetId}]`, this._linkedBrowser.messageManager); + this._actor = undefined; + this._actorSequenceNumber = 0; + this._channel = new SimpleChannel(`browser::page[${this._targetId}]`); this._videoRecordingInfo = undefined; this._screencastRecordingInfo = undefined; this._dialogs = new Map(); this.forcedColors = 'no-override'; - this._pageInitScripts = []; + this.mediumOverride = ''; + this.crossProcessCookie = { + initScripts: [], + bindings: [], + interceptFileChooserDialog: false, + }; const navigationListener = { QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), @@ -375,16 +370,61 @@ class PageTarget { helper.addObserver(this._updateModalDialogs.bind(this), 'tabmodal-dialog-loaded'), helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION), helper.addEventListener(this._linkedBrowser, 'DOMModalDialogClosed', event => this._updateModalDialogs()), + helper.addEventListener(this._linkedBrowser, 'WillChangeBrowserRemoteness', event => this._willChangeBrowserRemoteness()), ]; this._disposed = false; browserContext.pages.add(this); this._registry._browserToTarget.set(this._linkedBrowser, this); - this._registry._browserBrowsingContextToTarget.set(this._linkedBrowser.browsingContext, this); + this._registry._browserIdToTarget.set(this._linkedBrowser.browsingContext.browserId, this); this._registry.emit(TargetRegistry.Events.TargetCreated, this); } + async activateAndRun(callback = () => {}) { + const ownerWindow = this._tab.linkedBrowser.ownerGlobal; + const tabBrowser = ownerWindow.gBrowser; + // Serialize all tab-switching commands per tabbed browser + // to disallow concurrent tab switching. + const result = (tabBrowser.__serializedChain ?? Promise.resolve()).then(async () => { + this._window.focus(); + if (tabBrowser.selectedTab !== this._tab) { + const promise = helper.awaitEvent(ownerWindow, 'TabSwitchDone'); + tabBrowser.selectedTab = this._tab; + await promise; + } + await callback(); + }); + tabBrowser.__serializedChain = result.catch(error => { /* swallow errors to keep chain running */ }); + return result; + } + + frameIdToBrowsingContext(frameId) { + 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); + } + + removeActor(actor) { + // Note: the order between setActor and removeActor is non-deterministic. + // Therefore we check that we are still bound to the actor that is being removed. + if (this._actor !== actor) + return; + this._actor = undefined; + this._channel.resetTransport(); + } + + _willChangeBrowserRemoteness() { + this.removeActor(this._actor); + } + dialog(dialogId) { return this._dialogs.get(dialogId); } @@ -405,20 +445,31 @@ class PageTarget { return this._browserContext; } - updateTouchOverride() { - this._linkedBrowser.browsingContext.touchEventsOverride = this._browserContext.touchOverride ? 'enabled' : 'none'; + updateOverridesForBrowsingContext(browsingContext = undefined) { + this.updateTouchOverride(browsingContext); + this.updateUserAgent(browsingContext); + this.updatePlatform(browsingContext); + this.updateDPPXOverride(browsingContext); + this.updateEmulatedMedia(browsingContext); + this.updateColorSchemeOverride(browsingContext); + this.updateReducedMotionOverride(browsingContext); + this.updateForcedColorsOverride(browsingContext); } - updateUserAgent() { - this._linkedBrowser.browsingContext.customUserAgent = this._browserContext.defaultUserAgent; + updateTouchOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).touchEventsOverride = this._browserContext.touchOverride ? 'enabled' : 'none'; } - updatePlatform() { - this._linkedBrowser.browsingContext.customPlatform = this._browserContext.defaultPlatform; + updateUserAgent(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).customUserAgent = this._browserContext.defaultUserAgent; } - updateJavaScriptDisabled() { - this._linkedBrowser.browsingContext.allowJavascript = !this._browserContext.javaScriptDisabled; + updatePlatform(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).customPlatform = this._browserContext.defaultPlatform; + } + + updateDPPXOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).overrideDPPX = this._browserContext.deviceScaleFactor || this._initialDPPX; } _updateModalDialogs() { @@ -441,6 +492,9 @@ class PageTarget { } async updateViewportSize() { + await waitForWindowReady(this._window); + this.updateDPPXOverride(); + // Viewport size is defined by three arguments: // 1. default size. Could be explicit if set as part of `window.open` call, e.g. // `window.open(url, title, 'width=400,height=400')` @@ -451,17 +505,45 @@ class PageTarget { // Otherwise, explicitly set page viewport prevales over browser context // default viewport. const viewportSize = this._viewportSize || this._browserContext.defaultViewportSize; - const actualSize = await setViewportSizeForBrowser(viewportSize, this._linkedBrowser, this._window); - this._linkedBrowser.browsingContext.overrideDPPX = this._browserContext.deviceScaleFactor || this._initialDPPX; - await this._channel.connect('').send('awaitViewportDimensions', { - width: actualSize.width, - height: actualSize.height, - deviceSizeIsPageSize: !!this._browserContext.deviceScaleFactor, - }); + if (viewportSize) { + const {width, height} = viewportSize; + this._linkedBrowser.style.setProperty('width', width + 'px'); + this._linkedBrowser.style.setProperty('height', height + 'px'); + this._linkedBrowser.style.setProperty('box-sizing', 'content-box'); + this._linkedBrowser.closest('.browserStack').style.setProperty('overflow', 'auto'); + this._linkedBrowser.closest('.browserStack').style.setProperty('contain', 'size'); + this._linkedBrowser.closest('.browserStack').style.setProperty('scrollbar-width', 'none'); + this._linkedBrowser.browsingContext.inRDMPane = true; + + const stackRect = this._linkedBrowser.closest('.browserStack').getBoundingClientRect(); + const toolbarTop = stackRect.y; + this._window.resizeBy(width - this._window.innerWidth, height + toolbarTop - this._window.innerHeight); + + await this._channel.connect('').send('awaitViewportDimensions', { width, height }); + } else { + this._linkedBrowser.style.removeProperty('width'); + this._linkedBrowser.style.removeProperty('height'); + this._linkedBrowser.style.removeProperty('box-sizing'); + this._linkedBrowser.closest('.browserStack').style.removeProperty('overflow'); + this._linkedBrowser.closest('.browserStack').style.removeProperty('contain'); + this._linkedBrowser.closest('.browserStack').style.removeProperty('scrollbar-width'); + this._linkedBrowser.browsingContext.inRDMPane = false; + + const actualSize = this._linkedBrowser.getBoundingClientRect(); + await this._channel.connect('').send('awaitViewportDimensions', { + width: actualSize.width, + height: actualSize.height, + }); + } } setEmulatedMedia(mediumOverride) { - this._linkedBrowser.browsingContext.mediumOverride = mediumOverride || ''; + this.mediumOverride = mediumOverride || ''; + this.updateEmulatedMedia(); + } + + updateEmulatedMedia(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).mediumOverride = this.mediumOverride; } setColorScheme(colorScheme) { @@ -469,8 +551,8 @@ class PageTarget { this.updateColorSchemeOverride(); } - updateColorSchemeOverride() { - this._linkedBrowser.browsingContext.prefersColorSchemeOverride = this.colorScheme || this._browserContext.colorScheme || 'none'; + updateColorSchemeOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).prefersColorSchemeOverride = this.colorScheme || this._browserContext.colorScheme || 'none'; } setReducedMotion(reducedMotion) { @@ -478,8 +560,8 @@ class PageTarget { this.updateReducedMotionOverride(); } - updateReducedMotionOverride() { - this._linkedBrowser.browsingContext.prefersReducedMotionOverride = this.reducedMotion || this._browserContext.reducedMotion || 'none'; + updateReducedMotionOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).prefersReducedMotionOverride = this.reducedMotion || this._browserContext.reducedMotion || 'none'; } setForcedColors(forcedColors) { @@ -487,8 +569,14 @@ class PageTarget { this.updateForcedColorsOverride(); } - updateForcedColorsOverride() { - this._linkedBrowser.browsingContext.forcedColorsOverride = (this.forcedColors !== 'no-override' ? this.forcedColors : this._browserContext.forcedColors) || 'no-override'; + updateForcedColorsOverride(browsingContext = undefined) { + (browsingContext || this._linkedBrowser.browsingContext).forcedColorsOverride = (this.forcedColors !== 'no-override' ? this.forcedColors : this._browserContext.forcedColors) || 'no-override'; + } + + async setInterceptFileChooserDialog(enabled) { + this.crossProcessCookie.interceptFileChooserDialog = enabled; + this._updateCrossProcessCookie(); + await this._channel.connect('').send('setInterceptFileChooserDialog', enabled).catch(e => {}); } async setViewportSize(viewportSize) { @@ -524,20 +612,28 @@ class PageTarget { this._browserContext.grantPermissionsToOrigin(this._url); } + _updateCrossProcessCookie() { + Services.ppmm.sharedData.set('juggler:page-cookie-' + this._linkedBrowser.browsingContext.browserId, this.crossProcessCookie); + Services.ppmm.sharedData.flush(); + } + async ensurePermissions() { await this._channel.connect('').send('ensurePermissions', {}).catch(e => void e); } async setInitScripts(scripts) { - this._pageInitScripts = scripts; + this.crossProcessCookie.initScripts = scripts; + this._updateCrossProcessCookie(); await this.pushInitScripts(); } async pushInitScripts() { - await this._channel.connect('').send('setInitScripts', [...this._browserContext.initScripts, ...this._pageInitScripts]).catch(e => void e); + await this._channel.connect('').send('setInitScripts', [...this._browserContext.crossProcessCookie.initScripts, ...this.crossProcessCookie.initScripts]).catch(e => void e); } async addBinding(worldName, name, script) { + this.crossProcessCookie.bindings.push({ worldName, name, script }); + this._updateCrossProcessCookie(); await this._channel.connect('').send('addBinding', { worldName, name, script }).catch(e => void e); } @@ -633,7 +729,20 @@ class PageTarget { screencastService.stopVideoRecording(screencastId); } + ensureContextMenuClosed() { + // Close context menu, if any, since it might capture mouse events on Linux + // and prevent browser shutdown on MacOS. + const doc = this._linkedBrowser.ownerDocument; + const contextMenu = doc.getElementById("contentAreaContextMenu"); + if (contextMenu) + contextMenu.hidePopup(); + const autocompletePopup = doc.getElementById("PopupAutoComplete"); + if (autocompletePopup) + autocompletePopup.hidePopup(); + } + dispose() { + this.ensureContextMenuClosed(); this._disposed = true; if (this._videoRecordingInfo) this._stopVideoRecording(); @@ -641,7 +750,7 @@ class PageTarget { this.stopScreencast(); this._browserContext.pages.delete(this); this._registry._browserToTarget.delete(this._linkedBrowser); - this._registry._browserBrowsingContextToTarget.delete(this._linkedBrowser.browsingContext); + this._registry._browserIdToTarget.delete(this._linkedBrowser.browsingContext.browserId); try { helper.removeListeners(this._eventListeners); } catch (e) { @@ -712,18 +821,24 @@ class BrowserContext { this.deviceScaleFactor = undefined; this.defaultUserAgent = null; this.defaultPlatform = null; - this.javaScriptDisabled = false; this.touchOverride = false; this.colorScheme = 'none'; this.forcedColors = 'no-override'; this.reducedMotion = 'none'; this.videoRecordingOptions = undefined; - this.initScripts = []; - this.bindings = []; - this.settings = {}; + this.crossProcessCookie = { + initScripts: [], + bindings: [], + settings: {}, + }; this.pages = new Set(); } + _updateCrossProcessCookie() { + Services.ppmm.sharedData.set('juggler:context-cookie-' + this.userContextId, this.crossProcessCookie); + Services.ppmm.sharedData.flush(); + } + setColorScheme(colorScheme) { this.colorScheme = fromProtocolColorScheme(colorScheme); for (const page of this.pages) @@ -796,12 +911,6 @@ class BrowserContext { page.updatePlatform(); } - setJavaScriptDisabled(javaScriptDisabled) { - this.javaScriptDisabled = javaScriptDisabled; - for (const page of this.pages) - page.updateJavaScriptDisabled(); - } - setTouchOverride(touchOverride) { this.touchOverride = touchOverride; for (const page of this.pages) @@ -815,17 +924,20 @@ class BrowserContext { } async setInitScripts(scripts) { - this.initScripts = scripts; + this.crossProcessCookie.initScripts = scripts; + this._updateCrossProcessCookie(); await Promise.all(Array.from(this.pages).map(page => page.pushInitScripts())); } async addBinding(worldName, name, script) { - this.bindings.push({ worldName, name, script }); + this.crossProcessCookie.bindings.push({ worldName, name, script }); + this._updateCrossProcessCookie(); await Promise.all(Array.from(this.pages).map(page => page.addBinding(worldName, name, script))); } async applySetting(name, value) { - this.settings[name] = value; + this.crossProcessCookie.settings[name] = value; + this._updateCrossProcessCookie(); await Promise.all(Array.from(this.pages).map(page => page.applyContextSetting(name, value))); } @@ -1032,26 +1144,6 @@ async function waitForWindowReady(window) { await helper.awaitEvent(window, 'load'); } -async function setViewportSizeForBrowser(viewportSize, browser, window) { - await waitForWindowReady(window); - if (viewportSize) { - const {width, height} = viewportSize; - const rect = browser.getBoundingClientRect(); - window.resizeBy(width - rect.width, height - rect.height); - browser.style.setProperty('min-width', width + 'px'); - browser.style.setProperty('min-height', height + 'px'); - browser.style.setProperty('max-width', width + 'px'); - browser.style.setProperty('max-height', height + 'px'); - } else { - browser.style.removeProperty('min-width'); - browser.style.removeProperty('min-height'); - browser.style.removeProperty('max-width'); - browser.style.removeProperty('max-height'); - } - const rect = browser.getBoundingClientRect(); - return { width: rect.width, height: rect.height }; -} - TargetRegistry.Events = { TargetCreated: Symbol('TargetRegistry.Events.TargetCreated'), TargetDestroyed: Symbol('TargetRegistry.Events.TargetDestroyed'), diff --git a/browser_patches/firefox-beta/juggler/components/Juggler.js b/browser_patches/firefox/juggler/components/Juggler.js similarity index 82% rename from browser_patches/firefox-beta/juggler/components/Juggler.js rename to browser_patches/firefox/juggler/components/Juggler.js index ed4242406f2703..a3740acc45413d 100644 --- a/browser_patches/firefox-beta/juggler/components/Juggler.js +++ b/browser_patches/firefox/juggler/components/Juggler.js @@ -12,12 +12,36 @@ const {BrowserHandler} = ChromeUtils.import("chrome://juggler/content/protocol/B const {NetworkObserver} = ChromeUtils.import("chrome://juggler/content/NetworkObserver.js"); const {TargetRegistry} = ChromeUtils.import("chrome://juggler/content/TargetRegistry.js"); const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {ActorManagerParent} = ChromeUtils.import('resource://gre/modules/ActorManagerParent.jsm'); const helper = new Helper(); const Cc = Components.classes; const Ci = Components.interfaces; -const FRAME_SCRIPT = "chrome://juggler/content/content/main.js"; +// Register JSWindowActors that will be instantiated for each frame. +ActorManagerParent.addJSWindowActors({ + JugglerFrame: { + parent: { + moduleURI: 'chrome://juggler/content/JugglerFrameParent.jsm', + }, + child: { + moduleURI: 'chrome://juggler/content/content/JugglerFrameChild.jsm', + events: { + // Normally, we instantiate an actor when a new window is created. + DOMWindowCreated: {}, + // However, for same-origin iframes, the navigation from about:blank + // to the URL will share the same window, so we need to also create + // an actor for a new document via DOMDocElementInserted. + DOMDocElementInserted: {}, + // Also, listening to DOMContentLoaded. + DOMContentLoaded: {}, + DOMWillOpenModalDialog: {}, + DOMModalDialogClosed: {}, + }, + }, + allFrames: true, + }, +}); let browserStartupFinishedCallback; let browserStartupFinishedPromise = new Promise(x => browserStartupFinishedCallback = x); @@ -72,8 +96,7 @@ class Juggler { const targetRegistry = new TargetRegistry(); new NetworkObserver(targetRegistry); - const loadFrameScript = () => { - Services.mm.loadFrameScript(FRAME_SCRIPT, true /* aAllowDelayedLoad */); + const loadStyleSheet = () => { if (Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless) { const styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService); const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); @@ -110,15 +133,15 @@ class Juggler { }; pipe.init(connection); const dispatcher = new Dispatcher(connection); - browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry, () => { + browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry, browserStartupFinishedPromise, () => { if (this._silent) Services.startup.exitLastWindowClosingSurvivalArea(); connection.onclose(); pipe.stop(); pipeStopped = true; - }, () => browserStartupFinishedPromise); + }); dispatcher.rootSession().setHandler(browserHandler); - loadFrameScript(); + loadStyleSheet(); dump(`\nJuggler listening to the pipe\n`); break; } diff --git a/browser_patches/firefox-beta/juggler/components/components.conf b/browser_patches/firefox/juggler/components/components.conf similarity index 100% rename from browser_patches/firefox-beta/juggler/components/components.conf rename to browser_patches/firefox/juggler/components/components.conf diff --git a/browser_patches/firefox/juggler/components/juggler.js b/browser_patches/firefox/juggler/components/juggler.js deleted file mode 100644 index 7fd1ca3ad6e594..00000000000000 --- a/browser_patches/firefox/juggler/components/juggler.js +++ /dev/null @@ -1,131 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -const {ComponentUtils} = ChromeUtils.import("resource://gre/modules/ComponentUtils.jsm"); -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {Dispatcher} = ChromeUtils.import("chrome://juggler/content/protocol/Dispatcher.js"); -const {BrowserHandler} = ChromeUtils.import("chrome://juggler/content/protocol/BrowserHandler.js"); -const {NetworkObserver} = ChromeUtils.import("chrome://juggler/content/NetworkObserver.js"); -const {TargetRegistry} = ChromeUtils.import("chrome://juggler/content/TargetRegistry.js"); -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); -const helper = new Helper(); - -const Cc = Components.classes; -const Ci = Components.interfaces; - -const FRAME_SCRIPT = "chrome://juggler/content/content/main.js"; - -// Command Line Handler -function CommandLineHandler() { -}; - -CommandLineHandler.prototype = { - classDescription: "Sample command-line handler", - classID: Components.ID('{f7a74a33-e2ab-422d-b022-4fb213dd2639}'), - contractID: "@mozilla.org/remote/juggler;1", - _xpcom_categories: [{ - category: "command-line-handler", - entry: "m-juggler" - }], - - /* nsICommandLineHandler */ - handle: async function(cmdLine) { - const jugglerFlag = cmdLine.handleFlagWithParam("juggler", false); - const jugglerPipeFlag = cmdLine.handleFlag("juggler-pipe", false); - if (!jugglerPipeFlag && (!jugglerFlag || isNaN(jugglerFlag))) - return; - const silent = cmdLine.preventDefault; - if (silent) - Services.startup.enterLastWindowClosingSurvivalArea(); - - const targetRegistry = new TargetRegistry(); - new NetworkObserver(targetRegistry); - - const loadFrameScript = () => { - Services.mm.loadFrameScript(FRAME_SCRIPT, true /* aAllowDelayedLoad */); - if (Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless) { - const styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService); - const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); - const uri = ioService.newURI('chrome://juggler/content/content/hidden-scrollbars.css', null, null); - styleSheetService.loadAndRegisterSheet(uri, styleSheetService.AGENT_SHEET); - } - }; - - // Force create hidden window here, otherwise its creation later closes the web socket! - Services.appShell.hiddenDOMWindow; - - if (jugglerFlag) { - const port = parseInt(jugglerFlag, 10); - const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm"); - const WebSocketServer = require('devtools/server/socket/websocket-server'); - this._server = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket); - this._server.initSpecialConnection(port, Ci.nsIServerSocket.KeepWhenOffline | Ci.nsIServerSocket.LoopbackOnly, 4); - const token = helper.generateId(); - this._server.asyncListen({ - onSocketAccepted: async(socket, transport) => { - const input = transport.openInputStream(0, 0, 0); - const output = transport.openOutputStream(0, 0, 0); - const webSocket = await WebSocketServer.accept(transport, input, output, "/" + token); - const dispatcher = new Dispatcher(webSocket); - const browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry, () => { - if (silent) - Services.startup.exitLastWindowClosingSurvivalArea(); - }); - dispatcher.rootSession().setHandler(browserHandler); - } - }); - loadFrameScript(); - dump(`Juggler listening on ws://127.0.0.1:${this._server.port}/${token}\n`); - } else if (jugglerPipeFlag) { - let browserHandler; - let pipeStopped = false; - const pipe = Cc['@mozilla.org/juggler/remotedebuggingpipe;1'].getService(Ci.nsIRemoteDebuggingPipe); - const connection = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIRemoteDebuggingPipeClient]), - receiveMessage(message) { - if (this.onmessage) - this.onmessage({ data: message }); - }, - disconnected() { - if (browserHandler) - browserHandler['Browser.close'](); - }, - send(message) { - if (pipeStopped) { - // We are missing the response to Browser.close, - // but everything works fine. Once we actually need it, - // we have to stop the pipe after the response is sent. - return; - } - pipe.sendMessage(message); - }, - }; - pipe.init(connection); - const dispatcher = new Dispatcher(connection); - browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry, () => { - if (silent) - Services.startup.exitLastWindowClosingSurvivalArea(); - connection.onclose(); - pipe.stop(); - pipeStopped = true; - }); - dispatcher.rootSession().setHandler(browserHandler); - loadFrameScript(); - dump(`\nJuggler listening to the pipe\n`); - } - }, - - QueryInterface: ChromeUtils.generateQI([ Ci.nsICommandLineHandler ]), - - // CHANGEME: change the help info as appropriate, but - // follow the guidelines in nsICommandLineHandler.idl - // specifically, flag descriptions should start at - // character 24, and lines should be wrapped at - // 72 characters with embedded newlines, - // and finally, the string should end with a newline - helpInfo : " --juggler Enable Juggler automation\n" -}; - -var NSGetFactory = ComponentUtils.generateNSGetFactory([CommandLineHandler]); diff --git a/browser_patches/firefox/juggler/components/juggler.manifest b/browser_patches/firefox/juggler/components/juggler.manifest deleted file mode 100644 index 50f8930207563e..00000000000000 --- a/browser_patches/firefox/juggler/components/juggler.manifest +++ /dev/null @@ -1,3 +0,0 @@ -component {f7a74a33-e2ab-422d-b022-4fb213dd2639} juggler.js -contract @mozilla.org/remote/juggler;1 {f7a74a33-e2ab-422d-b022-4fb213dd2639} -category command-line-handler m-juggler @mozilla.org/remote/juggler;1 diff --git a/browser_patches/firefox/juggler/components/moz.build b/browser_patches/firefox/juggler/components/moz.build index 268fbc361d8053..bab81f83fcb290 100644 --- a/browser_patches/firefox/juggler/components/moz.build +++ b/browser_patches/firefox/juggler/components/moz.build @@ -2,8 +2,5 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -EXTRA_COMPONENTS += [ - "juggler.js", - "juggler.manifest", -] +XPCOM_MANIFESTS += ["components.conf"] diff --git a/browser_patches/firefox/juggler/content/FrameTree.js b/browser_patches/firefox/juggler/content/FrameTree.js index 61ff889e755fb9..0d35854a536ef0 100644 --- a/browser_patches/firefox/juggler/content/FrameTree.js +++ b/browser_patches/firefox/juggler/content/FrameTree.js @@ -9,16 +9,17 @@ const Cu = Components.utils; const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); -const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); const {Runtime} = ChromeUtils.import('chrome://juggler/content/content/Runtime.js'); const helper = new Helper(); class FrameTree { - constructor(rootDocShell) { - EventEmitter.decorate(this); + constructor(rootBrowsingContext) { + helper.decorateAsEventEmitter(this); - this._browsingContextGroup = rootDocShell.browsingContext.group; + this._rootBrowsingContext = rootBrowsingContext; + + this._browsingContextGroup = rootBrowsingContext.group; if (!this._browsingContextGroup.__jugglerFrameTrees) this._browsingContextGroup.__jugglerFrameTrees = new Set(); this._browsingContextGroup.__jugglerFrameTrees.add(this); @@ -30,11 +31,14 @@ class FrameTree { this._runtime = new Runtime(false /* isWorker */); this._workers = new Map(); - this._docShellToFrame = new Map(); this._frameIdToFrame = new Map(); this._pageReady = false; - this._mainFrame = this._createFrame(rootDocShell); - const webProgress = rootDocShell.QueryInterface(Ci.nsIInterfaceRequestor) + this._javaScriptDisabled = false; + for (const browsingContext of helper.collectAllBrowsingContexts(rootBrowsingContext)) + this._createFrame(browsingContext); + this._mainFrame = this.frameForBrowsingContext(rootBrowsingContext); + + const webProgress = rootBrowsingContext.docShell.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebProgress); this.QueryInterface = ChromeUtils.generateQI([ Ci.nsIWebProgressListener, @@ -57,12 +61,29 @@ class FrameTree { const flags = Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT | Ci.nsIWebProgress.NOTIFY_LOCATION; this._eventListeners = [ + helper.addObserver((docShell, topic, loadIdentifier) => { + const frame = this.frameForDocShell(docShell); + if (!frame) + return; + frame._pendingNavigationId = helper.toProtocolNavigationId(loadIdentifier); + this.emit(FrameTree.Events.NavigationStarted, frame); + }, 'juggler-navigation-started-renderer'), helper.addObserver(this._onDOMWindowCreated.bind(this), 'content-document-global-created'), helper.addObserver(this._onDOMWindowCreated.bind(this), 'juggler-dom-window-reused'), - helper.addObserver(subject => this._onDocShellCreated(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-create'), - helper.addObserver(subject => this._onDocShellDestroyed(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-destroy'), + helper.addObserver((browsingContext, topic, why) => { + this._onBrowsingContextAttached(browsingContext); + }, 'browsing-context-attached'), + helper.addObserver((browsingContext, topic, why) => { + this._onBrowsingContextDetached(browsingContext); + }, 'browsing-context-discarded'), + helper.addObserver((subject, topic, eventInfo) => { + const [type, jugglerEventId] = eventInfo.split(' '); + this.emit(FrameTree.Events.InputEvent, { type, jugglerEventId: +(jugglerEventId ?? '0') }); + }, 'juggler-mouse-event-hit-renderer'), helper.addProgressListener(webProgress, this, flags), ]; + + this._dragEventListeners = []; } workers() { @@ -105,8 +126,7 @@ class FrameTree { return null; if (!workerDebugger.window) return null; - const docShell = workerDebugger.window.docShell; - return this._docShellToFrame.get(docShell) || null; + return this.frameForDocShell(workerDebugger.window.docShell); } _onDOMWindowCreated(window) { @@ -118,7 +138,7 @@ class FrameTree { window.windowUtils.addSheet(sheet, styleSheetService.AGENT_SHEET); window[this._addedScrollbarsStylesheetSymbol] = true; } - const frame = this._docShellToFrame.get(window.docShell) || null; + const frame = this.frameForDocShell(window.docShell); if (!frame) return; frame._onGlobalObjectCleared(); @@ -128,6 +148,12 @@ class FrameTree { this.scrollbarsHidden = hidden; } + setJavaScriptDisabled(javaScriptDisabled) { + this._javaScriptDisabled = javaScriptDisabled; + for (const frame of this.frames()) + frame._updateJavaScriptDisabled(); + } + _onWorkerCreated(workerDebugger) { // Note: we do not interoperate with firefox devtools. if (workerDebugger.isInitialized) @@ -151,8 +177,19 @@ class FrameTree { allFramesInBrowsingContextGroup(group) { const frames = []; - for (const frameTree of (group.__jugglerFrameTrees || [])) - frames.push(...frameTree.frames()); + for (const frameTree of (group.__jugglerFrameTrees || [])) { + for (const frame of frameTree.frames()) { + try { + // Try accessing docShell and domWindow to filter out dead frames. + // This might happen for print-preview frames, but maybe for something else as well. + frame.docShell(); + frame.domWindow(); + frames.push(frame); + } catch (e) { + dump(`WARNING: unable to access docShell and domWindow of the frame[id=${frame.id()}]\n`); + } + } + } return frames; } @@ -176,8 +213,18 @@ class FrameTree { frame._addBinding(worldName, name, script); } + frameForBrowsingContext(browsingContext) { + if (!browsingContext) + return null; + const frameId = helper.browsingContextToFrameId(browsingContext); + return this._frameIdToFrame.get(frameId) ?? null; + } + frameForDocShell(docShell) { - return this._docShellToFrame.get(docShell) || null; + if (!docShell) + return null; + const frameId = helper.browsingContextToFrameId(docShell.browsingContext); + return this._frameIdToFrame.get(frameId) ?? null; } frame(frameId) { @@ -205,6 +252,51 @@ class FrameTree { this._wdm.removeListener(this._wdmListener); this._runtime.dispose(); helper.removeListeners(this._eventListeners); + helper.removeListeners(this._dragEventListeners); + } + + onWindowEvent(event) { + if (event.type !== 'DOMDocElementInserted' || !event.target.ownerGlobal) + return; + + const docShell = event.target.ownerGlobal.docShell; + const frame = this.frameForDocShell(docShell); + if (!frame) { + dump(`WARNING: ${event.type} for unknown frame ${helper.browsingContextToFrameId(docShell.browsingContext)}\n`); + return; + } + if (frame._pendingNavigationId) { + docShell.QueryInterface(Ci.nsIWebNavigation); + this._frameNavigationCommitted(frame, docShell.currentURI.spec); + } + + if (frame === this._mainFrame) { + helper.removeListeners(this._dragEventListeners); + const chromeEventHandler = docShell.chromeEventHandler; + const options = { + mozSystemGroup: true, + capture: true, + }; + const emitInputEvent = (event) => this.emit(FrameTree.Events.InputEvent, { type: event.type, jugglerEventId: 0 }); + // Drag events are dispatched from content process, so these we don't see in the + // `juggler-mouse-event-hit-renderer` instrumentation. + this._dragEventListeners = [ + helper.addEventListener(chromeEventHandler, 'dragstart', emitInputEvent, options), + helper.addEventListener(chromeEventHandler, 'dragover', emitInputEvent, options), + ]; + } + } + + _frameNavigationCommitted(frame, url) { + for (const subframe of frame._children) + this._detachFrame(subframe); + const navigationId = frame._pendingNavigationId; + frame._pendingNavigationId = null; + frame._lastCommittedNavigationId = navigationId; + frame._url = url; + this.emit(FrameTree.Events.NavigationCommitted, frame); + if (frame === this._mainFrame) + this.forcePageReady(); } onStateChange(progress, request, flag, status) { @@ -212,11 +304,9 @@ class FrameTree { return; const channel = request.QueryInterface(Ci.nsIChannel); const docShell = progress.DOMWindow.docShell; - const frame = this._docShellToFrame.get(docShell); - if (!frame) { - dump(`ERROR: got a state changed event for un-tracked docshell!\n`); + const frame = this.frameForDocShell(docShell); + if (!frame) return; - } if (!channel.isDocument) { // Somehow, we can get worker requests here, @@ -224,47 +314,22 @@ class FrameTree { return; } - const isStart = flag & Ci.nsIWebProgressListener.STATE_START; - const isTransferring = flag & Ci.nsIWebProgressListener.STATE_TRANSFERRING; const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP; - const isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT; - - if (isStart) { - // Starting a new navigation. - frame._pendingNavigationId = channelId(channel); - frame._pendingNavigationURL = channel.URI.spec; - this.emit(FrameTree.Events.NavigationStarted, frame); - } else if (isTransferring || (isStop && frame._pendingNavigationId && !status)) { - // Navigation is committed. - for (const subframe of frame._children) - this._detachFrame(subframe); - const navigationId = frame._pendingNavigationId; - frame._pendingNavigationId = null; - frame._pendingNavigationURL = null; - frame._lastCommittedNavigationId = navigationId; - frame._url = channel.URI.spec; - this.emit(FrameTree.Events.NavigationCommitted, frame); - if (frame === this._mainFrame) - this.forcePageReady(); - } else if (isStop && frame._pendingNavigationId && status) { + if (isStop && frame._pendingNavigationId && status) { // Navigation is aborted. const navigationId = frame._pendingNavigationId; frame._pendingNavigationId = null; - frame._pendingNavigationURL = null; // Always report download navigation as failure to match other browsers. const errorText = helper.getNetworkErrorStatusText(status); this.emit(FrameTree.Events.NavigationAborted, frame, navigationId, errorText); if (frame === this._mainFrame && status !== Cr.NS_BINDING_ABORTED) this.forcePageReady(); } - - if (isStop && isDocument) - this.emit(FrameTree.Events.Load, frame); } onLocationChange(progress, request, location, flags) { const docShell = progress.DOMWindow.docShell; - const frame = this._docShellToFrame.get(docShell); + const frame = this.frameForDocShell(docShell); const sameDocumentNavigation = !!(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT); if (frame && sameDocumentNavigation) { frame._url = location.spec; @@ -272,24 +337,29 @@ class FrameTree { } } - _onDocShellCreated(docShell) { - // Bug 1142752: sometimes, the docshell appears to be immediately - // destroyed, bailout early to prevent random exceptions. - if (docShell.isBeingDestroyed()) + _onBrowsingContextAttached(browsingContext) { + // If this browsing context doesn't belong to our frame tree - do nothing. + if (browsingContext.top !== this._rootBrowsingContext) + return; + this._createFrame(browsingContext); + } + + _onBrowsingContextDetached(browsingContext) { + const frame = this.frameForBrowsingContext(browsingContext); + if (frame) + this._detachFrame(frame); + } + + _createFrame(browsingContext) { + const parentFrame = this.frameForBrowsingContext(browsingContext.parent); + if (!parentFrame && this._mainFrame) { + dump(`WARNING: found docShell with the same root, but no parent!\n`); return; - // If this docShell doesn't belong to our frame tree - do nothing. - let root = docShell; - while (root.parent) - root = root.parent; - if (root === this._mainFrame._docShell) - this._createFrame(docShell); - } - - _createFrame(docShell) { - const parentFrame = this._docShellToFrame.get(docShell.parent) || null; - const frame = new Frame(this, this._runtime, docShell, parentFrame); - this._docShellToFrame.set(docShell, frame); + } + const frame = new Frame(this, this._runtime, browsingContext, parentFrame); this._frameIdToFrame.set(frame.id(), frame); + if (browsingContext.docShell?.domWindow && browsingContext.docShell?.domWindow.location) + frame._url = browsingContext.docShell.domWindow.location.href; this.emit(FrameTree.Events.FrameAttached, frame); // Create execution context **after** reporting frame. // This is our protocol contract. @@ -298,17 +368,15 @@ class FrameTree { return frame; } - _onDocShellDestroyed(docShell) { - const frame = this._docShellToFrame.get(docShell); - if (frame) - this._detachFrame(frame); - } - _detachFrame(frame) { // Detach all children first for (const subframe of frame._children) this._detachFrame(subframe); - this._docShellToFrame.delete(frame._docShell); + if (frame === this._mainFrame) { + // Do not detach main frame (happens during cross-process navigation), + // as it confuses the client. + return; + } this._frameIdToFrame.delete(frame.id()); if (frame._parentFrame) frame._parentFrame._children.delete(frame); @@ -333,7 +401,7 @@ FrameTree.Events = { NavigationAborted: 'navigationaborted', SameDocumentNavigation: 'samedocumentnavigation', PageReady: 'pageready', - Load: 'load', + InputEvent: 'inputevent', }; class IsolatedWorld { @@ -345,16 +413,14 @@ class IsolatedWorld { } class Frame { - constructor(frameTree, runtime, docShell, parentFrame) { + constructor(frameTree, runtime, browsingContext, parentFrame) { this._frameTree = frameTree; this._runtime = runtime; - this._docShell = docShell; + this._browsingContext = browsingContext; this._children = new Set(); - this._frameId = helper.browsingContextToFrameId(this._docShell.browsingContext); + this._frameId = helper.browsingContextToFrameId(browsingContext); this._parentFrame = null; this._url = ''; - if (docShell.domWindow && docShell.domWindow.location) - this._url = docShell.domWindow.location.href; if (parentFrame) { this._parentFrame = parentFrame; parentFrame._children.add(this); @@ -362,7 +428,6 @@ class Frame { this._lastCommittedNavigationId = null; this._pendingNavigationId = null; - this._pendingNavigationURL = null; this._textInputProcessor = null; @@ -495,7 +560,7 @@ class Frame { _onGlobalObjectCleared() { const webSocketService = this._frameTree._webSocketEventService; - if (this._webSocketListenerInnerWindowId) + if (this._webSocketListenerInnerWindowId && webSocketService.hasListenerFor(this._webSocketListenerInnerWindowId)) webSocketService.removeListener(this._webSocketListenerInnerWindowId, this._webSocketListener); this._webSocketListenerInnerWindowId = this.domWindow().windowGlobalChild.innerWindowId; webSocketService.addListener(this._webSocketListenerInnerWindowId, this._webSocketListener); @@ -518,6 +583,20 @@ class Frame { for (const script of world._scriptsToEvaluateOnNewDocument) executionContext.evaluateScriptSafely(script); } + + const url = this.domWindow().location?.href; + if (url === 'about:blank' && !this._url) { + // Sometimes FrameTree is created too early, before the location has been set. + this._url = url; + this._frameTree.emit(FrameTree.Events.NavigationCommitted, this); + } + + this._updateJavaScriptDisabled(); + } + + _updateJavaScriptDisabled() { + if (this._browsingContext.currentWindowContext) + this._browsingContext.currentWindowContext.allowJavascript = !this._frameTree._javaScriptDisabled; } mainExecutionContext() { @@ -528,7 +607,7 @@ class Frame { if (!this._textInputProcessor) { this._textInputProcessor = Cc["@mozilla.org/text-input-processor;1"].createInstance(Ci.nsITextInputProcessor); } - this._textInputProcessor.beginInputTransactionForTests(this._docShell.DOMWindow); + this._textInputProcessor.beginInputTransactionForTests(this.docShell().DOMWindow); return this._textInputProcessor; } @@ -536,24 +615,20 @@ class Frame { return this._pendingNavigationId; } - pendingNavigationURL() { - return this._pendingNavigationURL; - } - lastCommittedNavigationId() { return this._lastCommittedNavigationId; } docShell() { - return this._docShell; + return this._browsingContext.docShell; } domWindow() { - return this._docShell.domWindow; + return this.docShell()?.domWindow; } name() { - const frameElement = this._docShell.domWindow.frameElement; + const frameElement = this.domWindow()?.frameElement; let name = ''; if (frameElement) name = frameElement.getAttribute('name') || frameElement.getAttribute('id') || ''; @@ -592,7 +667,7 @@ class Worker { onMessage: msg => void this._channel._onMessage(JSON.parse(msg)), onClose: () => void this._channel.dispose(), onError: (filename, lineno, message) => { - dump(`Error in worker: ${message} @${filename}:${lineno}\n`); + dump(`WARNING: Error in worker: ${message} @${filename}:${lineno}\n`); }, }; workerDebugger.addListener(this._workerDebuggerListener); diff --git a/browser_patches/firefox/juggler/content/JugglerFrameChild.jsm b/browser_patches/firefox/juggler/content/JugglerFrameChild.jsm new file mode 100644 index 00000000000000..80b532c6b98e8e --- /dev/null +++ b/browser_patches/firefox/juggler/content/JugglerFrameChild.jsm @@ -0,0 +1,65 @@ +"use strict"; + +const { Helper } = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { initialize } = ChromeUtils.import('chrome://juggler/content/content/main.js'); + +const Ci = Components.interfaces; +const helper = new Helper(); + +let sameProcessInstanceNumber = 0; + +class JugglerFrameChild extends JSWindowActorChild { + constructor() { + super(); + + this._eventListeners = []; + } + + handleEvent(aEvent) { + if (this._agents && aEvent.type === 'DOMWillOpenModalDialog') { + this._agents.channel.pause(); + return; + } + if (this._agents && aEvent.type === 'DOMModalDialogClosed') { + this._agents.channel.resumeSoon(); + return; + } + if (this._agents && aEvent.target === this.document) + this._agents.pageAgent.onWindowEvent(aEvent); + if (this._agents && aEvent.target === this.document) + this._agents.frameTree.onWindowEvent(aEvent); + } + + actorCreated() { + this.actorName = `content::${this.browsingContext.browserId}/${this.browsingContext.id}/${++sameProcessInstanceNumber}`; + + this._eventListeners.push(helper.addEventListener(this.contentWindow, 'load', event => { + this._agents?.pageAgent.onWindowEvent(event); + })); + + if (this.document.documentURI.startsWith('moz-extension://')) + return; + this._agents = initialize(this.browsingContext, this.docShell, this); + } + + _dispose() { + helper.removeListeners(this._eventListeners); + // We do not cleanup since agents are shared for all frames in the process. + + // TODO: restore the cleanup. + // Reset transport so that all messages will be pending and will not throw any errors. + // this._channel.resetTransport(); + // this._agents.pageAgent.dispose(); + // this._agents.frameTree.dispose(); + // this._agents = undefined; + } + + didDestroy() { + this._dispose(); + } + + receiveMessage() { } +} + +var EXPORTED_SYMBOLS = ['JugglerFrameChild']; diff --git a/browser_patches/firefox/juggler/content/PageAgent.js b/browser_patches/firefox/juggler/content/PageAgent.js index 93473964829079..f3a3e745c2d456 100644 --- a/browser_patches/firefox/juggler/content/PageAgent.js +++ b/browser_patches/firefox/juggler/content/PageAgent.js @@ -4,12 +4,15 @@ "use strict"; const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); + const Ci = Components.interfaces; const Cr = Components.results; const Cu = Components.utils; const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); +const {setTimeout} = ChromeUtils.import('resource://gre/modules/Timer.jsm'); + const dragService = Cc["@mozilla.org/widget/dragservice;1"].getService( Ci.nsIDragService ); @@ -50,8 +53,7 @@ class WorkerData { } class PageAgent { - constructor(messageManager, browserChannel, frameTree) { - this._messageManager = messageManager; + constructor(browserChannel, frameTree) { this._browserChannel = browserChannel; this._browserPage = browserChannel.connect('page'); this._frameTree = frameTree; @@ -62,7 +64,6 @@ class PageAgent { const docShell = frameTree.mainFrame().docShell(); this._docShell = docShell; this._initialDPPX = docShell.contentViewer.overrideDPPX; - this._dragging = false; // Dispatch frameAttached events for all initial frames for (const frame of this._frameTree.frames()) { @@ -78,6 +79,7 @@ class PageAgent { this._onWorkerCreated(worker); // Report execution contexts. + this._browserPage.emit('runtimeExecutionContextsCleared', {}); for (const context of this._runtime.executionContexts()) this._onExecutionContextCreated(context); @@ -99,9 +101,7 @@ class PageAgent { helper.addObserver(this._linkClicked.bind(this, true), 'juggler-link-click-sync'), helper.addObserver(this._onWindowOpenInNewContext.bind(this), 'juggler-window-open-in-new-context'), helper.addObserver(this._filePickerShown.bind(this), 'juggler-file-picker-shown'), - helper.addEventListener(this._messageManager, 'DOMContentLoaded', this._onDOMContentLoaded.bind(this)), helper.addObserver(this._onDocumentOpenLoad.bind(this), 'juggler-document-open-loaded'), - helper.on(this._frameTree, 'load', this._onLoad.bind(this)), helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)), helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)), helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)), @@ -116,6 +116,16 @@ class PageAgent { helper.on(this._frameTree, 'websocketframesent', event => this._browserPage.emit('webSocketFrameSent', event)), helper.on(this._frameTree, 'websocketframereceived', event => this._browserPage.emit('webSocketFrameReceived', event)), helper.on(this._frameTree, 'websocketclosed', event => this._browserPage.emit('webSocketClosed', event)), + helper.on(this._frameTree, 'inputevent', inputEvent => { + this._browserPage.emit('pageInputEvent', inputEvent); + if (inputEvent.type === 'dragstart') { + // After the dragStart event is dispatched and handled by Web, + // it might or might not create a new drag session, depending on its preventing default. + setTimeout(() => { + this._browserPage.emit('pageInputEvent', { type: 'juggler-drag-finalized', dragSessionStarted: !!dragService.getCurrentSession() }); + }, 0); + } + }), helper.addObserver(this._onWindowOpen.bind(this), 'webNavigation-createdNavigationTarget-from-js'), this._runtime.events.onErrorFromWorker((domWindow, message, stack) => { const frame = this._frameTree.frameForDocShell(domWindow.docShell); @@ -133,25 +143,19 @@ class PageAgent { this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)), this._runtime.events.onBindingCalled(this._onBindingCalled.bind(this)), browserChannel.register('page', { - addBinding: ({ worldName, name, script }) => this._frameTree.addBinding(worldName, name, script), adoptNode: this._adoptNode.bind(this), crash: this._crash.bind(this), describeNode: this._describeNode.bind(this), dispatchKeyEvent: this._dispatchKeyEvent.bind(this), - dispatchMouseEvent: this._dispatchMouseEvent.bind(this), + dispatchDragEvent: this._dispatchDragEvent.bind(this), dispatchTouchEvent: this._dispatchTouchEvent.bind(this), dispatchTapEvent: this._dispatchTapEvent.bind(this), getContentQuads: this._getContentQuads.bind(this), getFullAXTree: this._getFullAXTree.bind(this), - goBack: this._goBack.bind(this), - goForward: this._goForward.bind(this), insertText: this._insertText.bind(this), - navigate: this._navigate.bind(this), - reload: this._reload.bind(this), scrollIntoViewIfNeeded: this._scrollIntoViewIfNeeded.bind(this), setCacheDisabled: this._setCacheDisabled.bind(this), setFileInputFiles: this._setFileInputFiles.bind(this), - setInterceptFileChooserDialog: this._setInterceptFileChooserDialog.bind(this), evaluate: this._runtime.evaluate.bind(this._runtime), callFunction: this._runtime.callFunction.bind(this._runtime), getObjectProperties: this._runtime.getObjectProperties.bind(this._runtime), @@ -224,10 +228,6 @@ class PageAgent { this._emitAllEvents(this._frameTree.mainFrame()); } - _setInterceptFileChooserDialog({enabled}) { - this._docShell.fileInputInterceptionEnabled = !!enabled; - } - _linkClicked(sync, anchorElement) { if (anchorElement.ownerGlobal.docShell !== this._docShell) return; @@ -259,7 +259,9 @@ class PageAgent { }); } - _onDOMContentLoaded(event) { + onWindowEvent(event) { + if (event.type !== 'DOMContentLoaded' && event.type !== 'load') + return; if (!event.target.ownerGlobal) return; const docShell = event.target.ownerGlobal.docShell; @@ -268,7 +270,7 @@ class PageAgent { return; this._browserPage.emit('pageEventFired', { frameId: frame.id(), - name: 'DOMContentLoaded', + name: event.type, }); } @@ -291,18 +293,10 @@ class PageAgent { }); } - _onLoad(frame) { - this._browserPage.emit('pageEventFired', { - frameId: frame.id(), - name: 'load' - }); - } - _onNavigationStarted(frame) { this._browserPage.emit('pageNavigationStarted', { frameId: frame.id(), navigationId: frame.pendingNavigationId(), - url: frame.pendingNavigationURL(), }); } @@ -362,68 +356,16 @@ class PageAgent { helper.removeListeners(this._eventListeners); } - async _navigate({frameId, url, referer}) { - try { - const uri = NetUtil.newURI(url); - } catch (e) { - throw new Error(`Invalid url: "${url}"`); - } - let referrerURI = null; - let referrerInfo = null; - if (referer) { - try { - referrerURI = NetUtil.newURI(referer); - const ReferrerInfo = Components.Constructor( - '@mozilla.org/referrer-info;1', - 'nsIReferrerInfo', - 'init' - ); - referrerInfo = new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, referrerURI); - } catch (e) { - throw new Error(`Invalid referer: "${referer}"`); - } - } - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell().QueryInterface(Ci.nsIWebNavigation); - docShell.loadURI(url, { - triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), - flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE, - referrerInfo, - postData: null, - headers: null, - }); - return {navigationId: frame.pendingNavigationId(), navigationURL: frame.pendingNavigationURL()}; - } - - async _reload({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell().QueryInterface(Ci.nsIWebNavigation); - docShell.reload(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); - } - - async _goBack({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell(); - if (!docShell.canGoBack) - return {success: false}; - docShell.goBack(); - return {success: true}; - } - - async _goForward({frameId, url}) { - const frame = this._frameTree.frame(frameId); - const docShell = frame.docShell(); - if (!docShell.canGoForward) - return {success: false}; - docShell.goForward(); - return {success: true}; - } - async _adoptNode({frameId, objectId, executionContextId}) { const frame = this._frameTree.frame(frameId); if (!frame) throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = frame.unsafeObject(objectId); + let unsafeObject; + if (!objectId) { + unsafeObject = frame.domWindow().frameElement; + } else { + unsafeObject = frame.unsafeObject(objectId); + } const context = this._runtime.findExecutionContext(executionContextId); const fromPrincipal = unsafeObject.nodePrincipal; const toFrame = this._frameTree.frame(context.auxData().frameId); @@ -520,12 +462,6 @@ class PageAgent { } async _dispatchKeyEvent({type, keyCode, code, key, repeat, location, text}) { - // key events don't fire if we are dragging. - if (this._dragging) { - if (type === 'keydown' && key === 'Escape') - this._cancelDragIfNeeded(); - return; - } const frame = this._frameTree.mainFrame(); const tip = frame.textInputProcessor(); if (key === 'Meta' && Services.appinfo.OS !== 'Darwin') @@ -567,7 +503,9 @@ class PageAgent { touchPoints.map(point => point.radiusY === undefined ? 1.0 : point.radiusY), touchPoints.map(point => point.rotationAngle === undefined ? 0.0 : point.rotationAngle), touchPoints.map(point => point.force === undefined ? 1.0 : point.force), - touchPoints.length, + touchPoints.map(point => 0), + touchPoints.map(point => 0), + touchPoints.map(point => 0), modifiers); return {defaultPrevented}; } @@ -595,7 +533,8 @@ class PageAgent { return; const frame = this._frameTree.mainFrame(); - frame.domWindow().windowUtils.sendMouseEvent( + const winUtils = frame.domWindow().windowUtils; + winUtils.jugglerSendMouseEvent( 'mousemove', x, y, @@ -603,15 +542,16 @@ class PageAgent { 0 /*clickCount*/, modifiers, false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, + 0.0 /*pressure*/, 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, + true /*isDOMEventSynthesized*/, false /*isWidgetEventSynthesized*/, 0 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); + winUtils.DEFAULT_MOUSE_POINTER_ID /* pointerIdentifier */, + true /*disablePointerEvent*/ + ); - frame.domWindow().windowUtils.sendMouseEvent( + winUtils.jugglerSendMouseEvent( 'mousedown', x, y, @@ -619,15 +559,16 @@ class PageAgent { 1 /*clickCount*/, modifiers, false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, + 0.0 /*pressure*/, 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, + true /*isDOMEventSynthesized*/, false /*isWidgetEventSynthesized*/, 1 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); + winUtils.DEFAULT_MOUSE_POINTER_ID /*pointerIdentifier*/, + true /*disablePointerEvent*/, + ); - frame.domWindow().windowUtils.sendMouseEvent( + winUtils.jugglerSendMouseEvent( 'mouseup', x, y, @@ -635,112 +576,45 @@ class PageAgent { 1 /*clickCount*/, modifiers, false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, + 0.0 /*pressure*/, 5 /*inputSource*/, - undefined /*isDOMEventSynthesized*/, + true /*isDOMEventSynthesized*/, false /*isWidgetEventSynthesized*/, 0 /*buttons*/, - undefined /*pointerIdentifier*/, - true /*disablePointerEvent*/); - } - - _startDragSessionIfNeeded() { - const sess = dragService.getCurrentSession(); - if (sess) return; - dragService.startDragSessionForTests( - Ci.nsIDragService.DRAGDROP_ACTION_MOVE | - Ci.nsIDragService.DRAGDROP_ACTION_COPY | - Ci.nsIDragService.DRAGDROP_ACTION_LINK + winUtils.DEFAULT_MOUSE_POINTER_ID /*pointerIdentifier*/, + true /*disablePointerEvent*/, ); } - _simulateDragEvent(type, x, y, modifiers) { - const window = this._frameTree.mainFrame().domWindow(); - const element = window.windowUtils.elementFromPoint(x, y, false, false); - const event = window.document.createEvent('DragEvent'); + async _dispatchDragEvent({type, x, y, modifiers}) { + const session = dragService.getCurrentSession(); + const dropEffect = session.dataTransfer.dropEffect; - event.initDragEvent( - type, - true /* bubble */, - true /* cancelable */, - window, - 0 /* clickCount */, - window.mozInnerScreenX + x, - window.mozInnerScreenY + y, - x, - y, - modifiers & 2 /* ctrlkey */, - modifiers & 1 /* altKey */, - modifiers & 4 /* shiftKey */, - modifiers & 8 /* metaKey */, - 0 /* button */, // firefox always has the button as 0 on drops, regardless of which was pressed - null /* relatedTarget */, - null, - ); - if (type !== 'drop' || dragService.dragAction) - window.windowUtils.dispatchDOMEventViaPresShellForTesting(element, event); - if (type === 'drop') - this._cancelDragIfNeeded(); - } - - _cancelDragIfNeeded() { - this._dragging = false; - const sess = dragService.getCurrentSession(); - if (sess) - dragService.endDragSession(true); - } - - async _dispatchMouseEvent({type, x, y, button, clickCount, modifiers, buttons}) { - this._startDragSessionIfNeeded(); - const trapDrag = subject => { - this._dragging = true; - } - - // Don't send mouse events if there is an active drag - if (!this._dragging) { - const frame = this._frameTree.mainFrame(); - - obs.addObserver(trapDrag, 'on-datatransfer-available'); - frame.domWindow().windowUtils.sendMouseEvent( + if ((type === 'drop' && dropEffect !== 'none') || type === 'dragover') { + const win = this._frameTree.mainFrame().domWindow(); + win.windowUtils.jugglerSendMouseEvent( type, x, y, - button, - clickCount, + 0, /*button*/ + 0, /*clickCount*/ modifiers, false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - undefined /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - undefined /*isWidgetEventSynthesized*/, - buttons); - obs.removeObserver(trapDrag, 'on-datatransfer-available'); - - if (type === 'mousedown' && button === 2) { - frame.domWindow().windowUtils.sendMouseEvent( - 'contextmenu', - x, - y, - button, - clickCount, - modifiers, - false /*aIgnoreRootScrollFrame*/, - undefined /*pressure*/, - undefined /*inputSource*/, - undefined /*isDOMEventSynthesized*/, - undefined /*isWidgetEventSynthesized*/, - buttons); - } + 0.0 /*pressure*/, + 0 /*inputSource*/, + true /*isDOMEventSynthesized*/, + false /*isWidgetEventSynthesized*/, + 0 /*buttons*/, + win.windowUtils.DEFAULT_MOUSE_POINTER_ID /* pointerIdentifier */, + false /*disablePointerEvent*/, + ); + return; } - - // update drag state - if (this._dragging) { - if (type === 'mousemove') - this._simulateDragEvent('dragover', x, y, modifiers); - else if (type === 'mouseup') // firefox will do drops when any mouse button is released - this._simulateDragEvent('drop', x, y, modifiers); - } else { - this._cancelDragIfNeeded(); + if (type === 'dragend') { + const session = dragService.getCurrentSession(); + if (session) + dragService.endDragSession(true); + return; } } diff --git a/browser_patches/firefox/juggler/content/Runtime.js b/browser_patches/firefox/juggler/content/Runtime.js index 20c046a1dbd36c..4b564390709f41 100644 --- a/browser_patches/firefox/juggler/content/Runtime.js +++ b/browser_patches/firefox/juggler/content/Runtime.js @@ -185,7 +185,13 @@ class Runtime { if (context._isIsolatedWorldContext()) return false; const domWindow = context._domWindow; - return domWindow && domWindow.windowGlobalChild.innerWindowId === wrappedJSObject.innerID; + try { + // `windowGlobalChild` might be dead already; accessing it will throw an error, message in a console, + // and infinite recursion. + return domWindow && domWindow.windowGlobalChild.innerWindowId === wrappedJSObject.innerID; + } catch (e) { + return false; + } }); if (!executionContext) return; @@ -311,8 +317,9 @@ class ExecutionContext { this._id = generateId(); this._auxData = auxData; this._jsonStringifyObject = this._debuggee.executeInGlobal(`((stringify, object) => { - const oldToJSON = Date.prototype.toJSON; - Date.prototype.toJSON = undefined; + const oldToJSON = Date.prototype?.toJSON; + if (oldToJSON) + Date.prototype.toJSON = undefined; const oldArrayToJSON = Array.prototype.toJSON; const oldArrayHadToJSON = Array.prototype.hasOwnProperty('toJSON'); if (oldArrayHadToJSON) @@ -325,7 +332,8 @@ class ExecutionContext { return value; }); - Date.prototype.toJSON = oldToJSON; + if (oldToJSON) + Date.prototype.toJSON = oldToJSON; if (oldArrayHadToJSON) Array.prototype.toJSON = oldArrayToJSON; @@ -367,7 +375,7 @@ class ExecutionContext { try { this._debuggee.executeInGlobal(script); } catch (e) { - dump(`ERROR: ${e.message}\n${e.stack}\n`); + dump(`WARNING: ${e.message}\n${e.stack}\n`); } } @@ -450,7 +458,7 @@ class ExecutionContext { subtype = 'array'; else if (Object.is(rawObj, null)) subtype = 'null'; - else if (this._instanceOf(debuggerObj, rawObj, 'Node')) + else if (typeof Node !== 'undefined' && Node.isInstance(rawObj)) subtype = 'node'; else if (this._instanceOf(debuggerObj, rawObj, 'RegExp')) subtype = 'regexp'; diff --git a/browser_patches/firefox/juggler/content/main.js b/browser_patches/firefox/juggler/content/main.js index d471ab955327d3..647238efde59dd 100644 --- a/browser_patches/firefox/juggler/content/main.js +++ b/browser_patches/firefox/juggler/content/main.js @@ -8,123 +8,121 @@ const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTr const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); const {PageAgent} = ChromeUtils.import('chrome://juggler/content/content/PageAgent.js'); -let frameTree; +const browsingContextToAgents = new Map(); const helper = new Helper(); -const messageManager = this; - -let pageAgent; - -let failedToOverrideTimezone = false; - -const applySetting = { - geolocation: (geolocation) => { - if (geolocation) { - docShell.setGeolocationOverride({ - coords: { - latitude: geolocation.latitude, - longitude: geolocation.longitude, - accuracy: geolocation.accuracy, - altitude: NaN, - altitudeAccuracy: NaN, - heading: NaN, - speed: NaN, - }, - address: null, - timestamp: Date.now() - }); - } else { - docShell.setGeolocationOverride(null); - } - }, - - onlineOverride: (onlineOverride) => { - if (!onlineOverride) { - docShell.onlineOverride = Ci.nsIDocShell.ONLINE_OVERRIDE_NONE; - return; - } - docShell.onlineOverride = onlineOverride === 'online' ? - Ci.nsIDocShell.ONLINE_OVERRIDE_ONLINE : Ci.nsIDocShell.ONLINE_OVERRIDE_OFFLINE; - }, - - bypassCSP: (bypassCSP) => { - docShell.bypassCSPEnabled = bypassCSP; - }, - - timezoneId: (timezoneId) => { - failedToOverrideTimezone = !docShell.overrideTimezone(timezoneId); - }, - - locale: (locale) => { - docShell.languageOverride = locale; - }, - - scrollbarsHidden: (hidden) => { - frameTree.setScrollbarsHidden(hidden); - }, - - colorScheme: (colorScheme) => { - frameTree.setColorScheme(colorScheme); - }, - - reducedMotion: (reducedMotion) => { - frameTree.setReducedMotion(reducedMotion); - }, - - forcedColors: (forcedColors) => { - frameTree.setForcedColors(forcedColors); - }, -}; - -const channel = SimpleChannel.createForMessageManager('content::page', messageManager); - -function initialize() { - const response = sendSyncMessage('juggler:content-ready')[0]; - // If we didn't get a response, then we don't want to do anything - // as a part of this frame script. - if (!response) - return; - const { - initScripts = [], - bindings = [], - settings = {} - } = response || {}; + +function initialize(browsingContext, docShell, actor) { + if (browsingContext.parent) { + // For child frames, return agents from the main frame. + return browsingContextToAgents.get(browsingContext.top); + } + + let data = browsingContextToAgents.get(browsingContext); + if (data) { + // Rebind from one main frame actor to another one. + data.channel.bindToActor(actor); + return data; + } + + data = { channel: undefined, pageAgent: undefined, frameTree: undefined, failedToOverrideTimezone: false }; + browsingContextToAgents.set(browsingContext, data); + + const applySetting = { + geolocation: (geolocation) => { + if (geolocation) { + docShell.setGeolocationOverride({ + coords: { + latitude: geolocation.latitude, + longitude: geolocation.longitude, + accuracy: geolocation.accuracy, + altitude: NaN, + altitudeAccuracy: NaN, + heading: NaN, + speed: NaN, + }, + address: null, + timestamp: Date.now() + }); + } else { + docShell.setGeolocationOverride(null); + } + }, + + onlineOverride: (onlineOverride) => { + if (!onlineOverride) { + docShell.onlineOverride = Ci.nsIDocShell.ONLINE_OVERRIDE_NONE; + return; + } + docShell.onlineOverride = onlineOverride === 'online' ? + Ci.nsIDocShell.ONLINE_OVERRIDE_ONLINE : Ci.nsIDocShell.ONLINE_OVERRIDE_OFFLINE; + }, + + bypassCSP: (bypassCSP) => { + docShell.bypassCSPEnabled = bypassCSP; + }, + + timezoneId: (timezoneId) => { + data.failedToOverrideTimezone = !docShell.overrideTimezone(timezoneId); + }, + + locale: (locale) => { + docShell.languageOverride = locale; + }, + + scrollbarsHidden: (hidden) => { + data.frameTree.setScrollbarsHidden(hidden); + }, + + javaScriptDisabled: (javaScriptDisabled) => { + data.frameTree.setJavaScriptDisabled(javaScriptDisabled); + }, + }; + + const contextCrossProcessCookie = Services.cpmm.sharedData.get('juggler:context-cookie-' + browsingContext.originAttributes.userContextId) || { initScripts: [], bindings: [], settings: {} }; + const pageCrossProcessCookie = Services.cpmm.sharedData.get('juggler:page-cookie-' + browsingContext.browserId) || { initScripts: [], bindings: [], interceptFileChooserDialog: false }; + // Enforce focused state for all top level documents. docShell.overrideHasFocus = true; docShell.forceActiveState = true; - frameTree = new FrameTree(docShell); - for (const [name, value] of Object.entries(settings)) { + docShell.disallowBFCache = true; + data.frameTree = new FrameTree(browsingContext); + for (const [name, value] of Object.entries(contextCrossProcessCookie.settings)) { if (value !== undefined) applySetting[name](value); } - for (const { worldName, name, script } of bindings) - frameTree.addBinding(worldName, name, script); - frameTree.setInitScripts(initScripts); - - pageAgent = new PageAgent(messageManager, channel, frameTree); - - channel.register('', { + for (const { worldName, name, script } of [...contextCrossProcessCookie.bindings, ...pageCrossProcessCookie.bindings]) + data.frameTree.addBinding(worldName, name, script); + data.frameTree.setInitScripts([...contextCrossProcessCookie.initScripts, ...pageCrossProcessCookie.initScripts]); + data.channel = SimpleChannel.createForActor(actor); + data.pageAgent = new PageAgent(data.channel, data.frameTree); + docShell.fileInputInterceptionEnabled = !!pageCrossProcessCookie.interceptFileChooserDialog; + + data.channel.register('', { setInitScripts(scripts) { - frameTree.setInitScripts(scripts); + data.frameTree.setInitScripts(scripts); }, addBinding({worldName, name, script}) { - frameTree.addBinding(worldName, name, script); + data.frameTree.addBinding(worldName, name, script); }, applyContextSetting({name, value}) { applySetting[name](value); }, + setInterceptFileChooserDialog(enabled) { + docShell.fileInputInterceptionEnabled = !!enabled; + }, + ensurePermissions() { // noop, just a rountrip. }, hasFailedToOverrideTimezone() { - return failedToOverrideTimezone; + return data.failedToOverrideTimezone; }, - async awaitViewportDimensions({width, height, deviceSizeIsPageSize}) { - docShell.deviceSizeIsPageSize = deviceSizeIsPageSize; + async awaitViewportDimensions({width, height}) { const win = docShell.domWindow; if (win.innerWidth === width && win.innerHeight === height) return; @@ -142,14 +140,8 @@ function initialize() { }, }); - const gListeners = [ - helper.addEventListener(messageManager, 'unload', msg => { - helper.removeListeners(gListeners); - pageAgent.dispose(); - frameTree.dispose(); - channel.dispose(); - }), - ]; + return data; } -initialize(); +var EXPORTED_SYMBOLS = ['initialize']; +this.initialize = initialize; diff --git a/browser_patches/firefox/juggler/jar.mn b/browser_patches/firefox/juggler/jar.mn index adc90edd79e69e..7f3ecf5cdf3108 100644 --- a/browser_patches/firefox/juggler/jar.mn +++ b/browser_patches/firefox/juggler/jar.mn @@ -4,15 +4,20 @@ juggler.jar: % content juggler %content/ + + content/components/Juggler.js (components/Juggler.js) + content/Helper.js (Helper.js) content/NetworkObserver.js (NetworkObserver.js) content/TargetRegistry.js (TargetRegistry.js) content/SimpleChannel.js (SimpleChannel.js) + content/JugglerFrameParent.jsm (JugglerFrameParent.jsm) content/protocol/PrimitiveTypes.js (protocol/PrimitiveTypes.js) content/protocol/Protocol.js (protocol/Protocol.js) content/protocol/Dispatcher.js (protocol/Dispatcher.js) content/protocol/PageHandler.js (protocol/PageHandler.js) content/protocol/BrowserHandler.js (protocol/BrowserHandler.js) + content/content/JugglerFrameChild.jsm (content/JugglerFrameChild.jsm) content/content/main.js (content/main.js) content/content/FrameTree.js (content/FrameTree.js) content/content/PageAgent.js (content/PageAgent.js) diff --git a/browser_patches/firefox/juggler/protocol/BrowserHandler.js b/browser_patches/firefox/juggler/protocol/BrowserHandler.js index 04a139343eb8d4..df32c10bb67769 100644 --- a/browser_patches/firefox/juggler/protocol/BrowserHandler.js +++ b/browser_patches/firefox/juggler/protocol/BrowserHandler.js @@ -14,7 +14,7 @@ const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.j const helper = new Helper(); class BrowserHandler { - constructor(session, dispatcher, targetRegistry, onclose) { + constructor(session, dispatcher, targetRegistry, startCompletePromise, onclose) { this._session = session; this._dispatcher = dispatcher; this._targetRegistry = targetRegistry; @@ -24,14 +24,27 @@ class BrowserHandler { this._createdBrowserContextIds = new Set(); this._attachedSessions = new Map(); this._onclose = onclose; + this._startCompletePromise = startCompletePromise; } - async ['Browser.enable']({attachToDefaultContext}) { + async ['Browser.enable']({attachToDefaultContext, userPrefs = []}) { if (this._enabled) return; + await this._startCompletePromise; this._enabled = true; this._attachToDefaultContext = attachToDefaultContext; + for (const { name, value } of userPrefs) { + if (value === true || value === false) + Services.prefs.setBoolPref(name, value); + else if (typeof value === 'string') + Services.prefs.setStringPref(name, value); + else if (typeof value === 'number') + Services.prefs.setIntPref(name, value); + else + throw new Error(`Preference "${name}" has unsupported value: ${JSON.stringify(value)}`); + } + this._eventListeners = [ helper.on(this._targetRegistry, TargetRegistry.Events.TargetCreated, this._onTargetCreated.bind(this)), helper.on(this._targetRegistry, TargetRegistry.Events.TargetDestroyed, this._onTargetDestroyed.bind(this)), @@ -134,6 +147,7 @@ class BrowserHandler { waitForWindowClosed(browserWindow), ]); } + await this._startCompletePromise; this._onclose(); Services.startup.quit(Ci.nsIAppStartup.eForceQuit); } @@ -150,6 +164,12 @@ class BrowserHandler { this._targetRegistry.browserContextForId(browserContextId).extraHTTPHeaders = headers; } + ['Browser.clearCache']() { + // Clearing only the context cache does not work: https://bugzilla.mozilla.org/show_bug.cgi?id=1819147 + Services.cache2.clear(); + ChromeUtils.clearStyleSheetCache(); + } + ['Browser.setHTTPCredentials']({browserContextId, credentials}) { this._targetRegistry.browserContextForId(browserContextId).httpCredentials = nullToUndefined(credentials); } @@ -212,7 +232,7 @@ class BrowserHandler { } async ['Browser.setJavaScriptDisabled']({browserContextId, javaScriptDisabled}) { - await this._targetRegistry.browserContextForId(browserContextId).setJavaScriptDisabled(javaScriptDisabled); + await this._targetRegistry.browserContextForId(browserContextId).applySetting('javaScriptDisabled', nullToUndefined(javaScriptDisabled)); } async ['Browser.setLocaleOverride']({browserContextId, locale}) { diff --git a/browser_patches/firefox/juggler/protocol/Dispatcher.js b/browser_patches/firefox/juggler/protocol/Dispatcher.js index af72f307ac4953..8542461d529ebb 100644 --- a/browser_patches/firefox/juggler/protocol/Dispatcher.js +++ b/browser_patches/firefox/juggler/protocol/Dispatcher.js @@ -74,6 +74,9 @@ class Dispatcher { this._connection.send(JSON.stringify({id, sessionId, result})); } catch (e) { + dump(` + ERROR: ${e.message} ${e.stack} + `); this._connection.send(JSON.stringify({id, sessionId, error: { message: e.message, data: e.stack diff --git a/browser_patches/firefox/juggler/protocol/PageHandler.js b/browser_patches/firefox/juggler/protocol/PageHandler.js index 415f395aaf048f..407ad8c6c7b38d 100644 --- a/browser_patches/firefox/juggler/protocol/PageHandler.js +++ b/browser_patches/firefox/juggler/protocol/PageHandler.js @@ -4,8 +4,9 @@ "use strict"; -const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {Helper, EventWatcher} = ChromeUtils.import('chrome://juggler/content/Helper.js'); const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); const {NetworkObserver, PageNetwork} = ChromeUtils.import('chrome://juggler/content/NetworkObserver.js'); const {PageTarget} = ChromeUtils.import('chrome://juggler/content/TargetRegistry.js'); const {setTimeout} = ChromeUtils.import('resource://gre/modules/Timer.jsm'); @@ -79,6 +80,9 @@ class PageHandler { return (...args) => this._session.emitEvent(eventName, ...args); } + this._isDragging = false; + this._lastMousePosition = { x: 0, y: 0 }; + this._reportedFrameIds = new Set(); this._networkEventsForUnreportedFrameIds = new Map(); @@ -92,6 +96,10 @@ class PageHandler { if (this._pageTarget.videoRecordingInfo()) this._onVideoRecordingStarted(); + this._pageEventSink = {}; + helper.decorateAsEventEmitter(this._pageEventSink); + + this._pendingEventWatchers = new Set(); this._eventListeners = [ helper.on(this._pageTarget, PageTarget.Events.DialogOpened, this._onDialogOpened.bind(this)), helper.on(this._pageTarget, PageTarget.Events.DialogClosed, this._onDialogClosed.bind(this)), @@ -117,6 +125,7 @@ class PageHandler { pageNavigationCommitted: emitProtocolEvent('Page.navigationCommitted'), pageNavigationStarted: emitProtocolEvent('Page.navigationStarted'), pageReady: this._onPageReady.bind(this), + pageInputEvent: (event) => this._pageEventSink.emit(event.type, event), pageSameDocumentNavigation: emitProtocolEvent('Page.sameDocumentNavigation'), pageUncaughtError: emitProtocolEvent('Page.uncaughtError'), pageWorkerCreated: this._onWorkerCreated.bind(this), @@ -129,10 +138,11 @@ class PageHandler { return; } } - emitProtocolEvent('Runtime.console')(params); + this._session.emitEvent('Runtime.console', params); }, runtimeExecutionContextCreated: emitProtocolEvent('Runtime.executionContextCreated'), runtimeExecutionContextDestroyed: emitProtocolEvent('Runtime.executionContextDestroyed'), + runtimeExecutionContextsCleared: emitProtocolEvent('Runtime.executionContextsCleared'), webSocketCreated: emitProtocolEvent('Page.webSocketCreated'), webSocketOpened: emitProtocolEvent('Page.webSocketOpened'), @@ -145,6 +155,8 @@ class PageHandler { async dispose() { this._contentPage.dispose(); + for (const watcher of this._pendingEventWatchers) + watcher.dispose(); helper.removeListeners(this._eventListeners); } @@ -288,22 +300,22 @@ class PageHandler { } async ['Page.bringToFront'](options) { - this._pageTarget._window.focus(); + await this._pageTarget.activateAndRun(() => {}); } async ['Page.setCacheDisabled'](options) { return await this._contentPage.send('setCacheDisabled', options); } - async ['Page.addBinding'](options) { - return await this._contentPage.send('addBinding', options); + async ['Page.addBinding']({ worldName, name, script }) { + return await this._pageTarget.addBinding(worldName, name, script); } async ['Page.adoptNode'](options) { return await this._contentPage.send('adoptNode', options); } - async ['Page.screenshot']({ mimeType, clip, omitDeviceScaleFactor }) { + async ['Page.screenshot']({ mimeType, clip, omitDeviceScaleFactor, quality = 80}) { const rect = new DOMRect(clip.x, clip.y, clip.width, clip.height); const browsingContext = this._pageTarget.linkedBrowser().browsingContext; @@ -346,7 +358,15 @@ class PageHandler { let ctx = canvas.getContext('2d'); ctx.drawImage(snapshot, 0, 0); snapshot.close(); - const dataURL = canvas.toDataURL(mimeType); + + if (mimeType === 'image/jpeg') { + if (quality < 0 || quality > 100) + throw new Error('Quality must be an integer value between 0 and 100; received ' + quality); + quality /= 100; + } else { + quality = undefined; + } + const dataURL = canvas.toDataURL(mimeType, quality); return { data: dataURL.substring(dataURL.indexOf(',') + 1) }; } @@ -354,20 +374,74 @@ class PageHandler { return await this._contentPage.send('getContentQuads', options); } - async ['Page.navigate'](options) { - return await this._contentPage.send('navigate', options); + async ['Page.navigate']({frameId, url, referer}) { + const browsingContext = this._pageTarget.frameIdToBrowsingContext(frameId); + let sameDocumentNavigation = false; + try { + const uri = NetUtil.newURI(url); + // This is the same check that verifes browser-side if this is the same-document navigation. + // See CanonicalBrowsingContext::SupportsLoadingInParent. + sameDocumentNavigation = browsingContext.currentURI && uri.hasRef && uri.equalsExceptRef(browsingContext.currentURI); + } catch (e) { + throw new Error(`Invalid url: "${url}"`); + } + let referrerURI = null; + let referrerInfo = null; + if (referer) { + try { + referrerURI = NetUtil.newURI(referer); + const ReferrerInfo = Components.Constructor( + '@mozilla.org/referrer-info;1', + 'nsIReferrerInfo', + 'init' + ); + referrerInfo = new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, referrerURI); + } catch (e) { + throw new Error(`Invalid referer: "${referer}"`); + } + } + + let navigationId; + const unsubscribe = helper.addObserver((browsingContext, topic, loadIdentifier) => { + navigationId = helper.toProtocolNavigationId(loadIdentifier); + }, 'juggler-navigation-started-browser'); + browsingContext.loadURI(Services.io.newURI(url), { + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_IS_LINK, + referrerInfo, + // postData: null, + // headers: null, + // Fake user activation. + hasValidUserGestureActivation: true, + }); + unsubscribe(); + + return { + navigationId: sameDocumentNavigation ? null : navigationId, + }; } - async ['Page.goBack'](options) { - return await this._contentPage.send('goBack', options); + async ['Page.goBack']({}) { + const browsingContext = this._pageTarget.linkedBrowser().browsingContext; + if (!browsingContext.embedderElement?.canGoBack) + return { success: false }; + browsingContext.goBack(); + return { success: true }; } - async ['Page.goForward'](options) { - return await this._contentPage.send('goForward', options); + async ['Page.goForward']({}) { + const browsingContext = this._pageTarget.linkedBrowser().browsingContext; + if (!browsingContext.embedderElement?.canGoForward) + return { success: false }; + browsingContext.goForward(); + return { success: true }; } - async ['Page.reload'](options) { - return await this._contentPage.send('reload', options); + async ['Page.reload']() { + await this._pageTarget.activateAndRun(() => { + const doc = this._pageTarget._tab.linkedBrowser.ownerDocument; + doc.getElementById('Browser:Reload').doCommand(); + }); } async ['Page.describeNode'](options) { @@ -382,8 +456,22 @@ class PageHandler { return await this._pageTarget.setInitScripts(scripts); } - async ['Page.dispatchKeyEvent'](options) { - return await this._contentPage.send('dispatchKeyEvent', options); + async ['Page.dispatchKeyEvent']({type, keyCode, code, key, repeat, location, text}) { + // key events don't fire if we are dragging. + if (this._isDragging) { + if (type === 'keydown' && key === 'Escape') { + await this._contentPage.send('dispatchDragEvent', { + type: 'dragover', + x: this._lastMousePosition.x, + y: this._lastMousePosition.y, + modifiers: 0 + }); + await this._contentPage.send('dispatchDragEvent', {type: 'dragend'}); + this._isDragging = false; + } + return; + } + return await this._contentPage.send('dispatchKeyEvent', {type, keyCode, code, key, repeat, location, text}); } async ['Page.dispatchTouchEvent'](options) { @@ -394,30 +482,154 @@ class PageHandler { return await this._contentPage.send('dispatchTapEvent', options); } - async ['Page.dispatchMouseEvent'](options) { - return await this._contentPage.send('dispatchMouseEvent', options); + async ['Page.dispatchMouseEvent']({type, x, y, button, clickCount, modifiers, buttons}) { + const win = this._pageTarget._window; + const sendEvents = async (types) => { + // 1. Scroll element to the desired location first; the coordinates are relative to the element. + this._pageTarget._linkedBrowser.scrollRectIntoViewIfNeeded(x, y, 0, 0); + // 2. Get element's bounding box in the browser after the scroll is completed. + const boundingBox = this._pageTarget._linkedBrowser.getBoundingClientRect(); + + const watcher = new EventWatcher(this._pageEventSink, types, this._pendingEventWatchers); + const promises = []; + for (const type of types) { + // This dispatches to the renderer synchronously. + const jugglerEventId = win.windowUtils.jugglerSendMouseEvent( + type, + x + boundingBox.left, + y + boundingBox.top, + button, + clickCount, + modifiers, + false /* aIgnoreRootScrollFrame */, + 0.0 /* pressure */, + 0 /* inputSource */, + true /* isDOMEventSynthesized */, + false /* isWidgetEventSynthesized */, + buttons, + win.windowUtils.DEFAULT_MOUSE_POINTER_ID /* pointerIdentifier */, + false /* disablePointerEvent */ + ); + promises.push(watcher.ensureEvent(type, eventObject => eventObject.jugglerEventId === jugglerEventId)); + } + await Promise.all(promises); + await watcher.dispose(); + }; + + // We must switch to proper tab in the tabbed browser so that + // 1. Event is dispatched to a proper renderer. + // 2. We receive an ack from the renderer for the dispatched event. + await this._pageTarget.activateAndRun(async () => { + this._pageTarget.ensureContextMenuClosed(); + // If someone asks us to dispatch mouse event outside of viewport, then we normally would drop it. + const boundingBox = this._pageTarget._linkedBrowser.getBoundingClientRect(); + if (x < 0 || y < 0 || x > boundingBox.width || y > boundingBox.height) { + if (type !== 'mousemove') + return; + + // A special hack: if someone tries to do `mousemove` outside of + // viewport coordinates, then move the mouse off from the Web Content. + // This way we can eliminate all the hover effects. + // NOTE: since this won't go inside the renderer, there's no need to wait for ACK. + win.windowUtils.sendMouseEvent( + 'mousemove', + 0 /* x */, + 0 /* y */, + button, + clickCount, + modifiers, + false /* aIgnoreRootScrollFrame */, + 0.0 /* pressure */, + 0 /* inputSource */, + true /* isDOMEventSynthesized */, + false /* isWidgetEventSynthesized */, + buttons, + win.windowUtils.DEFAULT_MOUSE_POINTER_ID /* pointerIdentifier */, + false /* disablePointerEvent */ + ); + return; + } + + if (type === 'mousedown') { + if (this._isDragging) + return; + + const eventNames = button === 2 ? ['mousedown', 'contextmenu'] : ['mousedown']; + await sendEvents(eventNames); + return; + } + + if (type === 'mousemove') { + this._lastMousePosition = { x, y }; + if (this._isDragging) { + const watcher = new EventWatcher(this._pageEventSink, ['dragover'], this._pendingEventWatchers); + await this._contentPage.send('dispatchDragEvent', {type:'dragover', x, y, modifiers}); + await watcher.ensureEventsAndDispose(['dragover']); + return; + } + + const watcher = new EventWatcher(this._pageEventSink, ['dragstart', 'juggler-drag-finalized'], this._pendingEventWatchers); + await sendEvents(['mousemove']); + + // The order of events after 'mousemove' is sent: + // 1. [dragstart] - might or might NOT be emitted + // 2. [mousemove] - always emitted. This was awaited as part of `sendEvents` call. + // 3. [juggler-drag-finalized] - only emitted if dragstart was emitted. + + if (watcher.hasEvent('dragstart')) { + const eventObject = await watcher.ensureEvent('juggler-drag-finalized'); + this._isDragging = eventObject.dragSessionStarted; + } + watcher.dispose(); + return; + } + + if (type === 'mouseup') { + if (this._isDragging) { + const watcher = new EventWatcher(this._pageEventSink, ['dragover'], this._pendingEventWatchers); + await this._contentPage.send('dispatchDragEvent', {type: 'dragover', x, y, modifiers}); + await this._contentPage.send('dispatchDragEvent', {type: 'drop', x, y, modifiers}); + await this._contentPage.send('dispatchDragEvent', {type: 'dragend', x, y, modifiers}); + // NOTE: + // - 'drop' event might not be dispatched at all, depending on dropAction. + // - 'dragend' event might not be dispatched at all, if the source element was removed + // during drag. However, it'll be dispatched synchronously in the renderer. + await watcher.ensureEventsAndDispose(['dragover']); + this._isDragging = false; + } else { + await sendEvents(['mouseup']); + } + return; + } + }); } async ['Page.dispatchWheelEvent']({x, y, button, deltaX, deltaY, deltaZ, modifiers }) { - const boundingBox = this._pageTarget._linkedBrowser.getBoundingClientRect(); - x += boundingBox.left; - y += boundingBox.top; const deltaMode = 0; // WheelEvent.DOM_DELTA_PIXEL const lineOrPageDeltaX = deltaX > 0 ? Math.floor(deltaX) : Math.ceil(deltaX); const lineOrPageDeltaY = deltaY > 0 ? Math.floor(deltaY) : Math.ceil(deltaY); - const win = this._pageTarget._window; - win.windowUtils.sendWheelEvent( - x, - y, - deltaX, - deltaY, - deltaZ, - deltaMode, - modifiers, - lineOrPageDeltaX, - lineOrPageDeltaY, - 0 /* options */); + await this._pageTarget.activateAndRun(() => { + this._pageTarget.ensureContextMenuClosed(); + + // 1. Scroll element to the desired location first; the coordinates are relative to the element. + this._pageTarget._linkedBrowser.scrollRectIntoViewIfNeeded(x, y, 0, 0); + // 2. Get element's bounding box in the browser after the scroll is completed. + const boundingBox = this._pageTarget._linkedBrowser.getBoundingClientRect(); + + const win = this._pageTarget._window; + win.windowUtils.sendWheelEvent( + x + boundingBox.left, + y + boundingBox.top, + deltaX, + deltaY, + deltaZ, + deltaMode, + modifiers, + lineOrPageDeltaX, + lineOrPageDeltaY, + 0 /* options */); + }); } async ['Page.insertText'](options) { @@ -438,8 +650,8 @@ class PageHandler { dialog.dismiss(); } - async ['Page.setInterceptFileChooserDialog'](options) { - return await this._contentPage.send('setInterceptFileChooserDialog', options); + async ['Page.setInterceptFileChooserDialog']({ enabled }) { + return await this._pageTarget.setInterceptFileChooserDialog(enabled); } async ['Page.startScreencast'](options) { diff --git a/browser_patches/firefox/juggler/protocol/Protocol.js b/browser_patches/firefox/juggler/protocol/Protocol.js index be0f15af0d5a74..5cd9e84330a444 100644 --- a/browser_patches/firefox/juggler/protocol/Protocol.js +++ b/browser_patches/firefox/juggler/protocol/Protocol.js @@ -15,6 +15,11 @@ browserTypes.TargetInfo = { openerId: t.Optional(t.String), }; +browserTypes.UserPreference = { + name: t.String, + value: t.Any, +}; + browserTypes.CookieOptions = { name: t.String, value: t.String, @@ -188,6 +193,7 @@ networkTypes.HTTPHeader = { networkTypes.HTTPCredentials = { username: t.String, password: t.String, + origin: t.Optional(t.String), }; networkTypes.SecurityDetails = { @@ -227,6 +233,7 @@ const Browser = { uuid: t.String, browserContextId: t.Optional(t.String), pageTargetId: t.String, + frameId: t.String, url: t.String, suggestedFileName: t.String, }, @@ -244,6 +251,7 @@ const Browser = { 'enable': { params: { attachToDefaultContext: t.Boolean, + userPrefs: t.Optional(t.Array(browserTypes.UserPreference)), }, }, 'createBrowserContext': { @@ -280,6 +288,7 @@ const Browser = { headers: t.Array(networkTypes.HTTPHeader), }, }, + 'clearCache': {}, 'setBrowserProxy': { params: { type: t.Enum(['http', 'https', 'socks', 'socks4']), @@ -573,6 +582,8 @@ const Runtime = { 'executionContextDestroyed': { executionContextId: t.String, }, + 'executionContextsCleared': { + }, 'console': { executionContextId: t.String, args: t.Array(runtimeTypes.RemoteObject), @@ -656,7 +667,6 @@ const Page = { 'navigationStarted': { frameId: t.String, navigationId: t.String, - url: t.String, }, 'navigationCommitted': { frameId: t.String, @@ -820,7 +830,6 @@ const Page = { }, returns: { navigationId: t.Nullable(t.String), - navigationURL: t.Nullable(t.String), } }, 'goBack': { @@ -840,14 +849,13 @@ const Page = { }, }, 'reload': { - params: { - frameId: t.String, - }, + params: { }, }, 'adoptNode': { params: { frameId: t.String, - objectId: t.String, + // Missing objectId adopts frame owner. + objectId: t.Optional(t.String), executionContextId: t.String, }, returns: { @@ -858,6 +866,7 @@ const Page = { params: { mimeType: t.Enum(['image/png', 'image/jpeg']), clip: pageTypes.Clip, + quality: t.Optional(t.Number), omitDeviceScaleFactor: t.Optional(t.Boolean), }, returns: { @@ -903,7 +912,7 @@ const Page = { }, 'dispatchMouseEvent': { params: { - type: t.String, + type: t.Enum(['mousedown', 'mousemove', 'mouseup']), button: t.Number, x: t.Number, y: t.Number, diff --git a/browser_patches/firefox/juggler/screencast/HeadlessWindowCapturer.cpp b/browser_patches/firefox/juggler/screencast/HeadlessWindowCapturer.cpp index 88d1791dde449b..d8aaae84432edd 100644 --- a/browser_patches/firefox/juggler/screencast/HeadlessWindowCapturer.cpp +++ b/browser_patches/firefox/juggler/screencast/HeadlessWindowCapturer.cpp @@ -19,7 +19,9 @@ using namespace webrtc; namespace mozilla { rtc::scoped_refptr HeadlessWindowCapturer::Create(HeadlessWidget* headlessWindow) { - return new rtc::RefCountedObject(headlessWindow); + return rtc::scoped_refptr( + new rtc::RefCountedObject(headlessWindow) + ); } HeadlessWindowCapturer::HeadlessWindowCapturer(mozilla::widget::HeadlessWidget* window) diff --git a/browser_patches/firefox/juggler/screencast/ScreencastEncoder.cpp b/browser_patches/firefox/juggler/screencast/ScreencastEncoder.cpp index 5891953392bb56..51466a0ab944ee 100644 --- a/browser_patches/firefox/juggler/screencast/ScreencastEncoder.cpp +++ b/browser_patches/firefox/juggler/screencast/ScreencastEncoder.cpp @@ -145,12 +145,34 @@ class ScreencastEncoder::VPXFrame { uint8_t* u_data = image->planes[VPX_PLANE_U]; uint8_t* v_data = image->planes[VPX_PLANE_V]; - double src_width = src->width() - m_margin.LeftRight(); - double src_height = src->height() - m_margin.top; - // YUV offsets must be even. + /** + * Let's say we have the following image of 6x3 pixels (same number = same pixel value): + * 112233 + * 112233 + * 445566 + * In I420 format (see https://en.wikipedia.org/wiki/YUV), the image will have the following data planes: + * Y [stride_Y = 6]: + * 112233 + * 112233 + * 445566 + * U [stride_U = 3] - this plane has aggregate for each 2x2 pixels: + * 123 + * 456 + * V [stride_V = 3] - this plane has aggregate for each 2x2 pixels: + * 123 + * 456 + * + * To crop this image efficiently, we can move src_Y/U/V pointer and + * adjust the src_width and src_height. However, we must cut off only **even** + * amount of lines and columns to retain semantic of U and V planes which + * contain only 1/4 of pixel information. + */ int yuvTopOffset = m_margin.top & 1 ? m_margin.top + 1 : m_margin.top; int yuvLeftOffset = m_margin.left & 1 ? m_margin.left + 1 : m_margin.left; + double src_width = src->width() - yuvLeftOffset; + double src_height = src->height() - yuvTopOffset; + if (src_width > image->w || src_height > image->h) { double scale = std::min(image->w / src_width, image->h / src_height); double dst_width = src_width * scale; diff --git a/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp b/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp index 20a766dc3735de..25f61718014148 100644 --- a/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp +++ b/browser_patches/firefox/juggler/screencast/nsScreencastService.cpp @@ -24,6 +24,8 @@ #include "modules/video_capture/video_capture.h" #include "mozilla/widget/PlatformWidgetTypes.h" #include "video_engine/desktop_capture_impl.h" +#include "VideoEngine.h" + extern "C" { #include "jpeglib.h" } @@ -55,7 +57,7 @@ rtc::scoped_refptr CreateWindowCapturer(nsIWidget* windowId.AppendPrintf("%" PRIuPTR, rawWindowId); bool captureCursor = false; static int moduleId = 0; - return webrtc::DesktopCaptureImpl::Create(++moduleId, windowId.get(), CaptureDeviceType::Window, captureCursor); + return rtc::scoped_refptr(webrtc::DesktopCaptureImpl::Create(++moduleId, windowId.get(), camera::CaptureDeviceType::Window, captureCursor)); } nsresult generateUid(nsString& uid) { @@ -80,6 +82,7 @@ class nsScreencastService::Session : public rtc::VideoSinkInterface&& capturer, std::unique_ptr encoder, int width, int height, @@ -87,6 +90,7 @@ class nsScreencastService::Session : public rtc::VideoSinkInterface Create( nsIScreencastServiceClient* client, + nsIWidget* widget, rtc::scoped_refptr&& capturer, std::unique_ptr encoder, int width, int height, int viewportWidth, int viewportHeight, gfx::IntMargin margin, uint32_t jpegQuality) { - return do_AddRef(new Session(client, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, jpegQuality)); + return do_AddRef(new Session(client, widget, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, jpegQuality)); + } + + rtc::scoped_refptr ReuseCapturer(nsIWidget* widget) { + if (mWidget == widget) + return mCaptureModule; + return nullptr; } bool Start() { @@ -141,10 +152,7 @@ class nsScreencastService::Session : public rtc::VideoSinkInterfaceDeRegisterCaptureDataCallback(this); else mCaptureModule->DeRegisterRawFrameCallback(this); - int error = mCaptureModule->StopCapture(); - if (error) { - fprintf(stderr, "StopCapture error %d\n", error); - } + mCaptureModule->StopCapture(); if (mEncoder) { mEncoder->finish([this, protect = RefPtr{this}] { NS_DispatchToMainThread(NS_NewRunnableFunction( @@ -279,6 +287,7 @@ class nsScreencastService::Session : public rtc::VideoSinkInterface mClient; + nsIWidget* mWidget; rtc::scoped_refptr mCaptureModule; std::unique_ptr mEncoder; uint32_t mJpegQuality; @@ -322,7 +331,14 @@ nsresult nsScreencastService::StartVideoRecording(nsIScreencastServiceClient* aC return NS_ERROR_UNEXPECTED; nsIWidget* widget = view->GetWidget(); - rtc::scoped_refptr capturer = CreateWindowCapturer(widget); + rtc::scoped_refptr capturer = nullptr; + for (auto& it : mIdToSession) { + capturer = it.second->ReuseCapturer(widget); + if (capturer) + break; + } + if (!capturer) + capturer = CreateWindowCapturer(widget); if (!capturer) return NS_ERROR_FAILURE; @@ -349,7 +365,7 @@ nsresult nsScreencastService::StartVideoRecording(nsIScreencastServiceClient* aC NS_ENSURE_SUCCESS(rv, rv); sessionId = uid; - auto session = Session::Create(aClient, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, isVideo ? 0 : quality); + auto session = Session::Create(aClient, widget, std::move(capturer), std::move(encoder), width, height, viewportWidth, viewportHeight, margin, isVideo ? 0 : quality); if (!session->Start()) return NS_ERROR_FAILURE; mIdToSession.emplace(sessionId, std::move(session)); diff --git a/browser_patches/firefox/patches/bootstrap.diff b/browser_patches/firefox/patches/bootstrap.diff index 6a406855c30abf..955f27c40633ac 100644 --- a/browser_patches/firefox/patches/bootstrap.diff +++ b/browser_patches/firefox/patches/bootstrap.diff @@ -1,8 +1,8 @@ diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h -index afb6230bb613ecde4a5e3271478a682d0396dc3b..a3a7d9786f9d18bad6afc292264b9dbc62c14cf2 100644 +index bc1a692c23d8599512a5ce956d99998640347c46..4e77897aa4a84ce88445ba45f1ba3b5b2dde9e23 100644 --- a/accessible/base/NotificationController.h +++ b/accessible/base/NotificationController.h -@@ -276,6 +276,8 @@ class NotificationController final : public EventQueue, +@@ -244,6 +244,8 @@ class NotificationController final : public EventQueue, } #endif @@ -59,10 +59,10 @@ index 416a1c5497c97ed80cc0f37d72545e36f7e36b4c..b81983cf7153378260a21f6af225e349 * Return XPCOM wrapper for the internal accessible. */ diff --git a/browser/app/winlauncher/LauncherProcessWin.cpp b/browser/app/winlauncher/LauncherProcessWin.cpp -index 4460774865769609b66c0710f7c83f4d5c02b6fa..2ca95607b9b093218d48f83adc95c514cebe661b 100644 +index 33b8ed52bff98c2216c16d47840fcd55907c414b..5a0320b4ad87055280c4fba4deb0cdc9b7557c50 100644 --- a/browser/app/winlauncher/LauncherProcessWin.cpp +++ b/browser/app/winlauncher/LauncherProcessWin.cpp -@@ -23,6 +23,7 @@ +@@ -24,6 +24,7 @@ #include "mozilla/WinHeaderOnlyUtils.h" #include "nsWindowsHelpers.h" @@ -70,7 +70,7 @@ index 4460774865769609b66c0710f7c83f4d5c02b6fa..2ca95607b9b093218d48f83adc95c514 #include #include -@@ -359,8 +360,19 @@ Maybe LauncherMain(int& argc, wchar_t* argv[], +@@ -430,8 +431,18 @@ Maybe LauncherMain(int& argc, wchar_t* argv[], HANDLE stdHandles[] = {::GetStdHandle(STD_INPUT_HANDLE), ::GetStdHandle(STD_OUTPUT_HANDLE), ::GetStdHandle(STD_ERROR_HANDLE)}; @@ -78,8 +78,7 @@ index 4460774865769609b66c0710f7c83f4d5c02b6fa..2ca95607b9b093218d48f83adc95c514 attrs.AddInheritableHandles(stdHandles); + // Playwright pipe installation. + bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, L"juggler-pipe", -+ static_cast(nullptr), ++ mozilla::CheckArg(argc, argv, "juggler-pipe", nullptr, + mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; + if (hasJugglerPipe) { + intptr_t stdio3 = _get_osfhandle(3); @@ -92,10 +91,10 @@ index 4460774865769609b66c0710f7c83f4d5c02b6fa..2ca95607b9b093218d48f83adc95c514 DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; diff --git a/browser/installer/allowed-dupes.mn b/browser/installer/allowed-dupes.mn -index b59fe4b1854fec7cb329139f9c6773498fb9de51..29973af04902848808e850b40bf85e5f694d349a 100644 +index 6ab29ba31e937e1c5bb1208a9a2508ff0496fd02..7989da51c5368fa80cc66cccdfc018a9b3fb2f38 100644 --- a/browser/installer/allowed-dupes.mn +++ b/browser/installer/allowed-dupes.mn -@@ -71,6 +71,12 @@ browser/features/webcompat@mozilla.org/shims/empty-shim.txt +@@ -67,6 +67,12 @@ browser/features/webcompat@mozilla.org/shims/empty-shim.txt removed-files #endif @@ -109,26 +108,24 @@ index b59fe4b1854fec7cb329139f9c6773498fb9de51..29973af04902848808e850b40bf85e5f gmp-clearkey/0.1/manifest.json i686/gmp-clearkey/0.1/manifest.json diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in -index 73a41dc25b9ad674750ce5849a9db8f9878e5e11..e669054d361a148fff895ee24d1ea28c11d0a484 100644 +index 8caff8de9465e44c3535448622386c9a0b8034c2..ea498cce8de6ee099fb36eb640590d0fdace081b 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in -@@ -198,6 +198,11 @@ +@@ -195,6 +195,9 @@ @RESPATH@/chrome/remote.manifest #endif +@RESPATH@/chrome/juggler@JAREXT@ +@RESPATH@/chrome/juggler.manifest -+@RESPATH@/components/juggler.manifest -+@RESPATH@/components/juggler.js + - #if defined(ENABLE_TESTS) && defined(MOZ_DEBUG) - @RESPATH@/components/TestInterfaceJS.js - @RESPATH@/components/TestInterfaceJS.manifest + ; [Extensions] + @RESPATH@/components/extensions-toolkit.manifest + @RESPATH@/browser/components/extensions-browser.manifest diff --git a/devtools/server/socket/websocket-server.js b/devtools/server/socket/websocket-server.js -index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c2835307f88 100644 +index a32156978aacd7c8cbe9001250bfa1516dbc360f..ff03ff48b505ef8a9117671bf21e8b0e8214ec1f 100644 --- a/devtools/server/socket/websocket-server.js +++ b/devtools/server/socket/websocket-server.js -@@ -133,13 +133,12 @@ function writeHttpResponse(output, response) { +@@ -134,13 +134,12 @@ function writeHttpResponse(output, response) { * Process the WebSocket handshake headers and return the key to be sent in * Sec-WebSocket-Accept response header. */ @@ -144,7 +141,7 @@ index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c28 throw new Error("The handshake request has unknown path"); } -@@ -189,13 +188,13 @@ function computeKey(key) { +@@ -190,13 +189,13 @@ function computeKey(key) { /** * Perform the server part of a WebSocket opening handshake on an incoming connection. */ @@ -160,7 +157,7 @@ index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c28 // Send response headers await writeHttpResponse(output, [ -@@ -217,8 +216,8 @@ const serverHandshake = async function(input, output) { +@@ -218,8 +217,8 @@ const serverHandshake = async function(input, output) { * Performs the WebSocket handshake and waits for the WebSocket to open. * Returns Promise with a WebSocket ready to send and receive messages. */ @@ -172,10 +169,10 @@ index 040c7b124dec6bb254563bbe74fe50012cb077a3..b4e6b8132786af70e8ad0dce88b67c28 const transportProvider = { setListener(upgradeListener) { diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp -index 2eb25e3e50f8865a1788e1043187eb78f5efc72f..a3435e5f28cc4932b530ae9890f0d8591f22c717 100644 +index 70191dfea28fb10c9f663f88b8cb9ce1ed240baf..b8eb68fca242e4cbe760545456e957cade24fbcb 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp -@@ -111,6 +111,20 @@ struct ParamTraits +@@ -112,6 +112,20 @@ struct ParamTraits mozilla::dom::PrefersColorSchemeOverride::None, mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {}; @@ -196,7 +193,7 @@ index 2eb25e3e50f8865a1788e1043187eb78f5efc72f..a3435e5f28cc4932b530ae9890f0d859 template <> struct ParamTraits : public ContiguousEnumSerializer< -@@ -2780,6 +2794,40 @@ void BrowsingContext::DidSet(FieldIndex, +@@ -2728,6 +2742,40 @@ void BrowsingContext::DidSet(FieldIndex, PresContextAffectingFieldChanged(); } @@ -238,10 +235,10 @@ index 2eb25e3e50f8865a1788e1043187eb78f5efc72f..a3435e5f28cc4932b530ae9890f0d859 nsString&& aOldValue) { MOZ_ASSERT(IsTop()); diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h -index e0b091feba6ce38e57681c62c386d3b70234de1f..4fae381a8bded7ae004ccb25187b3ace559fea41 100644 +index 9fd16974c089f6ad6eedc19c95a8a7d7af65cdf2..ed5296df0c78e57e5f00e0d339e9376c140c6ab0 100644 --- a/docshell/base/BrowsingContext.h +++ b/docshell/base/BrowsingContext.h -@@ -176,10 +176,10 @@ enum class ExplicitActiveStatus : uint8_t { +@@ -198,10 +198,10 @@ struct EmbedderColorSchemes { FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \ /* ScreenOrientation-related APIs */ \ FIELD(CurrentOrientationAngle, float) \ @@ -254,9 +251,9 @@ index e0b091feba6ce38e57681c62c386d3b70234de1f..4fae381a8bded7ae004ccb25187b3ace FIELD(EmbedderElementType, Maybe) \ FIELD(MessageManagerGroup, nsString) \ FIELD(MaxTouchPointsOverride, uint8_t) \ -@@ -217,6 +217,10 @@ enum class ExplicitActiveStatus : uint8_t { +@@ -239,6 +239,10 @@ struct EmbedderColorSchemes { * embedder element. */ \ - FIELD(EmbedderColorScheme, dom::PrefersColorSchemeOverride) \ + FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \ FIELD(DisplayMode, dom::DisplayMode) \ + /* playwright addition */ \ + FIELD(PrefersReducedMotionOverride, dom::PrefersReducedMotionOverride) \ @@ -265,7 +262,18 @@ index e0b091feba6ce38e57681c62c386d3b70234de1f..4fae381a8bded7ae004ccb25187b3ace /* The number of entries added to the session history because of this \ * browsing context. */ \ FIELD(HistoryEntryCount, uint32_t) \ -@@ -893,6 +897,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { +@@ -351,6 +355,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + + bool IsOwnedByProcess() const; + ++ uint64_t JugglerCurrentLoadIdentifier() const { ++ return GetCurrentLoadIdentifier() ? GetCurrentLoadIdentifier().value() : 0; ++ } ++ + bool CanHaveRemoteOuterProxies() const { + return !mIsInProcess || mDanglingRemoteOuterProxies; + } +@@ -921,6 +929,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { return GetPrefersColorSchemeOverride(); } @@ -280,8 +288,8 @@ index e0b091feba6ce38e57681c62c386d3b70234de1f..4fae381a8bded7ae004ccb25187b3ace bool IsInBFCache() const; bool AllowJavascript() const { return GetAllowJavascript(); } -@@ -1047,6 +1059,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { - +@@ -1078,6 +1094,23 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache { + void WalkPresContexts(Callback&&); void PresContextAffectingFieldChanged(); + bool CanSet(FieldIndex, @@ -304,8 +312,25 @@ index e0b091feba6ce38e57681c62c386d3b70234de1f..4fae381a8bded7ae004ccb25187b3ace void DidSet(FieldIndex, nsString&& aOldValue); bool CanSet(FieldIndex, bool, ContentParent*) { +diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp +index 9a2d3ea4b9aa5689dcc0c8f54ce395cc33ddcddf..054419bc63364ab3b8c4c0596597df56a3f3d48a 100644 +--- a/docshell/base/CanonicalBrowsingContext.cpp ++++ b/docshell/base/CanonicalBrowsingContext.cpp +@@ -1448,6 +1448,12 @@ void CanonicalBrowsingContext::LoadURI(nsIURI* aURI, + return; + } + ++ { ++ nsCOMPtr observerService = mozilla::services::GetObserverService(); ++ if (observerService) { ++ observerService->NotifyObservers(ToSupports(this), "juggler-navigation-started-browser", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, loadState->GetLoadIdentifier())).get()); ++ } ++ } + LoadURI(loadState, true); + } + diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp -index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f0de2000d 100644 +index 8b71aa6dff85bb12de087285ed980849289b2d80..6be5d6c2e141080492de281c3eb6423b374579e0 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -15,6 +15,12 @@ @@ -337,7 +362,7 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f #include "mozilla/net/DocumentChannel.h" #include "mozilla/net/DocumentChannelChild.h" #include "mozilla/net/ParentChannelWrapper.h" -@@ -114,6 +122,7 @@ +@@ -113,6 +121,7 @@ #include "nsIDocShellTreeOwner.h" #include "mozilla/dom/Document.h" #include "nsHTMLDocument.h" @@ -345,7 +370,7 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f #include "nsIDocumentLoaderFactory.h" #include "nsIDOMWindow.h" #include "nsIEditingSession.h" -@@ -208,6 +217,7 @@ +@@ -207,6 +216,7 @@ #include "nsFocusManager.h" #include "nsGlobalWindow.h" #include "nsJSEnvironment.h" @@ -353,7 +378,7 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsObjectLoadingContent.h" -@@ -371,6 +381,13 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, +@@ -349,6 +359,14 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext, mAllowDNSPrefetch(true), mAllowWindowControl(true), mCSSErrorReportingEnabled(false), @@ -361,13 +386,14 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f + mOverrideHasFocus(false), + mBypassCSPEnabled(false), + mForceActiveState(false), ++ mDisallowBFCache(false), + mOnlineOverride(nsIDocShell::ONLINE_OVERRIDE_NONE), + mReducedMotionOverride(REDUCED_MOTION_OVERRIDE_NONE), + mForcedColorsOverride(FORCED_COLORS_OVERRIDE_NO_OVERRIDE), mAllowAuth(mItemType == typeContent), mAllowKeywordFixup(false), mDisableMetaRefreshWhenInactive(false), -@@ -3266,6 +3283,221 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { +@@ -3186,6 +3204,234 @@ nsDocShell::GetMessageManager(ContentFrameMessageManager** aMessageManager) { return NS_OK; } @@ -407,6 +433,19 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f + return NS_OK; +} + ++NS_IMETHODIMP ++nsDocShell::GetDisallowBFCache(bool* aEnabled) { ++ MOZ_ASSERT(aEnabled); ++ *aEnabled = mDisallowBFCache; ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsDocShell::SetDisallowBFCache(bool aEnabled) { ++ mDisallowBFCache = aEnabled; ++ return NS_OK; ++} ++ +bool nsDocShell::IsBypassCSPEnabled() { + return GetRootDocShell()->mBypassCSPEnabled; +} @@ -589,7 +628,7 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f NS_IMETHODIMP nsDocShell::GetIsNavigating(bool* aOut) { *aOut = mIsNavigating; -@@ -4896,7 +5128,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { +@@ -4865,7 +5111,7 @@ nsDocShell::GetVisibility(bool* aVisibility) { } void nsDocShell::ActivenessMaybeChanged() { @@ -598,7 +637,18 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f if (RefPtr presShell = GetPresShell()) { presShell->ActivenessMaybeChanged(); } -@@ -8633,6 +8865,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { +@@ -6798,6 +7044,10 @@ bool nsDocShell::CanSavePresentation(uint32_t aLoadType, + return false; // no entry to save into + } + ++ if (mDisallowBFCache) { ++ return false; ++ } ++ + MOZ_ASSERT(!mozilla::SessionHistoryInParent(), + "mOSHE cannot be non-null with SHIP"); + nsCOMPtr viewer = mOSHE->GetContentViewer(); +@@ -8579,6 +8829,12 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) { true, // aForceNoOpener getter_AddRefs(newBC)); MOZ_ASSERT(!newBC); @@ -611,7 +661,24 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f return rv; } -@@ -12781,6 +13019,9 @@ class OnLinkClickEvent : public Runnable { +@@ -9611,6 +9867,16 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, + nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); + + nsCOMPtr req; ++ ++ // Juggler: report navigation started for non-same-document and non-javascript ++ // navigations. ++ if (!isJavaScript && !sameDocument) { ++ nsCOMPtr observerService = ++ mozilla::services::GetObserverService(); ++ if (observerService) { ++ observerService->NotifyObservers(GetAsSupports(this), "juggler-navigation-started-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("%" PRIu64, aLoadState->GetLoadIdentifier())).get()); ++ } ++ } + rv = DoURILoad(aLoadState, aCacheKey, getter_AddRefs(req)); + + if (NS_SUCCEEDED(rv)) { +@@ -12775,6 +13041,9 @@ class OnLinkClickEvent : public Runnable { mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied, mTriggeringPrincipal); } @@ -621,7 +688,7 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f return NS_OK; } -@@ -12860,6 +13101,8 @@ nsresult nsDocShell::OnLinkClick( +@@ -12854,6 +13123,8 @@ nsresult nsDocShell::OnLinkClick( nsCOMPtr ev = new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied, aIsTrusted, aTriggeringPrincipal); @@ -631,7 +698,7 @@ index c42f9450ce1a8e1b1b77ac3c5e5dd186f2b03d9f..dfb824b4b5ae54126beba8231111e93f } diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h -index 79b2af0c0f58e00965473edb55a4e184dd225b1b..4a991cba9d77207a631b5f076c37e7f9281e9a4a 100644 +index 7eb46fa817eeaab7264afa408e091dab54e3a4c9..66fd36a03a0eb130eb631644be73a0083dfeb5e3 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -16,6 +16,7 @@ @@ -642,7 +709,7 @@ index 79b2af0c0f58e00965473edb55a4e184dd225b1b..4a991cba9d77207a631b5f076c37e7f9 #include "mozilla/dom/WindowProxyHolder.h" #include "nsCOMPtr.h" #include "nsCharsetSource.h" -@@ -76,6 +77,7 @@ class nsCommandManager; +@@ -77,6 +78,7 @@ class nsCommandManager; class nsDocShellEditorData; class nsDOMNavigationTiming; class nsDSURIContentListener; @@ -650,7 +717,7 @@ index 79b2af0c0f58e00965473edb55a4e184dd225b1b..4a991cba9d77207a631b5f076c37e7f9 class nsGlobalWindowOuter; class FramingChecker; -@@ -408,6 +410,15 @@ class nsDocShell final : public nsDocLoader, +@@ -409,6 +411,15 @@ class nsDocShell final : public nsDocLoader, void SetWillChangeProcess() { mWillChangeProcess = true; } bool WillChangeProcess() { return mWillChangeProcess; } @@ -675,7 +742,7 @@ index 79b2af0c0f58e00965473edb55a4e184dd225b1b..4a991cba9d77207a631b5f076c37e7f9 // 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 -@@ -1308,6 +1321,16 @@ class nsDocShell final : public nsDocLoader, +@@ -1312,6 +1325,17 @@ class nsDocShell final : public nsDocLoader, bool mAllowDNSPrefetch : 1; bool mAllowWindowControl : 1; bool mCSSErrorReportingEnabled : 1; @@ -683,6 +750,7 @@ index 79b2af0c0f58e00965473edb55a4e184dd225b1b..4a991cba9d77207a631b5f076c37e7f9 + bool mOverrideHasFocus : 1; + bool mBypassCSPEnabled : 1; + bool mForceActiveState : 1; ++ bool mDisallowBFCache : 1; + nsString mLanguageOverride; + RefPtr mGeolocationServiceOverride; + OnlineOverride mOnlineOverride; @@ -693,7 +761,7 @@ index 79b2af0c0f58e00965473edb55a4e184dd225b1b..4a991cba9d77207a631b5f076c37e7f9 bool mAllowKeywordFixup : 1; bool mDisableMetaRefreshWhenInactive : 1; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl -index 6b85ddd842a6d2e29f86047017b78b2007b99867..e0b56c4f85544580b9a631619fb06799ad244494 100644 +index 68f32e968c7e1bc1d0b2b2894320a177a9ae44d2..9e61465ffad927d7b3e972f753940196fc986156 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -44,6 +44,7 @@ interface nsIURI; @@ -704,7 +772,7 @@ index 6b85ddd842a6d2e29f86047017b78b2007b99867..e0b56c4f85544580b9a631619fb06799 interface nsIEditor; interface nsIEditingSession; interface nsIInputStream; -@@ -803,6 +804,41 @@ interface nsIDocShell : nsIDocShellTreeItem +@@ -784,6 +785,43 @@ interface nsIDocShell : nsIDocShellTreeItem */ void synchronizeLayoutHistoryState(); @@ -716,6 +784,8 @@ index 6b85ddd842a6d2e29f86047017b78b2007b99867..e0b56c4f85544580b9a631619fb06799 + + attribute boolean forceActiveState; + ++ attribute boolean disallowBFCache; ++ + attribute AString languageOverride; + + boolean overrideTimezone(in AString timezoneId); @@ -747,10 +817,10 @@ index 6b85ddd842a6d2e29f86047017b78b2007b99867..e0b56c4f85544580b9a631619fb06799 * 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 feaee86ca5fd78d7df8d08a737ba9b8da173feac..86f31fb2d1e6b6e667e066eaff80763855cef08e 100644 +index 20571949675bbdcf16749767fab7f3a53c3f7a7e..9ae8a32fe69bb4863049faa870af04db85e84f11 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp -@@ -3645,6 +3645,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { +@@ -3643,6 +3643,9 @@ void Document::SendToConsole(nsCOMArray& aMessages) { } void Document::ApplySettingsFromCSP(bool aSpeculative) { @@ -760,7 +830,7 @@ index feaee86ca5fd78d7df8d08a737ba9b8da173feac..86f31fb2d1e6b6e667e066eaff807638 nsresult rv = NS_OK; if (!aSpeculative) { // 1) apply settings from regular CSP -@@ -3702,6 +3705,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { +@@ -3700,6 +3703,11 @@ nsresult Document::InitCSP(nsIChannel* aChannel) { MOZ_ASSERT(!mScriptGlobalObject, "CSP must be initialized before mScriptGlobalObject is set!"); @@ -772,7 +842,7 @@ index feaee86ca5fd78d7df8d08a737ba9b8da173feac..86f31fb2d1e6b6e667e066eaff807638 // If this is a data document - no need to set CSP. if (mLoadedAsData) { return NS_OK; -@@ -4508,6 +4516,10 @@ bool Document::HasFocus(ErrorResult& rv) const { +@@ -4533,6 +4541,10 @@ bool Document::HasFocus(ErrorResult& rv) const { return false; } @@ -783,7 +853,7 @@ index feaee86ca5fd78d7df8d08a737ba9b8da173feac..86f31fb2d1e6b6e667e066eaff807638 if (!fm->IsInActiveWindow(bc)) { return false; } -@@ -17654,6 +17666,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { +@@ -18172,6 +18184,71 @@ ColorScheme Document::PreferredColorScheme(IgnoreRFP aIgnoreRFP) const { return LookAndFeel::PreferredColorSchemeForContent(); } @@ -814,7 +884,7 @@ index feaee86ca5fd78d7df8d08a737ba9b8da173feac..86f31fb2d1e6b6e667e066eaff807638 + } + } + -+ if (nsContentUtils::ShouldResistFingerprinting(this)) { ++ if (ShouldResistFingerprinting()) { + return false; + } + return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; @@ -856,10 +926,10 @@ index feaee86ca5fd78d7df8d08a737ba9b8da173feac..86f31fb2d1e6b6e667e066eaff807638 if (!sLoadingForegroundTopLevelContentDocument) { return false; diff --git a/dom/base/Document.h b/dom/base/Document.h -index 7a4ddc544948509dfe6b7998f31fb9bdf2de841e..40d92e63470091fe3497291aa631464f0ee92b71 100644 +index 0224108e91636624250054308d57ef101f80078d..02d64d601fdc542319f4ce29b71581a9eb192005 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h -@@ -4001,6 +4001,9 @@ class Document : public nsINode, +@@ -4102,6 +4102,9 @@ class Document : public nsINode, // color-scheme meta tag. ColorScheme DefaultColorScheme() const; @@ -870,10 +940,10 @@ index 7a4ddc544948509dfe6b7998f31fb9bdf2de841e..40d92e63470091fe3497291aa631464f static bool AutomaticStorageAccessPermissionCanBeGranted( diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp -index 85f28cce26f37b5df95c4a96658b9328f13b5a47..917d89943589ba4d7b065bdacb76aa281508de29 100644 +index aebd8fb26596e0f701cc2173bd60d827e987e992..8fc5bdd912c9cf71fbd6541c5ae1189f56bb6bef 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp -@@ -325,14 +325,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const { +@@ -331,14 +331,18 @@ void Navigator::GetAppName(nsAString& aAppName, CallerType aCallerType) const { * for more detail. */ /* static */ @@ -894,7 +964,7 @@ index 85f28cce26f37b5df95c4a96658b9328f13b5a47..917d89943589ba4d7b065bdacb76aa28 // Split values on commas. for (nsDependentSubstring lang : -@@ -384,7 +388,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { +@@ -390,7 +394,13 @@ void Navigator::GetLanguage(nsAString& aLanguage) { } void Navigator::GetLanguages(nsTArray& aLanguages) { @@ -909,7 +979,7 @@ index 85f28cce26f37b5df95c4a96658b9328f13b5a47..917d89943589ba4d7b065bdacb76aa28 // The returned value is cached by the binding code. The window listens to the // accept languages change and will clear the cache when needed. It has to -@@ -563,7 +573,13 @@ bool Navigator::CookieEnabled() { +@@ -569,7 +579,13 @@ bool Navigator::CookieEnabled() { return granted; } @@ -925,10 +995,10 @@ index 85f28cce26f37b5df95c4a96658b9328f13b5a47..917d89943589ba4d7b065bdacb76aa28 void Navigator::GetBuildID(nsAString& aBuildID, CallerType aCallerType, ErrorResult& aRv) const { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h -index 2a16e5e18427944f007c3f33301f2faea92f63e0..69a2037379bc03f941789814d00c7e99e58bdf0e 100644 +index 9f6b85ecfac7196cc57c1b1979313403a41d4a6c..0fe045f38c36eb0284bb7c1fb6d3346378f4ae07 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h -@@ -216,7 +216,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { +@@ -217,7 +217,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { StorageManager* Storage(); @@ -938,21 +1008,69 @@ index 2a16e5e18427944f007c3f33301f2faea92f63e0..69a2037379bc03f941789814d00c7e99 dom::MediaCapabilities* MediaCapabilities(); dom::MediaSession* MediaSession(); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp -index efc42b7f547d9b8b8a202e2130c409b3bb63e9fb..ebf11bd9ed41c061863836a96ae0cda7e37d2032 100644 +index e0458cc3e4534f6e63d00ccb2cc64cd7fc50d7dc..7e60d9134fa4816ee6e0781393be81bba069d5b3 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp -@@ -8369,7 +8369,8 @@ nsresult nsContentUtils::SendMouseEvent( +@@ -8445,7 +8445,8 @@ nsresult nsContentUtils::SendMouseEvent( bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, PreventDefaultResult* aPreventDefault, bool aIsDOMEventSynthesized, - bool aIsWidgetEventSynthesized) { + bool aIsWidgetEventSynthesized, -+ bool convertToPointer) { ++ bool convertToPointer, uint32_t aJugglerEventId) { nsPoint offset; nsCOMPtr widget = GetWidget(aPresShell, &offset); if (!widget) return NS_ERROR_FAILURE; -@@ -8428,6 +8429,7 @@ nsresult nsContentUtils::SendMouseEvent( - event.mTime = PR_IntervalNow(); +@@ -8453,6 +8454,7 @@ nsresult nsContentUtils::SendMouseEvent( + EventMessage msg; + Maybe exitFrom; + bool contextMenuKey = false; ++ bool isDragEvent = false; + if (aType.EqualsLiteral("mousedown")) { + msg = eMouseDown; + } else if (aType.EqualsLiteral("mouseup")) { +@@ -8477,6 +8479,12 @@ nsresult nsContentUtils::SendMouseEvent( + msg = eMouseHitTest; + } else if (aType.EqualsLiteral("MozMouseExploreByTouch")) { + msg = eMouseExploreByTouch; ++ } else if (aType.EqualsLiteral("dragover")) { ++ msg = eDragOver; ++ isDragEvent = true; ++ } else if (aType.EqualsLiteral("drop")) { ++ msg = eDrop; ++ isDragEvent = true; + } else { + return NS_ERROR_FAILURE; + } +@@ -8485,12 +8493,21 @@ nsresult nsContentUtils::SendMouseEvent( + aInputSourceArg = MouseEvent_Binding::MOZ_SOURCE_MOUSE; + } + +- WidgetMouseEvent event(true, msg, widget, ++ std::unique_ptr eventOwner; ++ if (isDragEvent) { ++ eventOwner.reset(new WidgetDragEvent(true, msg, widget)); ++ eventOwner->mReason = aIsWidgetEventSynthesized ++ ? WidgetMouseEvent::eSynthesized ++ : WidgetMouseEvent::eReal; ++ } else { ++ eventOwner.reset(new WidgetMouseEvent(true, msg, widget, + aIsWidgetEventSynthesized + ? WidgetMouseEvent::eSynthesized + : WidgetMouseEvent::eReal, + contextMenuKey ? WidgetMouseEvent::eContextMenuKey +- : WidgetMouseEvent::eNormal); ++ : WidgetMouseEvent::eNormal)); ++ } ++ WidgetMouseEvent& event = *eventOwner.get(); + event.pointerId = aIdentifier; + event.mModifiers = GetWidgetModifiers(aModifiers); + event.mButton = aButton; +@@ -8501,8 +8518,10 @@ nsresult nsContentUtils::SendMouseEvent( + event.mPressure = aPressure; + event.mInputSource = aInputSourceArg; + event.mClickCount = aClickCount; ++ event.mJugglerEventId = aJugglerEventId; event.mFlags.mIsSynthesizedForTests = aIsDOMEventSynthesized; event.mExitFrom = exitFrom; + event.convertToPointer = convertToPointer; @@ -960,59 +1078,86 @@ index efc42b7f547d9b8b8a202e2130c409b3bb63e9fb..ebf11bd9ed41c061863836a96ae0cda7 nsPresContext* presContext = aPresShell->GetPresContext(); if (!presContext) return NS_ERROR_FAILURE; diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h -index 739e8ca23c858ac2bf0356ad8c0eb0da4471d9ea..afb76693d313dc3c97fb54d014ed146a5b1bfb01 100644 +index fc0eb7adef330cddedd9f30c7085426bee2e4a19..5b37ed6ef5c9cbe41d99fd8c179d3cd68503b700 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h -@@ -2943,7 +2943,8 @@ class nsContentUtils { +@@ -2921,7 +2921,8 @@ class nsContentUtils { int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, mozilla::PreventDefaultResult* aPreventDefault, - bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized); + bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -+ bool convertToPointer = true); ++ bool convertToPointer = true, uint32_t aJugglerEventId = 0); static void FirePageShowEventForFrameLoaderSwap( nsIDocShellTreeItem* aItem, diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp -index 24771c8d8fb251cb837f2c5c43a34f2f5e921188..1ccc540f4bf0a71546117479c86a07252ca00f1d 100644 +index 5ab2b4524c9ed06cac614102b93431a80834ebf6..426d7ec6e8652d273f19bf30be32ae76c5f9ceb2 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp -@@ -683,7 +683,7 @@ nsDOMWindowUtils::SendMouseEvent( - int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, - float aPressure, unsigned short aInputSourceArg, - bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, -- int32_t aButtons, uint32_t aIdentifier, uint8_t aOptionalArgCount, -+ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, uint8_t aOptionalArgCount, - bool* aPreventDefault) { - return SendMouseEventCommon( - aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, -@@ -691,7 +691,7 @@ nsDOMWindowUtils::SendMouseEvent( +@@ -683,6 +683,26 @@ nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { + return NS_ERROR_FAILURE; + } + ++static uint32_t sJugglerEventId = 1000; ++ ++NS_IMETHODIMP ++nsDOMWindowUtils::JugglerSendMouseEvent( ++ const nsAString& aType, float aX, float aY, int32_t aButton, ++ int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, ++ float aPressure, unsigned short aInputSourceArg, ++ bool aIsDOMEventSynthesized, bool aIsWidgetEventSynthesized, ++ int32_t aButtons, uint32_t aIdentifier, bool aDisablePointerEvent, ++ uint32_t* aJugglerEventId) { ++ *aJugglerEventId = ++sJugglerEventId; ++ return SendMouseEventCommon( ++ aType, aX, aY, aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, ++ aPressure, aInputSourceArg, ++ aIdentifier, false, ++ nullptr, aIsDOMEventSynthesized, ++ aIsWidgetEventSynthesized, ++ aButtons, !aDisablePointerEvent, *aJugglerEventId); ++} ++ + NS_IMETHODIMP + nsDOMWindowUtils::SendMouseEvent( + const nsAString& aType, float aX, float aY, int32_t aButton, +@@ -697,7 +717,7 @@ nsDOMWindowUtils::SendMouseEvent( aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, false, aPreventDefault, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, - aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); -+ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, !aDisablePointerEvent); ++ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, true, 0); } NS_IMETHODIMP -@@ -718,13 +718,13 @@ nsDOMWindowUtils::SendMouseEventCommon( +@@ -715,7 +735,7 @@ nsDOMWindowUtils::SendMouseEventToWindow( + aOptionalArgCount >= 7 ? aIdentifier : DEFAULT_MOUSE_POINTER_ID, true, + nullptr, aOptionalArgCount >= 4 ? aIsDOMEventSynthesized : true, + aOptionalArgCount >= 5 ? aIsWidgetEventSynthesized : false, +- aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED); ++ aOptionalArgCount >= 6 ? aButtons : MOUSE_BUTTONS_NOT_SPECIFIED, 0); + } + + NS_IMETHODIMP +@@ -724,13 +744,13 @@ nsDOMWindowUtils::SendMouseEventCommon( int32_t aClickCount, int32_t aModifiers, bool aIgnoreRootScrollFrame, float aPressure, unsigned short aInputSourceArg, uint32_t aPointerId, bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, - bool aIsWidgetEventSynthesized, int32_t aButtons) { -+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer) { ++ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer, uint32_t aJugglerEventId) { RefPtr presShell = GetPresShell(); PreventDefaultResult preventDefaultResult; nsresult rv = nsContentUtils::SendMouseEvent( presShell, aType, aX, aY, aButton, aButtons, aClickCount, aModifiers, aIgnoreRootScrollFrame, aPressure, aInputSourceArg, aPointerId, aToWindow, - &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized); -+ &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer); ++ &preventDefaultResult, aIsDOMEventSynthesized, aIsWidgetEventSynthesized, aConvertToPointer, aJugglerEventId); if (aPreventDefault) { *aPreventDefault = preventDefaultResult != PreventDefaultResult::No; diff --git a/dom/base/nsDOMWindowUtils.h b/dom/base/nsDOMWindowUtils.h -index 30e0fafa77857c33e9871259a6ac0cebac965df8..3d8810abcfac1c220529b4e6163b0159475723ff 100644 +index 63968c9b7a4e418e4c0de6e7a75fa215a36a9105..decf3ea3833ccdffd49a7aded2d600f9416e8306 100644 --- a/dom/base/nsDOMWindowUtils.h +++ b/dom/base/nsDOMWindowUtils.h @@ -93,7 +93,7 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils, @@ -1020,15 +1165,15 @@ index 30e0fafa77857c33e9871259a6ac0cebac965df8..3d8810abcfac1c220529b4e6163b0159 float aPressure, unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow, bool* aPreventDefault, bool aIsDOMEventSynthesized, - bool aIsWidgetEventSynthesized, int32_t aButtons); -+ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true); ++ bool aIsWidgetEventSynthesized, int32_t aButtons, bool aConvertToPointer = true, uint32_t aJugglerEventId = 0); MOZ_CAN_RUN_SCRIPT nsresult SendTouchEventCommon( diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp -index 6f226bbe93a5ba7621bcdeb910ff62568ae600d1..cca5be36464557439b7d119e97a173420b1bc4e2 100644 +index 2b5f95d4c68d0a854d65471bdf9fff2dd166f73e..b5c5cb37c662a91536ce0ab6a2e10e8e6d93712b 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp -@@ -1610,6 +1610,10 @@ void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags, +@@ -1656,6 +1656,10 @@ Maybe nsFocusManager::SetFocusInner(Element* aNewContent, (GetActiveBrowsingContext() == newRootBrowsingContext); } @@ -1038,8 +1183,8 @@ index 6f226bbe93a5ba7621bcdeb910ff62568ae600d1..cca5be36464557439b7d119e97a17342 + // Exit fullscreen if a website focuses another window if (StaticPrefs::full_screen_api_exit_on_windowRaise() && - !isElementInActiveWindow && (aFlags & FLAG_RAISE) && -@@ -2929,7 +2933,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, + !isElementInActiveWindow && (aFlags & FLAG_RAISE)) { +@@ -2935,7 +2939,9 @@ void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, } } @@ -1051,10 +1196,10 @@ index 6f226bbe93a5ba7621bcdeb910ff62568ae600d1..cca5be36464557439b7d119e97a17342 // 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 674353189dca391077370b899b69041305c440ca..5069dd0a761e5fd666d3ae4506cd6292fdbc92d3 100644 +index 9ac866bf9e6dc753088ce6d6b7d474075a3adfb1..52ca8ef4e9324a974fa7cd6d101d050e3d61eabc 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp -@@ -2478,7 +2478,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, +@@ -2483,7 +2483,7 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, &nsGlobalWindowInner::FireOnNewGlobalObject)); } @@ -1063,7 +1208,7 @@ index 674353189dca391077370b899b69041305c440ca..5069dd0a761e5fd666d3ae4506cd6292 // We should probably notify. However if this is the, arguably bad, // situation when we're creating a temporary non-chrome-about-blank // document in a chrome docshell, don't notify just yet. Instead wait -@@ -2497,10 +2497,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, +@@ -2502,10 +2502,16 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument, }(); if (!isContentAboutBlankInChromeDocshell) { @@ -1084,7 +1229,7 @@ index 674353189dca391077370b899b69041305c440ca..5069dd0a761e5fd666d3ae4506cd6292 } } -@@ -2621,6 +2627,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { +@@ -2626,6 +2632,19 @@ void nsGlobalWindowOuter::DispatchDOMWindowCreated() { } } @@ -1104,26 +1249,11 @@ index 674353189dca391077370b899b69041305c440ca..5069dd0a761e5fd666d3ae4506cd6292 void nsGlobalWindowOuter::ClearStatus() { SetStatusOuter(u""_ns); } void nsGlobalWindowOuter::SetDocShell(nsDocShell* aDocShell) { -@@ -3734,6 +3753,14 @@ Maybe nsGlobalWindowOuter::GetRDMDeviceSize( - } - } - } -+ if (topInProcessContentDoc) { -+ nsIDocShell* docShell = topInProcessContentDoc->GetDocShell(); -+ if (docShell && docShell->GetDeviceSizeIsPageSize()) { -+ nsPresContext* presContext = docShell->GetPresContext(); -+ if (presContext) -+ return Some(CSSPixel::FromAppUnitsRounded(presContext->GetVisibleArea().Size())); -+ } -+ } - return Nothing(); - } - diff --git a/dom/base/nsGlobalWindowOuter.h b/dom/base/nsGlobalWindowOuter.h -index 70cea10edfd5445c93900c876dbbcaa07dccf23b..814f29ac5fbd08e4b5b458995aa7ed17d16b5fce 100644 +index d74c8c066a6005583f06821de8be1e96f94edc04..357bbc5b34ee7c6868f8e5f8e8367623f3868bd1 100644 --- a/dom/base/nsGlobalWindowOuter.h +++ b/dom/base/nsGlobalWindowOuter.h -@@ -330,6 +330,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, +@@ -334,6 +334,7 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget, // Outer windows only. void DispatchDOMWindowCreated(); @@ -1132,10 +1262,10 @@ index 70cea10edfd5445c93900c876dbbcaa07dccf23b..814f29ac5fbd08e4b5b458995aa7ed17 // Outer windows only. virtual void EnsureSizeAndPositionUpToDate() override; diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp -index 88e24213ce8f052d1bbe00c4fcb385aa70496552..1810403a058c8eee5e7c2ec2ccaa387a28f6b13a 100644 +index 9f9a6d7c5fb6868a5eba3eaea9964850ba135729..727dbc65f00289a01d270ac5ebee5b96d03e3a00 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp -@@ -1324,6 +1324,62 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, +@@ -1348,6 +1348,61 @@ void nsINode::GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, mozilla::GetBoxQuadsFromWindowOrigin(this, aOptions, aResult, aRv); } @@ -1181,11 +1311,10 @@ index 88e24213ce8f052d1bbe00c4fcb385aa70496552..1810403a058c8eee5e7c2ec2ccaa387a + nsPresContext::CSSPixelsToAppUnits(w), + nsPresContext::CSSPixelsToAppUnits(h)); + } -+ presShell->ScrollFrameRectIntoView( -+ primaryFrame, rect, -+ nsMargin(), -+ ScrollAxis(kScrollToCenter, WhenToScroll::Always), -+ ScrollAxis(kScrollToCenter, WhenToScroll::Always), ++ presShell->ScrollFrameIntoView( ++ primaryFrame, Some(rect), ++ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), ++ ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotFullyVisible), + ScrollFlags::ScrollOverflowHidden); + // If a _visual_ scroll update is pending, cancel it; otherwise, it will + // clobber next scroll (e.g. subsequent window.scrollTo(0, 0) wlll break). @@ -1199,10 +1328,10 @@ index 88e24213ce8f052d1bbe00c4fcb385aa70496552..1810403a058c8eee5e7c2ec2ccaa387a DOMQuad& aQuad, const GeometryNode& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h -index 56adeeb339ec7dcf63785b46c194c38614e2b000..0421f57f310c397438090cbd3f4b4290cc21151b 100644 +index a168cd34eaa0baf6b79e8903c5475ace70d2dc17..5ec87aa5ac57724b332ce728924979177d247907 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h -@@ -2131,6 +2131,10 @@ class nsINode : public mozilla::dom::EventTarget { +@@ -2181,6 +2181,10 @@ class nsINode : public mozilla::dom::EventTarget { nsTArray>& aResult, ErrorResult& aRv); @@ -1214,7 +1343,7 @@ index 56adeeb339ec7dcf63785b46c194c38614e2b000..0421f57f310c397438090cbd3f4b4290 DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, const ConvertCoordinateOptions& aOptions, CallerType aCallerType, diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp -index 2b8e5f7f34ee91034ddd53c858937e0f67008645..7bb979dadfa1811593d4cc3fcb306f35b2b34093 100644 +index 86fe04583c34bd84f7239c3515c9f335d84f48a2..b6705bc48f216e856b556349d206756a0cf91867 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -169,6 +169,11 @@ bool nsJSUtils::GetScopeChainForElement( @@ -1230,7 +1359,7 @@ index 2b8e5f7f34ee91034ddd53c858937e0f67008645..7bb979dadfa1811593d4cc3fcb306f35 void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h -index 85a21e459305f556933f4dc0fa7441d8f9ed95a9..d7cb86479ba2ed06542307349d6d86dfd026d55d 100644 +index 67682173f45c6a83cbad176c2922263d4f7dece9..7dd97f27bdf07673289fce62aaebe3b96492a2eb 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -78,6 +78,7 @@ class nsJSUtils { @@ -1242,10 +1371,10 @@ index 85a21e459305f556933f4dc0fa7441d8f9ed95a9..d7cb86479ba2ed06542307349d6d86df static bool DumpEnabled(); diff --git a/dom/chrome-webidl/BrowsingContext.webidl b/dom/chrome-webidl/BrowsingContext.webidl -index 414e8367d19057d3249f07f6590fc84534406bf3..5872741f2e22d500cd3b939e66e730aaac5ad717 100644 +index 51e8ede57dc8432335e5038cd35fe6395c3b65dd..b9383fbd5828c93221942dbe5664e9348ddcc82d 100644 --- a/dom/chrome-webidl/BrowsingContext.webidl +++ b/dom/chrome-webidl/BrowsingContext.webidl -@@ -52,6 +52,24 @@ enum PrefersColorSchemeOverride { +@@ -53,6 +53,24 @@ enum PrefersColorSchemeOverride { "dark", }; @@ -1270,7 +1399,7 @@ index 414e8367d19057d3249f07f6590fc84534406bf3..5872741f2e22d500cd3b939e66e730aa /** * Allowed overrides of platform/pref default behaviour for touch events. */ -@@ -186,6 +204,12 @@ interface BrowsingContext { +@@ -199,6 +217,12 @@ interface BrowsingContext { // Color-scheme simulation, for DevTools. [SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride; @@ -1283,8 +1412,17 @@ index 414e8367d19057d3249f07f6590fc84534406bf3..5872741f2e22d500cd3b939e66e730aa /** * A unique identifier for the browser element that is hosting this * BrowsingContext tree. Every BrowsingContext in the element's tree will +@@ -257,6 +281,8 @@ interface BrowsingContext { + undefined resetLocationChangeRateLimit(); + + readonly attribute long childOffset; ++ ++ readonly attribute unsigned long long jugglerCurrentLoadIdentifier; + }; + + BrowsingContext includes LoadContextMixin; diff --git a/dom/geolocation/Geolocation.cpp b/dom/geolocation/Geolocation.cpp -index 5b85084f551faa37ed41a3f7c15482b68b653937..b0886dc9fdd5740d24359aed29d45351599950e1 100644 +index ff6fe276e3f5a19e3e22d98c4a38222880797d99..96157d17485534f97a4e39675ee77808ac495bfe 100644 --- a/dom/geolocation/Geolocation.cpp +++ b/dom/geolocation/Geolocation.cpp @@ -23,6 +23,7 @@ @@ -1308,7 +1446,7 @@ index 5b85084f551faa37ed41a3f7c15482b68b653937..b0886dc9fdd5740d24359aed29d45351 CachedPositionAndAccuracy lastPosition = gs->GetCachedPosition(); if (lastPosition.position) { EpochTimeStamp cachedPositionTime_ms; -@@ -436,8 +435,7 @@ void nsGeolocationRequest::Shutdown() { +@@ -441,8 +440,7 @@ void nsGeolocationRequest::Shutdown() { // If there are no other high accuracy requests, the geolocation service will // notify the provider to switch to the default accuracy. if (mOptions && mOptions->mEnableHighAccuracy) { @@ -1318,7 +1456,7 @@ index 5b85084f551faa37ed41a3f7c15482b68b653937..b0886dc9fdd5740d24359aed29d45351 if (gs) { gs->UpdateAccuracy(); } -@@ -727,8 +725,14 @@ void nsGeolocationService::StopDevice() { +@@ -732,8 +730,14 @@ void nsGeolocationService::StopDevice() { StaticRefPtr nsGeolocationService::sService; already_AddRefed @@ -1334,7 +1472,7 @@ index 5b85084f551faa37ed41a3f7c15482b68b653937..b0886dc9fdd5740d24359aed29d45351 if (nsGeolocationService::sService) { result = nsGeolocationService::sService; -@@ -820,7 +824,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { +@@ -825,7 +829,9 @@ nsresult Geolocation::Init(nsPIDOMWindowInner* aContentDom) { // If no aContentDom was passed into us, we are being used // by chrome/c++ and have no mOwner, no mPrincipal, and no need // to prompt. @@ -1346,7 +1484,7 @@ index 5b85084f551faa37ed41a3f7c15482b68b653937..b0886dc9fdd5740d24359aed29d45351 mService->AddLocator(this); } diff --git a/dom/geolocation/Geolocation.h b/dom/geolocation/Geolocation.h -index 5c0d2f96a22c6928d6aee5a226032c0944ae7a54..5a7bb1f6cea1946eea143dca4e2f1e19746a04a4 100644 +index 7e1af00d05fbafa2d828e2c7e4dcc5c82d115f5b..e85af9718d064e4d2865bc944e9d4ba1efb9a5d7 100644 --- a/dom/geolocation/Geolocation.h +++ b/dom/geolocation/Geolocation.h @@ -31,6 +31,7 @@ @@ -1383,18 +1521,18 @@ index 5c0d2f96a22c6928d6aee5a226032c0944ae7a54..5a7bb1f6cea1946eea143dca4e2f1e19 ~Geolocation(); diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp -index c8888eb6cfb0319e83d711d6958f8d03faf409d7..878a72a2aa005fd2ee7ac0290706629b66ddb837 100644 +index 3f7e20e43a9b048c1e24e41b79fa0da08ba68ac4..f9b58311ff73ce69f2f24cad75ad9632c5490fce 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp -@@ -53,6 +53,7 @@ - #include "nsMappedAttributes.h" - #include "nsIFormControl.h" +@@ -58,6 +58,7 @@ #include "mozilla/dom/Document.h" + #include "mozilla/dom/HTMLDataListElement.h" + #include "mozilla/dom/HTMLOptionElement.h" +#include "nsDocShell.h" #include "nsIFormControlFrame.h" #include "nsITextControlFrame.h" #include "nsIFrame.h" -@@ -746,6 +747,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { +@@ -780,6 +781,12 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) { return NS_ERROR_FAILURE; } @@ -1408,83 +1546,140 @@ index c8888eb6cfb0319e83d711d6958f8d03faf409d7..878a72a2aa005fd2ee7ac0290706629b return NS_OK; } diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl -index c16b813f29d8a519673129bb7debaaec0430145a..6f82922ac7e889e55beda7d43da3ebe6adeb7ca9 100644 +index 25633e4ed848996efb790f4d462d00cbffa13f6d..dc21dcafe7561c3bf226d5190670a1f9b389266b 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl -@@ -375,7 +375,8 @@ interface nsIDOMWindowUtils : nsISupports { - [optional] in boolean aIsDOMEventSynthesized, - [optional] in boolean aIsWidgetEventSynthesized, +@@ -374,6 +374,26 @@ interface nsIDOMWindowUtils : nsISupports { [optional] in long aButtons, -- [optional] in unsigned long aIdentifier); -+ [optional] in unsigned long aIdentifier, -+ [optional] in boolean aDisablePointerEvent); + [optional] in unsigned long aIdentifier); ++ /** ++ * Playwright: a separate method to dispatch mouse event with a ++ * specific `jugglerEventId`. ++ */ ++ [can_run_script] ++ unsigned long jugglerSendMouseEvent(in AString aType, ++ in float aX, ++ in float aY, ++ in long aButton, ++ in long aClickCount, ++ in long aModifiers, ++ in boolean aIgnoreRootScrollFrame, ++ in float aPressure, ++ in unsigned short aInputSourceArg, ++ in boolean aIsDOMEventSynthesized, ++ in boolean aIsWidgetEventSynthesized, ++ in long aButtons, ++ in unsigned long aIdentifier, ++ in boolean aDisablePointerEvent); ++ /** Synthesize a touch event. The event types supported are: * touchstart, touchend, touchmove, and touchcancel + * +diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp +index 591128fe5f76f0a1bbe5091a67ae7ac6d2364b68..4b23faa0eeb5262ddf233efd8dd1c899eb7c8e02 100644 +--- a/dom/ipc/BrowserChild.cpp ++++ b/dom/ipc/BrowserChild.cpp +@@ -1678,6 +1678,21 @@ void BrowserChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent, + if (postLayerization) { + postLayerization->Register(); + } ++ ++ // Playwright: notify content that mouse event has been received and handled. ++ nsCOMPtr observerService = ++ mozilla::services::GetObserverService(); ++ if (observerService && aEvent.mJugglerEventId) { ++ if (aEvent.mMessage == eMouseUp) { ++ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mouseup %" PRIu32, aEvent.mJugglerEventId)).get()); ++ } else if (aEvent.mMessage == eMouseDown) { ++ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousedown %" PRIu32, aEvent.mJugglerEventId)).get()); ++ } else if (aEvent.mMessage == eMouseMove) { ++ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("mousemove %" PRIu32, aEvent.mJugglerEventId)).get()); ++ } else if (aEvent.mMessage == eContextMenu) { ++ observerService->NotifyObservers(nullptr, "juggler-mouse-event-hit-renderer", NS_ConvertASCIItoUTF16(nsPrintfCString("contextmenu %" PRIu32, aEvent.mJugglerEventId)).get()); ++ } ++ } + } + + mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityRealMouseButtonEvent( +diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp +index 5aa445d2e0a6169e57c44569974d557b3baf7064..671f71979b407f0ca17c66f13805e851ba30479e 100644 +--- a/dom/ipc/CoalescedMouseData.cpp ++++ b/dom/ipc/CoalescedMouseData.cpp +@@ -67,6 +67,9 @@ bool CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent, + mCoalescedInputEvent->pointerId == aEvent.pointerId && + mCoalescedInputEvent->mButton == aEvent.mButton && + mCoalescedInputEvent->mButtons == aEvent.mButtons && mGuid == aGuid && ++ // `mJugglerEventId` is 0 for non-juggler events and a unique number for ++ // juggler-emitted events. ++ mCoalescedInputEvent->mJugglerEventId == aEvent.mJugglerEventId && + mInputBlockId == aInputBlockId); + } + diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -index 9d4e8fbbfe8d45cc6245c7659423004ad1ceedeb..f955c7bace3cedfe0469e59a5e8c5824158c4d50 100644 +index c5fc05f772900dd6d30b252783adb96dfbbde2a1..86d88db3ff9e411adf9fecb114e9ced1af29b610 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc -@@ -123,10 +123,11 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8, +@@ -132,11 +132,12 @@ int32_t ScreenDeviceInfoImpl::GetOrientation(const char* aDeviceUniqueIdUTF8, return 0; } --VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t id, -+VideoCaptureModuleEx* DesktopCaptureImpl::Create(const int32_t id, - const char* uniqueId, -- const CaptureDeviceType type) { -- return new rtc::RefCountedObject(id, uniqueId, type); -+ const CaptureDeviceType type, -+ bool captureCursor) { -+ return new rtc::RefCountedObject(id, uniqueId, type, captureCursor); +-VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t aModuleId, ++VideoCaptureModuleEx* DesktopCaptureImpl::Create(const int32_t aModuleId, + const char* aUniqueId, +- const CaptureDeviceType aType) { ++ const CaptureDeviceType aType, ++ bool aCaptureCursor) { + return new rtc::RefCountedObject(aModuleId, aUniqueId, +- aType); ++ aType, aCaptureCursor); } int32_t WindowDeviceInfoImpl::Init() { -@@ -358,9 +359,13 @@ int32_t DesktopCaptureImpl::Init() { - DesktopCapturer::SourceId sourceId = atoi(_deviceUniqueId.c_str()); - pWindowCapturer->SelectSource(sourceId); +@@ -436,8 +437,12 @@ int32_t DesktopCaptureImpl::EnsureCapturer() { + DesktopCapturer::SourceId sourceId = atoi(mDeviceUniqueId.c_str()); + windowCapturer->SelectSource(sourceId); -- desktop_capturer_cursor_composer_ = -- std::unique_ptr( -- new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); +- mCapturer = std::make_unique( +- std::move(windowCapturer), options); + if (capture_cursor_) { -+ desktop_capturer_cursor_composer_ = -+ std::unique_ptr( -+ new DesktopAndCursorComposer(std::move(pWindowCapturer), options)); ++ mCapturer = std::make_unique( ++ std::move(windowCapturer), options); + } else { -+ desktop_capturer_cursor_composer_ = std::move(pWindowCapturer); ++ mCapturer = std::move(windowCapturer); + } - } else if (_deviceType == CaptureDeviceType::Browser) { + } else if (mDeviceType == CaptureDeviceType::Browser) { // XXX We don't capture cursors, so avoid the extra indirection layer. We // could also pass null for the pMouseCursorMonitor. -@@ -377,13 +382,15 @@ int32_t DesktopCaptureImpl::Init() { +@@ -453,7 +458,8 @@ int32_t DesktopCaptureImpl::EnsureCapturer() { } - DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type) -+ const CaptureDeviceType type, -+ bool captureCursor) - : _id(id), - _deviceUniqueId(uniqueId), - _deviceType(type), - _requestedCapability(), - _rotateFrame(kVideoRotation_0), - last_capture_time_ms_(rtc::TimeMillis()), -+ capture_cursor_(captureCursor), - time_event_(EventWrapper::Create()), - #if defined(_WIN32) - capturer_thread_( -@@ -428,6 +435,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( + DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, +- const CaptureDeviceType aType) ++ const CaptureDeviceType aType, ++ bool aCaptureCursor) + : mModuleId(aId), + mTrackingId(mozilla::TrackingId(CaptureEngineToTrackingSourceStr([&] { + switch (aType) { +@@ -472,6 +478,7 @@ DesktopCaptureImpl::DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, + mDeviceType(aType), + mControlThread(mozilla::GetCurrentSerialEventTarget()), + mNextFrameMinimumTime(Timestamp::Zero()), ++ capture_cursor_(aCaptureCursor), + mRunning(false), + mCallbacks("DesktopCaptureImpl::mCallbacks") {} + +@@ -492,6 +499,19 @@ void DesktopCaptureImpl::DeRegisterCaptureDataCallback( } } +void DesktopCaptureImpl::RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&_apiCs); ++ rtc::CritScope lock(&mApiCs); + _rawFrameCallbacks.insert(rawFrameCallback); +} + +void DesktopCaptureImpl::DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) { -+ rtc::CritScope lock(&_apiCs); ++ rtc::CritScope lock(&mApiCs); + auto it = _rawFrameCallbacks.find(rawFrameCallback); + if (it != _rawFrameCallbacks.end()) { + _rawFrameCallbacks.erase(it); @@ -1492,16 +1687,16 @@ index 9d4e8fbbfe8d45cc6245c7659423004ad1ceedeb..f955c7bace3cedfe0469e59a5e8c5824 +} + int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() { - if (_dataCallBacks.empty()) { - return StopCapture(); -@@ -636,6 +656,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result result, - frameInfo.height = frame->size().height(); + { + auto callbacks = mCallbacks.Lock(); +@@ -618,6 +638,15 @@ void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result aResult, + frameInfo.height = aFrame->size().height(); frameInfo.videoType = VideoType::kARGB; + size_t videoFrameStride = + frameInfo.width * DesktopFrame::kBytesPerPixel; + { -+ rtc::CritScope cs(&_apiCs); ++ rtc::CritScope cs(&mApiCs); + for (auto rawFrameCallback : _rawFrameCallbacks) { + rawFrameCallback->OnRawFrame(videoFrame, videoFrameStride, frameInfo); + } @@ -1509,12 +1704,20 @@ index 9d4e8fbbfe8d45cc6245c7659423004ad1ceedeb..f955c7bace3cedfe0469e59a5e8c5824 + size_t videoFrameLength = frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel; - IncomingFrame(videoFrame, videoFrameLength, + diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h -index b725849dab1d1f898ab988e57a35c27e3eb44700..e2e13b0a0926475fe673fecf5e3c497569d158b3 100644 +index 162589cb0902820afae86f0def2afab7630b96aa..4b95c351d813f5af5e316ea32fc8128ca3e1c8fb 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.h +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h -@@ -46,6 +46,21 @@ namespace webrtc { +@@ -24,6 +24,7 @@ + #include "api/video/video_sink_interface.h" + #include "modules/desktop_capture/desktop_capturer.h" + #include "modules/video_capture/video_capture.h" ++#include "rtc_base/deprecated/recursive_critical_section.h" + + #include "desktop_device_info.h" + #include "mozilla/DataMutex.h" +@@ -43,6 +44,21 @@ namespace webrtc { class VideoCaptureEncodeInterface; @@ -1536,7 +1739,7 @@ index b725849dab1d1f898ab988e57a35c27e3eb44700..e2e13b0a0926475fe673fecf5e3c4975 // simulate deviceInfo interface for video engine, bridge screen/application and // real screen/application device info -@@ -158,12 +173,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { +@@ -155,13 +171,13 @@ class BrowserDeviceInfoImpl : public VideoCaptureModule::DeviceInfo { // As with video, DesktopCaptureImpl is a proxy for screen sharing // and follows the video pipeline design class DesktopCaptureImpl : public DesktopCapturer::Callback, @@ -1545,50 +1748,53 @@ index b725849dab1d1f898ab988e57a35c27e3eb44700..e2e13b0a0926475fe673fecf5e3c4975 public: /* Create a screen capture modules object */ -- static VideoCaptureModule* Create(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type); -+ static VideoCaptureModuleEx* Create(const int32_t id, const char* uniqueId, -+ const CaptureDeviceType type, -+ bool captureCursor = true); - static VideoCaptureModule::DeviceInfo* CreateDeviceInfo( - const int32_t id, const CaptureDeviceType type); - +- static VideoCaptureModule* Create( ++ static VideoCaptureModuleEx* Create( + const int32_t aModuleId, const char* aUniqueId, +- const mozilla::camera::CaptureDeviceType aType); ++ const mozilla::camera::CaptureDeviceType aType, bool aCaptureCursor = true); + + [[nodiscard]] static std::shared_ptr + CreateDeviceInfo(const int32_t aId, @@ -173,6 +189,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, void DeRegisterCaptureDataCallback( - rtc::VideoSinkInterface* dataCallback) override; + rtc::VideoSinkInterface* aCallback) override; int32_t StopCaptureIfAllClientsClose() override; + void RegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; + void DeRegisterRawFrameCallback(RawFrameCallback* rawFrameCallback) override; - int32_t SetCaptureRotation(VideoRotation rotation) override; - bool SetApplyRotation(bool enable) override; -@@ -193,7 +211,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, + int32_t SetCaptureRotation(VideoRotation aRotation) override; + bool SetApplyRotation(bool aEnable) override; +@@ -195,7 +213,8 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, protected: - DesktopCaptureImpl(const int32_t id, const char* uniqueId, -- const CaptureDeviceType type); -+ const CaptureDeviceType type, bool captureCursor); + DesktopCaptureImpl(const int32_t aId, const char* aUniqueId, +- const mozilla::camera::CaptureDeviceType aType); ++ const mozilla::camera::CaptureDeviceType aType, ++ bool aCaptureCusor); virtual ~DesktopCaptureImpl(); - int32_t DeliverCapturedFrame(webrtc::VideoFrame& captureFrame); - -@@ -215,6 +233,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - rtc::RecursiveCriticalSection _apiCs; - - std::set*> _dataCallBacks; -+ std::set _rawFrameCallbacks; - - int64_t _incomingFrameTimesNanos - [kFrameRateCountHistorySize]; // timestamp for local captured frames -@@ -237,6 +256,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, - void ProcessIter(); private: +@@ -204,6 +223,9 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, + int32_t EnsureCapturer(); + void InitOnThread(int aFramerate); + void ShutdownOnThread(); ++ ++ rtc::RecursiveCriticalSection mApiCs; ++ std::set _rawFrameCallbacks; + // DesktopCapturer::Callback interface. + void OnCaptureResult(DesktopCapturer::Result aResult, + std::unique_ptr aFrame) override; +@@ -215,6 +237,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, + const nsCOMPtr mControlThread; + // Set in StartCapture. mControlThread only. + VideoCaptureCapability mRequestedCapability; + bool capture_cursor_ = true; - // This is created on the main thread and accessed on both the main thread - // and the capturer thread. It is created prior to the capturer thread - // starting and is destroyed after it is stopped. + // This is created on mControlThread and accessed on both mControlThread and + // mCaptureThread. It is created prior to mCaptureThread starting and is + // destroyed after it is stopped. diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp -index 8c8a5810fd56512cf37635da1f43757719f06113..d2bc58fcd3b05f989f948839d574d00d0409873c 100644 +index 1f2d92bcb5d989bf9ecc044f8c51006f991b0007..9cf5dd885e658e0fe5e7ab75e7fc1f97a8d214b8 100644 --- a/dom/script/ScriptSettings.cpp +++ b/dom/script/ScriptSettings.cpp @@ -150,6 +150,30 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() { @@ -1632,7 +1838,7 @@ index 8c8a5810fd56512cf37635da1f43757719f06113..d2bc58fcd3b05f989f948839d574d00d return aGlobalOrNull; diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp -index b31ca1000cb1d7b8ca1af74b9ac0313aba053875..54abd38a35fc2b4906760c370d9f96d7f2ade0e2 100644 +index 2bc6c66de3e470786d33cf46ae14f9e20465a9fd..ce4a35adf82fc99e5a12181c06f2b9f97880ea74 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -127,6 +127,11 @@ void CSP_ApplyMetaCSPToDoc(mozilla::dom::Document& aDoc, @@ -1648,7 +1854,7 @@ index b31ca1000cb1d7b8ca1af74b9ac0313aba053875..54abd38a35fc2b4906760c370d9f96d7 nsContentUtils::TrimWhitespace( aPolicyStr)); diff --git a/dom/webidl/GeometryUtils.webidl b/dom/webidl/GeometryUtils.webidl -index 2f71b284ee5f7e11f117c447834b48355784448c..ddcc545da1efec5784273b032efa00ad8b89fec0 100644 +index 2f71b284ee5f7e11f117c447834b48355784448c..2640bd57123c2b03bf4b06a2419cd020ba95f155 100644 --- a/dom/webidl/GeometryUtils.webidl +++ b/dom/webidl/GeometryUtils.webidl @@ -16,6 +16,8 @@ dictionary BoxQuadOptions { @@ -1665,16 +1871,16 @@ index 2f71b284ee5f7e11f117c447834b48355784448c..ddcc545da1efec5784273b032efa00ad sequence getBoxQuads(optional BoxQuadOptions options = {}); + [ChromeOnly, Throws, Func="nsINode::HasBoxQuadsSupport"] -+ void scrollRectIntoViewIfNeeded(long x, long y, long w, long h); ++ undefined scrollRectIntoViewIfNeeded(long x, long y, long w, long h); + /* getBoxQuadsFromWindowOrigin is similar to getBoxQuads, but the * returned quads are further translated relative to the window * origin -- which is not the layout origin. Further translation diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp -index 1422ee80d2ac3cf24304f3b2318ad0bc7da7efe7..1940994c96c2c714761d242f374973b08e81d51d 100644 +index 499a2c1ef35bc7c610b4b329b9923ffee4af999a..e91fb8202ed4e2f7a0a59351d427c6dfdcb65b5e 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp -@@ -976,7 +976,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { +@@ -989,7 +989,7 @@ void PrefLanguagesChanged(const char* /* aPrefName */, void* /* aClosure */) { AssertIsOnMainThread(); nsTArray languages; @@ -1683,7 +1889,7 @@ index 1422ee80d2ac3cf24304f3b2318ad0bc7da7efe7..1940994c96c2c714761d242f374973b0 RuntimeService* runtime = RuntimeService::GetService(); if (runtime) { -@@ -1178,8 +1178,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { +@@ -1191,8 +1191,7 @@ bool RuntimeService::RegisterWorker(WorkerPrivate& aWorkerPrivate) { } // The navigator overridden properties should have already been read. @@ -1693,7 +1899,7 @@ index 1422ee80d2ac3cf24304f3b2318ad0bc7da7efe7..1940994c96c2c714761d242f374973b0 mNavigatorPropertiesLoaded = true; } -@@ -1783,6 +1782,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( +@@ -1808,6 +1807,13 @@ void RuntimeService::PropagateStorageAccessPermissionGranted( } } @@ -1707,7 +1913,7 @@ index 1422ee80d2ac3cf24304f3b2318ad0bc7da7efe7..1940994c96c2c714761d242f374973b0 template void RuntimeService::BroadcastAllWorkers(const Func& aFunc) { AssertIsOnMainThread(); -@@ -2198,6 +2204,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( +@@ -2329,6 +2335,14 @@ void PropagateStorageAccessPermissionGrantedToWorkers( } } @@ -1723,7 +1929,7 @@ index 1422ee80d2ac3cf24304f3b2318ad0bc7da7efe7..1940994c96c2c714761d242f374973b0 MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(aCx); diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h -index ef32cc847e8b86319830bb93879aaf809fe464d4..5db3be0dc87e50ff75177194ca734313b22509d6 100644 +index a770d7330edb2f99483ab0363211817ae40028b0..f677f14e2ac42c94483726bac8538b52129615cc 100644 --- a/dom/workers/RuntimeService.h +++ b/dom/workers/RuntimeService.h @@ -110,6 +110,8 @@ class RuntimeService final : public nsIObserver { @@ -1749,10 +1955,10 @@ index d10dabb5c5ff8e17851edf2bd2efc08e74584d8e..53c4070c5fde43b27fb8fbfdcf4c23d8 bool IsWorkerGlobal(JSObject* global); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp -index 957103c9baec027ed667ccea45cdde5f44961daf..2eb02b70b59c515d8c758cf576dac2b18c8df80e 100644 +index 1fc14724bc6f3fcf485e51f677c13ba328e385f7..363868b75703e29c5b0f924edac4cd927a06f97f 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp -@@ -695,6 +695,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { +@@ -704,6 +704,18 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable { } }; @@ -1771,7 +1977,7 @@ index 957103c9baec027ed667ccea45cdde5f44961daf..2eb02b70b59c515d8c758cf576dac2b1 class UpdateLanguagesRunnable final : public WorkerRunnable { nsTArray mLanguages; -@@ -1925,6 +1937,16 @@ void WorkerPrivate::UpdateContextOptions( +@@ -1982,6 +1994,16 @@ void WorkerPrivate::UpdateContextOptions( } } @@ -1788,7 +1994,7 @@ index 957103c9baec027ed667ccea45cdde5f44961daf..2eb02b70b59c515d8c758cf576dac2b1 void WorkerPrivate::UpdateLanguages(const nsTArray& aLanguages) { AssertIsOnParentThread(); -@@ -5086,6 +5108,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( +@@ -5289,6 +5311,15 @@ void WorkerPrivate::UpdateContextOptionsInternal( } } @@ -1805,10 +2011,10 @@ index 957103c9baec027ed667ccea45cdde5f44961daf..2eb02b70b59c515d8c758cf576dac2b1 const nsTArray& aLanguages) { WorkerGlobalScope* globalScope = GlobalScope(); diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h -index 1f31c4a6a94491cb6c981655e30e1fd42c4dbfc1..dbfdf4fc27f112e7cadbb768a858323f8ee919d1 100644 +index c9a7175a4da4ebb841a4a85d8c1a8b2c1f52f542..9105f4d737b991145c52f585a3932281b6abf049 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h -@@ -330,6 +330,8 @@ class WorkerPrivate final +@@ -414,6 +414,8 @@ class WorkerPrivate final void UpdateContextOptionsInternal(JSContext* aCx, const JS::ContextOptions& aContextOptions); @@ -1817,7 +2023,7 @@ index 1f31c4a6a94491cb6c981655e30e1fd42c4dbfc1..dbfdf4fc27f112e7cadbb768a858323f void UpdateLanguagesInternal(const nsTArray& aLanguages); void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, -@@ -966,6 +968,8 @@ class WorkerPrivate final +@@ -1032,6 +1034,8 @@ class WorkerPrivate final void UpdateContextOptions(const JS::ContextOptions& aContextOptions); @@ -1853,10 +2059,10 @@ index 145dd3f07112c2390325de50f8eae674484adfe6..8cb3787e1b6bb25c6a58f1d910ae7dbc Span aTimeZone) { #if MOZ_INTL_USE_ICU_CPP_TIMEZONE diff --git a/intl/components/src/TimeZone.h b/intl/components/src/TimeZone.h -index 180092bd3fc0b70462cc6ba67e72946e4c4c7604..bcaecb9fcd7b630c75289581a887cc6894733168 100644 +index 364cb45c2fafe9e419b415ee456b3411d5c38dea..ae119db52d55c3100df3d88f10c91d59b3fc07e8 100644 --- a/intl/components/src/TimeZone.h +++ b/intl/components/src/TimeZone.h -@@ -154,6 +154,8 @@ class TimeZone final { +@@ -155,6 +155,8 @@ class TimeZone final { return FillBufferWithICUCall(aBuffer, ucal_getHostTimeZone); } @@ -1866,7 +2072,7 @@ index 180092bd3fc0b70462cc6ba67e72946e4c4c7604..bcaecb9fcd7b630c75289581a887cc68 * Set the default time zone. */ diff --git a/js/public/Date.h b/js/public/Date.h -index bb69d58dc96ed7f0b37f73e26abdd0bdfeaaf556..8436d439f72287176a2fe6a1a837d3db73409e67 100644 +index 45c6a88602e078cb872d49a2f50b30a994f76d8e..90989ff259ef19af094bc6ddfabe7552b80d84f3 100644 --- a/js/public/Date.h +++ b/js/public/Date.h @@ -53,6 +53,8 @@ namespace JS { @@ -1879,10 +2085,10 @@ index bb69d58dc96ed7f0b37f73e26abdd0bdfeaaf556..8436d439f72287176a2fe6a1a837d3db inline ClippedTime TimeClip(double time); diff --git a/js/src/debugger/Object.cpp b/js/src/debugger/Object.cpp -index 1c00fed8e0dc84b12c9b1c169d841e27402579a1..ad25cb5f8a0572c9c8622f85551b79dd2ffea819 100644 +index 2ffac9f9d5fd369d5b66e7ae84da7085acd0c540..d531bd62f2599411b9395e1dd2b4f2a147e255ee 100644 --- a/js/src/debugger/Object.cpp +++ b/js/src/debugger/Object.cpp -@@ -2373,7 +2373,11 @@ Maybe DebuggerObject::call(JSContext* cx, +@@ -2431,7 +2431,11 @@ Maybe DebuggerObject::call(JSContext* cx, invokeArgs[i].set(args2[i]); } @@ -1895,10 +2101,10 @@ index 1c00fed8e0dc84b12c9b1c169d841e27402579a1..ad25cb5f8a0572c9c8622f85551b79dd } diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp -index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8eac31718cc 100644 +index 0dd93e00a1d206d7117e4404240b49a2f49bb415..6d6b394c5acf7bbd02475694661230758d0ca942 100644 --- a/js/src/vm/DateTime.cpp +++ b/js/src/vm/DateTime.cpp -@@ -178,6 +178,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { +@@ -187,6 +187,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { } } @@ -1910,7 +2116,7 @@ index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8ea void js::DateTimeInfo::updateTimeZone() { MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid); -@@ -502,10 +507,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { +@@ -529,10 +534,24 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { js::DateTimeInfo::resetTimeZone(mode); } @@ -1935,7 +2141,7 @@ index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8ea #if JS_HAS_INTL_API # if defined(XP_WIN) static bool IsOlsonCompatibleWindowsTimeZoneId(std::string_view tz) { -@@ -727,9 +746,17 @@ void js::ResyncICUDefaultTimeZone() { +@@ -750,6 +769,15 @@ static bool ReadTimeZoneLink(std::string_view tz, void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { #if JS_HAS_INTL_API @@ -1948,6 +2154,11 @@ index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8ea + return; + } + + // In the future we should not be setting a default ICU time zone at all, + // instead all accesses should go through the appropriate DateTimeInfo + // instance depending on the resist fingerprinting status. For now we return +@@ -761,7 +789,6 @@ void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { + if (const char* tzenv = std::getenv("TZ")) { std::string_view tz(tzenv); - @@ -1955,27 +2166,27 @@ index a86a6e9f7177c86624f118ebbc2e012766137bd1..5ebd1f106a556471fda5961d1f11f8ea # if defined(XP_WIN) diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h -index 3ce936fe3a4a83f9161eddc9e5289322d6a363e3..6b1c34244d8b2f2102ec423e2d96812fb5d41a9d 100644 +index 20feae33a82f1cd1262aa3679ad23aa75aaf0b38..4dbb75c0ee2d5079de7dcf04a3505e0dee2719f7 100644 --- a/js/src/vm/DateTime.h +++ b/js/src/vm/DateTime.h -@@ -63,6 +63,8 @@ enum class ResetTimeZoneMode : bool { +@@ -65,6 +65,8 @@ enum class ResetTimeZoneMode : bool { */ extern void ResetTimeZoneInternal(ResetTimeZoneMode mode); +extern void SetTimeZoneOverrideInternal(std::string timeZone); + /** - * ICU's default time zone, used for various date/time formatting operations - * that include the local time in the representation, is allowed to go stale -@@ -202,6 +204,7 @@ class DateTimeInfo { - // and js::ResyncICUDefaultTimeZone(). + * Stores date/time information, particularly concerning the current local + * time zone, and implements a small cache for daylight saving time offset +@@ -226,6 +228,7 @@ class DateTimeInfo { + private: + // The method below should only be called via js::ResetTimeZoneInternal(). friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); - friend void js::ResyncICUDefaultTimeZone(); + friend void js::SetTimeZoneOverrideInternal(std::string); static void resetTimeZone(ResetTimeZoneMode mode) { - auto guard = instance->lock(); -@@ -293,6 +296,8 @@ class DateTimeInfo { + { +@@ -322,6 +325,8 @@ class DateTimeInfo { JS::UniqueChars locale_; JS::UniqueTwoByteChars standardName_; JS::UniqueTwoByteChars daylightSavingsName_; @@ -1984,7 +2195,7 @@ index 3ce936fe3a4a83f9161eddc9e5289322d6a363e3..6b1c34244d8b2f2102ec423e2d96812f #else // Restrict the data-time range to the minimum required time_t range as // specified in POSIX. Most operating systems support 64-bit time_t -@@ -308,6 +313,8 @@ class DateTimeInfo { +@@ -337,6 +342,8 @@ class DateTimeInfo { void internalResetTimeZone(ResetTimeZoneMode mode); @@ -2044,10 +2255,10 @@ index dac899f7558b26d6848da8b98ed8a93555c8751a..2a07d67fa1c2840b25085566e84dc3b2 // No boxes to return return; diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp -index 8cd1cee03620a33e3301373bb0ba3f1f0cfa062b..7100faf245bf35af3da20dba3dc49d4f65fcb8a5 100644 +index ab8ddd3ed55f9f1d7997611abd0fc99c1a2c2d7a..224b2bc9752f52951ceb80ebae9cd3bbb08b7d33 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp -@@ -10901,7 +10901,9 @@ auto PresShell::ComputeActiveness() const -> Activeness { +@@ -10904,7 +10904,9 @@ auto PresShell::ComputeActiveness() const -> Activeness { if (!browserChild->IsVisible()) { MOZ_LOG(gLog, LogLevel::Debug, (" > BrowserChild %p is not visible", browserChild)); @@ -2059,26 +2270,26 @@ index 8cd1cee03620a33e3301373bb0ba3f1f0cfa062b..7100faf245bf35af3da20dba3dc49d4f // If the browser is visible but just due to be preserving layers diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h -index 8b434ea8977e1c3a4a9238d00477dd012a170596..1980be6beff1b4dc7720eb9518ed2b265cc675e0 100644 +index a131977e3367527596c525243a3f68cfa72d6e36..32adec9f433d9c74e78af1f32d54f6f2af1a9a4e 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h -@@ -567,6 +567,7 @@ void Gecko_MediaFeatures_GetDeviceSize(const mozilla::dom::Document*, - - float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); +@@ -632,6 +632,7 @@ float Gecko_MediaFeatures_GetResolution(const mozilla::dom::Document*); bool Gecko_MediaFeatures_PrefersReducedMotion(const mozilla::dom::Document*); + bool Gecko_MediaFeatures_PrefersReducedTransparency( + const mozilla::dom::Document*); +bool Gecko_MediaFeatures_ForcedColors(const mozilla::dom::Document*); mozilla::StylePrefersContrast Gecko_MediaFeatures_PrefersContrast( const mozilla::dom::Document*); mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp -index 2ef43008df12886ad00485ef743564774850c2ba..bb53b96ae491146d895e1c32d62dc0f2ea00812f 100644 +index 3fdb9e7c1ad6f3c7a641c6bfd9d4daca26f4a45b..f920aa3710a13e247e8b3a7a5fba4d1afe37266a 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp -@@ -260,10 +260,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { +@@ -277,10 +277,11 @@ bool Gecko_MediaFeatures_MatchesPlatform(StylePlatform aPlatform) { } bool Gecko_MediaFeatures_PrefersReducedMotion(const Document* aDocument) { -- if (nsContentUtils::ShouldResistFingerprinting(aDocument)) { +- if (aDocument->ShouldResistFingerprinting()) { - return false; - } - return LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1; @@ -2089,24 +2300,12 @@ index 2ef43008df12886ad00485ef743564774850c2ba..bb53b96ae491146d895e1c32d62dc0f2 + return aDocument->ForcedColors(); } - StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme( -diff --git a/media/libjpeg/jconfig.h b/media/libjpeg/jconfig.h -index f2723e654098ff27542e1eb16a536c11ad0af617..b0b480551ff7d895dfdeb5a9800874858929c8ba 100644 ---- a/media/libjpeg/jconfig.h -+++ b/media/libjpeg/jconfig.h -@@ -17,6 +17,7 @@ - /* #undef D_ARITH_CODING_SUPPORTED */ - - /* Support in-memory source/destination managers */ -+#define MEM_SRCDST_SUPPORTED 1 - /* #undef MEM_SRCDST_SUPPORTED */ - - /* Use accelerated SIMD routines. */ + bool Gecko_MediaFeatures_PrefersReducedTransparency(const Document* aDocument) { diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js -index 50434c8700f4e85c6b8de3f13e36423f9cfc916d..3484a503912754428fdfce6b92cb97f3745797ec 100644 +index d256c66f4d77d0342e8e0db3f2fd45f21cb2331e..edc5a33bf367c9d45354e352c51688fe28347c01 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js -@@ -4348,7 +4348,9 @@ pref("devtools.experiment.f12.shortcut_disabled", false); +@@ -4107,7 +4107,9 @@ pref("devtools.experiment.f12.shortcut_disabled", false); // doesn't provide a way to lock the pref pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); #else @@ -2116,9 +2315,9 @@ index 50434c8700f4e85c6b8de3f13e36423f9cfc916d..3484a503912754428fdfce6b92cb97f3 +pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", false); #endif - // Whether to start the private browsing mode at application startup + // Whether sites require the open-protocol-handler permission to open a diff --git a/netwerk/base/nsINetworkInterceptController.idl b/netwerk/base/nsINetworkInterceptController.idl -index e869cd28d396aa87c522241d3e63d435ee8dbae6..2d307f089209721d88d231b03e8628890b8228ea 100644 +index d72dc570dc82ff9d576942b9e7c23d8a74d68049..a5fcddc4b0e53a862e5a77120b4ccff8a27cfbab 100644 --- a/netwerk/base/nsINetworkInterceptController.idl +++ b/netwerk/base/nsINetworkInterceptController.idl @@ -59,6 +59,7 @@ interface nsIInterceptedChannel : nsISupports @@ -2130,12 +2329,12 @@ index e869cd28d396aa87c522241d3e63d435ee8dbae6..2d307f089209721d88d231b03e862889 /** * Set the status and reason for the forthcoming synthesized response. diff --git a/netwerk/protocol/http/InterceptedHttpChannel.cpp b/netwerk/protocol/http/InterceptedHttpChannel.cpp -index 019412c56ba24c06265d20a424dab4d4a850d04b..4ccb5e035fea85fe6b3393473cb620cbc9603de4 100644 +index 735b3a134a8c7104909ff9424eff74eab80c4830..a31e8b68e201dbf238d80ab32d46d4657f9b8cd7 100644 --- a/netwerk/protocol/http/InterceptedHttpChannel.cpp +++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp -@@ -663,6 +663,14 @@ void InterceptedHttpChannel::DoAsyncAbort(nsresult aStatus) { - Unused << AsyncAbort(aStatus); - } +@@ -728,6 +728,14 @@ NS_IMPL_ISUPPORTS(ResetInterceptionHeaderVisitor, nsIHttpHeaderVisitor) + + } // anonymous namespace +NS_IMETHODIMP +InterceptedHttpChannel::ResetInterceptionWithURI(nsIURI* aURI) { @@ -2147,12 +2346,31 @@ index 019412c56ba24c06265d20a424dab4d4a850d04b..4ccb5e035fea85fe6b3393473cb620cb + NS_IMETHODIMP InterceptedHttpChannel::ResetInterception(bool aBypass) { - if (mCanceled) { + INTERCEPTED_LOG(("InterceptedHttpChannel::ResetInterception [%p] bypass: %s", +@@ -1070,11 +1078,18 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) { + GetCallback(mProgressSink); + } + ++ // Playwright: main requests in firefox do not have loading principal. ++ // As they are intercepted by Playwright, they don't have ++ // serviceWorkerTainting as well. ++ // Thus these asserts are wrong for Playwright world. ++ // Note: these checks were added in https://github.com/mozilla/gecko-dev/commit/92e2cdde79c11510c3e4192e1b6264d00398ed95 ++ /* + MOZ_ASSERT_IF(!mLoadInfo->GetServiceWorkerTaintingSynthesized(), + mLoadInfo->GetLoadingPrincipal()); + // No need to do ORB checks if these conditions hold. + MOZ_DIAGNOSTIC_ASSERT(mLoadInfo->GetServiceWorkerTaintingSynthesized() || + mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()); ++ */ + + if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) { + mPump->PeekStream(CallTypeSniffers, static_cast(this)); diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp -index d956b3b5c6ecf6a983689d09e491193519f34ceb..826aabb5b794a2d4028950066ca3036223a35e0c 100644 +index 0908642956b66e867be59c5777f26e4c9f95d5ec..3d7677c454c5a0d2169686c2abad7b332f2413ce 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp -@@ -1330,6 +1330,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( +@@ -1372,6 +1372,10 @@ void nsHtml5TreeOpExecutor::UpdateReferrerInfoFromMeta( void nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); @@ -2164,10 +2382,10 @@ index d956b3b5c6ecf6a983689d09e491193519f34ceb..826aabb5b794a2d4028950066ca30362 nsCOMPtr preloadCsp = mDocument->GetPreloadCsp(); if (!preloadCsp) { diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp -index 153722c33b9db6475aa5134ad5b665051ac68658..74324d95f7088c65c3d52ab2a7c40e89901d9512 100644 +index 4ccd48215ea8500de02fbe54d79962b4d6bcfc57..57ca7a8bb78a680362f0b3b05cb10219494fcdf8 100644 --- a/security/manager/ssl/nsCertOverrideService.cpp +++ b/security/manager/ssl/nsCertOverrideService.cpp -@@ -572,7 +572,12 @@ nsCertOverrideService::HasMatchingOverride( +@@ -473,7 +473,12 @@ nsCertOverrideService::HasMatchingOverride( bool disableAllSecurityCheck = false; { MutexAutoLock lock(mMutex); @@ -2180,8 +2398,8 @@ index 153722c33b9db6475aa5134ad5b665051ac68658..74324d95f7088c65c3d52ab2a7c40e89 + } } if (disableAllSecurityCheck) { - nsCertOverride::OverrideBits all = nsCertOverride::OverrideBits::Untrusted | -@@ -789,14 +794,24 @@ static bool IsDebugger() { + *aIsTemporary = false; +@@ -690,14 +695,24 @@ static bool IsDebugger() { NS_IMETHODIMP nsCertOverrideService:: @@ -2210,22 +2428,22 @@ index 153722c33b9db6475aa5134ad5b665051ac68658..74324d95f7088c65c3d52ab2a7c40e89 nsCOMPtr nss(do_GetService(PSM_COMPONENT_CONTRACTID)); diff --git a/security/manager/ssl/nsCertOverrideService.h b/security/manager/ssl/nsCertOverrideService.h -index e601df1b13d9b2c028bffe6348d052960c80951c..0d782585199479db6218f4c72ed7b6133e3122b3 100644 +index f9d81c962aec06ccb7681d124d826f83eca743ec..aa85277808a150d766faa2130f8546cd1d6223c3 100644 --- a/security/manager/ssl/nsCertOverrideService.h +++ b/security/manager/ssl/nsCertOverrideService.h -@@ -134,6 +134,7 @@ class nsCertOverrideService final : public nsICertOverrideService, +@@ -120,6 +120,7 @@ class nsCertOverrideService final : public nsICertOverrideService, mozilla::Mutex mMutex; - bool mDisableAllSecurityCheck GUARDED_BY(mMutex); -+ mozilla::HashSet mUserContextIdsWithDisabledSecurityChecks GUARDED_BY(mMutex); - nsCOMPtr mSettingsFile GUARDED_BY(mMutex); - nsTHashtable mSettingsTable GUARDED_BY(mMutex); + bool mDisableAllSecurityCheck MOZ_GUARDED_BY(mMutex); ++ mozilla::HashSet mUserContextIdsWithDisabledSecurityChecks MOZ_GUARDED_BY(mMutex); + nsCOMPtr mSettingsFile MOZ_GUARDED_BY(mMutex); + nsTHashtable mSettingsTable MOZ_GUARDED_BY(mMutex); diff --git a/security/manager/ssl/nsICertOverrideService.idl b/security/manager/ssl/nsICertOverrideService.idl -index 3862fe6830874c036592fd217cab7ad5f4cd3e27..3166b37db0e52f7f2972d2bcb7a72ed819805794 100644 +index e31cf158dcac3540b0c721cbd677b8522d7549b3..029fc67df81911e3abf3724e8ed99e4bde010f4b 100644 --- a/security/manager/ssl/nsICertOverrideService.idl +++ b/security/manager/ssl/nsICertOverrideService.idl -@@ -201,7 +201,9 @@ interface nsICertOverrideService : nsISupports { +@@ -143,7 +143,9 @@ interface nsICertOverrideService : nsISupports { * @param aDisable If true, disable all security check and make * hasMatchingOverride always return true. */ @@ -2237,7 +2455,7 @@ index 3862fe6830874c036592fd217cab7ad5f4cd3e27..3166b37db0e52f7f2972d2bcb7a72ed8 readonly attribute boolean securityCheckDisabled; }; diff --git a/services/settings/Utils.jsm b/services/settings/Utils.jsm -index 23d6bf1a20bea134358347b43e8fc776a04617f3..12f96aece0b2c843c34815cafb80ff1b6b6528aa 100644 +index 94f47133802fd47a8a2bb800bdda8382d7ee82e5..2aa50e24dc1cb39012ed1d2b3b370cce546d28b1 100644 --- a/services/settings/Utils.jsm +++ b/services/settings/Utils.jsm @@ -103,7 +103,7 @@ function _isUndefined(value) { @@ -2250,10 +2468,10 @@ index 23d6bf1a20bea134358347b43e8fc776a04617f3..12f96aece0b2c843c34815cafb80ff1b : AppConstants.REMOTE_SETTINGS_SERVER_URL; }, diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs -index 8c93dfa24ce7810f004227fc0430338229a0bc3f..09a1f93dd027394345e910e00b765689490ac2a3 100644 +index ca59d311ef91d66e829dc3186bacc07f251d4f00..008c3c0390262010c47513565e46982b826430de 100644 --- a/servo/components/style/gecko/media_features.rs +++ b/servo/components/style/gecko/media_features.rs -@@ -224,10 +224,15 @@ pub enum ForcedColors { +@@ -290,10 +290,15 @@ pub enum ForcedColors { /// https://drafts.csswg.org/mediaqueries-5/#forced-colors fn eval_forced_colors(context: &Context, query_value: Option) -> bool { @@ -2272,11 +2490,24 @@ index 8c93dfa24ce7810f004227fc0430338229a0bc3f..09a1f93dd027394345e910e00b765689 } } +diff --git a/taskcluster/ci/toolchain/macos-sdk.yml b/taskcluster/ci/toolchain/macos-sdk.yml +index a446e90c26de1c55c57d6479cd2cf3df0ecaf508..c1880ff0dae136c66d1a91ddfc9343ed82f1ac78 100644 +--- a/taskcluster/ci/toolchain/macos-sdk.yml ++++ b/taskcluster/ci/toolchain/macos-sdk.yml +@@ -43,7 +43,7 @@ macosx64-sdk-13.0: + run: + script: unpack-sdk.py + arguments: +- - https://swdist.apple.com/content/downloads/38/50/012-70652-A_2ZHIRHCHLN/f8b81s6tzlzrj0z67ynydjx4x1lwhr08ab/CLTools_macOSNMOS_SDK.pkg ++ - https://swcdn.apple.com/content/downloads/38/50/012-70652-A_2ZHIRHCHLN/f8b81s6tzlzrj0z67ynydjx4x1lwhr08ab/CLTools_macOSNMOS_SDK.pkg + - 06f4a045854c456a553a5ee6acf678fbe26c06296fc68054ae918c206134aa20 + - Library/Developer/CommandLineTools/SDKs/MacOSX13.0.sdk + toolchain-artifact: project/gecko/mac-sdk/MacOSX13.0.sdk.tar.zst diff --git a/toolkit/components/browser/nsIWebBrowserChrome.idl b/toolkit/components/browser/nsIWebBrowserChrome.idl -index 4f7337926efbb086a2be97cdbcb3dca39e27c786..f2005cb726ff153d6b1011d6af0479dbf1af02a5 100644 +index 54de3abab5757dd706e3d909ccef6a0bed5deacc..f5c5480cd052ede0c76e5eec733dbb9283389045 100644 --- a/toolkit/components/browser/nsIWebBrowserChrome.idl +++ b/toolkit/components/browser/nsIWebBrowserChrome.idl -@@ -70,6 +70,9 @@ interface nsIWebBrowserChrome : nsISupports +@@ -71,6 +71,9 @@ interface nsIWebBrowserChrome : nsISupports // Whether this window should use out-of-process cross-origin subframes. const unsigned long CHROME_FISSION_WINDOW = 0x00200000; @@ -2286,11 +2517,11 @@ index 4f7337926efbb086a2be97cdbcb3dca39e27c786..f2005cb726ff153d6b1011d6af0479db // Prevents new window animations on MacOS and Windows. Currently // ignored for Linux. const unsigned long CHROME_SUPPRESS_ANIMATION = 0x01000000; -diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -index aecb28d95de7cc84a3e2010264a056e178cb11be..79b729d99e5d693d13223401ef72c7020c10fb1a 100644 ---- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -+++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.jsm -@@ -117,6 +117,12 @@ EnterprisePoliciesManager.prototype = { +diff --git a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs +index 0a0c9601be5cd028cf8894d2e8e32edff8e610a6..e13c1d643a941120e4bd0d2c87f8df7400020598 100644 +--- a/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs ++++ b/toolkit/components/enterprisepolicies/EnterprisePoliciesParent.sys.mjs +@@ -110,6 +110,12 @@ EnterprisePoliciesManager.prototype = { Services.prefs.clearUserPref(PREF_POLICIES_APPLIED); } @@ -2304,7 +2535,7 @@ index aecb28d95de7cc84a3e2010264a056e178cb11be..79b729d99e5d693d13223401ef72c702 if (provider.failed) { diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp -index a76e612bc7149155305468307bebf0e69679897d..ba3c5dc0af69a34fcfbf04a3dbc506ef45833107 100644 +index 34ced370120f843ab7afd330fb5626ae6f6da7e4..205fc4e5fe3adeacbfe5ab6c15d1bbccf7baf9e8 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -370,7 +370,7 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) { @@ -2317,7 +2548,7 @@ index a76e612bc7149155305468307bebf0e69679897d..ba3c5dc0af69a34fcfbf04a3dbc506ef if (windowEnumerator) { bool more; diff --git a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp -index 3e9672fdfe9ddab8acd0f8b18772aece92bb3b64..83454a9c27c96d72597445653beaa014c38728cd 100644 +index 654903fadb709be976b72f36f155e23bc0622152..815b3dc24c9fda6b1db6c4666ac68904c87ac0ab 100644 --- a/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp +++ b/toolkit/components/statusfilter/nsBrowserStatusFilter.cpp @@ -174,8 +174,8 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress* aWebProgress, @@ -2332,10 +2563,10 @@ index 3e9672fdfe9ddab8acd0f8b18772aece92bb3b64..83454a9c27c96d72597445653beaa014 int32_t aMaxSelfProgress, int32_t aCurTotalProgress, diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -index 33ffbeb8e969eccd0c40effc693d9191aab15891..386c3e76fdff6b6e60917ebf2ecf7595598ac57f 100644 +index d21b1fa97755260f09d92c0cac10e1d5233c65dd..948e4ce62d4d03ed29ecac48e04bd13eea80f8b3 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp -@@ -1814,7 +1814,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( +@@ -1877,7 +1877,11 @@ uint32_t nsWindowWatcher::CalculateChromeFlagsForContent( // Open a minimal popup. *aIsPopupRequested = true; @@ -2348,24 +2579,24 @@ index 33ffbeb8e969eccd0c40effc693d9191aab15891..386c3e76fdff6b6e60917ebf2ecf7595 } /** -diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm -index 285568a708854e5afb33268ccf8e7a2f3b4d4dcb..4667eb22474863c44e43e46f524b3362d14dcade 100644 ---- a/toolkit/mozapps/update/UpdateService.jsm -+++ b/toolkit/mozapps/update/UpdateService.jsm -@@ -3608,6 +3608,8 @@ UpdateService.prototype = { +diff --git a/toolkit/mozapps/update/UpdateService.sys.mjs b/toolkit/mozapps/update/UpdateService.sys.mjs +index b42661ca23cbfc53808f6f7dca4bbe8e9a4e3a5a..24aed9cd6c3f3281b0222c8ec40f5bd7b8984db1 100644 +--- a/toolkit/mozapps/update/UpdateService.sys.mjs ++++ b/toolkit/mozapps/update/UpdateService.sys.mjs +@@ -3855,6 +3855,8 @@ UpdateService.prototype = { }, get disabledForTesting() { -+ /* for playwright */ ++ /* playwright */ + return true; return ( (Cu.isInAutomation || lazy.Marionette.running || diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild -index 1241f1b0f94e0965b517898167ca1b52cfb48dc5..39c14eb7c548b81d564bd2a4ed15c70a920e173c 100644 +index 04453a437873b2e6339cb7e81ee11c2a5bb46bb1..2ce3151b9a97e7b86619109716a6d942b80f58ed 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild -@@ -154,6 +154,7 @@ if CONFIG['ENABLE_WEBDRIVER']: +@@ -153,6 +153,7 @@ if CONFIG['ENABLE_WEBDRIVER']: '/remote', '/testing/firefox-ui', '/testing/marionette', @@ -2374,7 +2605,7 @@ index 1241f1b0f94e0965b517898167ca1b52cfb48dc5..39c14eb7c548b81d564bd2a4ed15c70a ] diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp -index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..f993e78e02563cada8c131be3d4658bc8f7532b6 100644 +index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..28cb052c3115f91e6a036ad8466385ff1d740cd0 100644 --- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -14,9 +14,11 @@ @@ -2389,13 +2620,12 @@ index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..f993e78e02563cada8c131be3d4658bc #include #include -@@ -130,6 +132,20 @@ int wmain(int argc, WCHAR** argv) { +@@ -130,6 +132,19 @@ int wmain(int argc, WCHAR** argv) { SanitizeEnvironmentVariables(); SetDllDirectoryW(L""); + bool hasJugglerPipe = -+ mozilla::CheckArg(argc, argv, L"juggler-pipe", -+ static_cast(nullptr), ++ mozilla::CheckArg(argc, argv, "juggler-pipe", nullptr, + mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; + if (hasJugglerPipe && !mozilla::EnvHasValue("PW_PIPE_READ")) { + intptr_t stdio3 = _get_osfhandle(3); @@ -2411,10 +2641,10 @@ index ea14a59b80bbfbaa17d7569734b8409d9d21fcde..f993e78e02563cada8c131be3d4658bc // Only run this code if LauncherProcessWin.h was included beforehand, thus // signalling that the hosting process should support launcher mode. diff --git a/uriloader/base/nsDocLoader.cpp b/uriloader/base/nsDocLoader.cpp -index 9ca3975c99c8bff3829bce1cf49d1235910c3ab8..6606eb02fba53ea8bd401d07460b85b068abd2bd 100644 +index e1e46ccdceae595f95d100116ff480905047e82b..eaa0252e768140120158525723ad867b8cb020be 100644 --- a/uriloader/base/nsDocLoader.cpp +++ b/uriloader/base/nsDocLoader.cpp -@@ -827,6 +827,13 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, +@@ -830,6 +830,13 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout, ("DocLoader:%p: Firing load event for document.open\n", this)); @@ -2429,10 +2659,10 @@ index 9ca3975c99c8bff3829bce1cf49d1235910c3ab8..6606eb02fba53ea8bd401d07460b85b0 // 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 d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6309cf7f1 100644 +index 43dc9b0614ab007c938dbf66a02ff614524353b7..758dc42b1fcd4f81a1a13ae9e30942489a1b620c 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp -@@ -110,6 +110,7 @@ +@@ -112,6 +112,7 @@ #include "mozilla/Components.h" #include "mozilla/ClearOnShutdown.h" @@ -2440,7 +2670,7 @@ index d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6 #include "mozilla/Preferences.h" #include "mozilla/ipc/URIUtils.h" -@@ -834,6 +835,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( +@@ -836,6 +837,12 @@ NS_IMETHODIMP nsExternalHelperAppService::ApplyDecodingForExtension( return NS_OK; } @@ -2453,7 +2683,7 @@ index d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6 nsresult nsExternalHelperAppService::GetFileTokenForPath( const char16_t* aPlatformAppPath, nsIFile** aFile) { nsDependentString platformAppPath(aPlatformAppPath); -@@ -1443,7 +1450,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { +@@ -1446,7 +1453,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel* aChannel) { // Strip off the ".part" from mTempLeafName mTempLeafName.Truncate(mTempLeafName.Length() - ArrayLength(".part") + 1); @@ -2466,7 +2696,7 @@ index d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6 mSaver = do_CreateInstance(NS_BACKGROUNDFILESAVERSTREAMLISTENER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); -@@ -1634,7 +1646,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1635,7 +1647,36 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { return NS_OK; } @@ -2504,7 +2734,7 @@ index d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6 if (NS_FAILED(rv)) { nsresult transferError = rv; -@@ -1689,6 +1730,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { +@@ -1687,6 +1728,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest* request) { bool alwaysAsk = true; mMimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk); @@ -2514,7 +2744,7 @@ index d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6 if (alwaysAsk) { // But we *don't* ask if this mimeInfo didn't come from // our user configuration datastore and the user has said -@@ -2254,6 +2298,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, +@@ -2197,6 +2241,16 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver* aSaver, NotifyTransfer(aStatus); } @@ -2531,7 +2761,7 @@ index d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6 return NS_OK; } -@@ -2733,6 +2787,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { +@@ -2682,6 +2736,15 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason) { } } @@ -2548,10 +2778,10 @@ index d77d78b9ecb73ef9bfd14d6bd42f4b8d6bda4723..c3e27edc5393702abafbdb9ab6a007c6 // OnStartRequest) mDialog = nullptr; diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h -index f8832bbde4042df9631794ca45886dcb02b60457..6a28695117997f1fd3753a75c94bc0e67e49d215 100644 +index 6c8cbc5871d3aa721a3f1a3ff6c0ef8b0044c63e..8e7c9af1a2cfe60c9c543af1ab55f6c229000bd4 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h -@@ -241,6 +241,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, +@@ -257,6 +257,8 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, mozilla::dom::BrowsingContext* aContentContext, bool aForceSave, nsIInterfaceRequestor* aWindowContext, nsIStreamListener** aStreamListener); @@ -2560,7 +2790,7 @@ index f8832bbde4042df9631794ca45886dcb02b60457..6a28695117997f1fd3753a75c94bc0e6 }; /** -@@ -437,6 +439,9 @@ class nsExternalAppHandler final : public nsIStreamListener, +@@ -456,6 +458,9 @@ class nsExternalAppHandler final : public nsIStreamListener, * Upon successful return, both mTempFile and mSaver will be valid. */ nsresult SetUpTempFile(nsIChannel* aChannel); @@ -2571,7 +2801,7 @@ index f8832bbde4042df9631794ca45886dcb02b60457..6a28695117997f1fd3753a75c94bc0e6 * When we download a helper app, we are going to retarget all load * notifications into our own docloader and load group instead of diff --git a/uriloader/exthandler/nsIExternalHelperAppService.idl b/uriloader/exthandler/nsIExternalHelperAppService.idl -index 3554c69aaced17631d8d1e4d9a000f0dd8b7ba9c..52d6b60707d076906e79160fef155eaaf999470c 100644 +index 307e6196a89df52d0bccc3ebd1359f58e32de75d..c3692d0f76178ac3aeb1c77a0e973bfa22359346 100644 --- a/uriloader/exthandler/nsIExternalHelperAppService.idl +++ b/uriloader/exthandler/nsIExternalHelperAppService.idl @@ -6,6 +6,8 @@ @@ -2637,11 +2867,57 @@ index 1c25e9d9a101233f71e92288a0f93125b81ac1c5..22cf67b0f6e3ddd2b3ed725a314ba6a9 return new InProcessCompositorWidget(aOptions, widget); } #endif +diff --git a/widget/MouseEvents.h b/widget/MouseEvents.h +index 5a19cb4082674ede982a0c66c84bf7c4642abe2b..5fe6ae7b5bf605e5d9130aa164d7cbbb486e54e0 100644 +--- a/widget/MouseEvents.h ++++ b/widget/MouseEvents.h +@@ -203,6 +203,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, + : mReason(eReal), + mContextMenuTrigger(eNormal), + mClickCount(0), ++ mJugglerEventId(0), + mIgnoreRootScrollFrame(false), + mUseLegacyNonPrimaryDispatch(false), + mClickEventPrevented(false) {} +@@ -213,6 +214,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, + mReason(aReason), + mContextMenuTrigger(eNormal), + mClickCount(0), ++ mJugglerEventId(0), + mIgnoreRootScrollFrame(false), + mUseLegacyNonPrimaryDispatch(false), + mClickEventPrevented(false) {} +@@ -231,6 +233,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, + mReason(aReason), + mContextMenuTrigger(aContextMenuTrigger), + mClickCount(0), ++ mJugglerEventId(0), + mIgnoreRootScrollFrame(false), + mUseLegacyNonPrimaryDispatch(false), + mClickEventPrevented(false) { +@@ -280,6 +283,9 @@ class WidgetMouseEvent : public WidgetMouseEventBase, + // Otherwise, this must be 0. + uint32_t mClickCount; + ++ // Unique event ID ++ uint32_t mJugglerEventId; ++ + // Whether the event should ignore scroll frame bounds during dispatch. + bool mIgnoreRootScrollFrame; + +@@ -296,6 +302,7 @@ class WidgetMouseEvent : public WidgetMouseEventBase, + + mExitFrom = aEvent.mExitFrom; + mClickCount = aEvent.mClickCount; ++ mJugglerEventId = aEvent.mJugglerEventId; + mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame; + mUseLegacyNonPrimaryDispatch = aEvent.mUseLegacyNonPrimaryDispatch; + mClickEventPrevented = aEvent.mClickEventPrevented; diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c62b016eec 100644 --- a/widget/cocoa/NativeKeyBindings.mm +++ b/widget/cocoa/NativeKeyBindings.mm -@@ -492,6 +492,13 @@ +@@ -492,6 +492,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, break; case KEY_NAME_INDEX_ArrowLeft: if (aEvent.IsAlt()) { @@ -2655,7 +2931,7 @@ index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c6 break; } if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -512,6 +519,13 @@ +@@ -512,6 +519,13 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, break; case KEY_NAME_INDEX_ArrowRight: if (aEvent.IsAlt()) { @@ -2669,7 +2945,7 @@ index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c6 break; } if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) { -@@ -532,6 +546,10 @@ +@@ -532,6 +546,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, break; case KEY_NAME_INDEX_ArrowUp: if (aEvent.IsControl()) { @@ -2680,7 +2956,7 @@ index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c6 break; } if (aEvent.IsMeta()) { -@@ -541,7 +559,7 @@ +@@ -541,7 +559,7 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, instance->AppendEditCommandsForSelector( !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:)) @@ -2689,7 +2965,7 @@ index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c6 aCommands); break; } -@@ -564,6 +582,10 @@ +@@ -564,6 +582,10 @@ void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType, break; case KEY_NAME_INDEX_ArrowDown: if (aEvent.IsControl()) { @@ -2701,7 +2977,7 @@ index d3e5983259053175584254e7ac01ca9ce024f33a..97f5b851c402fea5477c0ee57af451c6 } if (aEvent.IsMeta()) { diff --git a/widget/headless/HeadlessCompositorWidget.cpp b/widget/headless/HeadlessCompositorWidget.cpp -index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6dfcbc2ab 100644 +index bb4ee9175e66dc40de1871a7f91368fe309494a3..856faef297c9eb0a510df123513b9ac095634e98 100644 --- a/widget/headless/HeadlessCompositorWidget.cpp +++ b/widget/headless/HeadlessCompositorWidget.cpp @@ -3,6 +3,7 @@ @@ -2712,15 +2988,14 @@ index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6 #include "mozilla/widget/PlatformWidgetTypes.h" #include "HeadlessCompositorWidget.h" #include "VsyncDispatcher.h" -@@ -13,10 +14,32 @@ namespace widget { - HeadlessCompositorWidget::HeadlessCompositorWidget( - const HeadlessCompositorWidgetInitData& aInitData, - const layers::CompositorOptions& aOptions, HeadlessWidget* aWindow) -- : CompositorWidget(aOptions), mWidget(aWindow) { -+ : CompositorWidget(aOptions), mWidget(aWindow), mMon("snapshotListener") { - mClientSize = aInitData.InitialClientSize(); - } - +@@ -16,7 +17,30 @@ HeadlessCompositorWidget::HeadlessCompositorWidget( + : CompositorWidget(aOptions), + mWidget(aWindow), + mClientSize(LayoutDeviceIntSize(aInitData.InitialClientSize()), +- "HeadlessCompositorWidget::mClientSize") {} ++ "HeadlessCompositorWidget::mClientSize"), ++ mMon("snapshotListener") {} ++ +void HeadlessCompositorWidget::SetSnapshotListener(HeadlessWidget::SnapshotListener&& listener) { + MOZ_ASSERT(NS_IsMainThread()); + @@ -2742,14 +3017,13 @@ index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6 + RefPtr result = mDrawTarget; + return result.forget(); +} -+ + void HeadlessCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { if (RefPtr cvd = - mWidget->GetCompositorVsyncDispatcher()) { -@@ -29,6 +52,59 @@ nsIWidget* HeadlessCompositorWidget::RealWidget() { return mWidget; } - void HeadlessCompositorWidget::NotifyClientSizeChanged( +@@ -31,6 +55,59 @@ void HeadlessCompositorWidget::NotifyClientSizeChanged( const LayoutDeviceIntSize& aClientSize) { - mClientSize = aClientSize; + auto size = mClientSize.Lock(); + *size = aClientSize; + layers::CompositorThread()->Dispatch(NewRunnableMethod( + "HeadlessCompositorWidget::UpdateDrawTarget", this, + &HeadlessCompositorWidget::UpdateDrawTarget, @@ -2807,7 +3081,7 @@ index b31a969b7ab3d0fc80912b110d91dfdf3e5991f4..52aed4f9fb51f3f58a440d7e57eaccd6 LayoutDeviceIntSize HeadlessCompositorWidget::GetClientSize() { diff --git a/widget/headless/HeadlessCompositorWidget.h b/widget/headless/HeadlessCompositorWidget.h -index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e65c24835 100644 +index facd2bc65afab8ec1aa322faa20a67464964dfb9..d6dea95472bec6006411753c3dfdab2e3659171f 100644 --- a/widget/headless/HeadlessCompositorWidget.h +++ b/widget/headless/HeadlessCompositorWidget.h @@ -6,6 +6,7 @@ @@ -2831,7 +3105,7 @@ index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e uintptr_t GetWidgetKey() override; -@@ -42,9 +47,17 @@ class HeadlessCompositorWidget final : public CompositorWidget, +@@ -42,10 +47,18 @@ class HeadlessCompositorWidget final : public CompositorWidget, } private: @@ -2842,7 +3116,8 @@ index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e HeadlessWidget* mWidget; + mozilla::ReentrantMonitor mMon; - LayoutDeviceIntSize mClientSize; + // See GtkCompositorWidget for the justification for this mutex. + DataMutex mClientSize; + + HeadlessWidget::SnapshotListener mSnapshotListener; + RefPtr mDrawTarget; @@ -2850,10 +3125,10 @@ index 7f91de9e67d7ffa02de3eef1d760e5cfd05e7ad6..753b8902026626e8f0a190ea3130ba5e } // namespace widget diff --git a/widget/headless/HeadlessWidget.cpp b/widget/headless/HeadlessWidget.cpp -index c1fbcccc93d9a6876aa82893cdf9c09b72087751..7a8073e3b746aec3a894957e87975189c06782d3 100644 +index 083d026d3c019cb76fff2b8f605f3d6ef8dd578f..84c049709ead92c980b86230513a634bf6337085 100644 --- a/widget/headless/HeadlessWidget.cpp +++ b/widget/headless/HeadlessWidget.cpp -@@ -109,6 +109,8 @@ void HeadlessWidget::Destroy() { +@@ -111,6 +111,8 @@ void HeadlessWidget::Destroy() { } } @@ -2862,11 +3137,10 @@ index c1fbcccc93d9a6876aa82893cdf9c09b72087751..7a8073e3b746aec3a894957e87975189 nsBaseWidget::OnDestroy(); nsBaseWidget::Destroy(); -@@ -564,5 +566,15 @@ nsresult HeadlessWidget::SynthesizeNativeTouchPadPinch( - DispatchPinchGestureInput(inputToDispatch); +@@ -621,5 +623,14 @@ nsresult HeadlessWidget::SynthesizeNativeTouchpadPan( return NS_OK; } -+ + +void HeadlessWidget::SetSnapshotListener(SnapshotListener&& listener) { + if (!mCompositorWidget) { + if (listener) @@ -2879,12 +3153,12 @@ index c1fbcccc93d9a6876aa82893cdf9c09b72087751..7a8073e3b746aec3a894957e87975189 } // namespace widget } // namespace mozilla diff --git a/widget/headless/HeadlessWidget.h b/widget/headless/HeadlessWidget.h -index 2b80eea70e58dd53c34edd9c5fa4415c42bcd632..72ecda7d8ddc7a9f87a954b547f8411e67ef1570 100644 +index 9856991ef32f25f51942f8cd664a09bec2192c70..948947a421179e91c51005aeb83ed0d18cfc84ce 100644 --- a/widget/headless/HeadlessWidget.h +++ b/widget/headless/HeadlessWidget.h -@@ -135,6 +135,9 @@ class HeadlessWidget : public nsBaseWidget { - TouchpadGesturePhase aEventPhase, float aScale, - LayoutDeviceIntPoint aPoint, int32_t aModifierFlags) override; +@@ -141,6 +141,9 @@ class HeadlessWidget : public nsBaseWidget { + int32_t aModifierFlags, + nsIObserver* aObserver) override; + using SnapshotListener = std::function&&)>; + void SetSnapshotListener(SnapshotListener&& listener); @@ -2892,21 +3166,26 @@ index 2b80eea70e58dd53c34edd9c5fa4415c42bcd632..72ecda7d8ddc7a9f87a954b547f8411e private: ~HeadlessWidget(); bool mEnabled; -diff --git a/widget/windows/nsAppShell.cpp b/widget/windows/nsAppShell.cpp -index e2cf83f3d6ee0b120bb22f46aa873d3bd6436cd0..8ea269c8de520d3a9eed42f99f66ad28f5e63fbc 100644 ---- a/widget/windows/nsAppShell.cpp -+++ b/widget/windows/nsAppShell.cpp -@@ -17,7 +17,9 @@ - #include "WinIMEHandler.h" - #include "mozilla/widget/AudioSession.h" - #include "mozilla/BackgroundHangMonitor.h" --#include "mozilla/BackgroundTasks.h" -+#ifdef MOZ_BACKGROUNDTASKS -+# include "mozilla/BackgroundTasks.h" -+#endif - #include "mozilla/Hal.h" - #include "nsIDOMWakeLockListener.h" - #include "nsIPowerManagerService.h" +diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h +index ad9c1887c6c95447b161b73c8623cef478137c75..c71e9ede72ff69c7e6c2080d804ec47c0051c397 100644 +--- a/widget/nsGUIEventIPC.h ++++ b/widget/nsGUIEventIPC.h +@@ -234,6 +234,7 @@ struct ParamTraits { + aParam.mExitFrom.value())); + } + WriteParam(aWriter, aParam.mClickCount); ++ WriteParam(aWriter, aParam.mJugglerEventId); + } + + static bool Read(MessageReader* aReader, paramType* aResult) { +@@ -258,6 +259,7 @@ struct ParamTraits { + aResult->mExitFrom = Some(static_cast(exitFrom)); + } + rv = rv && ReadParam(aReader, &aResult->mClickCount); ++ rv = rv && ReadParam(aReader, &aResult->mJugglerEventId); + return rv; + } + }; diff --git a/xpcom/reflect/xptinfo/xptinfo.h b/xpcom/reflect/xptinfo/xptinfo.h index 2456c2c2b58b27cd595880b547ed20fb687a1835..e967c089b2331c7cd36d34e511543fbc84320b7d 100644 --- a/xpcom/reflect/xptinfo/xptinfo.h diff --git a/browser_patches/firefox/preferences/playwright.cfg b/browser_patches/firefox/preferences/playwright.cfg index f58a6d10d43e94..6c33bd2545180b 100644 --- a/browser_patches/firefox/preferences/playwright.cfg +++ b/browser_patches/firefox/preferences/playwright.cfg @@ -8,24 +8,93 @@ pref("datareporting.policy.dataSubmissionEnabled", false); pref("datareporting.policy.dataSubmissionPolicyAccepted", false); pref("datareporting.policy.dataSubmissionPolicyBypassNotification", true); -// @see https://github.com/microsoft/playwright/issues/4297 -pref("browser.tabs.remote.useCrossOriginEmbedderPolicy", false); -pref("browser.tabs.remote.useCrossOriginOpenerPolicy", false); - -pref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false); - +// Force pdfs into downloads. pref("pdfjs.disabled", true); -// Disable all kinds of cross-process navigations until we are ready. -pref("fission.autostart", false); +// Disable cross-process iframes, but not cross-process navigations. pref("fission.webContentIsolationStrategy", 0); + +// Disable BFCache in parent process. +// We also separately disable BFCache in content via docSchell property. pref("fission.bfcacheInParent", false); -// Avoid about:blank loading cross-process until we are ready. -pref("browser.tabs.remote.systemTriggeredAboutBlankAnywhere", true); + +// Disable first-party-based cookie partitioning. +// When it is enabled, we have to retain "thirdPartyCookie^" permissions +// in the storageState. +pref("network.cookie.cookieBehavior", 4); + +// Increase max number of child web processes so that new pages +// get a new process by default and we have a process isolation +// between pages from different contexts. If this becomes a performance +// issue we can povide custom '@mozilla.org/ipc/processselector;1' +pref("dom.ipc.processCount", 60000); + +// Never reuse processes as they may keep previously overridden values +// (locale, timezone etc.). +pref("dom.ipc.processPrelaunch.enabled", false); + +// Isolate permissions by user context. +pref("permissions.isolateBy.userContext", true); + +// Allow creating files in content process - required for +// |Page.setFileInputFiles| protocol method. +pref("dom.file.createInChild", true); + +// Do not warn when closing all open tabs +pref("browser.tabs.warnOnClose", false); + +// Do not warn when closing all other open tabs +pref("browser.tabs.warnOnCloseOtherTabs", false); + +// Do not warn when multiple tabs will be opened +pref("browser.tabs.warnOnOpen", false); + +// Do not warn on quitting Firefox +pref("browser.warnOnQuit", false); + +// Disable popup-blocker +pref("dom.disable_open_during_load", false); + +// Disable the ProcessHangMonitor +pref("dom.ipc.reportProcessHangs", false); +pref("hangmonitor.timeout", 0); + +// Allow the application to have focus even it runs in the background +pref("focusmanager.testmode", true); + +// No ICC color correction. We need this for reproducible screenshots. +// See https://developer.mozilla.org/en/docs/Mozilla/Firefox/Releases/3.5/ICC_color_correction_in_Firefox. +pref("gfx.color_management.mode", 0); +pref("gfx.color_management.rendering_intent", 3); + +// Always use network provider for geolocation tests so we bypass the +// macOS dialog raised by the corelocation provider +pref("geo.provider.testing", true); + + + // ================================================================= +// THESE ARE NICHE PROPERTIES THAT ARE NICE TO HAVE // ================================================================= +// Enable software-backed webgl. See https://phabricator.services.mozilla.com/D164016 +pref("webgl.forbid-software", false); + +// Disable auto-fill for credit cards and addresses. +// See https://github.com/microsoft/playwright/issues/21393 +pref("extensions.formautofill.creditCards.supported", "off"); +pref("extensions.formautofill.addresses.supported", "off"); + +// Allow access to system-added self-signed certificates. This aligns +// firefox behavior with other browser defaults. +pref("security.enterprise_roots.enabled", true); + +// Avoid stalling on shutdown, after "xpcom-will-shutdown" phase. +// This at least happens when shutting down soon after launching. +// See AppShutdown.cpp for more details on shutdown phases. +pref("toolkit.shutdown.fastShutdownStage", 3); + // @see https://github.com/microsoft/playwright/issues/8178 pref("dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled", true); @@ -36,23 +105,9 @@ pref("ui.systemUsesDarkTheme", 0); // support for the new modal UI (see Bug 1686743). pref("prompts.contentPromptSubDialog", false); -// Increase max number of child web processes so that new pages -// get a new process by default and we have a process isolation -// between pages from different contexts. If this becomes a performance -// issue we can povide custom '@mozilla.org/ipc/processselector;1' -// -pref("dom.ipc.processCount", 60000); - -// Never reuse processes as they may keep previously overridden values -// (locale, timezone etc.). -pref("dom.ipc.processPrelaunch.enabled", false); - // Do not use system colors - they are affected by themes. pref("ui.use_standins_for_native_colors", true); -// Isolate permissions by user context. -pref("permissions.isolateBy.userContext", true); - pref("dom.push.serverURL", ""); // This setting breaks settings loading. pref("services.settings.server", ""); @@ -87,14 +142,10 @@ pref("browser.newtabpage.enabled", false); // Do not redirect user when a milstone upgrade of Firefox is detected pref("browser.startup.homepage_override.mstone", "ignore"); -pref("browser.tabs.remote.separateFileUriProcess", false); -pref("security.sandbox.content.level", 2); - // Disable topstories pref("browser.newtabpage.activity-stream.feeds.section.topstories", false); // DevTools JSONViewer sometimes fails to load dependencies with its require.js. -// This doesn't affect Puppeteer operations, but spams console with a lot of -// unpleasant errors. +// This spams console with a lot of unpleasant errors. // (bug 1424372) pref("devtools.jsonview.enabled", false); @@ -107,10 +158,6 @@ pref("devtools.jsonview.enabled", false); // (bug 1176798, bug 1177018, bug 1210465) pref("apz.content_response_timeout", 60000); -// Allow creating files in content process - required for -// |Page.setFileInputFiles| protocol method. -pref("dom.file.createInChild", true); - // Indicate that the download panel has been shown once so that // whichever download test runs first doesn't show the popup // inconsistently. @@ -142,15 +189,6 @@ pref("browser.tabs.closeWindowWithLastTab", true); // unloaded pref("browser.tabs.disableBackgroundZombification", false); -// Do not warn when closing all open tabs -pref("browser.tabs.warnOnClose", false); - -// Do not warn when closing all other open tabs -pref("browser.tabs.warnOnCloseOtherTabs", false); - -// Do not warn when multiple tabs will be opened -pref("browser.tabs.warnOnOpen", false); - // Disable first run splash page on Windows 10 pref("browser.usedOnWindows10.introURL", ""); @@ -163,9 +201,6 @@ pref("browser.uitour.enabled", false); // network connections. pref("browser.urlbar.suggest.searches", false); -// Do not warn on quitting Firefox -pref("browser.warnOnQuit", false); - // Do not show datareporting policy notifications which can // interfere with tests pref("datareporting.healthreport.documentServerURI", ""); @@ -178,13 +213,6 @@ pref("datareporting.healthreport.uploadEnabled", false); // Automatically unload beforeunload alerts pref("dom.disable_beforeunload", false); -// Disable popup-blocker -pref("dom.disable_open_during_load", false); - -// Disable the ProcessHangMonitor -pref("dom.ipc.reportProcessHangs", false); -pref("hangmonitor.timeout", 0); - // Disable slow script dialogues pref("dom.max_chrome_script_run_time", 0); pref("dom.max_script_run_time", 0); @@ -210,21 +238,9 @@ pref("extensions.webservice.discoverURL", ""); pref("extensions.screenshots.disabled", true); pref("extensions.screenshots.upload-disabled", true); -// Allow the application to have focus even it runs in the background -pref("focusmanager.testmode", true); - // Disable useragent updates pref("general.useragent.updates.enabled", false); -// No ICC color correction. -// See https://developer.mozilla.org/en/docs/Mozilla/Firefox/Releases/3.5/ICC_color_correction_in_Firefox. -pref("gfx.color_management.mode", 0); -pref("gfx.color_management.rendering_intent", 3); - -// Always use network provider for geolocation tests so we bypass the -// macOS dialog raised by the corelocation provider -pref("geo.provider.testing", true); - // Do not scan Wifi pref("geo.wifi.scan", false); diff --git a/browser_patches/get_xcode_version.js b/browser_patches/get_xcode_version.js deleted file mode 100755 index 29e2d55a2bd69d..00000000000000 --- a/browser_patches/get_xcode_version.js +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env node - -const child_process = require('child_process'); - -const XCODE_VERSIONS = { - "macos-10.15": { - webkit: '11.7', - }, - "macos-11": { - webkit: '12.5', // WebKit strongly requires xcode 12.5 and not higher on MacOS 11 - firefox: '13.2', // As of Oct 2021 building Firefox requires XCode 13 - ffmpeg: '13.2', - }, - "macos-12": { - webkit: '13.2', // WebKit requires xcode 13.2 to work on MacOS 12.2. - firefox: '13.2', // As of Oct 2021 building Firefox requires XCode 13 - chromium: '13.3', // As of Apr 2022 Chromium requires Xcode13.3 - ffmpeg: '13.2', - }, -}; - -const [major, minor, patch] = child_process.execSync(`sw_vers -productVersion`).toString().trim().split('.'); -const browserName = process.argv[2]; -const macosVersion = major === '10' ? `macos-${major}.${minor}` : `macos-${major}`; -const versions = XCODE_VERSIONS[macosVersion]; -if (!versions || !versions[browserName.toLowerCase()]) - throw new Error(`Compilation of ${browserName} is not supported on ${macosVersion}`); - -console.log(versions[browserName.toLowerCase()]); - diff --git a/browser_patches/prepare_checkout.sh b/browser_patches/prepare_checkout.sh deleted file mode 100755 index 2ec4a2d8a9e6c7..00000000000000 --- a/browser_patches/prepare_checkout.sh +++ /dev/null @@ -1,270 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_PATH=$(pwd -P) - -source "${SCRIPT_PATH}/utils.sh" - -REMOTE_BROWSER_UPSTREAM="browser_upstream" -BUILD_BRANCH="playwright-build" - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [firefox|firefox-beta|webkit] [custom_checkout_path]" - echo - echo "Prepares browser checkout. The checkout is a GIT repository that:" - echo "- has a '$REMOTE_BROWSER_UPSTREAM' remote pointing to a REMOTE_URL from UPSTREAM_CONFIG.sh" - echo "- has a '$BUILD_BRANCH' branch that is BASE_REVISION with all the patches applied." - echo - echo "You can optionally specify custom_checkout_path if you want to use some other browser checkout" - echo - exit 0 -fi - -if [[ $# == 0 ]]; then - echo "missing browser: 'firefox' or 'webkit'" - echo "try './$(basename "$0") --help' for more information" - exit 1 -fi - -function maybe_cmd { - if is_win; then - local args="$@" - /c/Windows/System32/cmd.exe "/c $args" - else - $@ - fi -} - -function prepare_chromium_checkout { - cd "${SCRIPT_PATH}" - - if [[ $1 == "chromium" ]]; then - source "${SCRIPT_PATH}/chromium/UPSTREAM_CONFIG.sh" - elif [[ "$1" == "chromium-tot" ]]; then - source "${SCRIPT_PATH}/chromium-tip-of-tree/UPSTREAM_CONFIG.sh" - else - echo "ERROR: unknown type of checkout to prepare - $1" - exit 1 - fi - source "${SCRIPT_PATH}/chromium/ensure_depot_tools.sh" - - if [[ -z "${CR_CHECKOUT_PATH}" ]]; then - CR_CHECKOUT_PATH="$HOME/chromium" - fi - - # Update Chromium checkout. - # - # This is based on https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md#get-the-code - if [[ ! -d "${CR_CHECKOUT_PATH}" ]]; then - rm -rf "${CR_CHECKOUT_PATH}" - mkdir -p "${CR_CHECKOUT_PATH}" - cd "${CR_CHECKOUT_PATH}" - maybe_cmd fetch --nohooks chromium - cd src - if is_linux; then - ./build/install-build-deps.sh - fi - maybe_cmd gclient runhooks - fi - if [[ ! -d "${CR_CHECKOUT_PATH}/src" ]]; then - echo "ERROR: CR_CHECKOUT_PATH does not have src/ subfolder; is this a chromium checkout?" - exit 1 - fi - - cd "${CR_CHECKOUT_PATH}/src" - maybe_cmd gclient sync --with_branch_heads - git fetch origin - git checkout "${BRANCH_COMMIT}" - maybe_cmd gclient sync -D --with_branch_heads -} - -# FRIENDLY_CHECKOUT_PATH is used only for logging. -FRIENDLY_CHECKOUT_PATH=""; -CHECKOUT_PATH="" -PATCHES_PATH="" -BUILD_NUMBER="" -WEBKIT_EXTRA_FOLDER_PATH="" -FIREFOX_EXTRA_FOLDER_PATH="" -if [[ ("$1" == "chromium") || ("$1" == "chromium/") || ("$1" == "cr") ]]; then - prepare_chromium_checkout chromium - exit 0 -elif [[ ("$1" == "chromium-tip-of-tree") || ("$1" == "chromium-tot") || ("$1" == "cr-tot") ]]; then - prepare_chromium_checkout chromium-tot - exit 0 -elif [[ ("$1" == "ffmpeg") || ("$1" == "ffmpeg/") ]]; then - echo "FYI: ffmpeg checkout is not supported. Use '//browser_patches/ffmpeg/build.sh' instead" - exit 0 -elif [[ ("$1" == "winldd") || ("$1" == "winldd/") ]]; then - echo "FYI: winldd source code is available right away" - exit 0 -elif [[ ("$1" == "firefox") || ("$1" == "firefox/") || ("$1" == "ff") ]]; then - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - PATCHES_PATH="$PWD/firefox/patches" - FIREFOX_EXTRA_FOLDER_PATH="$PWD/firefox/juggler" - BUILD_NUMBER=$(head -1 "$PWD/firefox/BUILD_NUMBER") - source "./firefox/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "firefox-beta") || ("$1" == "ff-beta") ]]; then - # NOTE: firefox-beta re-uses firefox checkout. - if [[ -z "${FF_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/firefox'; - CHECKOUT_PATH="$HOME/firefox" - else - echo "WARNING: using checkout path from FF_CHECKOUT_PATH env: ${FF_CHECKOUT_PATH}" - CHECKOUT_PATH="${FF_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - PATCHES_PATH="$PWD/firefox-beta/patches" - FIREFOX_EXTRA_FOLDER_PATH="$PWD/firefox-beta/juggler" - BUILD_NUMBER=$(head -1 "$PWD/firefox-beta/BUILD_NUMBER") - source "./firefox-beta/UPSTREAM_CONFIG.sh" -elif [[ ("$1" == "webkit") || ("$1" == "webkit/") || ("$1" == "wk") ]]; then - if [[ -z "${WK_CHECKOUT_PATH}" ]]; then - FRIENDLY_CHECKOUT_PATH='$HOME/webkit'; - CHECKOUT_PATH="$HOME/webkit" - else - echo "WARNING: using checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" - CHECKOUT_PATH="${WK_CHECKOUT_PATH}" - FRIENDLY_CHECKOUT_PATH="" - fi - - PATCHES_PATH="$PWD/webkit/patches" - WEBKIT_EXTRA_FOLDER_PATH="$PWD/webkit/embedder/Playwright" - BUILD_NUMBER=$(head -1 "$PWD/webkit/BUILD_NUMBER") - source "./webkit/UPSTREAM_CONFIG.sh" -else - echo ERROR: unknown browser - "$1" - exit 1 -fi - -# if there's no checkout folder - checkout one. -if ! [[ -d $CHECKOUT_PATH ]]; then - echo "-- $FRIENDLY_CHECKOUT_PATH is missing - checking out.." - if [[ -n "$CI" ]]; then - # In CI environment, we re-checkout constantly, so we do a shallow checkout to save time. - git clone --single-branch --depth 1 --branch "$BASE_BRANCH" "$REMOTE_URL" "$CHECKOUT_PATH" - else - # In non-CI environment, do a full checkout. This takes time, - # but liberates from the `git fetch --unshallow`. - git clone --single-branch --branch "$BASE_BRANCH" "$REMOTE_URL" "$CHECKOUT_PATH" - fi -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH folder - OK" -fi - -# if folder exists but not a git repository - bail out. -if ! [[ -d $CHECKOUT_PATH/.git ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH is not a git repository! Remove it and re-run the script." - exit 1 -else - echo "-- checking $FRIENDLY_CHECKOUT_PATH is a git repo - OK" -fi - -# ============== SETTING UP GIT REPOSITORY ============== -cd "$CHECKOUT_PATH" - -# Bail out if git repo is dirty. -if [[ -n $(git status -s --untracked-files=no) ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH has dirty GIT state - commit everything and re-run the script." - exit 1 -fi - -# Setting up |$REMOTE_BROWSER_UPSTREAM| remote and fetch the $BASE_BRANCH -if git remote get-url $REMOTE_BROWSER_UPSTREAM >/dev/null; then - echo "-- setting |$REMOTE_BROWSER_UPSTREAM| remote url to $REMOTE_URL" - git remote set-url $REMOTE_BROWSER_UPSTREAM "$REMOTE_URL" -else - echo "-- adding |$REMOTE_BROWSER_UPSTREAM| remote to $REMOTE_URL" - git remote rename origin $REMOTE_BROWSER_UPSTREAM -fi - -# Since we do a single-branch checkout by default, we might need to add a new remote base branch. -if ! git show-branch "remotes/$REMOTE_BROWSER_UPSTREAM/${BASE_BRANCH}" 2>&1 >/dev/null; then - git remote set-branches --add "$REMOTE_BROWSER_UPSTREAM" "${BASE_BRANCH}" -fi - -# if our remote branch does not contains "BASE_REVISION" - then fetch more stuff. -if [[ -z $(git branch -r --contains "${BASE_REVISION}" --list "${REMOTE_BROWSER_UPSTREAM}/${BASE_BRANCH}") ]]; then - # Detach git head so that we can fetch into branch. - git checkout --detach >/dev/null 2>/dev/null - - if [[ -z "$CI" ]]; then - # On non-CI, fetch everything. - git fetch "$REMOTE_BROWSER_UPSTREAM" "$BASE_BRANCH" - else - # On CI, fetch from REMOTE_BROWSER_UPSTREAM more and more commits - # until we find $BASE_REVISION. - # This technique allows us start with a shallow clone. - - # Fetch 128 commits first, and then double the amount every iteration. - FETCH_DEPTH=128 - SUCCESS="no" - while (( FETCH_DEPTH <= 8192 )); do - echo "Fetching ${FETCH_DEPTH} commits to find base revision..." - git fetch --depth "${FETCH_DEPTH}" "$REMOTE_BROWSER_UPSTREAM" "$BASE_BRANCH" - FETCH_DEPTH=$(( FETCH_DEPTH * 2 )); - if git cat-file -e "$BASE_REVISION"^{commit} >/dev/null; then - SUCCESS="yes" - break; - fi - done - if [[ "${SUCCESS}" == "no" ]]; then - echo "ERROR: $FRIENDLY_CHECKOUT_PATH/ does not include the BASE_REVISION (@$BASE_REVISION). Wrong revision number?" - exit 1 - fi - fi -fi - -echo "-- checking $FRIENDLY_CHECKOUT_PATH repo has BASE_REVISION (@$BASE_REVISION) commit - OK" - -# Check out the $BASE_REVISION -git checkout "$BASE_REVISION" - -# Create a playwright-build branch and apply all the patches to it. -if git show-ref --verify --quiet refs/heads/playwright-build; then - git branch -D playwright-build -fi -git checkout -b playwright-build -echo "-- applying patches" -git apply --index --whitespace=nowarn "$PATCHES_PATH"/* - -if [[ ! -z "${WEBKIT_EXTRA_FOLDER_PATH}" ]]; then - echo "-- adding WebKit embedders" - EMBEDDER_DIR="$PWD/Tools/Playwright" - # git status does not show empty directories, check it separately. - # XCode 13 and WebKit build on MacOS 12 now create empty folder here: - # ./Tools/Playwright/Playwright.xcodeproj/project.xcworkspace/xcshareddata/swiftpm - # As an easy work-around, let's remove it. - if [[ -d $EMBEDDER_DIR ]]; then - rm -rf "$EMBEDDER_DIR" - fi - cp -r "${WEBKIT_EXTRA_FOLDER_PATH}" "$EMBEDDER_DIR" - git add "$EMBEDDER_DIR" -elif [[ ! -z "${FIREFOX_EXTRA_FOLDER_PATH}" ]]; then - echo "-- adding juggler" - EMBEDDER_DIR="$PWD/juggler" - # git status does not show empty directories, check it separately. - # Remove for good if its empty but exists. - if [[ -d $EMBEDDER_DIR ]]; then - rm -rf "$EMBEDDER_DIR" - fi - cp -r "${FIREFOX_EXTRA_FOLDER_PATH}" "$EMBEDDER_DIR" - git add "$EMBEDDER_DIR" -fi - -git commit -a --author="playwright-devops " -m "chore($1): bootstrap build #$BUILD_NUMBER" - -echo -echo -echo "DONE. Browser is ready to be built." diff --git a/browser_patches/repack-juggler.mjs b/browser_patches/repack-juggler.mjs deleted file mode 100755 index 9c21b5dd9e136d..00000000000000 --- a/browser_patches/repack-juggler.mjs +++ /dev/null @@ -1,341 +0,0 @@ -#!/usr/bin/env node -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as path from 'path'; -import * as URL from 'url'; -import * as fs from 'fs'; -import * as http from 'http'; -import * as https from 'https'; -import * as os from 'os'; -import * as util from 'util'; -import * as child_process from 'child_process'; -import AdmZip from 'adm-zip'; - -const existsAsync = path => new Promise(resolve => fs.stat(path, err => resolve(!err))); - -const __filename = URL.fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -if (process.argv[2] === '--help' || process.argv[2] === '-h') { - console.log(`usage: ${path.basename(process.argv[1])} [firefox|ff|firefox-beta|ff-beta] [build number] [build platform]`); - console.log(``); - console.log(`Repackages Firefox with tip-of-tree Juggler implementation`); - process.exit(1); -} - -let browserName = ''; -if (process.argv[2] === 'firefox' || process.argv[2] === 'ff') { - browserName = 'firefox'; -} else if (process.argv[2] === 'firefox-beta' || process.argv[2] === 'ff-beta') { - browserName = 'firefox-beta'; -} else { - console.error('ERROR: unknown firefox to repackage - either "firefox", "ff", "firefox-beta" or "ff-beta" is allowed as first argument'); - process.exit(1); -} - -// Path to jar.mn in the juggler -const JARMN_PATH = path.join(__dirname, browserName, 'juggler', 'jar.mn'); -// Workdir for Firefox repackaging -const BUILD_DIRECTORY = os.platform() === 'win32' ? path.join(__dirname, '__repackaged_firefox__') : `/tmp/repackaged-firefox`; -// Information about currently downloaded build -const BUILD_INFO_PATH = path.join(BUILD_DIRECTORY, 'build-info.json'); -// Backup OMNI.JA - the original one before repackaging. -const OMNI_BACKUP_PATH = path.join(BUILD_DIRECTORY, 'omni.ja.backup'); -// Workdir to extract omni.ja -const OMNI_EXTRACT_DIR = path.join(BUILD_DIRECTORY, 'omni'); -// Path inside omni.ja to juggler -const OMNI_JUGGLER_DIR = path.join(OMNI_EXTRACT_DIR, 'chrome', 'juggler'); - -const EXECUTABLE_PATHS = { - 'ubuntu18.04': ['firefox', 'firefox'], - 'ubuntu20.04': ['firefox', 'firefox'], - 'mac10.14': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'mac10.15': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'mac11': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'mac11-arm64': ['firefox', 'Nightly.app', 'Contents', 'MacOS', 'firefox'], - 'win64': ['firefox', 'firefox.exe'], -}; - -const DOWNLOAD_URLS = { - 'firefox': { - 'ubuntu18.04': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-ubuntu-18.04.zip', - 'ubuntu20.04': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-ubuntu-20.04.zip', - 'mac10.14': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11.zip', - 'mac10.15': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11.zip', - 'mac11': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11.zip', - 'mac11-arm64': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-mac-11-arm64.zip', - 'win64': 'https://playwright.azureedge.net/builds/firefox/%s/firefox-win64.zip', - }, - 'firefox-beta': { - 'ubuntu18.04': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-ubuntu-18.04.zip', - 'ubuntu20.04': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip', - 'mac10.14': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11.zip', - 'mac10.15': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11.zip', - 'mac11': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11.zip', - 'mac11-arm64': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-mac-11-arm64.zip', - 'win64': 'https://playwright.azureedge.net/builds/firefox-beta/%s/firefox-beta-win64.zip', - }, -}; - -async function ensureFirefoxBuild(browserName, buildNumber, buildPlatform) { - if (!buildNumber) - buildNumber = (await fs.promises.readFile(path.join(__dirname, browserName, 'BUILD_NUMBER'), 'utf8')).split('\n').shift(); - if (!buildPlatform) - buildPlatform = getHostPlatform(); - const currentBuildInfo = await fs.promises.readFile(BUILD_INFO_PATH).then(text => JSON.parse(text)).catch(e => ({ buildPlatform: '', buildNumber: '', browserName: '' })); - - if (currentBuildInfo.buildPlatform === buildPlatform && currentBuildInfo.buildNumber === buildNumber && currentBuildInfo.browserName === browserName) - return currentBuildInfo; - await fs.promises.rm(BUILD_DIRECTORY, { recursive: true }).catch(e => {}); - await fs.promises.mkdir(BUILD_DIRECTORY); - const buildZipPath = path.join(BUILD_DIRECTORY, 'firefox.zip'); - - const urlTemplate = DOWNLOAD_URLS[browserName][buildPlatform]; - if (!urlTemplate) - throw new Error(`ERROR: repack-juggler does not support ${buildPlatform}`); - const url = util.format(urlTemplate, buildNumber); - console.log(`Downloading ${browserName} r${buildNumber} for ${buildPlatform} - it might take a few minutes`); - let downloadedPercentage = 0; - await downloadFile(url, buildZipPath, (downloaded, total) => { - const percentage = Math.round(downloaded / total * 10) * 10; - if (percentage === downloadedPercentage) - return; - downloadedPercentage = percentage; - console.log(`Downloaded: ${downloadedPercentage}%`); - }); - - const zip = new AdmZip(buildZipPath); - zip.extractAllTo(BUILD_DIRECTORY, false /* overwrite */, true /* keepOriginalPermission */); - - const buildInfo = { buildNumber, buildPlatform, browserName }; - await fs.promises.writeFile(BUILD_INFO_PATH, JSON.stringify(buildInfo), 'utf8'); - return buildInfo; -} - -async function listFiles(aPath, files = []) { - const stat = await fs.promises.lstat(aPath); - if (stat.isDirectory()) { - const entries = await fs.promises.readdir(aPath); - await Promise.all(entries.map(entry => listFiles(path.join(aPath, entry), files))); - } else { - files.push(aPath); - } - return files; -} - -async function repackageJuggler(browserName, buildInfo) { - const { buildNumber, buildPlatform } = buildInfo; - - // Find all omni.ja files in the Firefox build. - const omniPaths = (await listFiles(BUILD_DIRECTORY)).filter(filePath => filePath.endsWith('omni.ja')); - - // Iterate over all omni.ja files and find one that has juggler inside. - const omniWithJugglerPath = await (async () => { - for (const omniPath of omniPaths) { - const zip = new AdmZip(omniPath); - for (const zipEntry of zip.getEntries()) { - if (zipEntry.toString().includes('chrome/juggler')) - return omniPath; - } - } - return null; - })(); - - if (!omniWithJugglerPath) { - console.error('ERROR: did not find omni.ja file with baked in Juggler!'); - process.exit(1); - } else { - if (!(await existsAsync(OMNI_BACKUP_PATH))) - await fs.promises.copyFile(omniWithJugglerPath, OMNI_BACKUP_PATH); - } - - // Let's repackage omni folder! - await fs.promises.rm(OMNI_EXTRACT_DIR, { recursive: true }).catch(e => {}); - await fs.promises.mkdir(OMNI_EXTRACT_DIR); - - { - // Unzip omni - const zip = new AdmZip(OMNI_BACKUP_PATH); - zip.extractAllTo(OMNI_EXTRACT_DIR, false /* overwrite */, true /* keepOriginalPermission */); - } - - // Remove current juggler directory - await fs.promises.rm(OMNI_JUGGLER_DIR, { recursive: true }); - // Repopulate with tip-of-tree juggler files - const jarmn = await fs.promises.readFile(JARMN_PATH, 'utf8'); - const jarLines = jarmn.split('\n').map(line => line.trim()).filter(line => line.startsWith('content/') && line.endsWith(')')); - for (const line of jarLines) { - const tokens = line.split(/\s+/); - const toPath = path.join(OMNI_JUGGLER_DIR, tokens[0]); - const fromPath = path.join(__dirname, browserName, 'juggler', tokens[1].slice(1, -1)); - await fs.promises.mkdir(path.dirname(toPath), { recursive: true }); - await fs.promises.copyFile(fromPath, toPath); - } - - await fs.promises.unlink(omniWithJugglerPath); - { - const zip = new AdmZip(); - zip.addLocalFolder(OMNI_EXTRACT_DIR); - zip.writeZip(omniWithJugglerPath); - } - - const module = await import(URL.pathToFileURL(path.join(__dirname, browserName, 'install-preferences.js'))); - await module.default.installFirefoxPreferences(path.join(BUILD_DIRECTORY, 'firefox')); - - // Output executable path to be used in test. - console.log(` - browser: ${browserName} - buildNumber: ${buildNumber} - buildPlatform: ${buildPlatform} - executablePath: ${path.join(BUILD_DIRECTORY, ...EXECUTABLE_PATHS[buildPlatform])} - `); -} - - -function httpRequest(url, method, response) { - const options = URL.parse(url); - options.method = method; - - const requestCallback = res => { - if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) - httpRequest(res.headers.location, method, response); - else - response(res); - }; - const request = options.protocol === 'https:' ? - https.request(options, requestCallback) : - http.request(options, requestCallback); - request.end(); - return request; -} - -function downloadFile(url, destinationPath, progressCallback) { - let downloadedBytes = 0; - let totalBytes = 0; - - let fulfill, reject; - const promise = new Promise((x, y) => { fulfill = x; reject = y; }); - - const request = httpRequest(url, 'GET', response => { - if (response.statusCode !== 200) { - const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`); - // consume response data to free up memory - response.resume(); - reject(error); - return; - } - const file = fs.createWriteStream(destinationPath); - file.on('finish', () => fulfill()); - file.on('error', error => reject(error)); - response.pipe(file); - totalBytes = parseInt(response.headers['content-length'], 10); - if (progressCallback) - response.on('data', onData); - }); - request.on('error', error => reject(error)); - return promise; - - function onData(chunk) { - downloadedBytes += chunk.length; - progressCallback(downloadedBytes, totalBytes); - } -} - -function getUbuntuVersionSync() { - if (os.platform() !== 'linux') - return ''; - try { - let osReleaseText; - if (fs.existsSync('/etc/upstream-release/lsb-release')) - osReleaseText = fs.readFileSync('/etc/upstream-release/lsb-release', 'utf8'); - else - osReleaseText = fs.readFileSync('/etc/os-release', 'utf8'); - if (!osReleaseText) - return ''; - return getUbuntuVersionInternal(osReleaseText); - } catch (e) { - return ''; - } -} - -function getUbuntuVersionInternal(osReleaseText) { - const fields = new Map(); - for (const line of osReleaseText.split('\n')) { - const tokens = line.split('='); - const name = tokens.shift(); - let value = tokens.join('=').trim(); - if (value.startsWith('"') && value.endsWith('"')) - value = value.substring(1, value.length - 1); - if (!name) - continue; - fields.set(name.toLowerCase(), value); - } - // For Linux mint - if (fields.get('distrib_id') && fields.get('distrib_id').toLowerCase() === 'ubuntu') - return fields.get('distrib_release') || ''; - if (!fields.get('name') || fields.get('name').toLowerCase() !== 'ubuntu') - return ''; - return fields.get('version_id') || ''; -} - -function getHostPlatform() { - const platform = os.platform(); - if (platform === 'darwin') { - const [major, minor] = child_process.execSync('sw_vers -productVersion', { - stdio: ['ignore', 'pipe', 'ignore'] - }).toString('utf8').trim().split('.').map(x => parseInt(x, 10)); - let arm64 = false; - // BigSur is the first version that might run on Apple Silicon. - if (major >= 11) { - arm64 = child_process.execSync('/usr/sbin/sysctl -in hw.optional.arm64', { - stdio: ['ignore', 'pipe', 'ignore'] - }).toString().trim() === '1'; - } - const LAST_STABLE_MAC_MAJOR_VERSION = 11; - // All new MacOS releases increase major version. - let macVersion = `${major}`; - if (major === 10) { - // Pre-BigSur MacOS was increasing minor version every release. - macVersion = `${major}.${minor}`; - } else if (major > LAST_STABLE_MAC_MAJOR_VERSION) { - // Best-effort support for MacOS beta versions. - macVersion = LAST_STABLE_MAC_MAJOR_VERSION + ''; - } - const archSuffix = arm64 ? '-arm64' : ''; - return `mac${macVersion}${archSuffix}`; - } - if (platform === 'linux') { - const ubuntuVersion = getUbuntuVersionSync(); - if (parseInt(ubuntuVersion, 10) <= 19) - return 'ubuntu18.04'; - return 'ubuntu20.04'; - } - if (platform === 'win32') - return 'win64'; - return platform; -} - -async function main() { - const buildInfo = await ensureFirefoxBuild(browserName, process.argv[3], process.argv[4]).catch(e => { - console.log(e.message); - process.exit(1); - }); - await repackageJuggler(browserName, buildInfo); -} - -await main(); - diff --git a/browser_patches/roll_from_upstream.sh b/browser_patches/roll_from_upstream.sh new file mode 100755 index 00000000000000..ec8b6912c984a4 --- /dev/null +++ b/browser_patches/roll_from_upstream.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# A script to roll browser patches from internal repository. + +set -e +set +x + +trap "cd $(pwd -P)" EXIT +cd "$(dirname "$0")" + +SCRIPT_PATH=$(pwd -P) + +if [[ "$#" -ne 1 ]]; then + echo "Usage: $0 " + exit 1 +fi + +SOURCE_DIRECTORY="$1" + +if [[ $(basename "${SOURCE_DIRECTORY}") != "playwright-browsers" ]]; then + echo "ERROR: the source directory must be named 'playwright-browsers'" + exit 1 +fi + +if ! [[ -d "${SOURCE_DIRECTORY}/browser_patches" ]]; then + echo "ERROR: the ${SOURCE_DIRECTORY}/browser_patches does not exist" + exit 1 +fi + +files=( + "./firefox/juggler/" + "./firefox/patches/" + "./firefox/preferences/" + "./firefox/UPSTREAM_CONFIG.sh" + "./webkit/embedder/" + "./webkit/patches/" + "./webkit/pw_run.sh" + "./webkit/UPSTREAM_CONFIG.sh" + "./winldd/" +) + +for file in "${files[@]}"; do + rsync -av --delete "${SOURCE_DIRECTORY}/browser_patches/${file}" "${SCRIPT_PATH}/${file}" +done + diff --git a/browser_patches/sanitize_and_compress_log.js b/browser_patches/sanitize_and_compress_log.js deleted file mode 100755 index aa9f469a9a454d..00000000000000 --- a/browser_patches/sanitize_and_compress_log.js +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env node -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const fs = require('fs'); -const zlib = require('zlib'); -const readline = require('readline'); - -if (process.argv.length < 3) { - console.log('ERROR: output file path has to be specified!'); - process.exit(1); -} -const OUTPUT_PATH = process.argv[2]; - -// These env variable values should be removed from logs no matter what. -const BLOCKLIST_ENV_KEYS = new Set([ - 'AZ_ACCOUNT_NAME', - 'AZ_ACCOUNT_KEY', - 'TELEGRAM_BOT_KEY', -]); - -// These env variable values can stay in logs - they are harmless. -const ALLOWLIST_ENV_KEYS = new Set([ - 'SHELL', - 'TERM', - 'USER', - 'PWD', - 'EDITOR', - 'LANG', - 'HOME', - 'LOGNAME', - 'COLORTERM', - 'TMPDIR', -]); - -const sanitizeEnv = Object.entries(process.env).filter(([key, value]) => { - if (BLOCKLIST_ENV_KEYS.has(key)) - return true; - if (ALLOWLIST_ENV_KEYS.has(key)) - return false; - // Sanitize all env variables that have `KEY` or `ACCOUNT` as a name. - if (key.toUpperCase().includes('KEY') || key.toUpperCase().includes('ACCOUNT')) - return true; - // We shouldn't try sanitizing env values that are too short. - if (value.trim().length < 7) - return false; - return true; -}); - -const rl = readline.createInterface({ - input: process.stdin, - crlfDelay: Infinity, -}); - -const gzip = zlib.createGzip(); -gzip.pipe(fs.createWriteStream(OUTPUT_PATH)); - -rl.on('line', line => { - for (const [key, value] of sanitizeEnv) - line = line.split(value).join(`<${key}>`); - console.log(line); - gzip.write(line + '\n'); -}); - -rl.on('close', () => { - gzip.end(); -}); - diff --git a/browser_patches/send_telegram_message.js b/browser_patches/send_telegram_message.js deleted file mode 100644 index c7f3ad78622fe0..00000000000000 --- a/browser_patches/send_telegram_message.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// @ts-check -const https = require('https'); - -const TELEGRAM_CHAT_ID = "-1001225613794"; - -(async () => { - const { TELEGRAM_BOT_KEY } = process.env; - if (!TELEGRAM_BOT_KEY) { - console.log('environment variable \'TELEGRAM_BOT_KEY\' is not set'); - return; - } - - const text = process.argv[2]; - if (!text) { - console.log('Text not set!'); - console.log('Usage: node send_telegram_message.js '); - return; - } - - await sendTelegramMessage(TELEGRAM_BOT_KEY, text); - console.log('Telegram message sent successfully!'); -})().catch(error => { - console.error(`Failed to send Telegram message. Error: ${error}`); -}) - -/** - * @param {string} apiKey - * @param {string} text - */ -async function sendTelegramMessage(apiKey, text) { - await new Promise((resolve, reject) => { - const request = https.request({ - hostname: 'api.telegram.org', - path: `/bot${apiKey}/sendMessage`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - }, res => { - let body = ''; - res.on('data', chunk => body += chunk.toString()); - res.on('end', () => { - if (res.statusCode !== 200) - reject(new Error(`Telegram API returned status code ${res.statusCode}. Body: ${body}`)); - else - resolve(JSON.parse(body)); - }); - res.on('error', err => { - reject(err); - }); - }); - request.on('error',reject); - request.write(JSON.stringify({ - disable_web_page_preview: true, - chat_id: TELEGRAM_CHAT_ID, - parse_mode: 'html', - text, - disable_notification: false, - })); - request.end(); - }); -} diff --git a/browser_patches/upload.sh b/browser_patches/upload.sh deleted file mode 100755 index 70c813e939fd97..00000000000000 --- a/browser_patches/upload.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -source "./utils.sh" - -if [[ ($1 == '--help') || ($1 == '-h') ]]; then - echo "usage: $(basename "$0") [BLOB-PATH] [--check|ZIP-PATH]" - echo - echo "Upload ZIP-PATH to BLOB-PATH in 'builds' container." - echo - echo "--check pass |--check| as a second parameter instead of a zip-path to check for" - echo " existence of BLOB-PATH" - echo - echo "NOTE: \$AZ_ACCOUNT_KEY (azure account name) and \$AZ_ACCOUNT_NAME (azure account name)" - echo "env variables are required to upload builds to CDN." - exit 0 -fi - -if [[ (-z $AZ_ACCOUNT_KEY) || (-z $AZ_ACCOUNT_NAME) ]]; then - echo "ERROR: Either \$AZ_ACCOUNT_KEY or \$AZ_ACCOUNT_NAME environment variable is missing." - echo " 'Azure Account Name' and 'Azure Account Key' secrets that are required" - echo " to upload builds ot Azure CDN." - exit 1 -fi - -if [[ $# < 2 ]]; then - echo "not enought arguments!" - echo "try '$(basename "$0") --help' for more information" - exit 1 -fi - -BLOB_PATH="$1" -ZIP_PATH="$2" - -if [[ ("$2" == '--check') ]]; then - EXISTS=$(az storage blob exists -c builds --account-key "$AZ_ACCOUNT_KEY" --account-name "$AZ_ACCOUNT_NAME" -n "$BLOB_PATH" --query "exists") - if [[ $EXISTS == "true" ]]; then - exit 0 - else - exit 1 - fi -fi - -GENERATE_MD5_HASH=$(cat <&2 - exit 1; - fi -} - - -createZipForLinux() { - # create a TMP directory to copy all necessary files - local tmpdir=$(mktemp -d -p "$(pwd)/WebKitBuild" -t webkit-deploy-XXXXXXXXXX) - mkdir -p "$tmpdir" - - # copy runner - cp -t "$tmpdir" "$SCRIPTS_DIR"/pw_run.sh - # copy protocol - node "$SCRIPTS_DIR"/concat_protocol.js > "$tmpdir"/protocol.json - - # Generate and unpack MiniBrowser bundles for each port - for port in gtk wpe; do - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/${port^^} \ - Tools/Scripts/generate-bundle \ - --bundle=MiniBrowser --release \ - --platform=${port} --destination="${tmpdir}" - - unzip "${tmpdir}"/MiniBrowser_${port}_release.zip -d "${tmpdir}"/minibrowser-${port} - rm -f "${tmpdir}"/MiniBrowser_${port}_release.zip - done - - # Bundle libstdc++ version that comes from gcc-9. gcc-9 is not default on Ubuntu 18.04 - if is_linux ubuntu 18.04; then - cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 "${tmpdir}/minibrowser-wpe/lib/libstdc++.so.6" - cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 "${tmpdir}/minibrowser-gtk/lib/libstdc++.so.6" - fi - - cd "$tmpdir" - - # zip resulting directory and cleanup TMP. - zip --symlinks -r "$ZIP_PATH" ./ - cd - - rm -rf "$tmpdir" -} - -createZipForWindows() { - # create a TMP directory to copy all necessary files - local tmpdir="/tmp/webkit-deploy-$(date +%s)" - mkdir -p "$tmpdir" - - cp -t "$tmpdir" ./WebKitLibraries/win/bin64/*.dll - cd WebKitBuild/Release/bin64 - cp -r -t "$tmpdir" WebKit.resources - cp -t "$tmpdir" JavaScriptCore.dll PlaywrightLib.dll WTF.dll WebKit2.dll libEGL.dll libGLESv2.dll - cp -t "$tmpdir" Playwright.exe WebKitNetworkProcess.exe WebKitWebProcess.exe - cd - - cd "$(printMSVCRedistDir)" - cp -t "$tmpdir" msvcp140.dll vcruntime140.dll vcruntime140_1.dll msvcp140_2.dll - cd - - - # copy protocol - node "$SCRIPTS_DIR"/concat_protocol.js > "$tmpdir"/protocol.json - # tar resulting directory and cleanup TMP. - cd "$tmpdir" - zip -r "$ZIP_PATH" ./ - cd - - rm -rf "$tmpdir" -} - -createZipForMac() { - # create a TMP directory to copy all necessary files - local tmpdir=$(mktemp -d) - - # copy all relevant files - ditto {./WebKitBuild/Release,"$tmpdir"}/com.apple.WebKit.GPU.xpc - ditto {./WebKitBuild/Release,"$tmpdir"}/com.apple.WebKit.Networking.xpc - ditto {./WebKitBuild/Release,"$tmpdir"}/com.apple.WebKit.WebContent.xpc - ditto {./WebKitBuild/Release,"$tmpdir"}/JavaScriptCore.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/libANGLE-shared.dylib - ditto {./WebKitBuild/Release,"$tmpdir"}/libwebrtc.dylib - ditto {./WebKitBuild/Release,"$tmpdir"}/Playwright.app - ditto {./WebKitBuild/Release,"$tmpdir"}/WebCore.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/WebInspectorUI.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/WebKit.framework - ditto {./WebKitBuild/Release,"$tmpdir"}/WebKitLegacy.framework - ditto {"$SCRIPTS_DIR","$tmpdir"}/pw_run.sh - # copy protocol - node "$SCRIPTS_DIR"/concat_protocol.js > "$tmpdir"/protocol.json - - # Remove all broken symlinks. @see https://github.com/microsoft/playwright/issues/5472 - find "${tmpdir}" -type l ! -exec test -e {} \; -print | xargs rm - - # zip resulting directory and cleanup TMP. - ditto -c -k "$tmpdir" "$ZIP_PATH" - rm -rf "$tmpdir" -} - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPTS_DIR="$(pwd -P)" -source "${SCRIPTS_DIR}/../utils.sh" - -main "$@" diff --git a/browser_patches/webkit/build.sh b/browser_patches/webkit/build.sh deleted file mode 100755 index 209c86d832af29..00000000000000 --- a/browser_patches/webkit/build.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" -SCRIPT_FOLDER="$(pwd -P)" -source "${SCRIPT_FOLDER}/../utils.sh" - -build_gtk() { - if [[ ! -d "./WebKitBuild/GTK/DependenciesGTK" ]]; then - yes | WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/GTK \ - DEBIAN_FRONTEND=noninteractive \ - ./Tools/Scripts/update-webkitgtk-libs - fi - local CMAKE_ARGS=( - --cmakeargs=-DENABLE_INTROSPECTION=OFF - --cmakeargs=-DUSE_GSTREAMER_WEBRTC=FALSE - ) - if is_linux ubuntu 18.04; then - CMAKE_ARGS+=("--cmakeargs=-DUSE_SYSTEM_MALLOC=ON") - fi - if [[ -n "${EXPORT_COMPILE_COMMANDS}" ]]; then - CMAKE_ARGS+=("--cmakeargs=-DCMAKE_EXPORT_COMPILE_COMMANDS=1") - fi - WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/GTK \ - ./Tools/Scripts/build-webkit --gtk --release "${CMAKE_ARGS}" --touch-events --orientation-events --no-bubblewrap-sandbox "${CMAKE_ARGS[@]}" MiniBrowser -} - -build_wpe() { - if [[ ! -d "./WebKitBuild/WPE/DependenciesWPE" ]]; then - yes | WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/WPE \ - DEBIAN_FRONTEND=noninteractive \ - ./Tools/Scripts/update-webkitwpe-libs - fi - local CMAKE_ARGS=( - --cmakeargs=-DENABLE_COG=OFF - --cmakeargs=-DENABLE_INTROSPECTION=OFF - --cmakeargs=-DENABLE_WEBXR=OFF - --cmakeargs=-DUSE_GSTREAMER_WEBRTC=FALSE - ) - if is_linux ubuntu 18.04; then - CMAKE_ARGS+=("--cmakeargs=-DUSE_SYSTEM_MALLOC=ON") - fi - if [[ -n "${EXPORT_COMPILE_COMMANDS}" ]]; then - CMAKE_ARGS+=("--cmakeargs=-DCMAKE_EXPORT_COMPILE_COMMANDS=1") - fi - - WEBKIT_JHBUILD=1 \ - WEBKIT_JHBUILD_MODULESET=minimal \ - WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/WPE \ - ./Tools/Scripts/build-webkit --wpe --release "${CMAKE_ARGS}" --touch-events --orientation-events --no-bubblewrap-sandbox "${CMAKE_ARGS[@]}" MiniBrowser -} - -ensure_linux_deps() { - - yes | DEBIAN_FRONTEND=noninteractive ./Tools/gtk/install-dependencies - yes | DEBIAN_FRONTEND=noninteractive ./Tools/wpe/install-dependencies - # Install JHBuild deps. - yes | DEBIAN_FRONTEND=noninteractive WEBKIT_JHBUILD=1 WEBKIT_JHBUILD_MODULESET=minimal WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/WPE ./Tools/Scripts/update-webkitwpe-libs - yes | DEBIAN_FRONTEND=noninteractive WEBKIT_JHBUILD=1 WEBKIT_JHBUILD_MODULESET=minimal WEBKIT_OUTPUTDIR=$(pwd)/WebKitBuild/GTK ./Tools/Scripts/update-webkitgtk-libs -} - -if [[ ! -z "${WK_CHECKOUT_PATH}" ]]; then - cd "${WK_CHECKOUT_PATH}" - echo "WARNING: checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" -else - cd "$HOME/webkit" -fi - -if is_mac; then - selectXcodeVersionOrDie $(node "$SCRIPT_FOLDER/../get_xcode_version.js" webkit) - ./Tools/Scripts/build-webkit --release --touch-events --orientation-events -elif is_linux; then - args=("$@") - IS_FULL="" - BUILD_GTK="" - BUILD_WPE="" - for ((i="${#args[@]}"-1; i >= 0; --i)); do - case ${args[i]} in - --full) IS_FULL="1"; unset args[i]; ;; - --gtk) BUILD_GTK="1"; unset args[i]; ;; - --wpe) BUILD_WPE="1"; unset args[i]; ;; - esac - done - - # if neither gtk nor wpe is requested then build both. - if [[ -z "${BUILD_GTK}" && -z "${BUILD_WPE}" ]]; then - BUILD_GTK="1" - BUILD_WPE="1" - fi - - echo "== BUILD CONFIGURATION ==" - if [[ -n "${IS_FULL}" ]]; then - echo "- install dependencies: YES" - else - echo "- install dependencies: NO" - fi - if [[ -n "${BUILD_GTK}" ]]; then - echo "- build GTK: YES" - else - echo "- build GTK: NO" - fi - if [[ -n "${BUILD_WPE}" ]]; then - echo "- build WPE: YES" - else - echo "- build WPE: NO" - fi - - if [[ -n "${IS_FULL}" ]]; then - ensure_linux_deps - fi - - if [[ -n "${BUILD_WPE}" ]]; then - build_wpe - fi - - if [[ -n "${BUILD_GTK}" ]]; then - build_gtk - fi -elif is_win; then - /c/Windows/System32/cmd.exe "/c $(cygpath -w "${SCRIPT_FOLDER}"/buildwin.bat)" -else - echo "ERROR: cannot upload on this platform!" 1>&2 - exit 1; -fi diff --git a/browser_patches/webkit/buildwin.bat b/browser_patches/webkit/buildwin.bat deleted file mode 100644 index d3e8dec042e85c..00000000000000 --- a/browser_patches/webkit/buildwin.bat +++ /dev/null @@ -1,5 +0,0 @@ -set PATH=%WEBKIT_BUILD_PATH% -set WEBKIT_LIBRARIES=%CD%\WebKitLibraries\win -set WEBKIT_OUTPUTDIR=%CD%\WebKitBuild -perl %CD%\Tools\Scripts\build-webkit --wincairo --release --no-ninja --touch-events --orientation-events --dark-mode-css --generate-project-only --cmakeargs="-DLIBVPX_PACKAGE_PATH=C:\vcpkg\packages\libvpx_x64-windows" -%DEVENV% %CD%\WebKitBuild\Release\WebKit.sln /build "Release|x64" diff --git a/browser_patches/webkit/clean.sh b/browser_patches/webkit/clean.sh deleted file mode 100755 index fabc11297a4d79..00000000000000 --- a/browser_patches/webkit/clean.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -set -e -set +x - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -source "../utils.sh" - -if [[ ! -z "${WK_CHECKOUT_PATH}" ]]; then - cd "${WK_CHECKOUT_PATH}" - echo "WARNING: checkout path from WK_CHECKOUT_PATH env: ${WK_CHECKOUT_PATH}" -else - cd "$HOME/webkit" -fi - -if is_mac; then - rm -rf ./WebKitBuild -else - if [[ -d ./WebKitBuild ]]; then - rm -rf ./WebKitBuild/Release - fi - if [[ -d ./WebKitBuild/GTK ]]; then - rm -rf ./WebKitBuild/GTK/Release - fi - if [[ -d ./WebKitBuild/WPE ]]; then - rm -rf ./WebKitBuild/WPE/Release - fi -fi diff --git a/browser_patches/webkit/concat_protocol.js b/browser_patches/webkit/concat_protocol.js deleted file mode 100644 index 3e28fb6bb00a99..00000000000000 --- a/browser_patches/webkit/concat_protocol.js +++ /dev/null @@ -1,7 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const checkoutPath = process.env.WK_CHECKOUT_PATH || path.join(process.env.HOME, 'webkit'); -const protocolDir = path.join(checkoutPath, './Source/JavaScriptCore/inspector/protocol'); -const files = fs.readdirSync(protocolDir).filter(f => f.endsWith('.json')).map(f => path.join(protocolDir, f)); -const json = files.map(file => JSON.parse(fs.readFileSync(file))); -console.log(JSON.stringify(json)); diff --git a/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m b/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m index d4ec183fb2dbf1..a6c7be8ae48a96 100644 --- a/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m +++ b/browser_patches/webkit/embedder/Playwright/mac/AppDelegate.m @@ -180,7 +180,7 @@ - (WKWebsiteDataStore *)persistentDataStore _WKWebsiteDataStoreConfiguration *configuration = [[[_WKWebsiteDataStoreConfiguration alloc] init] autorelease]; if (_userDataDir) { // Local storage state should be stored in separate dirs for persistent contexts. - [configuration setShouldUseCustomStoragePaths:YES]; + [configuration setUnifiedOriginStorageLevel:_WKUnifiedOriginStorageLevelNone]; NSURL *cookieFile = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/cookie.db", _userDataDir]]; [configuration _setCookieStorageFile:cookieFile]; @@ -229,10 +229,13 @@ - (WKWebViewConfiguration *)defaultConfiguration if (!configuration) { configuration = [[WKWebViewConfiguration alloc] init]; configuration.websiteDataStore = [self persistentDataStore]; + configuration._controlledByAutomation = true; configuration.preferences._fullScreenEnabled = YES; configuration.preferences._developerExtrasEnabled = YES; configuration.preferences._mediaDevicesEnabled = YES; configuration.preferences._mockCaptureDevicesEnabled = YES; + // Enable WebM support. + configuration.preferences._alternateWebMPlayerEnabled = YES; configuration.preferences._hiddenPageDOMTimerThrottlingEnabled = NO; configuration.preferences._hiddenPageDOMTimerThrottlingAutoIncreases = NO; configuration.preferences._pageVisibilityBasedProcessSuppressionEnabled = NO; @@ -476,8 +479,20 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNaviga decisionHandler(WKNavigationResponsePolicyAllow); return; } + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)navigationResponse.response; + NSString *contentType = [httpResponse valueForHTTPHeaderField:@"Content-Type"]; + if (!navigationResponse.canShowMIMEType && (contentType && [contentType length] > 0)) { + decisionHandler(WKNavigationResponsePolicyDownload); + return; + } + + if (contentType && ([contentType isEqualToString:@"application/pdf"] || [contentType isEqualToString:@"text/pdf"])) { + decisionHandler(WKNavigationResponsePolicyDownload); + return; + } + NSString *disposition = [[httpResponse allHeaderFields] objectForKey:@"Content-Disposition"]; if (disposition && [disposition hasPrefix:@"attachment"]) { decisionHandler(WKNavigationResponsePolicyDownload); @@ -496,6 +511,12 @@ - (void)webView:(WKWebView *)webView navigationResponse:(WKNavigationResponse *) download.delegate = self; } +// Always automatically accept requestStorageAccess dialog. +- (void)_webView:(WKWebView *)webView requestStorageAccessPanelForDomain:(NSString *)requestingDomain underCurrentDomain:(NSString *)currentDomain completionHandler:(void (^)(BOOL result))completionHandler +{ + completionHandler(true); +} + #pragma mark WKDownloadDelegate - (void)download:(WKDownload *)download decideDestinationUsingResponse:(NSURLResponse *)response suggestedFilename:(NSString *)suggestedFilename completionHandler:(void (^)(NSURL * _Nullable destination))completionHandler diff --git a/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m b/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m index 365920d2fb4671..05f37a98d0584c 100644 --- a/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m +++ b/browser_patches/webkit/embedder/Playwright/mac/BrowserWindowController.m @@ -67,10 +67,22 @@ @implementation CustomWindow - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen { - // Retain the frame size, but make sure that - // the top of the window is always visible. - CGFloat yPos = NSHeight(self.screen.frame) - 100 - NSHeight(self.frame); - return NSMakeRect(frameRect.origin.x, yPos, frameRect.size.width, frameRect.size.height); + float kWindowControlBarHeight = 35; + + CGFloat screenHeight = screen.frame.size.height; // e.g. 1080 + CGFloat windowHeight = self.frame.size.height; // e.g. 5000 + CGFloat screenYOffset = screen.frame.origin.y; // screen arrangement offset + + bool exceedsAtTheTop = (NSMaxY(frameRect) - screenYOffset) > screenHeight; + bool exceedsAtTheBottom = (frameRect.origin.y + windowHeight + -screenYOffset - kWindowControlBarHeight) < 0; + CGFloat newOriginY = frameRect.origin.y; + // if it exceeds the height, then we move it to the top of the screen + if (screenHeight > 0 && exceedsAtTheTop) + newOriginY = screenHeight - windowHeight - kWindowControlBarHeight + screenYOffset; + // if it exceeds the bottom, then we move it to the bottom of the screen but make sure that the control bar is still visible + else if (screenHeight > 0 && exceedsAtTheBottom) + newOriginY = -windowHeight + screenYOffset + kWindowControlBarHeight; + return NSMakeRect(frameRect.origin.x, newOriginY, frameRect.size.width, frameRect.size.height); } @end @@ -199,7 +211,7 @@ - (void)awakeFromNib | _WKRenderingProgressEventFirstLayoutAfterSuppressedIncrementalRendering | _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering; - _webView.customUserAgent = @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15"; + _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; @@ -670,6 +682,12 @@ - (void)_webView:(WebView *)sender runBeforeUnloadConfirmPanelWithMessage:(NSStr }]; } +// Always automatically accept requestStorageAccess dialog. +- (void)_webView:(WKWebView *)webView requestStorageAccessPanelForDomain:(NSString *)requestingDomain underCurrentDomain:(NSString *)currentDomain completionHandler:(void (^)(BOOL result))completionHandler +{ + completionHandler(true); +} + - (WKDragDestinationAction)_webView:(WKWebView *)webView dragDestinationActionMaskForDraggingInfo:(id)draggingInfo { return WKDragDestinationActionAny; @@ -706,7 +724,7 @@ - (void)loadHTMLString:(NSString *)HTMLString [_webView loadHTMLString:HTMLString baseURL:nil]; } -static NSSet *dataTypes() +static NSSet *dataTypes(void) { return [WKWebsiteDataStore allWebsiteDataTypes]; } @@ -774,8 +792,20 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNaviga decisionHandler(WKNavigationResponsePolicyAllow); return; } + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)navigationResponse.response; + NSString *contentType = [httpResponse valueForHTTPHeaderField:@"Content-Type"]; + if (!navigationResponse.canShowMIMEType && (contentType && [contentType length] > 0)) { + decisionHandler(WKNavigationResponsePolicyDownload); + return; + } + + if (contentType && ([contentType isEqualToString:@"application/pdf"] || [contentType isEqualToString:@"text/pdf"])) { + decisionHandler(WKNavigationResponsePolicyDownload); + return; + } + NSString *disposition = [[httpResponse allHeaderFields] objectForKey:@"Content-Disposition"]; if (disposition && [disposition hasPrefix:@"attachment"]) { decisionHandler(WKNavigationResponsePolicyDownload); diff --git a/browser_patches/webkit/embedder/Playwright/win/Playwright.rc b/browser_patches/webkit/embedder/Playwright/win/Playwright.rc index 4430f19062cc9f..8d712765121dcb 100644 --- a/browser_patches/webkit/embedder/Playwright/win/Playwright.rc +++ b/browser_patches/webkit/embedder/Playwright/win/Playwright.rc @@ -1,76 +1,76 @@ -// Microsoft Visual C++ generated resource script. -// -#include "PlaywrightResource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#define APSTUDIO_HIDDEN_SYMBOLS -#include "windows.h" -#undef APSTUDIO_HIDDEN_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_PLAYWRIGHT ICON "Playwright.ico" - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "PlaywrightResource.\0" -END - -2 TEXTINCLUDE -BEGIN - "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""windows.h""\r\n" - "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "PlaywrightResource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_PLAYWRIGHT ICON "Playwright.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "PlaywrightResource.\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/browser_patches/webkit/embedder/Playwright/win/PlaywrightLib.rc b/browser_patches/webkit/embedder/Playwright/win/PlaywrightLib.rc index 83039d330fa60c..ddd837e49fa72a 100644 --- a/browser_patches/webkit/embedder/Playwright/win/PlaywrightLib.rc +++ b/browser_patches/webkit/embedder/Playwright/win/PlaywrightLib.rc @@ -1,354 +1,354 @@ -// Microsoft Visual C++ generated resource script. -// -#include "PlaywrightLibResource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#define APSTUDIO_HIDDEN_SYMBOLS -#include "windows.h" -#undef APSTUDIO_HIDDEN_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_PLAYWRIGHT ICON "Playwright.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDC_PLAYWRIGHT MENU -BEGIN - POPUP "&File" - BEGIN - MENUITEM "New Window\tCtrl-N" IDM_NEW_WINDOW - MENUITEM "Close\tCtrl-W", IDM_CLOSE_WINDOW - END - POPUP "&View" - BEGIN - MENUITEM "Actual Size\tCtrl+0", IDM_ACTUAL_SIZE - MENUITEM "Zoom In\tCtrl++", IDM_ZOOM_IN - MENUITEM "Zoom Out\tCtrl+-", IDM_ZOOM_OUT - MENUITEM "Invert Colors", IDM_INVERT_COLORS - END - POPUP "&History" - BEGIN - MENUITEM "Reload\tCtrl-R", IDM_RELOAD - MENUITEM "Back", IDM_HISTORY_BACKWARD - MENUITEM "Forward", IDM_HISTORY_FORWARD - END - POPUP "D&evelop" - BEGIN - MENUITEM "Show Web Inspector", IDM_WEB_INSPECTOR - END - POPUP "&Help" - BEGIN - MENUITEM "&About ...", IDM_ABOUT - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Accelerator -// - -IDC_PLAYWRIGHT ACCELERATORS -BEGIN - "/", IDM_ABOUT, ASCII, ALT, NOINVERT - "0", IDM_ACTUAL_SIZE, VIRTKEY, CONTROL, NOINVERT - "?", IDM_ABOUT, ASCII, ALT, NOINVERT - "R", IDM_RELOAD, VIRTKEY, CONTROL, NOINVERT - "N", IDM_NEW_WINDOW, VIRTKEY, CONTROL, NOINVERT - VK_ADD, IDM_ZOOM_IN, VIRTKEY, CONTROL, NOINVERT - VK_OEM_MINUS, IDM_ZOOM_OUT, VIRTKEY, CONTROL, NOINVERT - VK_OEM_PLUS, IDM_ZOOM_IN, VIRTKEY, CONTROL, NOINVERT - VK_SUBTRACT, IDM_ZOOM_OUT, VIRTKEY, CONTROL, NOINVERT -END - -IDR_ACCELERATORS_PRE ACCELERATORS -BEGIN - "W", IDM_CLOSE_WINDOW, VIRTKEY, CONTROL, NOINVERT -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUTBOX DIALOGEX 22, 17, 230, 41 -STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU -CAPTION "About" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - ICON IDI_PLAYWRIGHT,IDC_MYICON,14,9,20,20 - LTEXT "Playwright Version 1.1",IDC_STATIC,49,10,119,8 - LTEXT "Copyright (C) 2015-2019",IDC_STATIC,49,20,119,8 - DEFPUSHBUTTON "OK",IDOK,186,10,30,11,WS_GROUP -END - -IDD_CACHES DIALOGEX 0, 0, 401, 456 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,287,435,50,14 - PUSHBUTTON "Cancel",IDCANCEL,344,435,50,14 - GROUPBOX "FastMalloc",IDC_STATIC,208,14,186,67 - GROUPBOX "WebCore Cache",IDC_STATIC,17,83,376,105 - GROUPBOX "JavaScript Heap",IDC_STATIC,18,193,376,168 - GROUPBOX "Site Icon Database",IDC_STATIC,18,366,142,65 - GROUPBOX "Font and Glyph Caches",IDC_STATIC,168,366,226,66 - GROUPBOX "CFURLCache",IDC_STATIC,7,14,197,67 - PUSHBUTTON "Empty URLCache",IDC_EMPTY_URL_CACHE,131,63,69,14,WS_DISABLED - PUSHBUTTON "Return Free Memory",IDC_RETURN_FREE_MEMORY,308,63,76,14,WS_DISABLED - PUSHBUTTON "Empty WebCore Cache",IDC_EMPTY_WEBCORE_CACHE,21,170,83,14,WS_DISABLED - CONTROL "Disable WebCore Cache",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,119,172,93,10 - PUSHBUTTON "Garbage Collect JavaScript Objects",IDC_GC_JSC,253,343,135,14,WS_DISABLED - RTEXT "Reserved VM",IDC_STATIC,212,26,67,9 - RTEXT "0",IDC_RESERVED_VM,290,26,94,8 - RTEXT "Committed VM",IDC_STATIC,211,39,67,8 - RTEXT "0",IDC_COMMITTED_VM,290,39,94,8 - RTEXT "Free List Bytes",IDC_STATIC,211,52,67,8 - RTEXT "0",IDC_FREE_LIST_BYTES,290,52,94,8 - RTEXT "Images",IDC_STATIC,37,106,24,8 - RTEXT "CSS",IDC_STATIC,47,116,14,8 - RTEXT "XSL",IDC_STATIC,49,126,12,8 - RTEXT "JavaScript",IDC_STATIC,27,135,34,8 - RTEXT "Total",IDC_STATIC,43,146,17,8 - LTEXT "Objects",IDC_STATIC,111,96,26,8 - LTEXT "Bytes",IDC_STATIC,175,96,19,8 - LTEXT "Live",IDC_STATIC,232,96,14,8 - LTEXT "Decoded",IDC_STATIC,284,96,29,8 - LTEXT "Purgeable",IDC_STATIC,351,96,33,8 - RTEXT "0",IDC_IMAGES_OBJECT_COUNT,100,106,32,8 - RTEXT "0",IDC_CSS_OBJECT_COUNT,100,116,32,8 - RTEXT "0",IDC_XSL_OBJECT_COUNT,100,126,32,8 - RTEXT "0",IDC_JSC_OBJECT_COUNT,100,135,32,8 - RTEXT "0",IDC_TOTAL_OBJECT_COUNT,100,146,32,8 - RTEXT "0",IDC_IMAGES_BYTES,162,106,32,8 - RTEXT "0",IDC_CSS_BYTES,162,116,32,8 - RTEXT "0",IDC_XSL_BYTES,162,126,32,8 - RTEXT "0",IDC_JSC_BYTES,162,135,32,8 - RTEXT "0",IDC_TOTAL_BYTES,162,146,32,8 - RTEXT "0",IDC_IMAGES_LIVE_COUNT,221,106,32,8 - RTEXT "0",IDC_CSS_LIVE_COUNT,221,116,32,8 - RTEXT "0",IDC_XSL_LIVE_COUNT,221,126,32,8 - RTEXT "0",IDC_JSC_LIVE_COUNT,221,135,32,8 - RTEXT "0",IDC_TOTAL_LIVE_COUNT,221,146,32,8 - RTEXT "0",IDC_IMAGES_DECODED_COUNT,284,106,32,8 - RTEXT "0",IDC_CSS_DECODED_COUNT,284,116,32,8 - RTEXT "0",IDC_XSL_DECODED_COUNT,284,126,32,8 - RTEXT "0",IDC_JSC_DECODED_COUNT,284,135,32,8 - RTEXT "0",IDC_TOTAL_DECODED,284,146,32,8 - RTEXT "0",IDC_IMAGES_PURGEABLE_COUNT,354,106,32,8 - RTEXT "0",IDC_CSS_PURGEABLE_COUNT,354,116,32,8 - RTEXT "0",IDC_XSL_PURGEABLE_COUNT,354,126,32,8 - RTEXT "0",IDC_JSC_PURGEABLE_COUNT,354,135,32,8 - RTEXT "0",IDC_TOTAL_PURGEABLE,354,146,32,8 - RTEXT "Total Objects",IDC_STATIC,63,207,44,8 - RTEXT "Global Objects",IDC_STATIC,56,217,51,8 - RTEXT "Protected Objects",IDC_STATIC,48,227,59,8 - RTEXT "0",IDC_TOTAL_JSC_HEAP_OBJECTS,127,207,56,8 - RTEXT "0",IDC_GLOBAL_JSC_HEAP_OBJECTS,127,217,56,8 - RTEXT "0",IDC_PROTECTED_JSC_HEAP_OBJECTS,127,227,56,8 - RTEXT "Size",IDC_STATIC56,223,207,14,8 - RTEXT "Free",IDC_STATIC57,222,217,16,8 - RTEXT "0",IDC_JSC_HEAP_SIZE,270,207,56,8 - RTEXT "0",IDC_JSC_HEAP_FREE,270,217,56,8 - PUSHBUTTON "Purge Inactive Font Data",IDC_BUTTON5,293,415,95,14,WS_DISABLED - LTEXT "Total Font Data Objects",IDC_STATIC,208,379,78,8 - LTEXT "Inactive Font Data Objects",IDC_STATIC,198,390,88,8 - LTEXT "Glyph Pages",IDC_STATIC,246,402,40,8 - RTEXT "0",IDC_TOTAL_FONT_OBJECTS,329,379,56,8 - RTEXT "0",IDC_INACTIVE_FONT_OBJECTS,329,390,56,8 - RTEXT "0",IDC_GLYPH_PAGES,329,402,56,8 - LTEXT "Page URL Mappings",IDC_STATIC,33,380,64,8 - LTEXT "Retained Page URLs",IDC_STATIC,31,390,66,8 - LTEXT "Site Icon Records",IDC_STATIC,40,400,57,8 - LTEXT "Site Icons with Data",IDC_STATIC,32,410,65,8 - RTEXT "0",IDC_PAGE_URL_MAPPINGS,101,380,52,8 - RTEXT "0",IDC_RETAINED_PAGE_URLS,101,390,52,8 - RTEXT "0",IDC_SITE_ICON_RECORDS,101,400,52,8 - RTEXT "0",IDC_SITE_ICONS_WITH_DATA,101,410,52,8 -END - -IDD_AUTH DIALOGEX 0, 0, 231, 119 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Authentication Required" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "Sign In",IDOK,116,98,50,14 - PUSHBUTTON "Cancel",IDCANCEL,174,98,50,14 - LTEXT "Realm",IDC_REALM_TEXT,67,21,157,8 - RTEXT "User Name:",IDC_STATIC,7,41,57,8 - EDITTEXT IDC_AUTH_USER,67,39,157,14,ES_AUTOHSCROLL - RTEXT "Password:",IDC_STATIC,7,66,57,8 - EDITTEXT IDC_AUTH_PASSWORD,67,64,157,14,ES_PASSWORD | ES_AUTOHSCROLL -END - -IDD_PROXY DIALOGEX 0, 0, 310, 176 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Proxy Configuration" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,199,155,50,14 - PUSHBUTTON "Cancel",IDCANCEL,253,155,50,14 - CONTROL "Use system default proxy configuration.",IDC_PROXY_DEFAULT, - "Button",BS_AUTORADIOBUTTON | WS_GROUP,22,15,226,10 - CONTROL "Use custom proxy configuration:",IDC_PROXY_CUSTOM, - "Button",BS_AUTORADIOBUTTON,22,33,226,10 - CONTROL "Don't use proxy.",IDC_PROXY_DISABLE,"Button",BS_AUTORADIOBUTTON,22,117,226,10 - EDITTEXT IDC_PROXY_URL,76,52,193,14,ES_AUTOHSCROLL - EDITTEXT IDC_PROXY_EXCLUDE,76,85,193,14,ES_AUTOHSCROLL - LTEXT "URL:",IDC_STATIC,30,55,43,8,0,WS_EX_RIGHT - LTEXT "Excude list:",IDC_STATIC,30,88,43,8,0,WS_EX_RIGHT - LTEXT "Example: http://192.168.0.2:8000",IDC_STATIC,80,68,194,8 - LTEXT "Comma separated hostnames.",IDC_STATIC,80,101,194,8 -END - -IDD_SERVER_TRUST DIALOGEX 0, 0, 319, 184 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Server Trust Evaluation Request" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "Yes",IDOK,197,163,50,14 - PUSHBUTTON "No",IDCANCEL,262,163,50,14 - LTEXT "Certificate information",IDC_STATIC,7,7,294,17 - EDITTEXT IDC_SERVER_TRUST_TEXT,7,24,305,130,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "PlaywrightLibResource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""windows.h""\r\n" - "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ABOUTBOX, DIALOG - BEGIN - END - - IDD_CACHES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 394 - TOPMARGIN, 7 - BOTTOMMARGIN, 449 - END - - IDD_AUTH, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 224 - VERTGUIDE, 64 - VERTGUIDE, 67 - TOPMARGIN, 7 - BOTTOMMARGIN, 92 - HORZGUIDE, 25 - HORZGUIDE, 50 - END - - IDD_PROXY, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 303 - VERTGUIDE, 22 - TOPMARGIN, 7 - BOTTOMMARGIN, 169 - END - - IDD_SERVER_TRUST, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 312 - TOPMARGIN, 7 - BOTTOMMARGIN, 177 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDB_TOOLBAR BITMAP "toolbar.bmp" - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_APP_TITLE "Playwright" - IDC_PLAYWRIGHT "Playwright" -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "PlaywrightLibResource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_PLAYWRIGHT ICON "Playwright.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_PLAYWRIGHT MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "New Window\tCtrl-N" IDM_NEW_WINDOW + MENUITEM "Close\tCtrl-W", IDM_CLOSE_WINDOW + END + POPUP "&View" + BEGIN + MENUITEM "Actual Size\tCtrl+0", IDM_ACTUAL_SIZE + MENUITEM "Zoom In\tCtrl++", IDM_ZOOM_IN + MENUITEM "Zoom Out\tCtrl+-", IDM_ZOOM_OUT + MENUITEM "Invert Colors", IDM_INVERT_COLORS + END + POPUP "&History" + BEGIN + MENUITEM "Reload\tCtrl-R", IDM_RELOAD + MENUITEM "Back", IDM_HISTORY_BACKWARD + MENUITEM "Forward", IDM_HISTORY_FORWARD + END + POPUP "D&evelop" + BEGIN + MENUITEM "Show Web Inspector", IDM_WEB_INSPECTOR + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_PLAYWRIGHT ACCELERATORS +BEGIN + "/", IDM_ABOUT, ASCII, ALT, NOINVERT + "0", IDM_ACTUAL_SIZE, VIRTKEY, CONTROL, NOINVERT + "?", IDM_ABOUT, ASCII, ALT, NOINVERT + "R", IDM_RELOAD, VIRTKEY, CONTROL, NOINVERT + "N", IDM_NEW_WINDOW, VIRTKEY, CONTROL, NOINVERT + VK_ADD, IDM_ZOOM_IN, VIRTKEY, CONTROL, NOINVERT + VK_OEM_MINUS, IDM_ZOOM_OUT, VIRTKEY, CONTROL, NOINVERT + VK_OEM_PLUS, IDM_ZOOM_IN, VIRTKEY, CONTROL, NOINVERT + VK_SUBTRACT, IDM_ZOOM_OUT, VIRTKEY, CONTROL, NOINVERT +END + +IDR_ACCELERATORS_PRE ACCELERATORS +BEGIN + "W", IDM_CLOSE_WINDOW, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 22, 17, 230, 41 +STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + ICON IDI_PLAYWRIGHT,IDC_MYICON,14,9,20,20 + LTEXT "Playwright Version 1.1",IDC_STATIC,49,10,119,8 + LTEXT "Copyright (C) 2015-2019",IDC_STATIC,49,20,119,8 + DEFPUSHBUTTON "OK",IDOK,186,10,30,11,WS_GROUP +END + +IDD_CACHES DIALOGEX 0, 0, 401, 456 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,287,435,50,14 + PUSHBUTTON "Cancel",IDCANCEL,344,435,50,14 + GROUPBOX "FastMalloc",IDC_STATIC,208,14,186,67 + GROUPBOX "WebCore Cache",IDC_STATIC,17,83,376,105 + GROUPBOX "JavaScript Heap",IDC_STATIC,18,193,376,168 + GROUPBOX "Site Icon Database",IDC_STATIC,18,366,142,65 + GROUPBOX "Font and Glyph Caches",IDC_STATIC,168,366,226,66 + GROUPBOX "CFURLCache",IDC_STATIC,7,14,197,67 + PUSHBUTTON "Empty URLCache",IDC_EMPTY_URL_CACHE,131,63,69,14,WS_DISABLED + PUSHBUTTON "Return Free Memory",IDC_RETURN_FREE_MEMORY,308,63,76,14,WS_DISABLED + PUSHBUTTON "Empty WebCore Cache",IDC_EMPTY_WEBCORE_CACHE,21,170,83,14,WS_DISABLED + CONTROL "Disable WebCore Cache",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,119,172,93,10 + PUSHBUTTON "Garbage Collect JavaScript Objects",IDC_GC_JSC,253,343,135,14,WS_DISABLED + RTEXT "Reserved VM",IDC_STATIC,212,26,67,9 + RTEXT "0",IDC_RESERVED_VM,290,26,94,8 + RTEXT "Committed VM",IDC_STATIC,211,39,67,8 + RTEXT "0",IDC_COMMITTED_VM,290,39,94,8 + RTEXT "Free List Bytes",IDC_STATIC,211,52,67,8 + RTEXT "0",IDC_FREE_LIST_BYTES,290,52,94,8 + RTEXT "Images",IDC_STATIC,37,106,24,8 + RTEXT "CSS",IDC_STATIC,47,116,14,8 + RTEXT "XSL",IDC_STATIC,49,126,12,8 + RTEXT "JavaScript",IDC_STATIC,27,135,34,8 + RTEXT "Total",IDC_STATIC,43,146,17,8 + LTEXT "Objects",IDC_STATIC,111,96,26,8 + LTEXT "Bytes",IDC_STATIC,175,96,19,8 + LTEXT "Live",IDC_STATIC,232,96,14,8 + LTEXT "Decoded",IDC_STATIC,284,96,29,8 + LTEXT "Purgeable",IDC_STATIC,351,96,33,8 + RTEXT "0",IDC_IMAGES_OBJECT_COUNT,100,106,32,8 + RTEXT "0",IDC_CSS_OBJECT_COUNT,100,116,32,8 + RTEXT "0",IDC_XSL_OBJECT_COUNT,100,126,32,8 + RTEXT "0",IDC_JSC_OBJECT_COUNT,100,135,32,8 + RTEXT "0",IDC_TOTAL_OBJECT_COUNT,100,146,32,8 + RTEXT "0",IDC_IMAGES_BYTES,162,106,32,8 + RTEXT "0",IDC_CSS_BYTES,162,116,32,8 + RTEXT "0",IDC_XSL_BYTES,162,126,32,8 + RTEXT "0",IDC_JSC_BYTES,162,135,32,8 + RTEXT "0",IDC_TOTAL_BYTES,162,146,32,8 + RTEXT "0",IDC_IMAGES_LIVE_COUNT,221,106,32,8 + RTEXT "0",IDC_CSS_LIVE_COUNT,221,116,32,8 + RTEXT "0",IDC_XSL_LIVE_COUNT,221,126,32,8 + RTEXT "0",IDC_JSC_LIVE_COUNT,221,135,32,8 + RTEXT "0",IDC_TOTAL_LIVE_COUNT,221,146,32,8 + RTEXT "0",IDC_IMAGES_DECODED_COUNT,284,106,32,8 + RTEXT "0",IDC_CSS_DECODED_COUNT,284,116,32,8 + RTEXT "0",IDC_XSL_DECODED_COUNT,284,126,32,8 + RTEXT "0",IDC_JSC_DECODED_COUNT,284,135,32,8 + RTEXT "0",IDC_TOTAL_DECODED,284,146,32,8 + RTEXT "0",IDC_IMAGES_PURGEABLE_COUNT,354,106,32,8 + RTEXT "0",IDC_CSS_PURGEABLE_COUNT,354,116,32,8 + RTEXT "0",IDC_XSL_PURGEABLE_COUNT,354,126,32,8 + RTEXT "0",IDC_JSC_PURGEABLE_COUNT,354,135,32,8 + RTEXT "0",IDC_TOTAL_PURGEABLE,354,146,32,8 + RTEXT "Total Objects",IDC_STATIC,63,207,44,8 + RTEXT "Global Objects",IDC_STATIC,56,217,51,8 + RTEXT "Protected Objects",IDC_STATIC,48,227,59,8 + RTEXT "0",IDC_TOTAL_JSC_HEAP_OBJECTS,127,207,56,8 + RTEXT "0",IDC_GLOBAL_JSC_HEAP_OBJECTS,127,217,56,8 + RTEXT "0",IDC_PROTECTED_JSC_HEAP_OBJECTS,127,227,56,8 + RTEXT "Size",IDC_STATIC56,223,207,14,8 + RTEXT "Free",IDC_STATIC57,222,217,16,8 + RTEXT "0",IDC_JSC_HEAP_SIZE,270,207,56,8 + RTEXT "0",IDC_JSC_HEAP_FREE,270,217,56,8 + PUSHBUTTON "Purge Inactive Font Data",IDC_BUTTON5,293,415,95,14,WS_DISABLED + LTEXT "Total Font Data Objects",IDC_STATIC,208,379,78,8 + LTEXT "Inactive Font Data Objects",IDC_STATIC,198,390,88,8 + LTEXT "Glyph Pages",IDC_STATIC,246,402,40,8 + RTEXT "0",IDC_TOTAL_FONT_OBJECTS,329,379,56,8 + RTEXT "0",IDC_INACTIVE_FONT_OBJECTS,329,390,56,8 + RTEXT "0",IDC_GLYPH_PAGES,329,402,56,8 + LTEXT "Page URL Mappings",IDC_STATIC,33,380,64,8 + LTEXT "Retained Page URLs",IDC_STATIC,31,390,66,8 + LTEXT "Site Icon Records",IDC_STATIC,40,400,57,8 + LTEXT "Site Icons with Data",IDC_STATIC,32,410,65,8 + RTEXT "0",IDC_PAGE_URL_MAPPINGS,101,380,52,8 + RTEXT "0",IDC_RETAINED_PAGE_URLS,101,390,52,8 + RTEXT "0",IDC_SITE_ICON_RECORDS,101,400,52,8 + RTEXT "0",IDC_SITE_ICONS_WITH_DATA,101,410,52,8 +END + +IDD_AUTH DIALOGEX 0, 0, 231, 119 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Authentication Required" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Sign In",IDOK,116,98,50,14 + PUSHBUTTON "Cancel",IDCANCEL,174,98,50,14 + LTEXT "Realm",IDC_REALM_TEXT,67,21,157,8 + RTEXT "User Name:",IDC_STATIC,7,41,57,8 + EDITTEXT IDC_AUTH_USER,67,39,157,14,ES_AUTOHSCROLL + RTEXT "Password:",IDC_STATIC,7,66,57,8 + EDITTEXT IDC_AUTH_PASSWORD,67,64,157,14,ES_PASSWORD | ES_AUTOHSCROLL +END + +IDD_PROXY DIALOGEX 0, 0, 310, 176 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Proxy Configuration" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,199,155,50,14 + PUSHBUTTON "Cancel",IDCANCEL,253,155,50,14 + CONTROL "Use system default proxy configuration.",IDC_PROXY_DEFAULT, + "Button",BS_AUTORADIOBUTTON | WS_GROUP,22,15,226,10 + CONTROL "Use custom proxy configuration:",IDC_PROXY_CUSTOM, + "Button",BS_AUTORADIOBUTTON,22,33,226,10 + CONTROL "Don't use proxy.",IDC_PROXY_DISABLE,"Button",BS_AUTORADIOBUTTON,22,117,226,10 + EDITTEXT IDC_PROXY_URL,76,52,193,14,ES_AUTOHSCROLL + EDITTEXT IDC_PROXY_EXCLUDE,76,85,193,14,ES_AUTOHSCROLL + LTEXT "URL:",IDC_STATIC,30,55,43,8,0,WS_EX_RIGHT + LTEXT "Excude list:",IDC_STATIC,30,88,43,8,0,WS_EX_RIGHT + LTEXT "Example: http://192.168.0.2:8000",IDC_STATIC,80,68,194,8 + LTEXT "Comma separated hostnames.",IDC_STATIC,80,101,194,8 +END + +IDD_SERVER_TRUST DIALOGEX 0, 0, 319, 184 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Server Trust Evaluation Request" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Yes",IDOK,197,163,50,14 + PUSHBUTTON "No",IDCANCEL,262,163,50,14 + LTEXT "Certificate information",IDC_STATIC,7,7,294,17 + EDITTEXT IDC_SERVER_TRUST_TEXT,7,24,305,130,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "PlaywrightLibResource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + END + + IDD_CACHES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 394 + TOPMARGIN, 7 + BOTTOMMARGIN, 449 + END + + IDD_AUTH, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 224 + VERTGUIDE, 64 + VERTGUIDE, 67 + TOPMARGIN, 7 + BOTTOMMARGIN, 92 + HORZGUIDE, 25 + HORZGUIDE, 50 + END + + IDD_PROXY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 303 + VERTGUIDE, 22 + TOPMARGIN, 7 + BOTTOMMARGIN, 169 + END + + IDD_SERVER_TRUST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 312 + TOPMARGIN, 7 + BOTTOMMARGIN, 177 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_TOOLBAR BITMAP "toolbar.bmp" + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_APP_TITLE "Playwright" + IDC_PLAYWRIGHT "Playwright" +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.cpp b/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.cpp index 5116eba9527c7e..ee4ea065a71b24 100644 --- a/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.cpp +++ b/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -99,9 +100,11 @@ WebKitBrowserWindow::WebKitBrowserWindow(BrowserWindowClient& client, HWND mainW WKPagePolicyClientV1 policyClient = { }; policyClient.base.version = 1; policyClient.base.clientInfo = this; - policyClient.decidePolicyForResponse_deprecatedForUseWithV0 = decidePolicyForResponse; + policyClient.decidePolicyForResponse = decidePolicyForResponse; policyClient.decidePolicyForNavigationAction = decidePolicyForNavigationAction; WKPageSetPagePolicyClient(page, &policyClient.base); + + WKPageSetControlledByAutomation(page, true); resetZoom(); } @@ -399,9 +402,10 @@ void WebKitBrowserWindow::decidePolicyForNavigationAction(WKPageRef page, WKFram WKFramePolicyListenerUse(listener); } -void WebKitBrowserWindow::decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo) +void WebKitBrowserWindow::decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, bool canShowMIMEType, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo) { - if (WKURLResponseIsAttachment(response)) + // Safari renders resources without content-type as text. + if (WKURLResponseIsAttachment(response) || (!WKStringIsEmpty(WKURLResponseCopyMIMEType(response)) && !canShowMIMEType)) WKFramePolicyListenerDownload(listener); else WKFramePolicyListenerUse(listener); diff --git a/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.h b/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.h index a8d08516c137da..6b677e808fb900 100644 --- a/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.h +++ b/browser_patches/webkit/embedder/Playwright/win/WebKitBrowserWindow.h @@ -73,7 +73,7 @@ class WebKitBrowserWindow { static WKRect getWindowFrame(WKPageRef page, const void *clientInfo); static void didNotHandleKeyEvent(WKPageRef, WKNativeEventPtr, const void*); static void decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKFrameRef, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef, const void* clientInfo); - static void decidePolicyForResponse(WKPageRef, WKFrameRef, WKURLResponseRef, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef, const void*); + static void decidePolicyForResponse(WKPageRef, WKFrameRef, WKURLResponseRef, WKURLRequestRef, bool, WKFramePolicyListenerRef, WKTypeRef, const void*); BrowserWindowClient& m_client; WKRetainPtr m_view; diff --git a/browser_patches/webkit/patches/bootstrap.diff b/browser_patches/webkit/patches/bootstrap.diff index 7d8e8ce828fd72..cfe960294f6756 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 5cfff6ac7f3828fe6445140282e12a002b983f0f..19108d5e4e1baa6177baaa6e0df604cf2dcd4a36 100644 +index 522a3aeb15fb3148c4b55c287bbca1e9ef801594..c888f78cebf0dfa148ebc0259edeb5fba369ba7a 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt -@@ -1359,22 +1359,27 @@ set(JavaScriptCore_INSPECTOR_DOMAINS +@@ -1392,22 +1392,27 @@ set(JavaScriptCore_INSPECTOR_DOMAINS ${JAVASCRIPTCORE_DIR}/inspector/protocol/CSS.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Canvas.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Console.json @@ -31,10 +31,10 @@ index 5cfff6ac7f3828fe6445140282e12a002b983f0f..19108d5e4e1baa6177baaa6e0df604cf ${JAVASCRIPTCORE_DIR}/inspector/protocol/ServiceWorker.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Target.json diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make -index 92652ba9bcd53553ab52166b633a4f0d6263d324..da5c253e67adb8edec7df6af84fa65743972b63c 100644 +index e3f99308f7066a980fe75d717bd90a0a5b354b98..d7cd13f5f2a33e9d0fd3bce673244bd05388ccc4 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make -@@ -290,22 +290,27 @@ INSPECTOR_DOMAINS := \ +@@ -297,22 +297,27 @@ INSPECTOR_DOMAINS := \ $(JavaScriptCore)/inspector/protocol/CSS.json \ $(JavaScriptCore)/inspector/protocol/Canvas.json \ $(JavaScriptCore)/inspector/protocol/Console.json \ @@ -62,24 +62,8 @@ index 92652ba9bcd53553ab52166b633a4f0d6263d324..da5c253e67adb8edec7df6af84fa6574 $(JavaScriptCore)/inspector/protocol/Security.json \ $(JavaScriptCore)/inspector/protocol/ServiceWorker.json \ $(JavaScriptCore)/inspector/protocol/Target.json \ -diff --git a/Source/JavaScriptCore/bindings/ScriptValue.cpp b/Source/JavaScriptCore/bindings/ScriptValue.cpp -index d28bffd30f21910bb63f515efc6fa9c7749825a4..498ea4b88e0befb9b526c188e079bb5b9882b374 100644 ---- a/Source/JavaScriptCore/bindings/ScriptValue.cpp -+++ b/Source/JavaScriptCore/bindings/ScriptValue.cpp -@@ -79,7 +79,10 @@ static RefPtr jsToInspectorValue(JSGlobalObject* globalObject, JSVa - PropertyNameArray propertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); - object.methodTable()->getOwnPropertyNames(&object, globalObject, propertyNames, DontEnumPropertiesMode::Exclude); - for (auto& name : propertyNames) { -- auto inspectorValue = jsToInspectorValue(globalObject, object.get(globalObject, name), maxDepth); -+ JSValue childValue = object.get(globalObject, name); -+ if (childValue.isUndefined()) -+ continue; -+ auto inspectorValue = jsToInspectorValue(globalObject, childValue, maxDepth); - if (!inspectorValue) - return nullptr; - inspectorObject->setValue(name.string(), inspectorValue.releaseNonNull()); diff --git a/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp -index 18b6dab3b9df38d781c5c767f76a29d8d18dbe02..0f3a341056f429ff282abcab22be4843c60f546c 100644 +index 528cceee66a1b1c91a0d0e59d5f1a1770a050c17..0f3a341056f429ff282abcab22be4843c60f546c 100644 --- a/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp +++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp @@ -32,14 +32,21 @@ @@ -92,7 +76,7 @@ index 18b6dab3b9df38d781c5c767f76a29d8d18dbe02..0f3a341056f429ff282abcab22be4843 static String addPrefixToIdentifier(unsigned long identifier) { -- return makeString("0.", identifier); +- return makeString("0."_s, identifier); + return makeString(s_processID, ".", identifier); } @@ -118,19 +102,19 @@ index eb25aedee4cd9ebe007e06c2515b37ee095b06f4..badf6559595c8377db1089ca3c25008e static String requestId(unsigned long identifier); }; diff --git a/Source/JavaScriptCore/inspector/InjectedScript.cpp b/Source/JavaScriptCore/inspector/InjectedScript.cpp -index 8b290faebc1865519b0e7c514f497585dfc0bbda..53c68bca057c85c94201ef8e9870f0cb9e4cef6f 100644 +index 4ce807389f1643cdd6249c645f581641ec3a5c71..555fef137b2ff085089f9e4cbd150dc7555da926 100644 --- a/Source/JavaScriptCore/inspector/InjectedScript.cpp +++ b/Source/JavaScriptCore/inspector/InjectedScript.cpp -@@ -91,7 +91,7 @@ void InjectedScript::awaitPromise(const String& promiseObjectId, bool returnByVa +@@ -90,7 +90,7 @@ void InjectedScript::awaitPromise(const String& promiseObjectId, bool returnByVa makeAsyncCall(function, WTFMove(callback)); } -void InjectedScript::callFunctionOn(Protocol::ErrorString& errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr& result, std::optional& wasThrown) +void InjectedScript::callFunctionOn(const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, bool awaitPromise, AsyncCallCallback&& callback) { - Deprecated::ScriptFunctionCall function(injectedScriptObject(), "callFunctionOn"_s, inspectorEnvironment()->functionCallHandler()); + ScriptFunctionCall function(globalObject(), injectedScriptObject(), "callFunctionOn"_s, inspectorEnvironment()->functionCallHandler()); function.appendArgument(objectId); -@@ -99,10 +99,8 @@ void InjectedScript::callFunctionOn(Protocol::ErrorString& errorString, const St +@@ -98,10 +98,8 @@ void InjectedScript::callFunctionOn(Protocol::ErrorString& errorString, const St function.appendArgument(arguments); function.appendArgument(returnByValue); function.appendArgument(generatePreview); @@ -143,7 +127,7 @@ index 8b290faebc1865519b0e7c514f497585dfc0bbda..53c68bca057c85c94201ef8e9870f0cb } void InjectedScript::evaluateOnCallFrame(Protocol::ErrorString& errorString, JSC::JSValue callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr& result, std::optional& wasThrown, std::optional& savedResultIndex) -@@ -289,6 +287,10 @@ RefPtr InjectedScript::wrapObject(JSC::JSValue +@@ -288,6 +286,10 @@ RefPtr InjectedScript::wrapObject(JSC::JSValue auto callResult = callFunctionWithEvalEnabled(wrapFunction); if (!callResult) return nullptr; @@ -155,7 +139,7 @@ index 8b290faebc1865519b0e7c514f497585dfc0bbda..53c68bca057c85c94201ef8e9870f0cb auto resultValue = toInspectorValue(globalObject(), callResult.value()); if (!resultValue) diff --git a/Source/JavaScriptCore/inspector/InjectedScript.h b/Source/JavaScriptCore/inspector/InjectedScript.h -index e6b24967273095ae424ac9b3fe5e081ee8999ab7..9f7b72259ab79504b8bfcc24d35abe70d7372065 100644 +index f09e489283ebf688f73d1e740c3102306173017b..954c8cef9e9a2d3b7c0f128899fa0b2292258186 100644 --- a/Source/JavaScriptCore/inspector/InjectedScript.h +++ b/Source/JavaScriptCore/inspector/InjectedScript.h @@ -64,7 +64,7 @@ public: @@ -167,11 +151,27 @@ index e6b24967273095ae424ac9b3fe5e081ee8999ab7..9f7b72259ab79504b8bfcc24d35abe70 void getFunctionDetails(Protocol::ErrorString&, const String& functionId, RefPtr& result); void functionDetails(Protocol::ErrorString&, JSC::JSValue, RefPtr& result); void getPreview(Protocol::ErrorString&, const String& objectId, RefPtr& result); +diff --git a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp +index 14585eabd64a109573bed2336643f4c52e11f180..a1c34d3891405f1c8f6148a031f5045d2fa4d079 100644 +--- a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp ++++ b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp +@@ -84,7 +84,10 @@ static RefPtr jsToInspectorValue(JSC::JSGlobalObject* globalObject, + JSC::PropertyNameArray propertyNames(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude); + object.methodTable()->getOwnPropertyNames(&object, globalObject, propertyNames, JSC::DontEnumPropertiesMode::Exclude); + for (auto& name : propertyNames) { +- auto inspectorValue = jsToInspectorValue(globalObject, object.get(globalObject, name), maxDepth); ++ JSC::JSValue childValue = object.get(globalObject, name); ++ if (childValue.isUndefined()) ++ continue; ++ auto inspectorValue = jsToInspectorValue(globalObject, childValue, maxDepth); + if (!inspectorValue) + return nullptr; + inspectorObject->setValue(name.string(), inspectorValue.releaseNonNull()); diff --git a/Source/JavaScriptCore/inspector/InjectedScriptSource.js b/Source/JavaScriptCore/inspector/InjectedScriptSource.js -index 9f2623d75b9825639b0cc664c3b4d64a6615fedb..ecc1f6fe0cf2e005e8740a2f652ce88dd199dcca 100644 +index a665049c589ad59f92b147ef2e9e058eb72bb67c..71f4db75938e830e5d8e201c291c17da3aaff6c9 100644 --- a/Source/JavaScriptCore/inspector/InjectedScriptSource.js +++ b/Source/JavaScriptCore/inspector/InjectedScriptSource.js -@@ -167,7 +167,7 @@ let InjectedScript = class InjectedScript +@@ -172,7 +172,7 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase return; } @@ -180,7 +180,7 @@ index 9f2623d75b9825639b0cc664c3b4d64a6615fedb..ecc1f6fe0cf2e005e8740a2f652ce88d callback("Object with given id is not a Promise"); return; } -@@ -202,14 +202,16 @@ let InjectedScript = class InjectedScript +@@ -207,14 +207,16 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase return this._evaluateAndWrap(callFrame.evaluateWithScopeExtension, callFrame, expression, objectGroup, isEvalOnCallFrame, includeCommandLineAPI, returnByValue, generatePreview, saveResult); } @@ -200,7 +200,7 @@ index 9f2623d75b9825639b0cc664c3b4d64a6615fedb..ecc1f6fe0cf2e005e8740a2f652ce88d let resolvedArgs = @createArrayWithoutPrototype(); if (args) { -@@ -218,22 +220,37 @@ let InjectedScript = class InjectedScript +@@ -223,22 +225,37 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase try { resolvedArgs[i] = this._resolveCallArgument(callArgs[i]); } catch (e) { @@ -224,7 +224,7 @@ index 9f2623d75b9825639b0cc664c3b4d64a6615fedb..ecc1f6fe0cf2e005e8740a2f652ce88d + callback(this._createThrownValue("Given expression does not evaluate to a function", objectGroupName)); + return; + } -+ let result = func.apply(object, resolvedArgs); ++ let result = func.@apply(object, resolvedArgs); + if (awaitPromise && isDefined(result) && (InjectedScriptHost.internalConstructorName(result) === 'Promise')) { + result.then(value => { + callback({ @@ -248,7 +248,7 @@ index 9f2623d75b9825639b0cc664c3b4d64a6615fedb..ecc1f6fe0cf2e005e8740a2f652ce88d } diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp -index 1088a6a8f2965e17e52d7ba1d1142b9ed697ad3f..a928811c56eaac0ea5a9a350093cb69e7b3ad59d 100644 +index 820a08fc660633e09675d0e647bd0c50d2fa905a..5ca5ee5a6897b7ef332d906018b457122096df98 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp @@ -101,7 +101,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple @@ -338,7 +338,7 @@ index 4b95964db4d902b4b7f4b0b4c40afea51654ff2f..653842a82ed7a7be8603c9ef88ff48d1 bool m_isPaused { false }; }; diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp -index f06ff03be0fe272e08a46c84b0e81323ac06f90b..cf7b13aabfd13b7e8b258b4795933268c9e90c08 100644 +index 1c40b312afeca605fc8a6aefd993749fce3f3676..b7fbac213249fd15233b60e11a38aae7b934cf7e 100644 --- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp +++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp @@ -218,6 +218,14 @@ void JSGlobalObjectConsoleClient::screenshot(JSGlobalObject*, Ref&&); diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp -index 6e976621186326be53aedeeda618a441d7bea6a6..17bb59df54bb58782c3d5988736d4976794a412d 100644 +index aef96857b46e980a12f2c0a4d38d6035c024ac99..2eb163fe20cbbd975c7f49d9835485152057993d 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp @@ -177,41 +177,43 @@ void InspectorRuntimeAgent::awaitPromise(const Protocol::Runtime::RemoteObjectId @@ -541,7 +541,7 @@ index e81573fd0fffaaf6fd2af36635c78fcdf8608c69..c8cde6cfcde9612624f12e21bd9fa56b // FrontendChannel FrontendChannel::ConnectionType connectionType() const; diff --git a/Source/JavaScriptCore/inspector/protocol/DOM.json b/Source/JavaScriptCore/inspector/protocol/DOM.json -index 6b283d7f5f1804b921a0ffd175ddf5e66eed9fd1..e1a2a96bfed11a3186d59871132b3c7993e8fd4d 100644 +index da665b28060846786b6b2687c355ee68cc398875..81b012a976ad43871d7792edb38d4c0a89021d7b 100644 --- a/Source/JavaScriptCore/inspector/protocol/DOM.json +++ b/Source/JavaScriptCore/inspector/protocol/DOM.json @@ -80,6 +80,16 @@ @@ -561,7 +561,7 @@ index 6b283d7f5f1804b921a0ffd175ddf5e66eed9fd1..e1a2a96bfed11a3186d59871132b3c79 { "id": "EventListener", "type": "object", -@@ -177,6 +187,16 @@ +@@ -199,6 +209,16 @@ { "name": "pseudoId", "$ref": "CSS.PseudoId", "optional": true } ], "description": "An object referencing a node and a pseudo-element, primarily used to identify an animation effect target." @@ -578,18 +578,19 @@ index 6b283d7f5f1804b921a0ffd175ddf5e66eed9fd1..e1a2a96bfed11a3186d59871132b3c79 } ], "commands": [ -@@ -559,7 +579,9 @@ +@@ -628,7 +648,10 @@ "description": "Resolves JavaScript node object for given node id.", "targetTypes": ["page"], "parameters": [ - { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to resolve." }, + { "name": "nodeId", "$ref": "NodeId", "optional": true, "description": "Id of the node to resolve." }, + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "Source element handle." }, ++ { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to resolve the owner element." }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "optional": true, "description": "Specifies in which execution context to adopt to." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." } ], "returns": [ -@@ -626,6 +648,46 @@ +@@ -695,6 +718,46 @@ "parameters": [ { "name": "allow", "type": "boolean" } ] @@ -680,10 +681,10 @@ index 0000000000000000000000000000000000000000..79edea03fed4e9be5da96e1275e182a4 +} diff --git a/Source/JavaScriptCore/inspector/protocol/Emulation.json b/Source/JavaScriptCore/inspector/protocol/Emulation.json new file mode 100644 -index 0000000000000000000000000000000000000000..347a01b3fdd1a8277cb4104558e8bbfa63539374 +index 0000000000000000000000000000000000000000..2a49dd417360da37c83c4d375de468f949dce5db --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Emulation.json -@@ -0,0 +1,51 @@ +@@ -0,0 +1,52 @@ +{ + "domain": "Emulation", + "availability": ["web"], @@ -711,7 +712,8 @@ index 0000000000000000000000000000000000000000..347a01b3fdd1a8277cb4104558e8bbfa + "description": "Credentials to use during HTTP authentication.", + "parameters": [ + { "name": "username", "type": "string", "optional": true }, -+ { "name": "password", "type": "string", "optional": true } ++ { "name": "password", "type": "string", "optional": true }, ++ { "name": "origin", "type": "string", "optional": true } + ] + }, + { @@ -983,13 +985,13 @@ index 96af27ece2ac200e11c4311b3ca0d9d3b5a048da..3168f7806fcbdabec07acc5e304bae1e ], "events": [ diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json -index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61ed836918 100644 +index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..83ac8c3cbc4a57a27e99a48323fe61a936c10a8b 100644 --- a/Source/JavaScriptCore/inspector/protocol/Page.json +++ b/Source/JavaScriptCore/inspector/protocol/Page.json -@@ -21,7 +21,14 @@ +@@ -20,7 +20,14 @@ + "ScriptEnabled", "ShowDebugBorders", "ShowRepaintCounter", - "WebRTCEncryptionEnabled", - "WebSecurityEnabled" + "WebSecurityEnabled", + "DeviceOrientationEventEnabled", @@ -1002,20 +1004,20 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 ] }, { -@@ -49,6 +56,12 @@ - "enum": ["Light", "Dark"], - "description": "Page appearance name." +@@ -62,6 +69,12 @@ + "enum": ["None", "Lax", "Strict"], + "description": "Same-Site policy of a cookie." }, + { -+ "id": "ReducedMotion", ++ "id": "ForcedColors", + "type": "string", -+ "enum": ["Reduce", "NoPreference"], -+ "description": "Page reduced-motion media query override." ++ "enum": ["Active", "None"], ++ "description": "Page forced-colors media query override." + }, { "id": "Frame", "type": "object", -@@ -112,6 +125,51 @@ +@@ -125,6 +138,51 @@ { "name": "secure", "type": "boolean", "description": "True if cookie is secure." }, { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." } ] @@ -1067,7 +1069,7 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 } ], "commands": [ -@@ -131,6 +189,14 @@ +@@ -144,6 +202,14 @@ { "name": "revalidateAllResources", "type": "boolean", "optional": true, "description": "If true, all cached subresources will be revalidated when the main resource loads. Otherwise, only expired cached subresources will be revalidated (the default behavior for most WebKit clients)." } ] }, @@ -1082,7 +1084,7 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 { "name": "navigate", "description": "Navigates current page to the given URL.", -@@ -147,6 +213,14 @@ +@@ -160,6 +226,14 @@ { "name": "value", "type": "string", "optional": true, "description": "Value to override the user agent with. If this value is not provided, the override is removed. Overrides are removed when Web Inspector closes/disconnects." } ] }, @@ -1097,7 +1099,7 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 { "name": "overrideSetting", "description": "Allows the frontend to override the inspected page's settings.", -@@ -204,7 +278,8 @@ +@@ -226,7 +300,8 @@ "name": "setBootstrapScript", "targetTypes": ["page"], "parameters": [ @@ -1107,16 +1109,16 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 ] }, { -@@ -270,6 +345,28 @@ - { "name": "appearance", "$ref": "Appearance", "optional": true } +@@ -283,6 +358,28 @@ + { "name": "media", "type": "string", "description": "Media type to emulate. Empty string disables the override." } ] }, + { -+ "name": "setForcedReducedMotion", -+ "description": "Forces the reduced-motion media query for the page.", ++ "name": "setForcedColors", ++ "description": "Forces the forced-colors media query for the page.", + "targetTypes": ["page"], + "parameters": [ -+ { "name": "reducedMotion", "$ref": "ReducedMotion", "optional": true } ++ { "name": "forcedColors", "$ref": "ForcedColors", "optional": true } + ] + }, + { @@ -1136,7 +1138,7 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 { "name": "snapshotNode", "description": "Capture a snapshot of the specified node that does not include unrelated layers.", -@@ -290,7 +387,8 @@ +@@ -303,7 +400,8 @@ { "name": "y", "type": "integer", "description": "Y coordinate" }, { "name": "width", "type": "integer", "description": "Rectangle width" }, { "name": "height", "type": "integer", "description": "Rectangle height" }, @@ -1146,7 +1148,7 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 ], "returns": [ { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." } -@@ -308,12 +406,92 @@ +@@ -321,12 +419,92 @@ { "name": "setScreenSizeOverride", "description": "Overrides screen size exposed to DOM and used in media queries for testing with provided values.", @@ -1240,7 +1242,7 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 } ], "events": [ -@@ -321,14 +499,16 @@ +@@ -334,14 +512,16 @@ "name": "domContentEventFired", "targetTypes": ["page"], "parameters": [ @@ -1259,7 +1261,7 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 ] }, { -@@ -338,6 +518,14 @@ +@@ -351,6 +531,14 @@ { "name": "frame", "$ref": "Frame", "description": "Frame object." } ] }, @@ -1274,7 +1276,17 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 { "name": "frameDetached", "description": "Fired when frame has been detached from its parent.", -@@ -377,6 +565,22 @@ +@@ -379,7 +567,8 @@ + "targetTypes": ["page"], + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has scheduled a navigation." }, +- { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." } ++ { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." }, ++ { "name": "targetIsCurrentFrame", "type": "boolean", "description": "Whether the naviation will happen in the same frame." } + ] + }, + { +@@ -390,6 +579,22 @@ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } ] }, @@ -1295,11 +1307,11 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 + ] + }, { - "name": "defaultAppearanceDidChange", - "description": "Fired when page's default appearance changes, even if there is a forced appearance.", -@@ -385,6 +589,42 @@ + "name": "defaultUserPreferencesDidChange", + "description": "Fired when the default value of a user preference changes at the system level.", +@@ -397,6 +602,42 @@ "parameters": [ - { "name": "appearance", "$ref": "Appearance", "description": "Name of the appearance that is active (not considering any forced appearance.)" } + { "name": "preferences", "type": "array", "items": { "$ref": "UserPreference" }, "description": "List of user preferences that can be overriden and their new system (default) values." } ] + }, + { @@ -1342,10 +1354,10 @@ index 1c97ad011c5ec183a5866bb98319badd5ec9442f..658937fdc58425b9a164d9bc368a9e61 } diff --git a/Source/JavaScriptCore/inspector/protocol/Playwright.json b/Source/JavaScriptCore/inspector/protocol/Playwright.json new file mode 100644 -index 0000000000000000000000000000000000000000..91bdeadaeb77d223cd4dc47b8bb90850d54a9056 +index 0000000000000000000000000000000000000000..7f0cca1ec49681971d7dd81b8f29b50aff94a200 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Playwright.json -@@ -0,0 +1,277 @@ +@@ -0,0 +1,285 @@ +{ + "domain": "Playwright", + "availability": ["web"], @@ -1557,6 +1569,14 @@ index 0000000000000000000000000000000000000000..91bdeadaeb77d223cd4dc47b8bb90850 + { "name": "uuid", "type": "string" } + ], + "description": "Cancels a current running download." ++ }, ++ { ++ "name": "clearMemoryCache", ++ "description": "Clears browser memory cache.", ++ "async": true, ++ "parameters": [ ++ { "name": "browserContextId", "$ref": "ContextID", "optional": false, "description": "Browser context id." } ++ ] + } + ], + "events": [ @@ -1624,10 +1644,10 @@ index 0000000000000000000000000000000000000000..91bdeadaeb77d223cd4dc47b8bb90850 + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json -index 274b01596d490fb81b48cf89bf668e0634e8b423..357aad51bbdc1768efba89b736bb2964ebc4b30e 100644 +index dfbe4eece1af3748408b5fd968331799aa9e1d30..0e2ae5d96b3cdcc20ecc95ddc7b49538dcb3c302 100644 --- a/Source/JavaScriptCore/inspector/protocol/Runtime.json +++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json -@@ -261,12 +261,21 @@ +@@ -263,12 +263,21 @@ { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether function call should stop on exceptions and mute console. Overrides setPauseOnException state." }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, @@ -1651,7 +1671,7 @@ index 274b01596d490fb81b48cf89bf668e0634e8b423..357aad51bbdc1768efba89b736bb2964 }, { "name": "getPreview", -@@ -404,6 +413,15 @@ +@@ -406,6 +415,15 @@ "parameters": [ { "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution context." } ] @@ -1819,22 +1839,22 @@ index 72c81757450ad5ebacd5fd20d2a16095514802ec..b7d8ab1e04d3850180079870468b28ef private: enum ArgumentRequirement { ArgumentRequired, ArgumentNotRequired }; diff --git a/Source/ThirdParty/libwebrtc/CMakeLists.txt b/Source/ThirdParty/libwebrtc/CMakeLists.txt -index 0d42c17c6a85b2a9f6af319431332f7f8a709188..8899c8e85b11db81d1da14c7f27814883f75da50 100644 +index 026a804a74555ba7dbb13a0e0b84d9953424d85c..952162341951ca3a7713324305f41dd503a51615 100644 --- a/Source/ThirdParty/libwebrtc/CMakeLists.txt +++ b/Source/ThirdParty/libwebrtc/CMakeLists.txt -@@ -398,6 +398,11 @@ set(webrtc_SOURCES - Source/third_party/boringssl/src/ssl/tls13_server.cc - Source/third_party/boringssl/src/ssl/tls_method.cc - Source/third_party/boringssl/src/ssl/tls_record.cc +@@ -551,6 +551,11 @@ set(webrtc_SOURCES + Source/third_party/boringssl/src/util/fipstools/cavp/cavp_main.cc + Source/third_party/boringssl/src/util/fipstools/cavp/cavp_test_util.cc + Source/third_party/boringssl/src/util/fipstools/cavp/test_fips.c +# Playwright begin + Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc + Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc + Source/third_party/libwebm/mkvmuxer/mkvwriter.cc +# Playwright end + Source/third_party/libyuv/source/compare.cc Source/third_party/libyuv/source/compare_common.cc Source/third_party/libyuv/source/compare_gcc.cc - Source/third_party/libyuv/source/convert.cc -@@ -1857,6 +1862,10 @@ set(webrtc_INCLUDE_DIRECTORIES PRIVATE +@@ -2186,6 +2191,10 @@ set(webrtc_INCLUDE_DIRECTORIES PRIVATE Source/third_party/libsrtp/config Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include @@ -1845,14 +1865,14 @@ index 0d42c17c6a85b2a9f6af319431332f7f8a709188..8899c8e85b11db81d1da14c7f2781488 Source/third_party/libyuv/include Source/third_party/opus/src/celt Source/third_party/opus/src/include -diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp -index 4157c0a95fa332ac85a295814fda2fb61f3da434..f77a990c1a52f3ab2943a02a4375bb71d91c1656 100644 ---- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp -+++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp -@@ -338,3 +338,24 @@ __ZN6webrtc32createPixelBufferFromFrameBufferERNS_16VideoFrameBufferERKNSt3__18f - __ZN6webrtc25CreateTaskQueueGcdFactoryEv - __ZN6webrtc27CreatePeerConnectionFactoryEPN3rtc6ThreadES2_S2_NS0_13scoped_refptrINS_17AudioDeviceModuleEEENS3_INS_19AudioEncoderFactoryEEENS3_INS_19AudioDecoderFactoryEEENSt3__110unique_ptrINS_19VideoEncoderFactoryENSA_14default_deleteISC_EEEENSB_INS_19VideoDecoderFactoryENSD_ISG_EEEENS3_INS_10AudioMixerEEENS3_INS_15AudioProcessingEEEPNS_19AudioFrameProcessorENSB_INS_16TaskQueueFactoryENSD_ISP_EEEE - __ZN6webrtc16convertBGRAToYUVEP10__CVBufferS1_ +diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp +index 626efe5d02febd3d80066d2013dd479ecec29471..4c05722dfc3fe885968a69b64adc6f0a0470bcb1 100644 +--- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp ++++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp +@@ -376,3 +376,24 @@ __ZN6webrtc20VideoFrameBufferPoolC1Ebm + __ZN6webrtc20VideoFrameBufferPoolD1Ev + __ZTVN6webrtc12VideoDecoderE + __ZN6webrtc22CreateLibaomAv1EncoderEv +__ZN8mkvmuxer11SegmentInfo15set_writing_appEPKc +__ZN8mkvmuxer11SegmentInfo4InitEv +__ZN8mkvmuxer7Segment10OutputCuesEb @@ -1875,20 +1895,20 @@ index 4157c0a95fa332ac85a295814fda2fb61f3da434..f77a990c1a52f3ab2943a02a4375bb71 +_vpx_codec_version_str +_vpx_codec_vp8_cx diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig -index 64433d3d2a0be3d9b83bde060700af8ce57a0b9d..14e35310c06a3add1cbe951287706be705761580 100644 +index 39ddbe721ba57835c45a4e590726c7a7c99022c4..4020e136c002c0b768f266d87f656585e748d498 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig +++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig -@@ -50,7 +50,7 @@ DYLIB_INSTALL_NAME_BASE_WK_RELOCATABLE_FRAMEWORKS_ = $(NORMAL_WEBCORE_FRAMEWORKS +@@ -37,7 +37,7 @@ DYLIB_INSTALL_NAME_BASE_WK_RELOCATABLE_FRAMEWORKS_ = $(NORMAL_UMBRELLA_FRAMEWORK DYLIB_INSTALL_NAME_BASE_WK_RELOCATABLE_FRAMEWORKS_YES = @loader_path/../../../; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; --HEADER_SEARCH_PATHS = Source Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/third_party/usrsctp Source/third_party/usrsctp/usrsctplib Source/third_party/usrsctp/usrsctplib/usrsctplib Source/webrtc/sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/third_party/usrsctp/usrsctplib/usrsctplib/netinet Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/sdk/objc Source/webrtc/sdk/objc/base Source/webrtc/sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/sdk/objc/Framework/Classes/Common Source/webrtc/sdk/objc/Framework/Classes/Video Source/webrtc/sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include; -+HEADER_SEARCH_PATHS = Source Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/third_party/usrsctp Source/third_party/usrsctp/usrsctplib Source/third_party/usrsctp/usrsctplib/usrsctplib Source/webrtc/sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/third_party/usrsctp/usrsctplib/usrsctplib/netinet Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/sdk/objc Source/webrtc/sdk/objc/base Source/webrtc/sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/sdk/objc/Framework/Classes/Common Source/webrtc/sdk/objc/Framework/Classes/Video Source/webrtc/sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include Source/third_party/libvpx/source/libvpx/third_party/libwebm; +-HEADER_SEARCH_PATHS = Source Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/webrtc/sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/sdk/objc Source/webrtc/sdk/objc/base Source/webrtc/sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/sdk/objc/Framework/Classes/Common Source/webrtc/sdk/objc/Framework/Classes/Video Source/webrtc/sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include Source/third_party/crc32c/config Source/third_party/crc32c/include Source/third_party/crc32c/src/include Source/third_party/libaom/source/libaom; ++HEADER_SEARCH_PATHS = Source Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/webrtc/sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/sdk/objc Source/webrtc/sdk/objc/base Source/webrtc/sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/sdk/objc/Framework/Classes/Common Source/webrtc/sdk/objc/Framework/Classes/Video Source/webrtc/sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include Source/third_party/crc32c/config Source/third_party/crc32c/include Source/third_party/crc32c/src/include Source/third_party/libaom/source/libaom Source/third_party/libwebm/mkvmuxer Source/third_party/libvpx/source/libvpx/third_party/libwebm; PUBLIC_HEADERS_FOLDER_PREFIX = $(WK_LIBRARY_HEADERS_FOLDER_PATH); INSTALL_PUBLIC_HEADER_PREFIX = $(INSTALL_PATH_PREFIX)$(PUBLIC_HEADERS_FOLDER_PREFIX); diff --git a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj -index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6d0eaea03 100644 +index 3156829ef03b1c4d565a9decde0fa36a93736b2c..52f3a7e7ca8287ec2d1b2341f5f24f1e9171ed9d 100644 --- a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj +++ b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj @@ -6,6 +6,20 @@ @@ -1910,9 +1930,9 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 +/* End PBXAggregateTarget section */ + /* Begin PBXBuildFile section */ - 410091CF242CFD6500C5EDA2 /* internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A391FA1EFC493000C4516A /* internal.h */; }; - 410091D2242CFF6F00C5EDA2 /* gcm_nohw.c in Sources */ = {isa = PBXBuildFile; fileRef = 410091D0242CFD8200C5EDA2 /* gcm_nohw.c */; }; -@@ -4529,6 +4543,9 @@ + 2D6BFF60280A93DF00A1A74F /* video_coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45B234C81710028A615 /* video_coding.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D6BFF61280A93EC00A1A74F /* video_codec_initializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45E234C81720028A615 /* video_codec_initializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; +@@ -5081,6 +5095,9 @@ DDF30D9127C5C725006A526F /* receive_side_congestion_controller.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF30D9027C5C725006A526F /* receive_side_congestion_controller.h */; }; DDF30D9527C5C756006A526F /* bwe_defines.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF30D9327C5C756006A526F /* bwe_defines.h */; }; DDF30D9627C5C756006A526F /* remote_bitrate_estimator.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF30D9427C5C756006A526F /* remote_bitrate_estimator.h */; }; @@ -1922,7 +1942,7 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ -@@ -4779,6 +4796,13 @@ +@@ -5345,6 +5362,13 @@ remoteGlobalIDString = DDF30D0527C5C003006A526F; remoteInfo = absl; }; @@ -1936,7 +1956,7 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ -@@ -9558,6 +9582,9 @@ +@@ -10848,6 +10872,9 @@ DDF30D9027C5C725006A526F /* receive_side_congestion_controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = receive_side_congestion_controller.h; sourceTree = ""; }; DDF30D9327C5C756006A526F /* bwe_defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bwe_defines.h; sourceTree = ""; }; DDF30D9427C5C756006A526F /* remote_bitrate_estimator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remote_bitrate_estimator.h; sourceTree = ""; }; @@ -1946,7 +1966,7 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 FB39D0D11200F0E300088E69 /* libwebrtc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libwebrtc.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ -@@ -16876,6 +16903,7 @@ +@@ -19274,6 +19301,7 @@ isa = PBXGroup; children = ( CDFD2F9224C4B2F90048DAC3 /* common */, @@ -1954,7 +1974,7 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 CDEBB19224C0191800ADBD44 /* webm_parser */, ); path = libwebm; -@@ -17343,6 +17371,16 @@ +@@ -19736,6 +19764,16 @@ path = include; sourceTree = ""; }; @@ -1971,25 +1991,25 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 FB39D06E1200ED9200088E69 = { isa = PBXGroup; children = ( -@@ -20024,6 +20062,7 @@ - DDF30CFA27C5A98F006A526F /* PBXBuildRule */, +@@ -22693,6 +22731,7 @@ ); dependencies = ( + 410B3827292B73E90003E515 /* PBXTargetDependency */, + F31720B427FE273100EEE407 /* PBXTargetDependency */, DD2E76E827C6B69A00F2A74C /* PBXTargetDependency */, CDEBB4CC24C01AB400ADBD44 /* PBXTargetDependency */, 411ED040212E0811004320BA /* PBXTargetDependency */, -@@ -20084,6 +20123,7 @@ - 41F77D15215BE45E00E72967 /* yasm */, +@@ -22752,6 +22791,7 @@ CDEBB11824C0187400ADBD44 /* webm */, + DDEBB11824C0187400ADBD44 /* aom */, DDF30D0527C5C003006A526F /* absl */, + F31720AC27FE215900EEE407 /* Copy libvpx headers */, ); }; /* End PBXProject section */ -@@ -20217,6 +20257,23 @@ +@@ -22833,6 +22873,23 @@ shellPath = /bin/sh; - shellScript = "[ \"${WK_USE_NEW_BUILD_SYSTEM}\" = YES ] && exit 0\nxcodebuild -project \"${PROJECT_FILE_PATH}\" -target \"${TARGET_NAME}\" installhdrs SYMROOT=\"${TARGET_TEMP_DIR}/LegacyNestHeaders-build\" DSTROOT=\"${BUILT_PRODUCTS_DIR}\" SDKROOT=\"${SDKROOT}\" -UseNewBuildSystem=YES\n"; + shellScript = "\"${SRCROOT}/Scripts/create-symlink-to-altroot.sh\"\n"; }; + F31720B127FE216400EEE407 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; @@ -2011,17 +2031,17 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ -@@ -21787,6 +21844,9 @@ - 417953DB216983910028266B /* metrics.cc in Sources */, +@@ -24636,6 +24693,9 @@ 5CDD865E1E43B8B500621E92 /* min_max_operations.c in Sources */, 4189395B242A71F5007FDC41 /* min_video_bitrate_experiment.cc in Sources */, + 41B8D8FB28CB85CB00E5FA37 /* missing_mandatory_parameter_cause.cc in Sources */, + F3B7819A24C7CC5200FCB122 /* mkvmuxer.cc in Sources */, + F3B7819924C7CC5200FCB122 /* mkvmuxerutil.cc in Sources */, + F3B7819B24C7CC5200FCB122 /* mkvwriter.cc in Sources */, 4131C387234B957D0028A615 /* moving_average.cc in Sources */, 41FCBB1521B1F7AA00A5DF27 /* moving_average.cc in Sources */, 5CD286101E6A64C90094FDC8 /* moving_max.cc in Sources */, -@@ -22471,6 +22531,11 @@ +@@ -25360,6 +25420,11 @@ target = DDF30D0527C5C003006A526F /* absl */; targetProxy = DD2E76E727C6B69A00F2A74C /* PBXContainerItemProxy */; }; @@ -2033,7 +2053,7 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ -@@ -22719,6 +22784,27 @@ +@@ -25587,6 +25652,27 @@ }; name = Production; }; @@ -2061,7 +2081,7 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 FB39D0711200ED9200088E69 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */; -@@ -22851,6 +22937,16 @@ +@@ -25719,6 +25805,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Production; }; @@ -2078,42 +2098,36 @@ index e4b94b59216277aae01696e6d4846abf8f287dce..8cbe085788ba582ee4615faef20769b6 FB39D0731200ED9200088E69 /* Build configuration list for PBXProject "libwebrtc" */ = { isa = XCConfigurationList; buildConfigurations = ( -diff --git a/Source/WTF/Scripts/Preferences/WebPreferences.yaml b/Source/WTF/Scripts/Preferences/WebPreferences.yaml -index 909094b0ff2cc7273f3d4ac96cf4498f0d0c6e50..51958e6eba239952f834978515b6a3c72a2a52dd 100644 ---- a/Source/WTF/Scripts/Preferences/WebPreferences.yaml -+++ b/Source/WTF/Scripts/Preferences/WebPreferences.yaml -@@ -977,7 +977,7 @@ InspectorStartsAttached: - exposed: [ WebKit ] - defaultValue: +diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +index b8eae87efa5548a716e68bc4e14f79574cd2fc79..701f2f038b8b74c6bf586f68d8f6dfe47f523edb 100644 +--- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml ++++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +@@ -576,6 +576,7 @@ AspectRatioOfImgFromWidthAndHeightEnabled: + default: true + + # FIXME: This is on by default in WebKit2 PLATFORM(COCOA). Perhaps we should consider turning it on for WebKitLegacy as well. ++# Playwright: enable on all platforms to align with Safari. + AsyncClipboardAPIEnabled: + type: bool + status: mature +@@ -586,7 +587,7 @@ AsyncClipboardAPIEnabled: + default: false WebKit: -- default: true -+ default: false + "PLATFORM(COCOA) || PLATFORM(GTK)" : true +- default: false ++ default: true + WebCore: + default: false - InspectorWindowFrame: - type: String -@@ -1736,6 +1736,17 @@ PluginsEnabled: +@@ -1775,6 +1776,7 @@ CrossOriginEmbedderPolicyEnabled: WebCore: default: false -+PointerLockEnabled: -+ type: bool -+ condition: ENABLE(POINTER_LOCK) -+ defaultValue: -+ WebKitLegacy: -+ default: true -+ WebKit: -+ default: true -+ WebCore: -+ default: true -+ - PrivateClickMeasurementEnabled: ++# Playwright: disable setting. + CrossOriginOpenerPolicyEnabled: type: bool - humanReadableName: "Private Click Measurement" -diff --git a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml -index 8e180a9913870eeabba0960fb3eea2aca92bbdfc..be52610f76b05af1cf86a195a2e042909bd276dd 100644 ---- a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml -+++ b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml -@@ -527,7 +527,7 @@ CrossOriginOpenerPolicyEnabled: + status: stable +@@ -1785,7 +1787,7 @@ CrossOriginOpenerPolicyEnabled: WebKitLegacy: default: false WebKit: @@ -2122,27 +2136,58 @@ index 8e180a9913870eeabba0960fb3eea2aca92bbdfc..be52610f76b05af1cf86a195a2e04290 WebCore: default: false -@@ -860,6 +860,7 @@ IsThirdPartyCookieBlockingDisabled: +@@ -1815,7 +1817,7 @@ CustomPasteboardDataEnabled: + WebKitLegacy: + default: false + WebKit: +- "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WIN)": true ++ "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true + default: false + + DNSPrefetchingEnabled: +@@ -1860,6 +1862,7 @@ DOMAudioSessionFullEnabled: WebCore: default: false -+# Playwright: disable loading=lazy - LazyIframeLoadingEnabled: ++# Playwright: enable on all platforms to align with Safari. + DOMPasteAccessRequestsEnabled: type: bool - humanReadableName: "Lazy iframe loading" -@@ -868,9 +869,9 @@ LazyIframeLoadingEnabled: - WebKitLegacy: - default: true + status: internal +@@ -1871,7 +1874,7 @@ DOMPasteAccessRequestsEnabled: + default: false WebKit: -- default: true -+ default: false + "PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(GTK)": true +- default: false ++ default: true WebCore: + default: false + +@@ -3229,6 +3232,7 @@ InspectorAttachmentSide: + WebKit: + default: 0 + ++# Playwright: disable setting. + InspectorStartsAttached: + type: bool + status: embedder +@@ -3236,7 +3240,7 @@ InspectorStartsAttached: + exposed: [ WebKit ] + defaultValue: + WebKit: - default: true + default: false - LazyImageLoadingEnabled: + InspectorWindowFrame: + type: String +@@ -3605,6 +3609,7 @@ LayoutViewportHeightExpansionFactor: + WebCore: + default: 0 + ++# Playwright: disable setting. + LazyIframeLoadingEnabled: type: bool -@@ -929,9 +930,9 @@ MaskWebGLStringsEnabled: + status: stable +@@ -3615,9 +3620,9 @@ LazyIframeLoadingEnabled: WebKitLegacy: default: true WebKit: @@ -2152,62 +2197,69 @@ index 8e180a9913870eeabba0960fb3eea2aca92bbdfc..be52610f76b05af1cf86a195a2e04290 - default: true + default: false - # FIXME: This is on by default in WebKit2. Perhaps we should consider turning it on for WebKitLegacy as well. - MediaCapabilitiesExtensionsEnabled: -@@ -1438,7 +1439,7 @@ SpeechRecognitionEnabled: - WebKitLegacy: - default: false - WebKit: -- "HAVE(SPEECHRECOGNIZER) && ENABLE(MEDIA_STREAM)": true -+ "ENABLE(MEDIA_STREAM)": true - default: false + LazyImageLoadingEnabled: + type: bool +@@ -4971,6 +4976,19 @@ PluginsEnabled: WebCore: default: false -@@ -1553,6 +1554,7 @@ UseGPUProcessForDisplayCapture: - WebKit: - default: true -+# Playwright: force-disable on Windows - UseGPUProcessForWebGLEnabled: ++# Playwright: add preference 'PointerLockEnabled'. ++PointerLockEnabled: ++ type: bool ++ status: embedder ++ condition: ENABLE(POINTER_LOCK) ++ defaultValue: ++ WebKitLegacy: ++ default: true ++ WebKit: ++ default: true ++ WebCore: ++ default: true ++ + PopoverAttributeEnabled: type: bool - humanReadableName: "GPU Process: WebGL" -@@ -1563,7 +1565,7 @@ UseGPUProcessForWebGLEnabled: - default: false - WebKit: - "ENABLE(GPU_PROCESS_BY_DEFAULT) && PLATFORM(IOS_FAMILY) && !HAVE(UIKIT_WEBKIT_INTERNALS)": true -- "PLATFORM(WIN)": true -+ "PLATFORM(WIN)": false - default: false - WebCore: - "ENABLE(GPU_PROCESS_BY_DEFAULT) && PLATFORM(IOS_FAMILY) && !HAVE(UIKIT_WEBKIT_INTERNALS)": true -diff --git a/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml b/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml -index 4ab12fa7bb55377e66167b4f5686abfce6b3e297..27fa81ae823bc360964422bfea153f9253867075 100644 ---- a/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml -+++ b/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml -@@ -979,6 +979,7 @@ UseCGDisplayListsForDOMRendering: + status: stable +@@ -6620,6 +6638,7 @@ UseCGDisplayListsForDOMRendering: WebKit: default: true -+# Playwright: force-disable on Windows ++# Playwright: force-disable on Windows. UseGPUProcessForCanvasRenderingEnabled: type: bool - humanReadableName: "GPU Process: Canvas Rendering" -@@ -989,7 +990,7 @@ UseGPUProcessForCanvasRenderingEnabled: + status: stable +@@ -6632,7 +6651,7 @@ UseGPUProcessForCanvasRenderingEnabled: defaultValue: WebKit: "ENABLE(GPU_PROCESS_BY_DEFAULT)": true -- "PLATFORM(WIN)": true -+ "PLATFORM(WIN)": false +- "USE(GRAPHICS_LAYER_WC)": true ++ "USE(GRAPHICS_LAYER_WC)": false + default: false + + UseGPUProcessForDOMRenderingEnabled: +@@ -6674,6 +6693,7 @@ UseGPUProcessForMediaEnabled: + "ENABLE(GPU_PROCESS_BY_DEFAULT)": true default: false - UseGPUProcessForMediaEnabled: ++# Playwright: force-disable on Windows. + UseGPUProcessForWebGLEnabled: + type: bool + status: internal +@@ -6685,7 +6705,7 @@ UseGPUProcessForWebGLEnabled: + default: false + WebKit: + "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true +- "USE(GRAPHICS_LAYER_WC)": true ++ "USE(GRAPHICS_LAYER_WC)": false + default: false + WebCore: + "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h -index 8863f57db1e6a6c21b61fe7598a39806d1be4028..30ebe6a4609540551c64fd0d7ec49a6afda54338 100644 +index f5f9888057a27c7cb98a5e27e8d79df3044a16f8..621dc90e4003145f61d8c9eb7b4a4569d5c1f1b1 100644 --- a/Source/WTF/wtf/PlatformEnable.h +++ b/Source/WTF/wtf/PlatformEnable.h -@@ -416,7 +416,7 @@ - #endif +@@ -412,7 +412,7 @@ + // ORIENTATION_EVENTS should never get enabled on Desktop, only Mobile. #if !defined(ENABLE_ORIENTATION_EVENTS) -#define ENABLE_ORIENTATION_EVENTS 0 +#define ENABLE_ORIENTATION_EVENTS 1 @@ -2223,21 +2275,8 @@ index 8863f57db1e6a6c21b61fe7598a39806d1be4028..30ebe6a4609540551c64fd0d7ec49a6a #endif #if !defined(ENABLE_TOUCH_ACTION_REGIONS) -diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h -index a7a9a06cb94a14616127b6accebeb9fb106c9699..54fc2622b16096695624a24f044f73ca7373aec1 100644 ---- a/Source/WTF/wtf/PlatformEnableCocoa.h -+++ b/Source/WTF/wtf/PlatformEnableCocoa.h -@@ -255,7 +255,7 @@ - #define ENABLE_DATA_DETECTION 1 - #endif - --#if !defined(ENABLE_DEVICE_ORIENTATION) && !PLATFORM(MAC) && !PLATFORM(MACCATALYST) -+#if !defined(ENABLE_DEVICE_ORIENTATION) && !PLATFORM(MACCATALYST) - #define ENABLE_DEVICE_ORIENTATION 1 - #endif - diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h -index 17ef2b99a00c53e854210ad488369ad232944c5e..59a4dfb0b80a6f8d30ec361b2dbde8e5e2bf3c3d 100644 +index 9465006787c3d98cfac6777dc70eaec84cc3e57e..30e9482570993f847fb0cec3a4fa8403c6903a9f 100644 --- a/Source/WTF/wtf/PlatformHave.h +++ b/Source/WTF/wtf/PlatformHave.h @@ -422,7 +422,7 @@ @@ -2249,7 +2288,7 @@ index 17ef2b99a00c53e854210ad488369ad232944c5e..59a4dfb0b80a6f8d30ec361b2dbde8e5 #define HAVE_OS_DARK_MODE_SUPPORT 1 #endif -@@ -1301,7 +1301,8 @@ +@@ -1328,7 +1328,8 @@ #endif #if PLATFORM(MAC) @@ -2260,10 +2299,10 @@ index 17ef2b99a00c53e854210ad488369ad232944c5e..59a4dfb0b80a6f8d30ec361b2dbde8e5 #if (!defined(HAVE_LOCKDOWN_MODE_PDF_ADDITIONS) && \ diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make -index 818de728babd72eab591b6c29243a62eb66e5192..ed532edaa08fd4d4f2814b82d358e4c69124da10 100644 +index f4c0f3bf7d49dc3e28295a352193db668bb2ca01..09bf179b35afafaa4372fd9f99e769fa965afb87 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make -@@ -994,6 +994,10 @@ JS_BINDING_IDLS := \ +@@ -1063,6 +1063,10 @@ JS_BINDING_IDLS := \ $(WebCore)/dom/Slotable.idl \ $(WebCore)/dom/StaticRange.idl \ $(WebCore)/dom/StringCallback.idl \ @@ -2274,10 +2313,10 @@ index 818de728babd72eab591b6c29243a62eb66e5192..ed532edaa08fd4d4f2814b82d358e4c6 $(WebCore)/dom/Text.idl \ $(WebCore)/dom/TextDecoder.idl \ $(WebCore)/dom/TextDecoderStream.idl \ -@@ -1542,9 +1546,6 @@ JS_BINDING_IDLS := \ - ADDITIONAL_BINDING_IDLS = \ - DocumentTouch.idl \ +@@ -1626,9 +1630,6 @@ ADDITIONAL_BINDING_IDLS = \ GestureEvent.idl \ + Internals+Additions.idl \ + InternalsAdditions.idl \ - Touch.idl \ - TouchEvent.idl \ - TouchList.idl \ @@ -2285,37 +2324,25 @@ index 818de728babd72eab591b6c29243a62eb66e5192..ed532edaa08fd4d4f2814b82d358e4c6 vpath %.in $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) diff --git a/Source/WebCore/Modules/geolocation/Geolocation.cpp b/Source/WebCore/Modules/geolocation/Geolocation.cpp -index a0f3a2f50826db31cf7d6c133e4dfc47bac27528..a09ba013dc815b3f14f67ce799c2edb4bf77134b 100644 +index 9dfd25d4160011d576e9c636e4c805bfd486fd26..573edcb686440ea8426e3a59540250a5dbba5a9b 100644 --- a/Source/WebCore/Modules/geolocation/Geolocation.cpp +++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp -@@ -371,8 +371,9 @@ bool Geolocation::shouldBlockGeolocationRequests() +@@ -362,8 +362,9 @@ bool Geolocation::shouldBlockGeolocationRequests() bool isSecure = SecurityOrigin::isSecure(document()->url()) || document()->isSecureContext(); bool hasMixedContent = !document()->foundMixedContent().isEmpty(); bool isLocalOrigin = securityOrigin()->isLocal(); + bool isPotentiallyTrustworthy = securityOrigin()->isPotentiallyTrustworthy(); if (document()->canAccessResource(ScriptExecutionContext::ResourceType::Geolocation) != ScriptExecutionContext::HasResourceAccess::No) { -- if (isLocalOrigin || (isSecure && !hasMixedContent) || isRequestFromIBooks()) -+ if (isLocalOrigin || isPotentiallyTrustworthy || (isSecure && !hasMixedContent) || isRequestFromIBooks()) +- if (isLocalOrigin || (isSecure && !hasMixedContent)) ++ if (isLocalOrigin || isPotentiallyTrustworthy || (isSecure && !hasMixedContent)) return false; } -diff --git a/Source/WebCore/Modules/speech/SpeechSynthesisErrorEventInit.h b/Source/WebCore/Modules/speech/SpeechSynthesisErrorEventInit.h -index 2472c255319384d9f7361130f2db186b82875e9c..c9f8884711ef948a2d426b1afb21d12cf9e47848 100644 ---- a/Source/WebCore/Modules/speech/SpeechSynthesisErrorEventInit.h -+++ b/Source/WebCore/Modules/speech/SpeechSynthesisErrorEventInit.h -@@ -28,6 +28,7 @@ - #if ENABLE(SPEECH_SYNTHESIS) - - #include "SpeechSynthesisEventInit.h" -+#include "SpeechSynthesisErrorCode.h" - - namespace WebCore { - diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm -index a941d76a4f748718df1e3cff2a6c5e0827f48891..f62db5a27ac0e4c12430e7d19e60c83d768ace22 100644 +index 316aa5b17c5346b2d3e420e7262e7e76e254f427..c2beed6bd1e83257095252146ee3506ce5c92b07 100644 --- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm +++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm -@@ -198,6 +198,7 @@ NS_ASSUME_NONNULL_BEGIN +@@ -195,6 +195,7 @@ - (void)sendEndIfNeeded - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available { @@ -2323,7 +2350,7 @@ index a941d76a4f748718df1e3cff2a6c5e0827f48891..f62db5a27ac0e4c12430e7d19e60c83d ASSERT(isMainThread()); if (available || !_task) -@@ -211,6 +212,7 @@ NS_ASSUME_NONNULL_BEGIN +@@ -208,6 +209,7 @@ - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidC - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription { @@ -2331,15 +2358,15 @@ index a941d76a4f748718df1e3cff2a6c5e0827f48891..f62db5a27ac0e4c12430e7d19e60c83d ASSERT(isMainThread()); [self sendSpeechStartIfNeeded]; -@@ -219,6 +221,7 @@ NS_ASSUME_NONNULL_BEGIN +@@ -216,6 +218,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTran - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult { + UNUSED_PARAM(task); ASSERT(isMainThread()); - [self callbackWithTranscriptions:recognitionResult.transcriptions isFinal:YES]; -@@ -230,6 +233,7 @@ NS_ASSUME_NONNULL_BEGIN + if (task.state == SFSpeechRecognitionTaskStateCanceling || (!_doMultipleRecognitions && task.state == SFSpeechRecognitionTaskStateCompleted)) +@@ -229,6 +232,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecogniti - (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task { @@ -2348,10 +2375,10 @@ index a941d76a4f748718df1e3cff2a6c5e0827f48891..f62db5a27ac0e4c12430e7d19e60c83d [self sendSpeechEndIfNeeded]; diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake -index 9604d21ceb51ab8d20a337c8dbe52c4059043d2c..86a9eec09c4ac457bdd4567eeab570210c1beec3 100644 +index e8647e7b05931395f7b497bfb16408331c278ebf..1aceec655433e68c7829c8b1df3c06f1e8b4c90d 100644 --- a/Source/WebCore/PlatformWPE.cmake +++ b/Source/WebCore/PlatformWPE.cmake -@@ -49,6 +49,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS +@@ -48,6 +48,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/wayland/PlatformDisplayWayland.h platform/graphics/wayland/WlUniquePtr.h @@ -2360,10 +2387,10 @@ index 9604d21ceb51ab8d20a337c8dbe52c4059043d2c..86a9eec09c4ac457bdd4567eeab57021 set(CSS_VALUE_PLATFORM_DEFINES "HAVE_OS_DARK_MODE_SUPPORT=1") diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt -index 9d1777db8db0f19e0bf93f027878d882e0b4e268..97c4a6ac951e302086d8e91ad431bcea26607e09 100644 +index 73659fb63491ffb4e3b13f6f0e1be05a4ab7d5bd..9dfbac4c044116073c953b251af186abab67d660 100644 --- a/Source/WebCore/SourcesCocoa.txt +++ b/Source/WebCore/SourcesCocoa.txt -@@ -641,3 +641,9 @@ platform/graphics/angle/GraphicsContextGLANGLE.cpp @no-unify +@@ -692,3 +692,9 @@ platform/graphics/angle/GraphicsContextGLANGLE.cpp @no-unify platform/graphics/cocoa/ANGLEUtilitiesCocoa.cpp @no-unify platform/graphics/cocoa/GraphicsContextGLCocoa.mm @no-unify platform/graphics/cv/GraphicsContextGLCVCocoa.cpp @no-unify @@ -2374,13 +2401,13 @@ index 9d1777db8db0f19e0bf93f027878d882e0b4e268..97c4a6ac951e302086d8e91ad431bcea +JSTouchList.cpp +// Playwright end diff --git a/Source/WebCore/SourcesGTK.txt b/Source/WebCore/SourcesGTK.txt -index a2504495796d1d625afd0092ffd21739be30470f..64be77d2ed6ef550e1f7d6779516187b471d1026 100644 +index 7df855a40eb3a6d436344f62be590ae6b04dd075..d361e813dec0bc71bb88ee720f31d00b4202c5e9 100644 --- a/Source/WebCore/SourcesGTK.txt +++ b/Source/WebCore/SourcesGTK.txt -@@ -138,3 +138,10 @@ platform/xdg/MIMETypeRegistryXdg.cpp +@@ -127,3 +127,10 @@ platform/text/hyphen/HyphenationLibHyphen.cpp + platform/unix/LoggingUnix.cpp - rendering/RenderThemeAdwaita.cpp - rendering/RenderThemeGtk.cpp + platform/xdg/MIMETypeRegistryXdg.cpp + +// Playwright: begin. +JSSpeechSynthesisErrorCode.cpp @@ -2389,10 +2416,10 @@ index a2504495796d1d625afd0092ffd21739be30470f..64be77d2ed6ef550e1f7d6779516187b +JSSpeechSynthesisEventInit.cpp +// Playwright: end. diff --git a/Source/WebCore/SourcesWPE.txt b/Source/WebCore/SourcesWPE.txt -index 3351067102d0e96e185ec0e6ac01bf7273346de3..4ba7934bb5ec781525bb732dbe0736ee67d415be 100644 +index 59835e77a29bb8f7de658f64e2a3665dd46f40c4..950ccf859147d92c79f110525a28263163c35d54 100644 --- a/Source/WebCore/SourcesWPE.txt +++ b/Source/WebCore/SourcesWPE.txt -@@ -43,6 +43,8 @@ editing/libwpe/EditorLibWPE.cpp +@@ -45,6 +45,8 @@ editing/libwpe/EditorLibWPE.cpp loader/soup/ResourceLoaderSoup.cpp @@ -2401,7 +2428,7 @@ index 3351067102d0e96e185ec0e6ac01bf7273346de3..4ba7934bb5ec781525bb732dbe0736ee page/linux/ResourceUsageOverlayLinux.cpp page/linux/ResourceUsageThreadLinux.cpp -@@ -93,8 +95,19 @@ platform/text/LocaleICU.cpp +@@ -91,6 +93,17 @@ platform/text/LocaleICU.cpp platform/unix/LoggingUnix.cpp @@ -2410,34 +2437,20 @@ index 3351067102d0e96e185ec0e6ac01bf7273346de3..4ba7934bb5ec781525bb732dbe0736ee platform/wpe/PlatformScreenWPE.cpp platform/xdg/MIMETypeRegistryXdg.cpp - - rendering/RenderThemeAdwaita.cpp + ++// Playwright: begin. +platform/wpe/SelectionData.cpp + -+// Playwright: begin. +JSSpeechSynthesisErrorCode.cpp +JSSpeechSynthesisErrorEvent.cpp +JSSpeechSynthesisErrorEventInit.cpp +JSSpeechSynthesisEventInit.cpp +// Playwright: end. -diff --git a/Source/WebCore/WebCore.order b/Source/WebCore/WebCore.order -index a5938677622935e2c6ca3ed76c3a12d0eb7e04a7..cea2a0e330cfdf01b172b3f6acc60acbb680776f 100644 ---- a/Source/WebCore/WebCore.order -+++ b/Source/WebCore/WebCore.order -@@ -3089,7 +3089,6 @@ __ZN7WebCore14DocumentLoader23stopLoadingSubresourcesEv - __ZN7WebCore14DocumentLoader18stopLoadingPlugInsEv - __ZN7WebCore14DocumentLoader15detachFromFrameEv - __ZN7WebCore20ApplicationCacheHost22setDOMApplicationCacheEPNS_19DOMApplicationCacheE --__ZN7WebCore24InspectorInstrumentation27loaderDetachedFromFrameImplEPNS_19InstrumentingAgentsEPNS_14DocumentLoaderE - __ZN7WebCore14DocumentLoaderD0Ev - __ZN7WebCore14DocumentLoaderD2Ev - __ZN7WebCore14DocumentLoader17clearMainResourceEv diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj -index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf219ae334 100644 +index 1d29265b3d4c2d9f27f0b0e9abbadef62f5b5b39..26760067772988145a752952c3112256ddd05f8b 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj -@@ -5589,6 +5589,13 @@ +@@ -5885,6 +5885,13 @@ EDE3A5000C7A430600956A37 /* ColorMac.h in Headers */ = {isa = PBXBuildFile; fileRef = EDE3A4FF0C7A430600956A37 /* ColorMac.h */; settings = {ATTRIBUTES = (Private, ); }; }; EDEC98030AED7E170059137F /* WebCorePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEC98020AED7E170059137F /* WebCorePrefix.h */; }; EFCC6C8F20FE914400A2321B /* CanvasActivityRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -2451,7 +2464,7 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf F12171F616A8CF0B000053CA /* WebVTTElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F12171F416A8BC63000053CA /* WebVTTElement.h */; }; F32BDCD92363AACA0073B6AE /* UserGestureEmulationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = F32BDCD72363AACA0073B6AE /* UserGestureEmulationScope.h */; }; F344C7141125B82C00F26EEE /* InspectorFrontendClient.h in Headers */ = {isa = PBXBuildFile; fileRef = F344C7121125B82C00F26EEE /* InspectorFrontendClient.h */; settings = {ATTRIBUTES = (Private, ); }; }; -@@ -18089,6 +18096,14 @@ +@@ -19086,6 +19093,14 @@ EDEC98020AED7E170059137F /* WebCorePrefix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebCorePrefix.h; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; EFB7287B2124C73D005C2558 /* CanvasActivityRecord.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CanvasActivityRecord.cpp; sourceTree = ""; }; EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasActivityRecord.h; sourceTree = ""; }; @@ -2466,7 +2479,7 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf F12171F316A8BC63000053CA /* WebVTTElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebVTTElement.cpp; sourceTree = ""; }; F12171F416A8BC63000053CA /* WebVTTElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTElement.h; sourceTree = ""; }; F32BDCD52363AAC90073B6AE /* UserGestureEmulationScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserGestureEmulationScope.cpp; sourceTree = ""; }; -@@ -24827,6 +24842,11 @@ +@@ -26228,6 +26243,11 @@ BC4A5324256055590028C592 /* TextDirectionSubmenuInclusionBehavior.h */, 2D4F96F11A1ECC240098BF88 /* TextIndicator.cpp */, 2D4F96F21A1ECC240098BF88 /* TextIndicator.h */, @@ -2478,7 +2491,7 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf F48570A42644C76D00C05F71 /* TranslationContextMenuInfo.h */, F4E1965F21F26E4E00285078 /* UndoItem.cpp */, 2ECDBAD521D8906300F00ECD /* UndoItem.h */, -@@ -30682,6 +30702,8 @@ +@@ -32347,6 +32367,8 @@ 29E4D8DF16B0940F00C84704 /* PlatformSpeechSynthesizer.h */, 1AD8F81A11CAB9E900E93E54 /* PlatformStrategies.cpp */, 1AD8F81911CAB9E900E93E54 /* PlatformStrategies.h */, @@ -2487,7 +2500,7 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf 0FD7C21D23CE41E30096D102 /* PlatformWheelEvent.cpp */, 935C476A09AC4D4F00A6AAB4 /* PlatformWheelEvent.h */, BCBB8AB513F1AFB000734DF0 /* PODInterval.h */, -@@ -33038,6 +33060,7 @@ +@@ -34870,6 +34892,7 @@ AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */, 6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */, 6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */, @@ -2495,7 +2508,7 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf 7CE7FA5B1EF882300060C9D6 /* DocumentTouch.cpp */, 7CE7FA591EF882300060C9D6 /* DocumentTouch.h */, A8185F3209765765005826D9 /* DocumentType.cpp */, -@@ -37354,6 +37377,8 @@ +@@ -39370,6 +39393,8 @@ 1AD8F81B11CAB9E900E93E54 /* PlatformStrategies.h in Headers */, 0F7D07331884C56C00B4AF86 /* PlatformTextTrack.h in Headers */, 074E82BB18A69F0E007EF54C /* PlatformTimeRanges.h in Headers */, @@ -2504,7 +2517,7 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf CDD08ABD277E542600EA3755 /* PlatformTrackConfiguration.h in Headers */, CD1F9B022700323D00617EB6 /* PlatformVideoColorPrimaries.h in Headers */, CD1F9B01270020B700617EB6 /* PlatformVideoColorSpace.h in Headers */, -@@ -38502,6 +38527,7 @@ +@@ -40599,6 +40624,7 @@ 0F54DD081881D5F5003EEDBB /* Touch.h in Headers */, 71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */, 0F54DD091881D5F5003EEDBB /* TouchEvent.h in Headers */, @@ -2512,17 +2525,19 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf 0F54DD0A1881D5F5003EEDBB /* TouchList.h in Headers */, 070334D71459FFD5008D8D45 /* TrackBase.h in Headers */, BE88E0C21715CE2600658D98 /* TrackListBase.h in Headers */, -@@ -39447,6 +39473,7 @@ +@@ -41555,6 +41581,9 @@ 1ABA76CA11D20E50004C201C /* CSSPropertyNames.cpp in Sources */, 2D22830323A8470700364B7E /* CursorMac.mm in Sources */, 5CBD59592280E926002B22AA /* CustomHeaderFields.cpp in Sources */, + F050E17423AD6A800011CE47 /* DocumentTouch.cpp in Sources */, ++ 329C0C2528BD96EB00F187D2 /* ElementName.cpp in Sources */, ++ 329C0C2528BD96EB00F187D2 /* ElementName.cpp in Sources */, 7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */, - 5130F2F624AEA60A00E1D0A0 /* GameControllerSoftLink.mm in Sources */, - 51A4BB0A1954D61600FA5C2E /* Gamepad.cpp in Sources */, -@@ -39524,6 +39551,9 @@ - C1692DD223D23ABD006E88F7 /* SystemBattery.mm in Sources */, + 4667EA3E2968D9DA00BAB1E2 /* GameControllerHapticEffect.mm in Sources */, + 46FE73D32968E52000B8064C /* GameControllerHapticEngines.mm in Sources */, +@@ -41632,6 +41661,9 @@ CE88EE262414467B007F29C2 /* TextAlternativeWithRange.mm in Sources */, + BE39137129B267F500FA5D4F /* TextTransformCocoa.cpp in Sources */, 51DF6D800B92A18E00C2DC85 /* ThreadCheck.mm in Sources */, + F050E16A23AD660C0011CE47 /* Touch.cpp in Sources */, + F050E17123AD669F0011CE47 /* TouchEvent.cpp in Sources */, @@ -2531,18 +2546,18 @@ index 2326514b9a201dce8dbe41a03fb7fdc4ff3ebc37..ad96db9efce294a9f462a7ef83a2acbf 538EC8021F96AF81004D22A8 /* UnifiedSource1.cpp in Sources */, 538EC8051F96AF81004D22A8 /* UnifiedSource2-mm.mm in Sources */, diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp -index b07f94f5ab6ee350110a1d9b9bd93344ea7eb692..167e4bbd7e170be76b71f5d893f1b9f6f02a975d 100644 +index d03040fc82d17e0dff9bd6c158354911a9471238..923713dce16b4fa848b9404cf5390c255d103406 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityObject.cpp -@@ -61,6 +61,7 @@ +@@ -64,6 +64,7 @@ #include "HTMLParserIdioms.h" #include "HTMLTextAreaElement.h" #include "HitTestResult.h" +#include "InspectorInstrumentation.h" + #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MathMLNames.h" - #include "NodeList.h" -@@ -3777,9 +3778,14 @@ AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const +@@ -3861,9 +3862,14 @@ AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const if (roleValue() == AccessibilityRole::ApplicationDialog) return AccessibilityObjectInclusion::IncludeObject; @@ -2559,71 +2574,64 @@ index b07f94f5ab6ee350110a1d9b9bd93344ea7eb692..167e4bbd7e170be76b71f5d893f1b9f6 bool AccessibilityObject::accessibilityIsIgnored() const { AXComputedObjectAttributeCache* attributeCache = nullptr; -diff --git a/Source/WebCore/accessibility/AccessibilityObjectInterface.h b/Source/WebCore/accessibility/AccessibilityObjectInterface.h -index 68eb22fa17f9057d5cc18baee2431f71fe665bcb..98b79d929730993e2ffe773462a6beae3cbc30ee 100644 ---- a/Source/WebCore/accessibility/AccessibilityObjectInterface.h -+++ b/Source/WebCore/accessibility/AccessibilityObjectInterface.h -@@ -57,7 +57,7 @@ typedef const struct __AXTextMarkerRange* AXTextMarkerRangeRef; - #elif USE(ATSPI) - typedef WebCore::AccessibilityObjectAtspi AccessibilityObjectWrapper; - #else --class AccessibilityObjectWrapper; -+class AccessibilityObjectWrapper : public RefCounted {}; - #endif +diff --git a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp +index 22b679d638964ee52e822e01d4e597db82692ff0..b98d1de7f7905c63983032cf436e641ae0e42cbe 100644 +--- a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp ++++ b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp +@@ -475,7 +475,7 @@ static IndexKey::Data createKeyPathArray(JSGlobalObject& lexicalGlobalObject, JS + void generateIndexKeyForValue(JSGlobalObject& lexicalGlobalObject, const IDBIndexInfo& info, JSValue value, IndexKey& outKey, const std::optional& objectStoreKeyPath, const IDBKeyData& objectStoreKey) + { + auto keyDatas = createKeyPathArray(lexicalGlobalObject, value, info, objectStoreKeyPath, objectStoreKey); +- if (std::holds_alternative(keyDatas)) ++ if (std::holds_alternative(keyDatas)) + return; - namespace PAL { -@@ -1559,6 +1559,8 @@ private: - COMPtr m_wrapper; - #elif USE(ATSPI) - RefPtr m_wrapper; -+#else -+ RefPtr m_wrapper; - #endif - virtual void detachPlatformWrapper(AccessibilityDetachmentType) = 0; - }; + outKey = IndexKey(WTFMove(keyDatas)); diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h -index 66d16a6e4075540d291204fc6e10fdd41aba0d42..e11edda46dca31abbd9498b0eaeca48aabf47669 100644 +index 2db24fbae41f43e8f31e0560e9aaf422f7e45997..cd033ed79b1049302cc180ff105733b3a859b285 100644 --- a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h +++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h -@@ -157,6 +157,8 @@ namespace WebCore { - macro(DecompressionStreamDecoder) \ +@@ -169,6 +169,8 @@ namespace WebCore { macro(DecompressionStreamTransform) \ macro(DelayNode) \ + macro(DeprecationReportBody) \ + macro(DeviceMotionEvent) \ + macro(DeviceOrientationEvent) \ macro(DocumentTimeline) \ macro(DynamicsCompressorNode) \ - macro(ExtendableEvent) \ -diff --git a/Source/WebCore/css/MediaQueryEvaluator.cpp b/Source/WebCore/css/MediaQueryEvaluator.cpp -index 871eb7cc9333921c4848b909786de27d4b2827b5..6b51751a07b547d13aa4f0c75423e48168bb6a66 100644 ---- a/Source/WebCore/css/MediaQueryEvaluator.cpp -+++ b/Source/WebCore/css/MediaQueryEvaluator.cpp -@@ -874,7 +874,11 @@ static bool prefersContrastEvaluate(CSSValue* value, const CSSToLengthConversion - static bool prefersReducedMotionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) - { - bool userPrefersReducedMotion = false; -- -+ -+ std::optional reducedMotionOverride = frame.page()->useReducedMotionOverride(); -+ if (reducedMotionOverride) -+ userPrefersReducedMotion = reducedMotionOverride.value(); -+ else { - switch (frame.settings().forcedPrefersReducedMotionAccessibilityValue()) { - case ForcedAccessibilityValue::On: - userPrefersReducedMotion = true; -@@ -887,6 +891,7 @@ static bool prefersReducedMotionEvaluate(CSSValue* value, const CSSToLengthConve - #endif - break; - } -+ } - - if (!value) - return userPrefersReducedMotion; + macro(ElementInternals) \ +diff --git a/Source/WebCore/css/query/MediaQueryFeatures.cpp b/Source/WebCore/css/query/MediaQueryFeatures.cpp +index b40c3214248cebffe812e2291c338c2a90e02c7a..5978fb6fa188d0ff0f6487f8b36914182359e0b8 100644 +--- a/Source/WebCore/css/query/MediaQueryFeatures.cpp ++++ b/Source/WebCore/css/query/MediaQueryFeatures.cpp +@@ -369,7 +369,11 @@ const FeatureSchema& forcedColors() + static MainThreadNeverDestroyed schema { + "forced-colors"_s, + Vector { CSSValueNone, CSSValueActive }, +- [](auto&) { ++ [](auto& context) { ++ auto* page = context.document.frame()->page(); ++ std::optional forcedColorsOverride = page->useForcedColorsOverride(); ++ if (forcedColorsOverride) ++ return forcedColorsOverride.value() ? MatchingIdentifiers { CSSValueActive } : MatchingIdentifiers { CSSValueNone }; + return MatchingIdentifiers { CSSValueNone }; + } + }; +@@ -552,6 +556,9 @@ const FeatureSchema& prefersReducedMotion() + [](auto& context) { + bool userPrefersReducedMotion = [&] { + auto& frame = *context.document.frame(); ++ std::optional reducedMotionOverride = frame.page()->useReducedMotionOverride(); ++ if (reducedMotionOverride) ++ return reducedMotionOverride.value(); + switch (frame.settings().forcedPrefersReducedMotionAccessibilityValue()) { + case ForcedAccessibilityValue::On: + return true; diff --git a/Source/WebCore/dom/DataTransfer.cpp b/Source/WebCore/dom/DataTransfer.cpp -index e252c8972cdff190f99ec8c4dc5251b23080b428..82dc8f09c5d94ce32d97bd5815475adb9ef8ec7a 100644 +index c0d746b41650937256e73ff4cfab5db426658523..3e4d570e3e35dd31eefa9c80a56c2ca1315bf6ec 100644 --- a/Source/WebCore/dom/DataTransfer.cpp +++ b/Source/WebCore/dom/DataTransfer.cpp -@@ -496,6 +496,14 @@ Ref DataTransfer::createForDrag(const Document& document) +@@ -511,6 +511,14 @@ Ref DataTransfer::createForDrag(const Document& document) return adoptRef(*new DataTransfer(StoreMode::ReadWrite, Pasteboard::createForDragAndDrop(PagePasteboardContext::create(document.pageID())), Type::DragAndDropData)); } @@ -2639,7 +2647,7 @@ index e252c8972cdff190f99ec8c4dc5251b23080b428..82dc8f09c5d94ce32d97bd5815475adb { auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique(), Type::DragAndDropData)); diff --git a/Source/WebCore/dom/DataTransfer.h b/Source/WebCore/dom/DataTransfer.h -index fbcdea3855b8a42ab5f69ba06839b78857abb1f1..a5686a98b117836df7656d4360056be8ef2a2878 100644 +index fb2decfc7dfc6c8a4e5a7dd79c0e23798f6d83b8..ba5f16cf2b443167b8307510f06e985698353319 100644 --- a/Source/WebCore/dom/DataTransfer.h +++ b/Source/WebCore/dom/DataTransfer.h @@ -90,6 +90,9 @@ public: @@ -2677,7 +2685,7 @@ index 9043052540b13d8120fb641de6337af46c3b36ef..a0f89e64b64640d2d4dbc14734868c4d ] interface DeviceOrientationEvent : Event { readonly attribute unrestricted double? alpha; diff --git a/Source/WebCore/dom/Document+PointerLock.idl b/Source/WebCore/dom/Document+PointerLock.idl -index 898027004b8553cac8130541026af70ffb5ee073..883d6a7df7a164625037cd8cee95c8fe4312b9e8 100644 +index 2e9c9fda6a920cd8904432bd1bdbfbf32d01c085..2fd33597e905b0544665ff765f310945305a0c4a 100644 --- a/Source/WebCore/dom/Document+PointerLock.idl +++ b/Source/WebCore/dom/Document+PointerLock.idl @@ -25,6 +25,7 @@ @@ -2687,7 +2695,7 @@ index 898027004b8553cac8130541026af70ffb5ee073..883d6a7df7a164625037cd8cee95c8fe + EnabledBySetting=PointerLockEnabled, Conditional=POINTER_LOCK ] partial interface Document { - [NotEnumerable] attribute EventHandler onpointerlockchange; // FIXME: Should be enumerable. + attribute EventHandler onpointerlockchange; diff --git a/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl b/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl index 9b8dbfc15ce078702321abcd6c0e636df7a60510..2956f7098e87af10ab8f5584b456ce9a6d432a20 100644 --- a/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl @@ -2713,14 +2721,22 @@ index f27718c1e2b8cd0a8075e556d4cdba7d9ae8fc54..2b61721594e5435845f3151e0de345e9 ] partial interface Element { undefined requestPointerLock(); diff --git a/Source/WebCore/dom/PointerEvent.cpp b/Source/WebCore/dom/PointerEvent.cpp -index 4433bc1c4a055d0a8386fd01e7e9d44b99425516..a8a43743370f3a00bed40a206ae98a5cc50bc7c7 100644 +index 936f9913c28269fa1a425b87f8458328e1a7d715..c979965716db643209daae81d14b334a94c2523d 100644 --- a/Source/WebCore/dom/PointerEvent.cpp +++ b/Source/WebCore/dom/PointerEvent.cpp -@@ -114,4 +114,61 @@ EventInterface PointerEvent::eventInterface() const +@@ -28,6 +28,7 @@ + + #include "EventNames.h" + #include "Node.h" ++#include "PlatformTouchEvent.h" + #include + + namespace WebCore { +@@ -116,4 +117,63 @@ EventInterface PointerEvent::eventInterface() const return PointerEventInterfaceType; } -+#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) ++#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) && !PLATFORM(WPE) + +static const AtomString& pointerEventType(PlatformTouchPoint::State state) +{ @@ -2750,23 +2766,25 @@ index 4433bc1c4a055d0a8386fd01e7e9d44b99425516..a8a43743370f3a00bed40a206ae98a5c +static unsigned short buttonsForType(const AtomString& type) +{ + // We have contact with the touch surface for most events except when we've released the touch or canceled it. -+ return (type == eventNames().pointerupEvent || type == eventNames().pointeroutEvent || type == eventNames().pointerleaveEvent || type == eventNames().pointercancelEvent) ? 0 : 1; ++ auto& eventNames = WebCore::eventNames(); ++ return (type == eventNames.pointerupEvent || type == eventNames.pointeroutEvent || type == eventNames.pointerleaveEvent || type == eventNames.pointercancelEvent) ? 0 : 1; +} + -+Ref PointerEvent::create(const PlatformTouchEvent& event, unsigned index, bool isPrimary, Ref&& view) ++Ref PointerEvent::create(const PlatformTouchEvent& event, unsigned index, bool isPrimary, Ref&& view, const IntPoint& touchDelta) +{ + const auto& type = pointerEventType(event.touchPoints().at(index).state()); -+ return adoptRef(*new PointerEvent(type, event, typeIsCancelable(type), index, isPrimary, WTFMove(view))); ++ return adoptRef(*new PointerEvent(type, event, typeIsCancelable(type), index, isPrimary, WTFMove(view), touchDelta)); +} + -+Ref PointerEvent::create(const AtomString& type, const PlatformTouchEvent& event, unsigned index, bool isPrimary, Ref&& view) ++Ref PointerEvent::create(const AtomString& type, const PlatformTouchEvent& event, unsigned index, bool isPrimary, Ref&& view, const IntPoint& touchDelta) +{ -+ return adoptRef(*new PointerEvent(type, event, typeIsCancelable(type), index, isPrimary, WTFMove(view))); ++ return adoptRef(*new PointerEvent(type, event, typeIsCancelable(type), index, isPrimary, WTFMove(view), touchDelta)); +} + -+PointerEvent::PointerEvent(const AtomString& type, const PlatformTouchEvent& event, IsCancelable isCancelable, unsigned index, bool isPrimary, Ref&& view) -+ : MouseEvent(type, typeCanBubble(type), isCancelable, typeIsComposed(type), event.timestamp().approximateMonotonicTime(), WTFMove(view), 0, event.touchPoints().at(index).pos(), event.touchPoints().at(index).pos(), { }, event.modifiers(), buttonForType(type), buttonsForType(type), nullptr, 0, 0, IsSimulated::No, IsTrusted::Yes) -+ , m_pointerId(2) ++PointerEvent::PointerEvent(const AtomString& type, const PlatformTouchEvent& event, IsCancelable isCancelable, unsigned index, bool isPrimary, Ref&& view, const IntPoint& touchDelta) ++ : MouseEvent(type, typeCanBubble(type), isCancelable, typeIsComposed(type), event.timestamp().approximateMonotonicTime(), WTFMove(view), 0, ++ event.touchPoints().at(index).pos(), event.touchPoints().at(index).pos(), touchDelta.x(), touchDelta.y(), event.modifiers(), buttonForType(type), buttonsForType(type), nullptr, 0, 0, IsSimulated::No, IsTrusted::Yes) ++ , m_pointerId(event.touchPoints().at(index).id()) + , m_width(2 * event.touchPoints().at(index).radiusX()) + , m_height(2 * event.touchPoints().at(index).radiusY()) + , m_pressure(event.touchPoints().at(index).force()) @@ -2779,7 +2797,7 @@ index 4433bc1c4a055d0a8386fd01e7e9d44b99425516..a8a43743370f3a00bed40a206ae98a5c + } // namespace WebCore diff --git a/Source/WebCore/dom/PointerEvent.h b/Source/WebCore/dom/PointerEvent.h -index 7542bab569d49879f0eb460520738b3da37116f6..17c92229cc596bc80a718911b74737d3575137e1 100644 +index 17784dfc482c3033ea0e3ce7fdcf75b2eb4fc9d7..956c05246b5c1368e2c5257b347848d1dab4b969 100644 --- a/Source/WebCore/dom/PointerEvent.h +++ b/Source/WebCore/dom/PointerEvent.h @@ -33,6 +33,8 @@ @@ -2790,27 +2808,27 @@ index 7542bab569d49879f0eb460520738b3da37116f6..17c92229cc596bc80a718911b74737d3 +#include "PlatformTouchEvent.h" #endif - namespace WebCore { -@@ -81,7 +83,7 @@ public: + #if ENABLE(TOUCH_EVENTS) && PLATFORM(WPE) +@@ -85,7 +87,7 @@ public: static Ref create(const AtomString& type, short button, const MouseEvent&, PointerID, const String& pointerType); static Ref create(const AtomString& type, PointerID, const String& pointerType, IsPrimary = IsPrimary::No); --#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) - static Ref create(const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref&&); - static Ref create(const AtomString& type, const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref&&); + static Ref create(const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref&&, const IntPoint& touchDelta = { }); + static Ref create(const AtomString& type, const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref&&, const IntPoint& touchDelta = { }); #endif -@@ -121,7 +123,7 @@ private: +@@ -134,7 +136,7 @@ private: PointerEvent(const AtomString&, Init&&); PointerEvent(const AtomString& type, short button, const MouseEvent&, PointerID, const String& pointerType); PointerEvent(const AtomString& type, PointerID, const String& pointerType, IsPrimary); --#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) - PointerEvent(const AtomString& type, const PlatformTouchEvent&, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref&&); + PointerEvent(const AtomString& type, const PlatformTouchEvent&, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref&&, const IntPoint& touchDelta = { }); #endif diff --git a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp -index e060d8178fe501a0c6d47d4affaf4d422d15e358..5064f6ae31464a109b3dad0fc69e186661e274d9 100644 +index 52ee00ea5df1b7eabedc3e9c344bd6d715d462fa..e311d17d5f18c9bf239e9fab3c1090c3578fc96c 100644 --- a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp +++ b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp @@ -34,6 +34,7 @@ @@ -2837,18 +2855,18 @@ index e060d8178fe501a0c6d47d4affaf4d422d15e358..5064f6ae31464a109b3dad0fc69e1866 #endif // USE(LIBWPE) diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp -index c43310a5628456dddbdb27d5496c580854d40758..c962f3b962e28ef82baa1bf3da377e26b983ba77 100644 +index 161a668d55aa0d3de7d7acb9ea752119c06130de..80d9a99b4346cbbbc23d7647fe6ebef071681230 100644 --- a/Source/WebCore/html/FileInputType.cpp +++ b/Source/WebCore/html/FileInputType.cpp -@@ -38,6 +38,7 @@ +@@ -37,6 +37,7 @@ #include "HTMLNames.h" #include "Icon.h" #include "InputTypeNames.h" +#include "InspectorInstrumentation.h" + #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MIMETypeRegistry.h" - #include "RenderFileUploadControl.h" -@@ -202,6 +203,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) +@@ -205,6 +206,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) if (input.isDisabledFormControl()) return; @@ -2860,11 +2878,22 @@ index c43310a5628456dddbdb27d5496c580854d40758..c962f3b962e28ef82baa1bf3da377e26 if (!UserGestureIndicator::processingUserGesture()) return; +@@ -378,7 +384,9 @@ void FileInputType::setFiles(RefPtr&& files, RequestIcon shouldRequest + pathsChanged = true; + else { + for (unsigned i = 0; i < length; ++i) { +- if (files->file(i).path() != m_fileList->file(i).path() || !FileSystem::fileIDsAreEqual(files->file(i).fileID(), m_fileList->file(i).fileID())) { ++ if (files->file(i).path() != m_fileList->file(i).path() || !FileSystem::fileIDsAreEqual(files->file(i).fileID(), m_fileList->file(i).fileID()) || ++ // Files created from Blob have empty path. ++ (files->file(i).path().isEmpty() && files->file(i).name() != m_fileList->file(i).name())) { + pathsChanged = true; + break; + } diff --git a/Source/WebCore/inspector/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp -index 9e4515b7e7f7261f936471b81557ec96697c34e6..3b32377172112fc143b5e719122e8bf648be5b25 100644 +index c2dabfbc86e46d14048134545031159757e7c2e4..d3833a407a9e47c8809620ef5cf97346891dd29c 100644 --- a/Source/WebCore/inspector/InspectorController.cpp +++ b/Source/WebCore/inspector/InspectorController.cpp -@@ -285,6 +285,8 @@ void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel) +@@ -288,6 +288,8 @@ void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel) // Unplug all instrumentations since they aren't needed now. InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get()); @@ -2873,7 +2902,7 @@ index 9e4515b7e7f7261f936471b81557ec96697c34e6..3b32377172112fc143b5e719122e8bf6 } m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount()); -@@ -304,6 +306,8 @@ void InspectorController::disconnectAllFrontends() +@@ -307,6 +309,8 @@ void InspectorController::disconnectAllFrontends() // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow(). ASSERT(!m_inspectorFrontendClient); @@ -2882,7 +2911,7 @@ index 9e4515b7e7f7261f936471b81557ec96697c34e6..3b32377172112fc143b5e719122e8bf6 if (!m_frontendRouter->hasFrontends()) return; -@@ -392,8 +396,8 @@ void InspectorController::inspect(Node* node) +@@ -395,8 +399,8 @@ void InspectorController::inspect(Node* node) if (!enabled()) return; @@ -2893,7 +2922,7 @@ index 9e4515b7e7f7261f936471b81557ec96697c34e6..3b32377172112fc143b5e719122e8bf6 ensureDOMAgent().inspect(node); } -@@ -534,4 +538,24 @@ void InspectorController::didComposite(Frame& frame) +@@ -539,4 +543,24 @@ void InspectorController::didComposite(LocalFrame& frame) InspectorInstrumentation::didComposite(frame); } @@ -2919,12 +2948,12 @@ index 9e4515b7e7f7261f936471b81557ec96697c34e6..3b32377172112fc143b5e719122e8bf6 + } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorController.h b/Source/WebCore/inspector/InspectorController.h -index 4d5a3859ec6a46d07d45c80a3b5870ee2ef13d36..75eb55a024a6ae3892a4fedc535bf6a647cc3bc7 100644 +index 3a981b5bf5ca0bbf4d1c9f0b125564742cd8cad9..f8fc2ca6700461627933f149c5837075226a51a9 100644 --- a/Source/WebCore/inspector/InspectorController.h +++ b/Source/WebCore/inspector/InspectorController.h @@ -101,6 +101,10 @@ public: - WEBCORE_EXPORT void willComposite(Frame&); - WEBCORE_EXPORT void didComposite(Frame&); + WEBCORE_EXPORT void willComposite(LocalFrame&); + WEBCORE_EXPORT void didComposite(LocalFrame&); + WEBCORE_EXPORT void pauseWhenShown(); + WEBCORE_EXPORT void resumeIfPausedInNewWindow(); @@ -2942,10 +2971,10 @@ index 4d5a3859ec6a46d07d45c80a3b5870ee2ef13d36..75eb55a024a6ae3892a4fedc535bf6a6 } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp -index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32fb0407fc0 100644 +index e3d0e7fc02ff131196a62f6469194e1e19b14182..398f9bc4f7ee3d85cb424218246ec72449b0fcaf 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp -@@ -572,6 +572,13 @@ void InspectorInstrumentation::applyUserAgentOverrideImpl(InstrumentingAgents& i +@@ -601,6 +601,12 @@ void InspectorInstrumentation::applyUserAgentOverrideImpl(InstrumentingAgents& i pageAgent->applyUserAgentOverride(userAgent); } @@ -2955,15 +2984,14 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f + pageAgent->applyPlatformOverride(platform); +} + -+ - void InspectorInstrumentation::applyEmulatedMediaImpl(InstrumentingAgents& instrumentingAgents, String& media) + void InspectorInstrumentation::applyEmulatedMediaImpl(InstrumentingAgents& instrumentingAgents, AtomString& media) { if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) -@@ -651,6 +658,12 @@ void InspectorInstrumentation::didFailLoadingImpl(InstrumentingAgents& instrumen +@@ -684,6 +690,12 @@ void InspectorInstrumentation::didFailLoadingImpl(InstrumentingAgents& instrumen consoleAgent->didFailLoading(identifier, error); // This should come AFTER resource notification, front-end relies on this. } -+void InspectorInstrumentation::didReceiveMainResourceErrorImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, const ResourceError&) ++void InspectorInstrumentation::didReceiveMainResourceErrorImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame, const ResourceError&) +{ + if (auto* pageRuntimeAgent = instrumentingAgents.enabledPageRuntimeAgent()) + pageRuntimeAgent->didReceiveMainResourceError(frame); @@ -2972,9 +3000,9 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents) { if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) -@@ -683,20 +696,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& +@@ -716,20 +728,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& - void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) + void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { - if (!frame.isMainFrame()) - return; @@ -2984,7 +3012,7 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f + pageAgent->domContentEventFired(frame); } - void InspectorInstrumentation::loadEventFiredImpl(InstrumentingAgents& instrumentingAgents, Frame* frame) + void InspectorInstrumentation::loadEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame* frame) { - if (!frame || !frame->isMainFrame()) + if (!frame) @@ -2995,8 +3023,8 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f + pageAgent->loadEventFired(*frame); } - void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) -@@ -777,12 +787,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins + void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) +@@ -812,12 +821,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins pageDOMDebuggerAgent->frameDocumentUpdated(frame); } @@ -3006,23 +3034,36 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f - inspectorPageAgent->loaderDetachedFromFrame(loader); -} - - void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) + void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { if (frame.isMainFrame()) { -@@ -819,6 +823,12 @@ void InspectorInstrumentation::frameClearedScheduledNavigationImpl(Instrumenting - inspectorPageAgent->frameClearedScheduledNavigation(frame); +@@ -848,10 +851,10 @@ void InspectorInstrumentation::frameStoppedLoadingImpl(InstrumentingAgents& inst + inspectorPageAgent->frameStoppedLoading(frame); + } + +-void InspectorInstrumentation::frameScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, Seconds delay) ++void InspectorInstrumentation::frameScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, Seconds delay, bool targetIsCurrentFrame) + { + if (auto* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) +- inspectorPageAgent->frameScheduledNavigation(frame, delay); ++ inspectorPageAgent->frameScheduledNavigation(frame, delay, targetIsCurrentFrame); + } + + void InspectorInstrumentation::frameClearedScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) +@@ -866,6 +869,12 @@ void InspectorInstrumentation::accessibilitySettingsDidChangeImpl(InstrumentingA + inspectorPageAgent->accessibilitySettingsDidChange(); } -+void InspectorInstrumentation::didNavigateWithinPageImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) ++void InspectorInstrumentation::didNavigateWithinPageImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) +{ + if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) + inspectorPageAgent->didNavigateWithinPage(frame); +} + #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) - void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents, bool useDarkAppearance) + void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents) { -@@ -1001,6 +1011,12 @@ void InspectorInstrumentation::consoleStopRecordingCanvasImpl(InstrumentingAgent +@@ -1048,6 +1057,12 @@ void InspectorInstrumentation::consoleStopRecordingCanvasImpl(InstrumentingAgent canvasAgent->consoleStopRecordingCanvas(context); } @@ -3035,7 +3076,7 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f void InspectorInstrumentation::didOpenDatabaseImpl(InstrumentingAgents& instrumentingAgents, Database& database) { if (auto* databaseAgent = instrumentingAgents.enabledDatabaseAgent()) -@@ -1301,6 +1317,36 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins +@@ -1348,6 +1363,36 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins layerTreeAgent->renderLayerDestroyed(renderLayer); } @@ -3045,7 +3086,7 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f + pageAgent->runOpenPanel(element, intercept); +} + -+void InspectorInstrumentation::frameAttachedImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) { ++void InspectorInstrumentation::frameAttachedImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->frameAttached(frame); +} @@ -3057,13 +3098,13 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f + return false; +} + -+void InspectorInstrumentation::willCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) ++void InspectorInstrumentation::willCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->willCheckNavigationPolicy(frame); +} + -+void InspectorInstrumentation::didCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, bool cancel) ++void InspectorInstrumentation::didCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame, bool cancel) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->didCheckNavigationPolicy(frame, cancel); @@ -3072,7 +3113,7 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(WorkerOrWorkletGlobalScope& globalScope) { return globalScope.inspectorController().m_instrumentingAgents; -@@ -1312,6 +1358,13 @@ InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(Page& page) +@@ -1359,6 +1404,13 @@ InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(Page& page) return page.inspectorController().m_instrumentingAgents.get(); } @@ -3087,7 +3128,7 @@ index 3fe459d4ee185f9c1ab157c61d651fe2ed6ebedf..82ec00871a74db0fc0cb898c77aab32f { if (is(context)) diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h -index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218ebc99e69 100644 +index f4579829b5ba02e407b9265a26e3360f9a3a4daa..d7b46ccce46c4191b286af05db70993996d4cb9a 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -31,6 +31,7 @@ @@ -3098,15 +3139,15 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 #include "CSSSelector.h" #include "CanvasBase.h" #include "CanvasRenderingContext.h" -@@ -45,6 +46,7 @@ - #include "HitTestResult.h" - #include "InspectorInstrumentationPublic.h" +@@ -46,6 +47,7 @@ + #include "LocalFrame.h" + #include "LocalFrameView.h" #include "Page.h" +#include "ResourceError.h" #include "ResourceLoader.h" #include "ResourceLoaderIdentifier.h" #include "StorageArea.h" -@@ -77,6 +79,7 @@ class DOMWrapperWorld; +@@ -78,6 +80,7 @@ class DOMWrapperWorld; class Document; class DocumentLoader; class EventListener; @@ -3114,36 +3155,39 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 class HTTPHeaderMap; class InspectorTimelineAgent; class InstrumentingAgents; -@@ -189,6 +192,7 @@ public: +@@ -192,6 +195,7 @@ public: static void didRecalculateStyle(Document&); static void didScheduleStyleRecalculation(Document&); - static void applyUserAgentOverride(Frame&, String&); -+ static void applyPlatformOverride(Frame&, String&); - static void applyEmulatedMedia(Frame&, String&); + static void applyUserAgentOverride(LocalFrame&, String&); ++ static void applyPlatformOverride(LocalFrame&, String&); + static void applyEmulatedMedia(LocalFrame&, AtomString&); static void flexibleBoxRendererBeganLayout(const RenderObject&); -@@ -201,6 +205,7 @@ public: - static void didReceiveData(Frame*, ResourceLoaderIdentifier, const SharedBuffer*, int encodedDataLength); - static void didFinishLoading(Frame*, DocumentLoader*, ResourceLoaderIdentifier, const NetworkLoadMetrics&, ResourceLoader*); - static void didFailLoading(Frame*, DocumentLoader*, ResourceLoaderIdentifier, const ResourceError&); -+ static void didReceiveMainResourceError(Frame&, const ResourceError&); +@@ -204,6 +208,7 @@ public: + static void didReceiveData(LocalFrame*, ResourceLoaderIdentifier, const SharedBuffer*, int encodedDataLength); + static void didFinishLoading(LocalFrame*, DocumentLoader*, ResourceLoaderIdentifier, const NetworkLoadMetrics&, ResourceLoader*); + static void didFailLoading(LocalFrame*, DocumentLoader*, ResourceLoaderIdentifier, const ResourceError&); ++ static void didReceiveMainResourceError(LocalFrame&, const ResourceError&); static void willSendRequest(WorkerOrWorkletGlobalScope&, ResourceLoaderIdentifier, ResourceRequest&); static void didReceiveResourceResponse(WorkerOrWorkletGlobalScope&, ResourceLoaderIdentifier, const ResourceResponse&); -@@ -227,11 +232,11 @@ public: - static void frameDetachedFromParent(Frame&); - static void didCommitLoad(Frame&, DocumentLoader*); - static void frameDocumentUpdated(Frame&); -- static void loaderDetachedFromFrame(Frame&, DocumentLoader&); - static void frameStartedLoading(Frame&); - static void frameStoppedLoading(Frame&); - static void frameScheduledNavigation(Frame&, Seconds delay); +@@ -230,13 +235,13 @@ public: + static void frameDetachedFromParent(LocalFrame&); + static void didCommitLoad(LocalFrame&, DocumentLoader*); + static void frameDocumentUpdated(LocalFrame&); +- static void loaderDetachedFromFrame(LocalFrame&, DocumentLoader&); + static void frameStartedLoading(LocalFrame&); + static void frameStoppedLoading(LocalFrame&); + static void didCompleteRenderingFrame(LocalFrame&); +- static void frameScheduledNavigation(Frame&, Seconds delay); ++ static void frameScheduledNavigation(Frame&, Seconds delay, bool targetIsCurrentFrame); static void frameClearedScheduledNavigation(Frame&); -+ static void didNavigateWithinPage(Frame&); + static void accessibilitySettingsDidChange(Page&); ++ static void didNavigateWithinPage(LocalFrame&); #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) - static void defaultAppearanceDidChange(Page&, bool useDarkAppearance); + static void defaultAppearanceDidChange(Page&); #endif -@@ -263,6 +268,7 @@ public: +@@ -268,6 +273,7 @@ public: static void stopProfiling(Page&, JSC::JSGlobalObject*, const String& title); static void consoleStartRecordingCanvas(CanvasRenderingContext&, JSC::JSGlobalObject&, JSC::JSObject* options); static void consoleStopRecordingCanvas(CanvasRenderingContext&); @@ -3151,58 +3195,61 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 static void didRequestAnimationFrame(Document&, int callbackId); static void didCancelAnimationFrame(Document&, int callbackId); -@@ -318,6 +324,12 @@ public: +@@ -323,6 +329,12 @@ public: static void layerTreeDidChange(Page*); static void renderLayerDestroyed(Page*, const RenderLayer&); -+ static void runOpenPanel(Frame*, HTMLInputElement*, bool*); -+ static void frameAttached(Frame*); ++ static void runOpenPanel(LocalFrame*, HTMLInputElement*, bool*); ++ static void frameAttached(LocalFrame*); + static bool shouldBypassCSP(ScriptExecutionContext*); -+ static void willCheckNavigationPolicy(Frame&); -+ static void didCheckNavigationPolicy(Frame&, bool cancel); ++ static void willCheckNavigationPolicy(LocalFrame&); ++ static void didCheckNavigationPolicy(LocalFrame&, bool cancel); + static void frontendCreated(); static void frontendDeleted(); static bool hasFrontends() { return InspectorInstrumentationPublic::hasFrontends(); } -@@ -334,6 +346,8 @@ public: +@@ -339,6 +351,8 @@ public: static void registerInstrumentingAgents(InstrumentingAgents&); static void unregisterInstrumentingAgents(InstrumentingAgents&); + static void maybeOverrideDefaultObjectInclusion(Page&, AccessibilityObjectInclusion&); + private: - static void didClearWindowObjectInWorldImpl(InstrumentingAgents&, Frame&, DOMWrapperWorld&); + static void didClearWindowObjectInWorldImpl(InstrumentingAgents&, LocalFrame&, DOMWrapperWorld&); static bool isDebuggerPausedImpl(InstrumentingAgents&); -@@ -411,6 +425,7 @@ private: +@@ -418,6 +432,7 @@ private: static void didRecalculateStyleImpl(InstrumentingAgents&); static void didScheduleStyleRecalculationImpl(InstrumentingAgents&, Document&); static void applyUserAgentOverrideImpl(InstrumentingAgents&, String&); + static void applyPlatformOverrideImpl(InstrumentingAgents&, String&); - static void applyEmulatedMediaImpl(InstrumentingAgents&, String&); + static void applyEmulatedMediaImpl(InstrumentingAgents&, AtomString&); static void flexibleBoxRendererBeganLayoutImpl(InstrumentingAgents&, const RenderObject&); -@@ -425,6 +440,7 @@ private: +@@ -432,6 +447,7 @@ private: static void didReceiveDataImpl(InstrumentingAgents&, ResourceLoaderIdentifier, const SharedBuffer*, int encodedDataLength); static void didFinishLoadingImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, const NetworkLoadMetrics&, ResourceLoader*); static void didFailLoadingImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, const ResourceError&); -+ static void didReceiveMainResourceErrorImpl(InstrumentingAgents&, Frame&, const ResourceError&); ++ static void didReceiveMainResourceErrorImpl(InstrumentingAgents&, LocalFrame&, const ResourceError&); static void willLoadXHRSynchronouslyImpl(InstrumentingAgents&); static void didLoadXHRSynchronouslyImpl(InstrumentingAgents&); static void scriptImportedImpl(InstrumentingAgents&, ResourceLoaderIdentifier, const String& sourceString); -@@ -435,11 +451,11 @@ private: - static void frameDetachedFromParentImpl(InstrumentingAgents&, Frame&); - static void didCommitLoadImpl(InstrumentingAgents&, Frame&, DocumentLoader*); - static void frameDocumentUpdatedImpl(InstrumentingAgents&, Frame&); +@@ -442,13 +458,13 @@ private: + static void frameDetachedFromParentImpl(InstrumentingAgents&, LocalFrame&); + static void didCommitLoadImpl(InstrumentingAgents&, LocalFrame&, DocumentLoader*); + static void frameDocumentUpdatedImpl(InstrumentingAgents&, LocalFrame&); - static void loaderDetachedFromFrameImpl(InstrumentingAgents&, DocumentLoader&); - static void frameStartedLoadingImpl(InstrumentingAgents&, Frame&); - static void frameStoppedLoadingImpl(InstrumentingAgents&, Frame&); - static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay); + static void frameStartedLoadingImpl(InstrumentingAgents&, LocalFrame&); + static void didCompleteRenderingFrameImpl(InstrumentingAgents&); + static void frameStoppedLoadingImpl(InstrumentingAgents&, LocalFrame&); +- static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay); ++ static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay, bool targetIsCurrentFrame); static void frameClearedScheduledNavigationImpl(InstrumentingAgents&, Frame&); -+ static void didNavigateWithinPageImpl(InstrumentingAgents&, Frame&); + static void accessibilitySettingsDidChangeImpl(InstrumentingAgents&); ++ static void didNavigateWithinPageImpl(InstrumentingAgents&, LocalFrame&); #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) - static void defaultAppearanceDidChangeImpl(InstrumentingAgents&, bool useDarkAppearance); + static void defaultAppearanceDidChangeImpl(InstrumentingAgents&); #endif -@@ -466,6 +482,7 @@ private: +@@ -475,6 +491,7 @@ private: static void stopProfilingImpl(InstrumentingAgents&, JSC::JSGlobalObject*, const String& title); static void consoleStartRecordingCanvasImpl(InstrumentingAgents&, CanvasRenderingContext&, JSC::JSGlobalObject&, JSC::JSObject* options); static void consoleStopRecordingCanvasImpl(InstrumentingAgents&, CanvasRenderingContext&); @@ -3210,66 +3257,80 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 static void didRequestAnimationFrameImpl(InstrumentingAgents&, int callbackId, Document&); static void didCancelAnimationFrameImpl(InstrumentingAgents&, int callbackId, Document&); -@@ -521,6 +538,12 @@ private: +@@ -530,6 +547,12 @@ private: static void layerTreeDidChangeImpl(InstrumentingAgents&); static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&); + static void runOpenPanelImpl(InstrumentingAgents&, HTMLInputElement*, bool*); -+ static void frameAttachedImpl(InstrumentingAgents&, Frame&); ++ static void frameAttachedImpl(InstrumentingAgents&, LocalFrame&); + static bool shouldBypassCSPImpl(InstrumentingAgents&); -+ static void willCheckNavigationPolicyImpl(InstrumentingAgents&, Frame&); -+ static void didCheckNavigationPolicyImpl(InstrumentingAgents&, Frame&, bool cancel); ++ static void willCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&); ++ static void didCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&, bool cancel); + static InstrumentingAgents& instrumentingAgents(Page&); static InstrumentingAgents& instrumentingAgents(WorkerOrWorkletGlobalScope&); -@@ -1039,6 +1062,13 @@ inline void InspectorInstrumentation::applyUserAgentOverride(Frame& frame, Strin +@@ -1063,6 +1086,13 @@ inline void InspectorInstrumentation::applyUserAgentOverride(LocalFrame& frame, applyUserAgentOverrideImpl(*agents, userAgent); } -+inline void InspectorInstrumentation::applyPlatformOverride(Frame& frame, String& platform) ++inline void InspectorInstrumentation::applyPlatformOverride(LocalFrame& frame, String& platform) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + applyPlatformOverrideImpl(*agents, platform); +} + - inline void InspectorInstrumentation::applyEmulatedMedia(Frame& frame, String& media) + inline void InspectorInstrumentation::applyEmulatedMedia(LocalFrame& frame, AtomString& media) { FAST_RETURN_IF_NO_FRONTENDS(void()); -@@ -1141,6 +1171,13 @@ inline void InspectorInstrumentation::didFailLoading(WorkerOrWorkletGlobalScope& +@@ -1165,6 +1195,13 @@ inline void InspectorInstrumentation::didFailLoading(WorkerOrWorkletGlobalScope& didFailLoadingImpl(instrumentingAgents(globalScope), identifier, nullptr, error); } -+inline void InspectorInstrumentation::didReceiveMainResourceError(Frame& frame, const ResourceError& error) ++inline void InspectorInstrumentation::didReceiveMainResourceError(LocalFrame& frame, const ResourceError& error) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + didReceiveMainResourceErrorImpl(*agents, frame, error); +} + - inline void InspectorInstrumentation::continueAfterXFrameOptionsDenied(Frame& frame, ResourceLoaderIdentifier identifier, DocumentLoader& loader, const ResourceResponse& response) + inline void InspectorInstrumentation::continueAfterXFrameOptionsDenied(LocalFrame& frame, ResourceLoaderIdentifier identifier, DocumentLoader& loader, const ResourceResponse& response) { // Treat the same as didReceiveResponse. -@@ -1231,13 +1268,6 @@ inline void InspectorInstrumentation::frameDocumentUpdated(Frame& frame) +@@ -1255,13 +1292,6 @@ inline void InspectorInstrumentation::frameDocumentUpdated(LocalFrame& frame) frameDocumentUpdatedImpl(*agents, frame); } --inline void InspectorInstrumentation::loaderDetachedFromFrame(Frame& frame, DocumentLoader& loader) +-inline void InspectorInstrumentation::loaderDetachedFromFrame(LocalFrame& frame, DocumentLoader& loader) -{ - FAST_RETURN_IF_NO_FRONTENDS(void()); - if (auto* agents = instrumentingAgents(frame)) - loaderDetachedFromFrameImpl(*agents, loader); -} - - inline void InspectorInstrumentation::frameStartedLoading(Frame& frame) + inline void InspectorInstrumentation::frameStartedLoading(LocalFrame& frame) + { + FAST_RETURN_IF_NO_FRONTENDS(void()); +@@ -1283,11 +1313,11 @@ inline void InspectorInstrumentation::frameStoppedLoading(LocalFrame& frame) + frameStoppedLoadingImpl(*agents, frame); + } + +-inline void InspectorInstrumentation::frameScheduledNavigation(Frame& frame, Seconds delay) ++inline void InspectorInstrumentation::frameScheduledNavigation(Frame& frame, Seconds delay, bool targetIsCurrentFrame) { FAST_RETURN_IF_NO_FRONTENDS(void()); -@@ -1266,6 +1296,13 @@ inline void InspectorInstrumentation::frameClearedScheduledNavigation(Frame& fra - frameClearedScheduledNavigationImpl(*agents, frame); + if (auto* agents = instrumentingAgents(frame)) +- frameScheduledNavigationImpl(*agents, frame, delay); ++ frameScheduledNavigationImpl(*agents, frame, delay, targetIsCurrentFrame); + } + + inline void InspectorInstrumentation::frameClearedScheduledNavigation(Frame& frame) +@@ -1303,6 +1333,13 @@ inline void InspectorInstrumentation::accessibilitySettingsDidChange(Page& page) + accessibilitySettingsDidChangeImpl(instrumentingAgents(page)); } -+inline void InspectorInstrumentation::didNavigateWithinPage(Frame& frame) ++inline void InspectorInstrumentation::didNavigateWithinPage(LocalFrame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) @@ -3277,9 +3338,9 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 +} + #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) - inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page, bool useDarkAppearance) + inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page) { -@@ -1640,6 +1677,11 @@ inline void InspectorInstrumentation::consoleStopRecordingCanvas(CanvasRendering +@@ -1677,6 +1714,11 @@ inline void InspectorInstrumentation::consoleStopRecordingCanvas(CanvasRendering consoleStopRecordingCanvasImpl(*agents, context); } @@ -3291,18 +3352,18 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 inline void InspectorInstrumentation::didRequestAnimationFrame(Document& document, int callbackId) { FAST_RETURN_IF_NO_FRONTENDS(void()); -@@ -1696,6 +1738,42 @@ inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const Ren +@@ -1733,6 +1775,42 @@ inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const Ren renderLayerDestroyedImpl(*agents, renderLayer); } -+inline void InspectorInstrumentation::runOpenPanel(Frame* frame, HTMLInputElement* element, bool* intercept) ++inline void InspectorInstrumentation::runOpenPanel(LocalFrame* frame, HTMLInputElement* element, bool* intercept) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(*frame)) + runOpenPanelImpl(*agents, element, intercept); +} + -+inline void InspectorInstrumentation::frameAttached(Frame* frame) ++inline void InspectorInstrumentation::frameAttached(LocalFrame* frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) @@ -3317,14 +3378,14 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 + return false; +} + -+inline void InspectorInstrumentation::willCheckNavigationPolicy(Frame& frame) ++inline void InspectorInstrumentation::willCheckNavigationPolicy(LocalFrame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + willCheckNavigationPolicyImpl(*agents, frame); +} + -+inline void InspectorInstrumentation::didCheckNavigationPolicy(Frame& frame, bool cancel) ++inline void InspectorInstrumentation::didCheckNavigationPolicy(LocalFrame& frame, bool cancel) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) @@ -3334,31 +3395,17 @@ index 9ef49586f5125ac3670007e6c09733fdd1e303ba..ccc8d93cc7a53fe7e13a80bc6ce0c218 inline InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(ScriptExecutionContext* context) { return context ? instrumentingAgents(*context) : nullptr; -diff --git a/Source/WebCore/inspector/UserGestureEmulationScope.h b/Source/WebCore/inspector/UserGestureEmulationScope.h -index 07103c35e0a9193a010a85cf2ea8017b2ad59212..338d158be5a6f35adc6817dc94d6084b8bc593c5 100644 ---- a/Source/WebCore/inspector/UserGestureEmulationScope.h -+++ b/Source/WebCore/inspector/UserGestureEmulationScope.h -@@ -37,6 +37,7 @@ namespace WebCore { - class ChromeClient; - class Document; - class Page; -+class Document; - - class UserGestureEmulationScope { - WTF_MAKE_NONCOPYABLE(UserGestureEmulationScope); diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp -index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183f954f35b 100644 +index eb23c60fabfd012bd3e41d9f55a3c015ea6fbdae..57225822f7354c0f44c3d9ba282ac12502d0f27a 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp -@@ -62,12 +62,16 @@ +@@ -61,10 +61,14 @@ #include "Event.h" #include "EventListener.h" #include "EventNames.h" +#include "File.h" +#include "FileList.h" - #include "Frame.h" #include "FrameTree.h" - #include "FrameView.h" #include "FullscreenManager.h" +#include "FloatQuad.h" #include "HTMLElement.h" @@ -3366,8 +3413,8 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 +#include "HTMLInputElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" - #include "HTMLParserIdioms.h" -@@ -95,12 +99,14 @@ + #include "HTMLScriptElement.h" +@@ -94,12 +98,14 @@ #include "Pasteboard.h" #include "PseudoElement.h" #include "RenderGrid.h" @@ -3382,7 +3429,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 #include "StaticNodeList.h" #include "StyleProperties.h" #include "StyleResolver.h" -@@ -134,7 +140,8 @@ using namespace HTMLNames; +@@ -133,7 +139,8 @@ using namespace HTMLNames; static const size_t maxTextSize = 10000; static const UChar ellipsisUChar[] = { 0x2026, 0 }; @@ -3392,16 +3439,16 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 { if (!colorObject) return std::nullopt; -@@ -153,7 +160,7 @@ static std::optional parseColor(RefPtr&& colorObject) +@@ -152,7 +159,7 @@ static std::optional parseColor(RefPtr&& colorObject) - static Color parseConfigColor(const String& fieldName, JSON::Object& configObject) + static std::optional parseRequiredConfigColor(const String& fieldName, JSON::Object& configObject) { -- return parseColor(configObject.getObject(fieldName)).value_or(Color::transparentBlack); -+ return InspectorDOMAgent::parseColor(configObject.getObject(fieldName)).value_or(Color::transparentBlack); +- return parseColor(configObject.getObject(fieldName)); ++ return InspectorDOMAgent::parseColor(configObject.getObject(fieldName)); } - static bool parseQuad(Ref&& quadArray, FloatQuad* quad) -@@ -176,6 +183,20 @@ static bool parseQuad(Ref&& quadArray, FloatQuad* quad) + static Color parseOptionalConfigColor(const String& fieldName, JSON::Object& configObject) +@@ -180,6 +187,20 @@ static bool parseQuad(Ref&& quadArray, FloatQuad* quad) return true; } @@ -3422,7 +3469,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 class RevalidateStyleAttributeTask { WTF_MAKE_FAST_ALLOCATED; public: -@@ -451,6 +472,20 @@ Node* InspectorDOMAgent::assertNode(Protocol::ErrorString& errorString, Protocol +@@ -461,6 +482,20 @@ Node* InspectorDOMAgent::assertNode(Protocol::ErrorString& errorString, Protocol return node; } @@ -3443,8 +3490,8 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 Document* InspectorDOMAgent::assertDocument(Protocol::ErrorString& errorString, Protocol::DOM::NodeId nodeId) { Node* node = assertNode(errorString, nodeId); -@@ -1442,16 +1477,7 @@ Protocol::ErrorStringOr InspectorDOMAgent::highlightSelector(Ref InspectorDOMAgent::highlightNode(Ref&& highlightInspectorObject, std::optional&& nodeId, const Protocol::Runtime::RemoteObjectId& objectId) +@@ -1536,16 +1571,7 @@ Protocol::ErrorStringOr InspectorDOMAgent::highlightNode(std::optional InspectorDOMAgent::highlightNode(std::optional&& nodeId, const Protocol::Runtime::RemoteObjectId& objectId, Ref&& highlightInspectorObject, RefPtr&& gridOverlayInspectorObject, RefPtr&& flexOverlayInspectorObject, std::optional&& showRulers) { Protocol::ErrorString errorString; - @@ -3461,19 +3508,17 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 if (!node) return makeUnexpected(errorString); -@@ -1689,15 +1715,141 @@ Protocol::ErrorStringOr InspectorDOMAgent::setInspectedNode(Protocol::DOM: +@@ -1800,15 +1826,155 @@ Protocol::ErrorStringOr InspectorDOMAgent::setInspectedNode(Protocol::DOM: return { }; } -Protocol::ErrorStringOr> InspectorDOMAgent::resolveNode(Protocol::DOM::NodeId nodeId, const String& objectGroup) -+static FloatPoint contentsToRootView(FrameView& containingView, const FloatPoint& point) - { -- Protocol::ErrorString errorString; ++static FloatPoint contentsToRootView(LocalFrameView& containingView, const FloatPoint& point) ++{ + return containingView.convertToRootView(point - toFloatSize(containingView.documentScrollPositionRelativeToViewOrigin())); +} - -- Node* node = assertNode(errorString, nodeId); -+static void frameQuadToViewport(FrameView& containingView, FloatQuad& quad, float pageScaleFactor) ++ ++static void frameQuadToViewport(LocalFrameView& containingView, FloatQuad& quad, float pageScaleFactor) +{ + // Return css (not dip) coordinates by scaling back. + quad.setP1(contentsToRootView(containingView, quad.p1()).scaled(1 / pageScaleFactor)); @@ -3522,7 +3567,8 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 + String contentFrameId; + if (is(*node)) { + const auto& frameOwner = downcast(*node); -+ String frameId = pageAgent->frameId(frameOwner.contentFrame()); ++ // TODO(playwright): Unnecessary downcast to LocalFrame? ++ String frameId = pageAgent->frameId(dynamicDowncast(frameOwner.contentFrame())); + if (!frameId.isEmpty()) + contentFrameId = frameId; + } @@ -3554,7 +3600,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 + if (!renderer) + return makeUnexpected("Node does not have a layout object"_s); + -+ bool insideFixed; ++ bool insideFixed = false; + LayoutRect absoluteBounds = renderer->absoluteBoundingBoxRect(true, &insideFixed); + if (rect) { + std::optional x = rect->getDouble("x"_s); @@ -3571,7 +3617,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 + } + ScrollAlignment alignment = ScrollAlignment::alignCenterIfNeeded; + alignment.m_enableLegacyHorizontalVisibilityThreshold = false; // Disable RenderLayer minium horizontal scroll threshold. -+ FrameView::scrollRectToVisible(absoluteBounds, *renderer, insideFixed, { SelectionRevealMode::Reveal, alignment, alignment, ShouldAllowCrossOriginScrolling::Yes, ScrollBehavior::Instant }); ++ LocalFrameView::scrollRectToVisible(absoluteBounds, *renderer, insideFixed, { SelectionRevealMode::Reveal, alignment, alignment, ShouldAllowCrossOriginScrolling::Yes, ScrollBehavior::Instant }); + return { }; +} + @@ -3584,7 +3630,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 + // Ensure quads are up to date. + m_inspectedPage.isolatedUpdateRendering(); + -+ FrameView* containingView = node->document().view(); ++ LocalFrameView* containingView = node->document().view(); + if (!containingView) + return makeUnexpected("Internal error: no containing view"_s); + @@ -3595,10 +3641,24 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 + return buildArrayOfQuads(quads); +} + -+Protocol::ErrorStringOr> InspectorDOMAgent::resolveNode(std::optional&& nodeId, const String& objectId, std::optional&& contextId, const String& objectGroup) -+{ -+ Protocol::ErrorString errorString; -+ Node* node = assertNode(errorString, WTFMove(nodeId), objectId); ++Protocol::ErrorStringOr> InspectorDOMAgent::resolveNode(std::optional&& nodeId, const String& objectId, const Inspector::Protocol::Network::FrameId& frameId, std::optional&& contextId, const String& objectGroup) + { + Protocol::ErrorString errorString; ++ Node* node = nullptr; ++ if (!!frameId) { ++ auto* pageAgent = m_instrumentingAgents.enabledPageAgent(); ++ if (!pageAgent) ++ return makeUnexpected("Page domain must be enabled"_s); + +- Node* node = assertNode(errorString, nodeId); ++ auto* frame = pageAgent->assertFrame(errorString, frameId); ++ if (!frame) ++ return makeUnexpected(errorString); ++ ++ node = frame->ownerElement(); ++ } else { ++ node = assertNode(errorString, WTFMove(nodeId), objectId); ++ } if (!node) return makeUnexpected(errorString); @@ -3607,7 +3667,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 if (!object) return makeUnexpected("Missing injected script for given nodeId"_s); -@@ -2952,7 +3104,7 @@ Protocol::ErrorStringOr InspectorDOMAgent::pushNodeByPath +@@ -3062,7 +3228,7 @@ Protocol::ErrorStringOr InspectorDOMAgent::pushNodeByPath return makeUnexpected("Missing node for given path"_s); } @@ -3616,7 +3676,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 { Document* document = &node->document(); if (auto* templateHost = document->templateDocumentHost()) -@@ -2961,12 +3113,18 @@ RefPtr InspectorDOMAgent::resolveNode(Node* nod +@@ -3071,12 +3237,18 @@ RefPtr InspectorDOMAgent::resolveNode(Node* nod if (!frame) return nullptr; @@ -3638,7 +3698,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 } Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value) -@@ -2989,4 +3147,57 @@ Protocol::ErrorStringOr InspectorDOMAgent::setAllowEditingUserAgentShadowT +@@ -3099,4 +3271,57 @@ Protocol::ErrorStringOr InspectorDOMAgent::setAllowEditingUserAgentShadowT return { }; } @@ -3697,7 +3757,7 @@ index 169f443ebf6139b8c48e700d73d11053ef443b86..505c79042cf9fa238277979304f13183 + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h -index 262829afb3c7151464de876368db47bf733e7f2e..fdcc8c44f3d24f13003b3eed3f2af79c9746896f 100644 +index 9cd98d4bfb8e3b15c995e8968f0052d498b8dff8..bd6d6930a71ce2f23f18f9ee096c86becc5ed9dc 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h @@ -57,6 +57,7 @@ namespace WebCore { @@ -3721,11 +3781,11 @@ index 262829afb3c7151464de876368db47bf733e7f2e..fdcc8c44f3d24f13003b3eed3f2af79c Inspector::Protocol::ErrorStringOr>> getSearchResults(const String& searchId, int fromIndex, int toIndex); Inspector::Protocol::ErrorStringOr discardSearchResults(const String& searchId); - Inspector::Protocol::ErrorStringOr> resolveNode(Inspector::Protocol::DOM::NodeId, const String& objectGroup); -+ Inspector::Protocol::ErrorStringOr> resolveNode(std::optional&& nodeId, const String& objectId, std::optional&& contextId, const String& objectGroup); ++ Inspector::Protocol::ErrorStringOr> resolveNode(std::optional&& nodeId, const String& objectId, const Inspector::Protocol::Network::FrameId& frameId, std::optional&& contextId, const String& objectGroup); Inspector::Protocol::ErrorStringOr>> getAttributes(Inspector::Protocol::DOM::NodeId); #if PLATFORM(IOS_FAMILY) - Inspector::Protocol::ErrorStringOr setInspectModeEnabled(bool, RefPtr&& highlightConfig); -@@ -159,6 +161,10 @@ public: + Inspector::Protocol::ErrorStringOr setInspectModeEnabled(bool, RefPtr&& highlightConfig, RefPtr&& gridOverlayConfig, RefPtr&& flexOverlayConfig); +@@ -168,6 +170,10 @@ public: Inspector::Protocol::ErrorStringOr focus(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::ErrorStringOr setInspectedNode(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::ErrorStringOr setAllowEditingUserAgentShadowTrees(bool); @@ -3736,7 +3796,7 @@ index 262829afb3c7151464de876368db47bf733e7f2e..fdcc8c44f3d24f13003b3eed3f2af79c // InspectorInstrumentation Inspector::Protocol::DOM::NodeId identifierForNode(Node&); -@@ -200,7 +206,7 @@ public: +@@ -209,7 +215,7 @@ public: Node* nodeForId(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::DOM::NodeId boundNodeId(const Node*); @@ -3745,7 +3805,7 @@ index 262829afb3c7151464de876368db47bf733e7f2e..fdcc8c44f3d24f13003b3eed3f2af79c bool handleMousePress(); void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); void inspect(Node*); -@@ -212,12 +218,15 @@ public: +@@ -221,12 +227,15 @@ public: void reset(); Node* assertNode(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); @@ -3761,7 +3821,7 @@ index 262829afb3c7151464de876368db47bf733e7f2e..fdcc8c44f3d24f13003b3eed3f2af79c private: #if ENABLE(VIDEO) void mediaMetricsTimerFired(); -@@ -246,7 +255,6 @@ private: +@@ -256,7 +265,6 @@ private: void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf&); Node* nodeForPath(const String& path); @@ -3770,18 +3830,10 @@ index 262829afb3c7151464de876368db47bf733e7f2e..fdcc8c44f3d24f13003b3eed3f2af79c void discardBindings(); diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp -index 3f095032390bb73cd3d72422b969bcf3cb66f781..97a7ad9612301d5c00943cd2aa5ca475683b1c3a 100644 +index 958e55d7ab1dd3503301a65d9a73f4086d61cca2..ef1d8212902787f8933ae8a8a34578521431e591 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp -@@ -45,6 +45,7 @@ - #include "DocumentThreadableLoader.h" - #include "FormData.h" - #include "Frame.h" -+#include "FormData.h" - #include "FrameLoader.h" - #include "HTTPHeaderMap.h" - #include "HTTPHeaderNames.h" -@@ -58,6 +59,7 @@ +@@ -59,6 +59,7 @@ #include "MIMETypeRegistry.h" #include "MemoryCache.h" #include "NetworkResourcesData.h" @@ -3789,7 +3841,7 @@ index 3f095032390bb73cd3d72422b969bcf3cb66f781..97a7ad9612301d5c00943cd2aa5ca475 #include "Page.h" #include "PlatformStrategies.h" #include "ProgressTracker.h" -@@ -335,8 +337,8 @@ static Ref buildObjectForResourceRequest(const Resou +@@ -337,8 +338,8 @@ static Ref buildObjectForResourceRequest(const Resou .release(); if (request.httpBody() && !request.httpBody()->isEmpty()) { @@ -3800,7 +3852,7 @@ index 3f095032390bb73cd3d72422b969bcf3cb66f781..97a7ad9612301d5c00943cd2aa5ca475 } if (resourceLoader) { -@@ -389,6 +391,8 @@ RefPtr InspectorNetworkAgent::buildObjectForResourc +@@ -391,6 +392,8 @@ RefPtr InspectorNetworkAgent::buildObjectForResourc .setSource(responseSource(response.source())) .release(); @@ -3809,7 +3861,61 @@ index 3f095032390bb73cd3d72422b969bcf3cb66f781..97a7ad9612301d5c00943cd2aa5ca475 if (resourceLoader) { auto* metrics = response.deprecatedNetworkLoadMetricsOrNull(); responseObject->setTiming(buildObjectForTiming(metrics ? *metrics : NetworkLoadMetrics::emptyMetrics(), *resourceLoader)); -@@ -954,6 +958,7 @@ void InspectorNetworkAgent::continuePendingResponses() +@@ -471,22 +474,6 @@ void InspectorNetworkAgent::willSendRequest(ResourceLoaderIdentifier identifier, + auto loaderId = loaderIdentifier(loader); + String targetId = request.initiatorIdentifier(); + +- if (type == InspectorPageAgent::OtherResource) { +- if (m_loadingXHRSynchronously || request.requester() == ResourceRequestRequester::XHR) +- type = InspectorPageAgent::XHRResource; +- else if (request.requester() == ResourceRequestRequester::Fetch) +- type = InspectorPageAgent::FetchResource; +- else if (loader && equalIgnoringFragmentIdentifier(request.url(), loader->url()) && !loader->isCommitted()) +- type = InspectorPageAgent::DocumentResource; +- else if (loader) { +- for (auto& linkIcon : loader->linkIcons()) { +- if (equalIgnoringFragmentIdentifier(request.url(), linkIcon.url)) { +- type = InspectorPageAgent::ImageResource; +- break; +- } +- } +- } +- } + + m_resourcesData->resourceCreated(requestId, loaderId, type); + +@@ -528,9 +515,27 @@ static InspectorPageAgent::ResourceType resourceTypeForLoadType(InspectorInstrum + + void InspectorNetworkAgent::willSendRequest(ResourceLoaderIdentifier identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse, const CachedResource* cachedResource, ResourceLoader* resourceLoader) + { +- if (!cachedResource && loader) +- cachedResource = InspectorPageAgent::cachedResource(loader->frame(), request.url()); +- willSendRequest(identifier, loader, request, redirectResponse, resourceTypeForCachedResource(cachedResource), resourceLoader); ++ InspectorPageAgent::ResourceType type = InspectorPageAgent::OtherResource; ++ if (m_loadingXHRSynchronously || request.requester() == ResourceRequestRequester::XHR) ++ type = InspectorPageAgent::XHRResource; ++ else if (request.requester() == ResourceRequestRequester::Fetch) ++ type = InspectorPageAgent::FetchResource; ++ else if (loader && equalIgnoringFragmentIdentifier(request.url(), loader->url()) && !loader->isCommitted()) ++ type = InspectorPageAgent::DocumentResource; ++ else if (loader) { ++ for (auto& linkIcon : loader->linkIcons()) { ++ if (equalIgnoringFragmentIdentifier(request.url(), linkIcon.url)) { ++ type = InspectorPageAgent::ImageResource; ++ break; ++ } ++ } ++ } ++ if (type == InspectorPageAgent::OtherResource) { ++ if (!cachedResource && loader) ++ cachedResource = InspectorPageAgent::cachedResource(loader->frame(), request.url()); ++ type = resourceTypeForCachedResource(cachedResource); ++ } ++ willSendRequest(identifier, loader, request, redirectResponse, type, resourceLoader); + } + + void InspectorNetworkAgent::willSendRequestOfType(ResourceLoaderIdentifier identifier, DocumentLoader* loader, ResourceRequest& request, InspectorInstrumentation::LoadType loadType) +@@ -956,6 +961,7 @@ void InspectorNetworkAgent::continuePendingResponses() Protocol::ErrorStringOr InspectorNetworkAgent::setExtraHTTPHeaders(Ref&& headers) { @@ -3817,7 +3923,7 @@ index 3f095032390bb73cd3d72422b969bcf3cb66f781..97a7ad9612301d5c00943cd2aa5ca475 for (auto& entry : headers.get()) { auto stringValue = entry.value->asString(); if (!!stringValue) -@@ -1234,6 +1239,9 @@ Protocol::ErrorStringOr InspectorNetworkAgent::interceptWithRequest(const +@@ -1236,6 +1242,9 @@ Protocol::ErrorStringOr InspectorNetworkAgent::interceptWithRequest(const return makeUnexpected("Missing pending intercept request for given requestId"_s); auto& loader = *pendingRequest->m_loader; @@ -3827,7 +3933,7 @@ index 3f095032390bb73cd3d72422b969bcf3cb66f781..97a7ad9612301d5c00943cd2aa5ca475 ResourceRequest request = loader.request(); if (!!url) request.setURL(URL({ }, url)); -@@ -1333,14 +1341,23 @@ Protocol::ErrorStringOr InspectorNetworkAgent::interceptRequestWithRespons +@@ -1335,14 +1344,23 @@ Protocol::ErrorStringOr InspectorNetworkAgent::interceptRequestWithRespons response.setHTTPStatusCode(status); response.setHTTPStatusText(AtomString { statusText }); HTTPHeaderMap explicitHeaders; @@ -3853,7 +3959,7 @@ index 3f095032390bb73cd3d72422b969bcf3cb66f781..97a7ad9612301d5c00943cd2aa5ca475 if (loader->reachedTerminalState()) return; -@@ -1403,6 +1420,12 @@ Protocol::ErrorStringOr InspectorNetworkAgent::setEmulatedConditions(std:: +@@ -1405,6 +1423,12 @@ Protocol::ErrorStringOr InspectorNetworkAgent::setEmulatedConditions(std:: #endif // ENABLE(INSPECTOR_NETWORK_THROTTLING) @@ -3888,10 +3994,10 @@ index c6ebcc9d7e399a35f71350c9374df0f2107c518b..3bfa03ae7f27d9128fe207c1de1bfea9 // InspectorInstrumentation void willRecalculateStyle(); diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp -index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834be24f1729 100644 +index 2c8fa3981b36f9bd53320791c278c67049f9fae8..ed99c1104190d497bf57f300e3119a7d10ac4963 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp -@@ -32,20 +32,28 @@ +@@ -32,19 +32,27 @@ #include "config.h" #include "InspectorPageAgent.h" @@ -3909,22 +4015,24 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b +#include "Editor.h" #include "ElementInlines.h" +#include "FocusController.h" - #include "Frame.h" + #include "ForcedAccessibilityValue.h" #include "FrameLoadRequest.h" #include "FrameLoader.h" +#include "FrameLoaderClient.h" #include "FrameSnapshotting.h" - #include "FrameView.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" #include "InspectorClient.h" -@@ -56,19 +64,29 @@ +@@ -55,10 +63,13 @@ + #include "LocalFrame.h" + #include "LocalFrameView.h" #include "MIMETypeRegistry.h" - #include "MemoryCache.h" +-#include "MemoryCache.h" #include "Page.h" +#include "PageRuntimeAgent.h" ++#include "PlatformScreen.h" #include "RenderObject.h" #include "RenderTheme.h" +#include "DeprecatedGlobalSettings.h" @@ -3932,8 +4040,9 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b #include "ScriptController.h" #include "ScriptSourceCode.h" #include "SecurityOrigin.h" - #include "Settings.h" +@@ -66,11 +77,18 @@ #include "StyleScope.h" + #include "Theme.h" #include +#include "TextIterator.h" +#include "TypingCommand.h" @@ -3950,7 +4059,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b #include #include #include -@@ -81,11 +99,15 @@ +@@ -83,11 +101,15 @@ #include "LegacyWebArchive.h" #endif @@ -3967,7 +4076,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b static bool decodeBuffer(const uint8_t* buffer, unsigned size, const String& textEncodingName, String* result) { if (buffer) { -@@ -326,6 +348,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClien +@@ -334,6 +356,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClien , m_frontendDispatcher(makeUnique(context.frontendRouter)) , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this)) , m_inspectedPage(context.inspectedPage) @@ -3975,9 +4084,9 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b , m_client(client) , m_overlay(overlay) { -@@ -357,12 +380,20 @@ Protocol::ErrorStringOr InspectorPageAgent::enable() - defaultAppearanceDidChange(m_inspectedPage.defaultUseDarkAppearance()); - #endif +@@ -363,12 +386,20 @@ Protocol::ErrorStringOr InspectorPageAgent::enable() + + defaultUserPreferencesDidChange(); + if (!createdUserWorlds().isEmpty()) { + Vector worlds; @@ -3996,7 +4105,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b setShowPaintRects(false); #if !PLATFORM(IOS_FAMILY) -@@ -411,6 +442,22 @@ Protocol::ErrorStringOr InspectorPageAgent::reload(std::optional&& i +@@ -420,6 +451,22 @@ Protocol::ErrorStringOr InspectorPageAgent::reload(std::optional&& i return { }; } @@ -4018,8 +4127,8 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + Protocol::ErrorStringOr InspectorPageAgent::navigate(const String& url) { - Frame& frame = m_inspectedPage.mainFrame(); -@@ -432,6 +479,13 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideUserAgent(const String + auto* localMainFrame = dynamicDowncast(m_inspectedPage.mainFrame()); +@@ -443,6 +490,13 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideUserAgent(const String return { }; } @@ -4033,7 +4142,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page::Setting setting, std::optional&& value) { auto& inspectedPageSettings = m_inspectedPage.settings(); -@@ -445,6 +499,12 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page +@@ -456,6 +510,12 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page inspectedPageSettings.setAuthorAndUserStylesEnabledInspectorOverride(value); return { }; @@ -4046,7 +4155,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b case Protocol::Page::Setting::ICECandidateFilteringEnabled: inspectedPageSettings.setICECandidateFilteringEnabledInspectorOverride(value); return { }; -@@ -470,6 +530,36 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page +@@ -481,6 +541,38 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page inspectedPageSettings.setNeedsSiteSpecificQuirksInspectorOverride(value); return { }; @@ -4062,17 +4171,19 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + return { }; +#endif + -+#if ENABLE(INPUT_TYPE_MONTH) + case Protocol::Page::Setting::InputTypeMonthEnabled: ++// Playwright client sends it even if it's not supported. ++#if ENABLE(INPUT_TYPE_MONTH) + inspectedPageSettings.setInputTypeMonthEnabled(value.value_or(false)); -+ return { }; +#endif ++ return { }; + -+#if ENABLE(INPUT_TYPE_WEEK) + case Protocol::Page::Setting::InputTypeWeekEnabled: ++// Playwright client sends it even if it's not supported. ++#if ENABLE(INPUT_TYPE_WEEK) + inspectedPageSettings.setInputTypeWeekEnabled(value.value_or(false)); -+ return { }; +#endif ++ return { }; + +#if ENABLE(POINTER_LOCK) + case Protocol::Page::Setting::PointerLockEnabled: @@ -4083,7 +4194,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b case Protocol::Page::Setting::ScriptEnabled: inspectedPageSettings.setScriptEnabledInspectorOverride(value); return { }; -@@ -482,6 +572,12 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page +@@ -493,6 +585,12 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page inspectedPageSettings.setShowRepaintCounterInspectorOverride(value); return { }; @@ -4093,10 +4204,10 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + return { }; +#endif + - case Protocol::Page::Setting::WebRTCEncryptionEnabled: - inspectedPageSettings.setWebRTCEncryptionEnabledInspectorOverride(value); + case Protocol::Page::Setting::WebSecurityEnabled: + inspectedPageSettings.setWebSecurityEnabledInspectorOverride(value); return { }; -@@ -702,9 +798,13 @@ Protocol::ErrorStringOr> InspectorP +@@ -785,9 +883,13 @@ Protocol::ErrorStringOr> InspectorP return { { content, base64Encoded } }; } @@ -4112,12 +4223,12 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b return { }; } -@@ -807,15 +907,16 @@ Protocol::ErrorStringOr InspectorPageAgent::setShowPaintRects(bool show) +@@ -893,15 +995,16 @@ Protocol::ErrorStringOr InspectorPageAgent::setShowPaintRects(bool show) return { }; } -void InspectorPageAgent::domContentEventFired() -+void InspectorPageAgent::domContentEventFired(Frame& frame) ++void InspectorPageAgent::domContentEventFired(LocalFrame& frame) { - m_isFirstLayoutAfterOnLoad = true; - m_frontendDispatcher->domContentEventFired(timestamp()); @@ -4127,30 +4238,32 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b } -void InspectorPageAgent::loadEventFired() -+void InspectorPageAgent::loadEventFired(Frame& frame) ++void InspectorPageAgent::loadEventFired(LocalFrame& frame) { - m_frontendDispatcher->loadEventFired(timestamp()); + m_frontendDispatcher->loadEventFired(timestamp(), frameId(&frame)); } - void InspectorPageAgent::frameNavigated(Frame& frame) -@@ -823,13 +924,23 @@ void InspectorPageAgent::frameNavigated(Frame& frame) + void InspectorPageAgent::frameNavigated(LocalFrame& frame) +@@ -909,13 +1012,25 @@ void InspectorPageAgent::frameNavigated(LocalFrame& frame) m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame)); } +String InspectorPageAgent::makeFrameID(ProcessIdentifier processID, FrameIdentifier frameID) +{ -+ return makeString(processID.toUInt64(), ".", frameID.toUInt64()); ++ return makeString(processID.toUInt64(), ".", frameID.object().toUInt64()); +} + +static String globalIDForFrame(Frame& frame) +{ -+ return InspectorPageAgent::makeFrameID(Process::identifier(), *frame.loader().client().frameID()); ++ // TODO(playwright): for OOPIF we have to use id of the web process where the frame is hosted. ++ // Working at the moment because OOPIF is diabled. ++ return InspectorPageAgent::makeFrameID(Process::identifier(), frame.frameID()); +} + - void InspectorPageAgent::frameDetached(Frame& frame) + void InspectorPageAgent::frameDetached(LocalFrame& frame) { -- auto identifier = m_frameToIdentifier.take(&frame); +- auto identifier = m_frameToIdentifier.take(frame); - if (identifier.isNull()) + String identifier = globalIDForFrame(frame); + if (!m_identifierToFrame.take(identifier)) @@ -4161,16 +4274,15 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b } Frame* InspectorPageAgent::frameForId(const Protocol::Network::FrameId& frameId) -@@ -841,20 +952,18 @@ String InspectorPageAgent::frameId(Frame* frame) +@@ -927,20 +1042,17 @@ String InspectorPageAgent::frameId(Frame* frame) { if (!frame) return emptyString(); -- return m_frameToIdentifier.ensure(frame, [this, frame] { +- return m_frameToIdentifier.ensure(*frame, [this, frame] { - auto identifier = IdentifiersFactory::createIdentifier(); - m_identifierToFrame.set(identifier, frame); - return identifier; - }).iterator->value; -+ + String identifier = globalIDForFrame(*frame); + m_identifierToFrame.set(identifier, frame); + return identifier; @@ -4187,8 +4299,8 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + return String::number(loader->loaderIDForInspector()); } - Frame* InspectorPageAgent::assertFrame(Protocol::ErrorString& errorString, const Protocol::Network::FrameId& frameId) -@@ -865,11 +974,6 @@ Frame* InspectorPageAgent::assertFrame(Protocol::ErrorString& errorString, const + LocalFrame* InspectorPageAgent::assertFrame(Protocol::ErrorString& errorString, const Protocol::Network::FrameId& frameId) +@@ -951,11 +1063,6 @@ LocalFrame* InspectorPageAgent::assertFrame(Protocol::ErrorString& errorString, return frame; } @@ -4197,25 +4309,37 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b - m_loaderToIdentifier.remove(&loader); -} - - void InspectorPageAgent::frameStartedLoading(Frame& frame) + void InspectorPageAgent::frameStartedLoading(LocalFrame& frame) { m_frontendDispatcher->frameStartedLoading(frameId(&frame)); -@@ -890,6 +994,12 @@ void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame) - m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame)); +@@ -966,9 +1073,9 @@ void InspectorPageAgent::frameStoppedLoading(LocalFrame& frame) + m_frontendDispatcher->frameStoppedLoading(frameId(&frame)); + } + +-void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay) ++void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay, bool targetIsCurrentFrame) + { +- m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value()); ++ m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value(), targetIsCurrentFrame); + } + + void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame) +@@ -1023,6 +1130,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange() + m_frontendDispatcher->defaultUserPreferencesDidChange(WTFMove(defaultUserPreferences)); } -+void InspectorPageAgent::didNavigateWithinPage(Frame& frame) ++void InspectorPageAgent::didNavigateWithinPage(LocalFrame& frame) +{ + String url = frame.document()->url().string(); + m_frontendDispatcher->navigatedWithinDocument(frameId(&frame), url); +} + #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) - void InspectorPageAgent::defaultAppearanceDidChange(bool useDarkAppearance) + void InspectorPageAgent::defaultAppearanceDidChange() { -@@ -899,13 +1009,22 @@ void InspectorPageAgent::defaultAppearanceDidChange(bool useDarkAppearance) +@@ -1032,13 +1145,22 @@ void InspectorPageAgent::defaultAppearanceDidChange() - void InspectorPageAgent::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world) + void InspectorPageAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapperWorld& world) { - if (&world != &mainThreadNormalWorld()) + if (m_worldNameToBootstrapScript.isEmpty()) @@ -4239,7 +4363,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b } void InspectorPageAgent::didPaint(RenderObject& renderer, const LayoutRect& rect) -@@ -949,6 +1068,52 @@ void InspectorPageAgent::didRecalculateStyle() +@@ -1086,6 +1208,51 @@ void InspectorPageAgent::didRecalculateStyle() m_overlay->update(); } @@ -4267,10 +4391,9 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + m_frontendDispatcher->fileChooserOpened(frameId(frame), object.releaseNonNull()); +} + -+void InspectorPageAgent::frameAttached(Frame& frame) ++void InspectorPageAgent::frameAttached(LocalFrame& frame) +{ -+ Frame* parent = frame.tree().parent(); -+ String parentFrameId = frameId(parent); ++ String parentFrameId = frameId(dynamicDowncast(frame.tree().parent())); + m_frontendDispatcher->frameAttached(frameId(&frame), parentFrameId); +} + @@ -4279,20 +4402,20 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + return m_bypassCSP; +} + -+void InspectorPageAgent::willCheckNavigationPolicy(Frame& frame) ++void InspectorPageAgent::willCheckNavigationPolicy(LocalFrame& frame) +{ + m_frontendDispatcher->willCheckNavigationPolicy(frameId(&frame)); +} + -+void InspectorPageAgent::didCheckNavigationPolicy(Frame& frame, bool cancel) ++void InspectorPageAgent::didCheckNavigationPolicy(LocalFrame& frame, bool cancel) +{ + m_frontendDispatcher->didCheckNavigationPolicy(frameId(&frame), cancel); +} + - Ref InspectorPageAgent::buildObjectForFrame(Frame* frame) + Ref InspectorPageAgent::buildObjectForFrame(LocalFrame* frame) { ASSERT_ARG(frame, frame); -@@ -1062,6 +1227,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent) +@@ -1183,6 +1350,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent) userAgent = m_userAgentOverride; } @@ -4302,10 +4425,10 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + platform = m_platformOverride; +} + - void InspectorPageAgent::applyEmulatedMedia(String& media) + void InspectorPageAgent::applyEmulatedMedia(AtomString& media) { if (!m_emulatedMedia.isEmpty()) -@@ -1085,11 +1256,13 @@ Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Protocol::DOM:: +@@ -1210,11 +1383,13 @@ Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Protocol::DOM:: return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } @@ -4319,24 +4442,24 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + options.flags.add(SnapshotFlags::OmitDeviceScaleFactor); IntRect rectangle(x, y, width, height); - auto snapshot = snapshotFrameRect(m_inspectedPage.mainFrame(), rectangle, WTFMove(options)); -@@ -1100,6 +1273,47 @@ Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int x, int y, i + auto* localMainFrame = dynamicDowncast(m_inspectedPage.mainFrame()); +@@ -1228,6 +1403,43 @@ Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int x, int y, i return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } -+Protocol::ErrorStringOr InspectorPageAgent::setForcedReducedMotion(std::optional&& reducedMotion) ++Protocol::ErrorStringOr InspectorPageAgent::setForcedColors(std::optional&& forcedColors) +{ -+ if (!reducedMotion) { -+ m_inspectedPage.setUseReducedMotionOverride(std::nullopt); ++ if (!forcedColors) { ++ m_inspectedPage.setUseForcedColorsOverride(std::nullopt); + return { }; + } + -+ switch (*reducedMotion) { -+ case Protocol::Page::ReducedMotion::Reduce: -+ m_inspectedPage.setUseReducedMotionOverride(true); ++ switch (*forcedColors) { ++ case Protocol::Page::ForcedColors::Active: ++ m_inspectedPage.setUseForcedColorsOverride(true); + return { }; -+ case Protocol::Page::ReducedMotion::NoPreference: -+ m_inspectedPage.setUseReducedMotionOverride(false); ++ case Protocol::Page::ForcedColors::None: ++ m_inspectedPage.setUseForcedColorsOverride(false); + return { }; + } + @@ -4355,20 +4478,16 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + +Protocol::ErrorStringOr InspectorPageAgent::setTouchEmulationEnabled(bool enabled) +{ -+#if ENABLE(TOUCH_EVENTS) -+ DeprecatedGlobalSettings::setTouchEventsEnabled(enabled); -+ return { }; -+#else -+ UNUSED_PARAM(enabled); -+ return makeUnexpected("Not supported"_s); -+#endif ++ setScreenHasTouchDeviceOverride(enabled); ++ m_inspectedPage.settings().setTouchEventsEnabled(enabled); ++ return { }; +} + + #if ENABLE(WEB_ARCHIVE) && USE(CF) Protocol::ErrorStringOr InspectorPageAgent::archive() { -@@ -1112,7 +1326,6 @@ Protocol::ErrorStringOr InspectorPageAgent::archive() +@@ -1244,7 +1456,6 @@ Protocol::ErrorStringOr InspectorPageAgent::archive() } #endif @@ -4376,28 +4495,28 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverride(std::optional&& width, std::optional&& height) { if (width.has_value() != height.has_value()) -@@ -1127,6 +1340,632 @@ Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverride(std::opt - m_inspectedPage.mainFrame().setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0))); +@@ -1262,6 +1473,629 @@ Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverride(std::opt + localMainFrame->setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0))); return { }; } + +Protocol::ErrorStringOr InspectorPageAgent::insertText(const String& text) +{ + UserGestureIndicator indicator { ProcessingUserGesture }; -+ Frame& frame = m_inspectedPage.focusController().focusedOrMainFrame(); ++ LocalFrame& frame = m_inspectedPage.focusController().focusedOrMainFrame(); + + if (frame.editor().hasComposition()) { + frame.editor().confirmComposition(text); + } else { + Document* focusedDocument = frame.document(); -+ TypingCommand::insertText(*focusedDocument, text, 0); ++ TypingCommand::insertText(*focusedDocument, text, { }); + } + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::setComposition(const String& text, int selectionStart, int selectionLength, std::optional&& replacementStart, std::optional&& replacementLength) +{ -+ Frame& frame = m_inspectedPage.focusController().focusedOrMainFrame(); ++ LocalFrame& frame = m_inspectedPage.focusController().focusedOrMainFrame(); + + UserGestureIndicator indicator { ProcessingUserGesture }; + @@ -4460,6 +4579,8 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + return "Cell"_s; + case AccessibilityRole::CheckBox: + return "CheckBox"_s; ++ case AccessibilityRole::Code: ++ return "Code"_s; + case AccessibilityRole::ColorWell: + return "ColorWell"_s; + case AccessibilityRole::Column: @@ -4484,8 +4605,6 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + return "Directory"_s; + case AccessibilityRole::DisclosureTriangle: + return "DisclosureTriangle"_s; -+ case AccessibilityRole::Div: -+ return "Div"_s; + case AccessibilityRole::Document: + return "Document"_s; + case AccessibilityRole::DocumentArticle: @@ -4508,6 +4627,8 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + return "Footnote"_s; + case AccessibilityRole::Form: + return "Form"_s; ++ case AccessibilityRole::Generic: ++ return "Generic"_s; + case AccessibilityRole::GraphicsDocument: + return "GraphicsDocument"_s; + case AccessibilityRole::GraphicsObject: @@ -4735,15 +4856,16 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + auto axNode = Inspector::Protocol::Page::AXNode::create() + .setRole(roleFromObject(axObject)) + .release(); ++ auto* liveObject = dynamicDowncast(axObject.get()); + -+ if (!axObject->computedLabel().isEmpty()) -+ axNode->setName(axObject->computedLabel()); ++ if (liveObject && !liveObject->computedLabel().isEmpty()) ++ axNode->setName(liveObject->computedLabel()); + if (!axObject->stringValue().isEmpty()) + axNode->setValue(JSON::Value::create(axObject->stringValue())); -+ if (!axObject->accessibilityDescription().isEmpty()) -+ axNode->setDescription(axObject->accessibilityDescription()); -+ if (!axObject->keyShortcutsValue().isEmpty()) -+ axNode->setKeyshortcuts(axObject->keyShortcutsValue()); ++ if (liveObject && !liveObject->description().isEmpty()) ++ axNode->setDescription(liveObject->description()); ++ if (!axObject->keyShortcuts().isEmpty()) ++ axNode->setKeyshortcuts(axObject->keyShortcuts()); + if (!axObject->valueDescription().isEmpty()) + axNode->setValuetext(axObject->valueDescription()); + if (!axObject->roleDescription().isEmpty()) @@ -4761,7 +4883,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + axNode->setMultiline(multiline); + if (axObject->isMultiSelectable()) + axNode->setMultiselectable(axObject->isMultiSelectable()); -+ if (axObject->supportsReadOnly() && !axObject->canSetValueAttribute() && axObject->isEnabled()) ++ if (liveObject && liveObject->supportsReadOnly() && !axObject->canSetValueAttribute() && axObject->isEnabled()) + axNode->setReadonly(true); + if (axObject->supportsRequiredAttribute()) + axNode->setRequired(axObject->isRequired()); @@ -4781,20 +4903,6 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + break; + } + } -+ if (axObject->supportsPressed()) { -+ AccessibilityButtonState checkedState = axObject->checkboxOrRadioValue(); -+ switch (checkedState) { -+ case AccessibilityButtonState::On: -+ axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::True); -+ break; -+ case AccessibilityButtonState::Off: -+ axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::False); -+ break; -+ case AccessibilityButtonState::Mixed: -+ axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::Mixed); -+ break; -+ } -+ } + unsigned level = axObject->hierarchicalLevel() ? axObject->hierarchicalLevel() : axObject->headingLevel(); + if (level) + axNode->setLevel(level); @@ -4802,7 +4910,7 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + axNode->setValuemin(axObject->minValueForRange()); + if (axObject->maxValueForRange() != 0) + axNode->setValuemax(axObject->maxValueForRange()); -+ if (axObject->supportsAutoComplete()) ++ if (liveObject && liveObject->supportsAutoComplete()) + axNode->setAutocomplete(axObject->autoCompleteValue()); + if (axObject->hasPopup()) + axNode->setHaspopup(axObject->popupValue()); @@ -4847,7 +4955,12 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b +{ + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); -+ RefPtr document = m_inspectedPage.mainFrame().document(); ++ ++ auto* localMainFrame = dynamicDowncast(m_inspectedPage.mainFrame()); ++ if (!localMainFrame) ++ return makeUnexpected("No local main frame"_s); ++ ++ RefPtr document = localMainFrame->document(); + if (!document) + return makeUnexpected("No document for main frame"_s); + @@ -4882,7 +4995,8 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + +Protocol::ErrorStringOr InspectorPageAgent::setDefaultBackgroundColorOverride(RefPtr&& color) +{ -+ FrameView* view = m_inspectedPage.mainFrame().view(); ++ auto* localFrame = dynamicDowncast(m_inspectedPage.mainFrame()); ++ LocalFrameView* view = localFrame ? localFrame->view() : nullptr; + if (!view) + return makeUnexpected("Internal error: No frame view to set color two"_s); + @@ -4909,8 +5023,9 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b +void InspectorPageAgent::ensureUserWorldsExistInAllFrames(const Vector& worlds) +{ + for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) { ++ auto* localFrame = dynamicDowncast(frame); + for (auto* world : worlds) -+ frame->windowProxy().jsWindowProxy(*world)->window(); ++ localFrame->windowProxy().jsWindowProxy(*world)->window(); + } +} + @@ -4961,7 +5076,8 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b + +Protocol::ErrorStringOr InspectorPageAgent::setVisibleContentRects(RefPtr&& unobscuredContentRect, RefPtr&& contentInsets, RefPtr&& obscuredInsets, RefPtr&& unobscuredInsets) +{ -+ FrameView* view = m_inspectedPage.mainFrame().view(); ++ auto* localFrame = dynamicDowncast(m_inspectedPage.mainFrame()); ++ LocalFrameView* view = localFrame ? localFrame->view() : nullptr; + if (!view) + return makeUnexpected("Internal error: No frame view to set content rects for"_s); + @@ -5010,10 +5126,10 @@ index a6e415a9bf47e0f4c98b9f375b3195df287fe67b..2dbdbdee399a1f31b1d71024c916834b } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h -index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a2c60b5ad 100644 +index f270cb7c3bcc1b5d7d646d9c6e6bda7063cf82e3..5f80d34d6476250a2495ccd4871aed1c2ef13ccc 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h -@@ -32,19 +32,26 @@ +@@ -32,8 +32,10 @@ #pragma once #include "CachedResource.h" @@ -5023,7 +5139,8 @@ index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a +#include "ProcessIdentifier.h" #include #include - #include + #include +@@ -41,11 +43,16 @@ #include #include @@ -5039,16 +5156,16 @@ index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a +class HTMLInputElement; class InspectorClient; class InspectorOverlay; - class Page; -@@ -76,6 +83,7 @@ public: + class LocalFrame; +@@ -78,6 +85,7 @@ public: OtherResource, }; + WEBCORE_EXPORT static String makeFrameID(ProcessIdentifier processID, FrameIdentifier frameID); static bool sharedBufferContent(RefPtr&&, const String& textEncodingName, bool withBase64Encode, String* result); - static Vector cachedResourcesForFrame(Frame*); - static void resourceContent(Inspector::Protocol::ErrorString&, Frame*, const URL&, String* result, bool* base64Encoded); -@@ -96,15 +104,18 @@ public: + static Vector cachedResourcesForFrame(LocalFrame*); + static void resourceContent(Inspector::Protocol::ErrorString&, LocalFrame*, const URL&, String* result, bool* base64Encoded); +@@ -98,8 +106,11 @@ public: Inspector::Protocol::ErrorStringOr enable(); Inspector::Protocol::ErrorStringOr disable(); Inspector::Protocol::ErrorStringOr reload(std::optional&& ignoreCache, std::optional&& revalidateAllResources); @@ -5058,8 +5175,9 @@ index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a Inspector::Protocol::ErrorStringOr overrideUserAgent(const String&); + Inspector::Protocol::ErrorStringOr overridePlatform(const String&); Inspector::Protocol::ErrorStringOr overrideSetting(Inspector::Protocol::Page::Setting, std::optional&& value); + Inspector::Protocol::ErrorStringOr overrideUserPreference(Inspector::Protocol::Page::UserPreferenceName, std::optional&&); Inspector::Protocol::ErrorStringOr>> getCookies(); - Inspector::Protocol::ErrorStringOr setCookie(Ref&&); +@@ -107,7 +118,7 @@ public: Inspector::Protocol::ErrorStringOr deleteCookie(const String& cookieName, const String& url); Inspector::Protocol::ErrorStringOr> getResourceTree(); Inspector::Protocol::ErrorStringOr> getResourceContent(const Inspector::Protocol::Network::FrameId&, const String& url); @@ -5068,11 +5186,11 @@ index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a Inspector::Protocol::ErrorStringOr>> searchInResource(const Inspector::Protocol::Network::FrameId&, const String& url, const String& query, std::optional&& caseSensitive, std::optional&& isRegex, const Inspector::Protocol::Network::RequestId&); Inspector::Protocol::ErrorStringOr>> searchInResources(const String&, std::optional&& caseSensitive, std::optional&& isRegex); #if !PLATFORM(IOS_FAMILY) -@@ -115,35 +126,55 @@ public: - #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) - Inspector::Protocol::ErrorStringOr setForcedAppearance(std::optional&&); +@@ -115,37 +126,57 @@ public: #endif -+ Inspector::Protocol::ErrorStringOr setForcedReducedMotion(std::optional&&); + Inspector::Protocol::ErrorStringOr setShowPaintRects(bool); + Inspector::Protocol::ErrorStringOr setEmulatedMedia(const String&); ++ Inspector::Protocol::ErrorStringOr setForcedColors(std::optional&&); + Inspector::Protocol::ErrorStringOr setTimeZone(const String&); + Inspector::Protocol::ErrorStringOr setTouchEmulationEnabled(bool); Inspector::Protocol::ErrorStringOr snapshotNode(Inspector::Protocol::DOM::NodeId); @@ -5100,45 +5218,48 @@ index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a // InspectorInstrumentation - void domContentEventFired(); - void loadEventFired(); -+ void domContentEventFired(Frame&); -+ void loadEventFired(Frame&); - void frameNavigated(Frame&); - void frameDetached(Frame&); ++ void domContentEventFired(LocalFrame&); ++ void loadEventFired(LocalFrame&); + void frameNavigated(LocalFrame&); + void frameDetached(LocalFrame&); - void loaderDetachedFromFrame(DocumentLoader&); - void frameStartedLoading(Frame&); - void frameStoppedLoading(Frame&); - void frameScheduledNavigation(Frame&, Seconds delay); + void frameStartedLoading(LocalFrame&); + void frameStoppedLoading(LocalFrame&); +- void frameScheduledNavigation(Frame&, Seconds delay); ++ void frameScheduledNavigation(Frame&, Seconds delay, bool targetIsCurrentFrame); void frameClearedScheduledNavigation(Frame&); -+ void didNavigateWithinPage(Frame&); + void accessibilitySettingsDidChange(); + void defaultUserPreferencesDidChange(); ++ void didNavigateWithinPage(LocalFrame&); #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) - void defaultAppearanceDidChange(bool useDarkAppearance); + void defaultAppearanceDidChange(); #endif void applyUserAgentOverride(String&); + void applyPlatformOverride(String&); - void applyEmulatedMedia(String&); - void didClearWindowObjectInWorld(Frame&, DOMWrapperWorld&); + void applyEmulatedMedia(AtomString&); + void didClearWindowObjectInWorld(LocalFrame&, DOMWrapperWorld&); void didPaint(RenderObject&, const LayoutRect&); void didLayout(); void didScroll(); void didRecalculateStyle(); + void runOpenPanel(HTMLInputElement* element, bool* intercept); -+ void frameAttached(Frame&); ++ void frameAttached(LocalFrame&); + bool shouldBypassCSP(); -+ void willCheckNavigationPolicy(Frame&); -+ void didCheckNavigationPolicy(Frame&, bool cancel); ++ void willCheckNavigationPolicy(LocalFrame&); ++ void didCheckNavigationPolicy(LocalFrame&, bool cancel); + bool doingAccessibilitySnapshot() const { return m_doingAccessibilitySnapshot; }; Frame* frameForId(const Inspector::Protocol::Network::FrameId&); WEBCORE_EXPORT String frameId(Frame*); -@@ -152,6 +183,7 @@ public: +@@ -154,6 +185,7 @@ public: private: double timestamp(); + void ensureUserWorldsExistInAllFrames(const Vector&); - static bool mainResourceContent(Frame*, bool withBase64Encode, String* result); + static bool mainResourceContent(LocalFrame*, bool withBase64Encode, String* result); static bool dataContent(const uint8_t* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result); -@@ -163,18 +195,20 @@ private: +@@ -169,17 +201,21 @@ private: RefPtr m_backendDispatcher; Page& m_inspectedPage; @@ -5146,15 +5267,14 @@ index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a InspectorClient* m_client { nullptr }; InspectorOverlay* m_overlay { nullptr }; -- // FIXME: Make a WeakHashMap and use it for m_frameToIdentifier and m_loaderToIdentifier. -- HashMap m_frameToIdentifier; +- WeakHashMap m_frameToIdentifier; MemoryCompactRobinHoodHashMap> m_identifierToFrame; - HashMap m_loaderToIdentifier; + HashMap m_worldNameToBootstrapScript; String m_userAgentOverride; + String m_platformOverride; - String m_emulatedMedia; -- String m_bootstrapScript; + AtomString m_emulatedMedia; + String m_bootstrapScript; bool m_isFirstLayoutAfterOnLoad { false }; bool m_showPaintRects { false }; + bool m_interceptFileChooserDialog { false }; @@ -5164,10 +5284,20 @@ index 6d94ad131257d8d7cdb05898fd3f42e0c72766bf..6a85dba5cac19bf0adc93e0015ad223a } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp b/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp -index fe1cc2dbb9863cd4480476d2e21a5a229dc8a0e8..35dd7ca4cabe0d0ec76d44e260870a99becaa128 100644 +index bbed7e5e9aeab664743b7751ae6c4f1367cc6deb..88153c5a5e493e086245f0a48988ac7a2d6a43b8 100644 --- a/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp -@@ -168,7 +168,11 @@ void InspectorWorkerAgent::connectToWorkerInspectorProxy(WorkerInspectorProxy& p +@@ -27,7 +27,9 @@ + #include "InspectorWorkerAgent.h" + + #include "Document.h" ++#include "FrameDestructionObserverInlines.h" + #include "InstrumentingAgents.h" ++#include "InspectorPageAgent.h" + #include "Page.h" + #include + #include +@@ -168,7 +170,11 @@ void InspectorWorkerAgent::connectToWorkerInspectorProxy(WorkerInspectorProxy& p m_connectedProxies.set(proxy.identifier(), proxy); @@ -5181,17 +5311,17 @@ index fe1cc2dbb9863cd4480476d2e21a5a229dc8a0e8..35dd7ca4cabe0d0ec76d44e260870a99 void InspectorWorkerAgent::disconnectFromWorkerInspectorProxy(WorkerInspectorProxy& proxy) diff --git a/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp b/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp -index 6f4e9972a701f81facda14feffa905135f473916..c26d72c6e502ba19076fd5355f0af64a7bdb75f8 100644 +index 242aea89da38d22a2c2b314f337e6aa4f3becdb8..51f978caae1a6a76fb1833fbfef76837a79406ea 100644 --- a/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp -@@ -38,6 +38,7 @@ - #include "Frame.h" +@@ -37,6 +37,7 @@ + #include "Document.h" #include "InspectorPageAgent.h" #include "InstrumentingAgents.h" +#include "JSDOMWindowBase.h" - #include "JSDOMWindowCustom.h" #include "JSExecState.h" - #include "Page.h" + #include "JSLocalDOMWindowCustom.h" + #include "LocalFrame.h" @@ -74,7 +75,9 @@ Protocol::ErrorStringOr, std::op if (injectedScript.hasNoValue()) return makeUnexpected("Missing injected script for given callFrameId"_s); @@ -5204,17 +5334,17 @@ index 6f4e9972a701f81facda14feffa905135f473916..c26d72c6e502ba19076fd5355f0af64a } diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp -index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab9319c78905a 100644 +index 77b093ba149993094dc059d6cf8348095500bcb7..dc0a611a9da1ae4ffb54f1b57bba6ea290a57f48 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp -@@ -35,6 +35,7 @@ +@@ -34,6 +34,7 @@ + #include "DOMWrapperWorld.h" #include "Document.h" - #include "Frame.h" +#include "FrameLoader.h" #include "InspectorPageAgent.h" #include "InstrumentingAgents.h" - #include "JSDOMWindowCustom.h" + #include "JSExecState.h" @@ -42,6 +43,7 @@ #include "Page.h" #include "PageConsoleClient.h" @@ -5232,7 +5362,7 @@ index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab931 return InspectorRuntimeAgent::disable(); } -@@ -94,8 +98,66 @@ void PageRuntimeAgent::frameNavigated(Frame& frame) +@@ -94,8 +98,66 @@ void PageRuntimeAgent::frameNavigated(LocalFrame& frame) mainWorldGlobalObject(frame); } @@ -5259,7 +5389,7 @@ index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab931 + return result; +} + -+static void addBindingToFrame(Frame& frame, const String& name) ++static void addBindingToFrame(LocalFrame& frame, const String& name) +{ + JSC::JSGlobalObject* globalObject = frame.script().globalObject(mainThreadNormalWorld()); + auto& vm = globalObject->vm(); @@ -5271,8 +5401,8 @@ index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab931 + if (!m_bindingNames.add(name).isNewEntry) + return {}; + -+ m_inspectedPage.forEachFrame([&](Frame& frame) { -+ if (!frame.script().canExecuteScripts(NotAboutToExecuteScript)) ++ m_inspectedPage.forEachFrame([&](LocalFrame& frame) { ++ if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) + return; + + addBindingToFrame(frame, name); @@ -5289,7 +5419,7 @@ index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab931 + m_frontendDispatcher->bindingCalled(injectedScriptManager().injectedScriptIdFor(globalObject), name, arg); +} + - void PageRuntimeAgent::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world) + void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapperWorld& world) { + if (world.isNormal()) { + for (const auto& name : m_bindingNames) @@ -5299,11 +5429,11 @@ index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab931 auto* pageAgent = m_instrumentingAgents.enabledPageAgent(); if (!pageAgent) return; -@@ -103,6 +165,15 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld +@@ -103,6 +165,15 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper notifyContextCreated(pageAgent->frameId(&frame), frame.script().globalObject(world), world); } -+void PageRuntimeAgent::didReceiveMainResourceError(Frame& frame) ++void PageRuntimeAgent::didReceiveMainResourceError(LocalFrame& frame) +{ + if (frame.loader().stateMachine().isDisplayingInitialEmptyDocument()) { + // Ensure execution context is created for the empty docment to make @@ -5315,8 +5445,18 @@ index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab931 InjectedScript PageRuntimeAgent::injectedScriptForEval(Protocol::ErrorString& errorString, std::optional&& executionContextId) { if (!executionContextId) { -@@ -196,18 +267,24 @@ Protocol::ErrorStringOr, std::op - if (injectedScript.hasNoValue()) +@@ -139,9 +210,6 @@ void PageRuntimeAgent::reportExecutionContextCreation() + return; + + m_inspectedPage.forEachFrame([&](LocalFrame& frame) { +- if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) +- return; +- + auto frameId = pageAgent->frameId(&frame); + + // Always send the main world first. +@@ -200,18 +268,24 @@ Protocol::ErrorStringOr, std::op + if (injectedScript.hasNoValue()) return makeUnexpected(errorString); - UserGestureEmulationScope userGestureScope(m_inspectedPage, emulateUserGesture.value_or(false), dynamicDowncast(executionContext(injectedScript.globalObject()))); @@ -5347,7 +5487,7 @@ index 5e7a1214da060ba3a168cf21b22e6c398c0e07f7..d0cabe5df9b3ae42b3e99f02cc4ab931 } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h -index 6aba3a2c6e8bbb7a0bca4f07824cf4de8ce36f8e..38684b33e3b1cfc0c565297d1942f21c7d87967e 100644 +index fe3de3ee1ff4b61f66cc92bc0b9c2136c05769a3..3206e3ae64611c02abcfd6cc2e2a7b6f939eb560 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h @@ -37,6 +37,7 @@ @@ -5373,9 +5513,9 @@ index 6aba3a2c6e8bbb7a0bca4f07824cf4de8ce36f8e..38684b33e3b1cfc0c565297d1942f21c + Inspector::Protocol::ErrorStringOr addBinding(const String& name) final; // InspectorInstrumentation - void frameNavigated(Frame&); - void didClearWindowObjectInWorld(Frame&, DOMWrapperWorld&); -+ void didReceiveMainResourceError(Frame&); + void frameNavigated(LocalFrame&); + void didClearWindowObjectInWorld(LocalFrame&, DOMWrapperWorld&); ++ void didReceiveMainResourceError(LocalFrame&); + void bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg); private: @@ -5421,10 +5561,21 @@ index 21e33e46bdb1af8434527747e3c308cbe53f60f0..c17c4de17f439c04d27caa532771934c protected: static SameSiteInfo sameSiteInfo(const Document&, IsForDOMCookieAccess = IsForDOMCookieAccess::No); diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp -index e601aa9c6d3b04df2e9ffb341626013778e4c9d7..13eb5ec5286b6c5ea76b786e6af50ff88e1ea39a 100644 +index e2fbec049e671fe51adb60a83150e1d23e674088..0e4c1f2133fc506686dd039c0f12d5c8db607069 100644 --- a/Source/WebCore/loader/DocumentLoader.cpp +++ b/Source/WebCore/loader/DocumentLoader.cpp -@@ -1510,8 +1510,6 @@ void DocumentLoader::detachFromFrame() +@@ -743,8 +743,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc + if (!didReceiveRedirectResponse) + return completionHandler(WTFMove(newRequest)); + ++ InspectorInstrumentation::willCheckNavigationPolicy(*m_frame); + auto navigationPolicyCompletionHandler = [this, protectedThis = Ref { *this }, protectedFrame = Ref { *m_frame }, completionHandler = WTFMove(completionHandler)] (ResourceRequest&& request, WeakPtr&&, NavigationPolicyDecision navigationPolicyDecision) mutable { + m_waitingForNavigationPolicy = false; ++ InspectorInstrumentation::didCheckNavigationPolicy(protectedFrame.get(), navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad); + switch (navigationPolicyDecision) { + case NavigationPolicyDecision::IgnoreLoad: + case NavigationPolicyDecision::StopAllLoads: +@@ -1521,8 +1523,6 @@ void DocumentLoader::detachFromFrame() if (!m_frame) return; @@ -5434,14 +5585,14 @@ index e601aa9c6d3b04df2e9ffb341626013778e4c9d7..13eb5ec5286b6c5ea76b786e6af50ff8 } diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h -index 4287ac055edca73b3ca4c2d58b53a34a59f255e2..6f38d54ef3b333b5935ffd7484e10da91788fed4 100644 +index 9453e1ca4c6662090a08bf837db24e044a09226a..3f6a5700229b5ae4fb16303645da0e74259cac02 100644 --- a/Source/WebCore/loader/DocumentLoader.h +++ b/Source/WebCore/loader/DocumentLoader.h -@@ -181,9 +181,13 @@ public: +@@ -187,9 +187,13 @@ public: WEBCORE_EXPORT virtual void detachFromFrame(); -+ virtual void replacedByFragmentNavigation(Frame&) { } ++ virtual void replacedByFragmentNavigation(LocalFrame&) { } + WEBCORE_EXPORT FrameLoader* frameLoader() const; WEBCORE_EXPORT SubresourceLoader* mainResourceLoader() const; @@ -5452,10 +5603,10 @@ index 4287ac055edca73b3ca4c2d58b53a34a59f255e2..6f38d54ef3b333b5935ffd7484e10da9 DocumentWriter& writer() const { return m_writer; } diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp -index fd0a865aa9ca1e34eeae0cb522e0c03c4a72d774..9cecc4a144300f0d60aa7ed8d35372884721b8c9 100644 +index dabfc8188950af6cf2eb67fff5817ed8efd6de82..fa7e24e7d278307ea3c543ad0284bb5b3a638b11 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp -@@ -1174,6 +1174,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr stat +@@ -1214,6 +1214,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr stat } m_client->dispatchDidNavigateWithinPage(); @@ -5463,7 +5614,7 @@ index fd0a865aa9ca1e34eeae0cb522e0c03c4a72d774..9cecc4a144300f0d60aa7ed8d3537288 m_frame.document()->statePopped(stateObject ? stateObject.releaseNonNull() : SerializedScriptValue::nullValue()); m_client->dispatchDidPopStateWithinPage(); -@@ -1610,6 +1611,8 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t +@@ -1660,6 +1661,8 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t const String& httpMethod = loader->request().httpMethod(); if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) { @@ -5472,7 +5623,7 @@ index fd0a865aa9ca1e34eeae0cb522e0c03c4a72d774..9cecc4a144300f0d60aa7ed8d3537288 RefPtr oldDocumentLoader = m_documentLoader; NavigationAction action { *m_frame.document(), loader->request(), InitiatedByMainFrame::Unknown, policyChecker().loadType(), isFormSubmission }; action.setIsRequestFromClientOrUserInput(loader->isRequestFromClientOrUserInput()); -@@ -1639,7 +1642,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t +@@ -1692,7 +1695,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t } RELEASE_ASSERT(!isBackForwardLoadType(policyChecker().loadType()) || history().provisionalItem()); @@ -5482,17 +5633,19 @@ index fd0a865aa9ca1e34eeae0cb522e0c03c4a72d774..9cecc4a144300f0d60aa7ed8d3537288 continueLoadAfterNavigationPolicy(request, formState.get(), navigationPolicyDecision, allowNavigationToInvalidURL); completionHandler(); }, PolicyDecisionMode::Asynchronous); -@@ -2806,12 +2811,17 @@ String FrameLoader::userAgent(const URL& url) const +@@ -2945,14 +2950,19 @@ String FrameLoader::userAgent(const URL& url) const String FrameLoader::navigatorPlatform() const { + String platform; + - if (auto* documentLoader = m_frame.mainFrame().loader().activeDocumentLoader()) { - auto& customNavigatorPlatform = documentLoader->customNavigatorPlatform(); - if (!customNavigatorPlatform.isEmpty()) -- return customNavigatorPlatform; -+ platform = customNavigatorPlatform; + if (auto* localFrame = dynamicDowncast(m_frame.mainFrame())) { + if (auto* documentLoader = localFrame->loader().activeDocumentLoader()) { + auto& customNavigatorPlatform = documentLoader->customNavigatorPlatform(); + if (!customNavigatorPlatform.isEmpty()) +- return customNavigatorPlatform; ++ platform = customNavigatorPlatform; + } } - return String(); + @@ -5502,7 +5655,7 @@ index fd0a865aa9ca1e34eeae0cb522e0c03c4a72d774..9cecc4a144300f0d60aa7ed8d3537288 } void FrameLoader::dispatchOnloadEvents() -@@ -3222,6 +3232,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error) +@@ -3374,6 +3384,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error) checkCompleted(); if (m_frame.page()) checkLoadComplete(); @@ -5510,25 +5663,25 @@ index fd0a865aa9ca1e34eeae0cb522e0c03c4a72d774..9cecc4a144300f0d60aa7ed8d3537288 + InspectorInstrumentation::didReceiveMainResourceError(m_frame, error); } - void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue) -@@ -4030,9 +4042,6 @@ String FrameLoader::referrer() const + void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, const SecurityOrigin* requesterOrigin, bool shouldContinue) +@@ -4204,9 +4216,6 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() { -- if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) +- if (!m_frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) - return; - Vector> worlds; ScriptController::getAllWorlds(worlds); for (auto& world : worlds) -@@ -4041,13 +4050,13 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() +@@ -4215,13 +4224,13 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) { -- if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript) || !m_frame.windowProxy().existingJSWindowProxy(world)) +- if (!m_frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript) || !m_frame.windowProxy().existingJSWindowProxy(world)) - return; + if (m_frame.windowProxy().existingJSWindowProxy(world)) { -+ if (m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) ++ if (m_frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) + m_client->dispatchDidClearWindowObjectInWorld(world); - m_client->dispatchDidClearWindowObjectInWorld(world); @@ -5542,7 +5695,7 @@ index fd0a865aa9ca1e34eeae0cb522e0c03c4a72d774..9cecc4a144300f0d60aa7ed8d3537288 InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world); } diff --git a/Source/WebCore/loader/LoaderStrategy.h b/Source/WebCore/loader/LoaderStrategy.h -index 29d2e3f46140aaa51160e6a28562f370e371eb21..676ddc9369050c19454fbf5faffac2b27e0fad41 100644 +index 91340dc21042f545592b442bc42dbceed06219b2..f3591fe333761b10a25ddaf4a4f8d72170dfe336 100644 --- a/Source/WebCore/loader/LoaderStrategy.h +++ b/Source/WebCore/loader/LoaderStrategy.h @@ -86,6 +86,7 @@ public: @@ -5553,23 +5706,36 @@ index 29d2e3f46140aaa51160e6a28562f370e371eb21..676ddc9369050c19454fbf5faffac2b2 virtual bool shouldPerformSecurityChecks() const { return false; } virtual bool havePerformedSecurityChecks(const ResourceResponse&) const { return false; } +diff --git a/Source/WebCore/loader/NavigationScheduler.cpp b/Source/WebCore/loader/NavigationScheduler.cpp +index 4e222e82af9d35ccff71c4ac758b430ada2d512d..a219dabfd7ba5a7b5989fac9029058d41e7b4bbd 100644 +--- a/Source/WebCore/loader/NavigationScheduler.cpp ++++ b/Source/WebCore/loader/NavigationScheduler.cpp +@@ -682,7 +682,7 @@ void NavigationScheduler::startTimer() + + Seconds delay = 1_s * m_redirect->delay(); + m_timer.startOneShot(delay); +- InspectorInstrumentation::frameScheduledNavigation(m_frame, delay); ++ InspectorInstrumentation::frameScheduledNavigation(m_frame, delay, m_redirect->targetIsCurrentFrame()); + m_redirect->didStartTimer(m_frame, m_timer); // m_redirect may be null on return (e.g. the client canceled the load) + } + diff --git a/Source/WebCore/loader/PolicyChecker.cpp b/Source/WebCore/loader/PolicyChecker.cpp -index 8079a61388ccbdc52d585ba2d1568b8d5312e718..caceb12b5460454293c820bd1ebcd7fa9017610d 100644 +index 40b6c39d9997acfadeb2668e443358b1d3f6ad07..c935a647248619a5c38a9538d8806292ae647b2f 100644 --- a/Source/WebCore/loader/PolicyChecker.cpp +++ b/Source/WebCore/loader/PolicyChecker.cpp -@@ -47,6 +47,7 @@ +@@ -43,6 +43,7 @@ #include "HTMLFormElement.h" #include "HTMLFrameOwnerElement.h" #include "HTMLPlugInElement.h" +#include "InspectorInstrumentation.h" - #include "Logging.h" - #include "ThreadableBlobRegistry.h" - #include + #include "LocalDOMWindow.h" + #include "LocalFrame.h" + #include "LocalFrameLoaderClient.h" diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp -index a2c6d72b5ba0f04a49ca6dc710ef6fa5e0125c33..759b0d34b7db839027063a1b6ce8fb0f7ee2acd4 100644 +index 258b45354b3f4c1854373c3cd2679d379fa60302..79c7abd308276ffec67686b145edc422c382e5db 100644 --- a/Source/WebCore/loader/ProgressTracker.cpp +++ b/Source/WebCore/loader/ProgressTracker.cpp -@@ -160,6 +160,8 @@ void ProgressTracker::progressCompleted(Frame& frame) +@@ -160,6 +160,8 @@ void ProgressTracker::progressCompleted(LocalFrame& frame) if (!m_numProgressTrackedFrames || m_originatingProgressFrame == &frame) finalProgressComplete(); @@ -5587,53 +5753,54 @@ index a2c6d72b5ba0f04a49ca6dc710ef6fa5e0125c33..759b0d34b7db839027063a1b6ce8fb0f } void ProgressTracker::incrementProgress(ResourceLoaderIdentifier identifier, const ResourceResponse& response) +diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp +index 0a11887f8d97fd5c1791d224f88cc28a032031e0..2e757e4d68b567e4c90fbc8aee969d7bbd8c4af2 100644 +--- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp ++++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp +@@ -1011,8 +1011,11 @@ ResourceErrorOr> CachedResourceLoader::requ + + request.updateReferrerPolicy(document() ? document()->referrerPolicy() : ReferrerPolicy::Default); + +- if (InspectorInstrumentation::willIntercept(&frame, request.resourceRequest())) +- request.setCachingPolicy(CachingPolicy::DisallowCaching); ++ if (InspectorInstrumentation::willIntercept(&frame, request.resourceRequest())) { ++ // Playwright: we don't disable such caching in other browsers and it breaks css resource downloads, ++ // see https://github.com/microsoft/playwright/issues/19158 ++ // request.setCachingPolicy(CachingPolicy::DisallowCaching); ++ } + + auto& page = *frame.page(); + +@@ -1657,8 +1660,9 @@ Vector> CachedResourceLoader::allCachedSVGImages() const + + ResourceErrorOr> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request) + { +- if (InspectorInstrumentation::willIntercept(frame(), request.resourceRequest())) +- return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s }); ++ // Playwright: requests are intercepted (see https://github.com/microsoft/playwright/issues/16745) ++ // if (InspectorInstrumentation::willIntercept(frame(), request.resourceRequest())) ++ // return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s }); + + if (request.charset().isEmpty() && (type == CachedResource::Type::Script || type == CachedResource::Type::CSSStyleSheet)) + request.setCharset(m_document->charset()); diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h -index 45da6b795b2f1b28e79bc549effa2fed862cec4c..dfc6c68665eb1c88fcdc116f08764eaa37f8782a 100644 +index e8ace8c734502a5d491379f2d7a993322825fa46..959932d69d746f2f12637feaa4e04a67fa8880d3 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h -@@ -319,7 +319,7 @@ public: +@@ -325,7 +325,7 @@ public: #endif #if ENABLE(ORIENTATION_EVENTS) -- virtual int deviceOrientation() const = 0; -+ virtual int deviceOrientation() const { return 0; } +- virtual IntDegrees deviceOrientation() const = 0; ++ virtual IntDegrees deviceOrientation() const { return 0; } #endif #if ENABLE(INPUT_TYPE_COLOR) -diff --git a/Source/WebCore/page/DeprecatedGlobalSettings.cpp b/Source/WebCore/page/DeprecatedGlobalSettings.cpp -index f23dab33290785df9bfe0a8e305dbc780f33f381..f5cb5d7d7fc6934b0aa8421a3ef120c941c2c09b 100644 ---- a/Source/WebCore/page/DeprecatedGlobalSettings.cpp -+++ b/Source/WebCore/page/DeprecatedGlobalSettings.cpp -@@ -79,7 +79,11 @@ DeprecatedGlobalSettings& DeprecatedGlobalSettings::shared() - #if ENABLE(TOUCH_EVENTS) - bool DeprecatedGlobalSettings::touchEventsEnabled() - { -- return shared().m_touchEventsEnabled.value_or(screenHasTouchDevice()); -+ return shared().m_touchEventsEnabled.value_or(platformScreenHasTouchDevice()); -+} -+bool DeprecatedGlobalSettings::isTouchPrimaryInputDevice() -+{ -+ return shared().m_touchEventsEnabled.value_or(platformScreenIsTouchPrimaryInputDevice()); - } - #endif - -diff --git a/Source/WebCore/page/DeprecatedGlobalSettings.h b/Source/WebCore/page/DeprecatedGlobalSettings.h -index 58fbc5e15aff1ab5c04952f056d48575c9c68498..2a638ab7da4557ec9be2c5e655f0666d106f9f71 100644 ---- a/Source/WebCore/page/DeprecatedGlobalSettings.h -+++ b/Source/WebCore/page/DeprecatedGlobalSettings.h -@@ -216,6 +216,7 @@ public: - static void setMouseEventsSimulationEnabled(bool isEnabled) { shared().m_mouseEventsSimulationEnabled = isEnabled; } - static bool touchEventsEnabled(); - static void setTouchEventsEnabled(bool isEnabled) { shared().m_touchEventsEnabled = isEnabled; } -+ static bool isTouchPrimaryInputDevice(); - #endif - - static bool pageAtRuleSupportEnabled() { return shared().m_pageAtRuleSupportEnabled; } diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp -index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a2b60e3a9 100644 +index 021ad598ec0873d8f0c2a2c6c6ee7ebf345ad805..3109f224e68a3df4ef587cd80b0f5701701b1455 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp -@@ -142,6 +142,7 @@ +@@ -144,6 +144,7 @@ #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) #include "PlatformTouchEvent.h" @@ -5641,7 +5808,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a #endif #if ENABLE(MAC_GESTURE_EVENTS) -@@ -807,9 +808,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve +@@ -819,9 +820,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve m_mousePressNode = event.targetNode(); m_frame.document()->setFocusNavigationStartingNode(event.targetNode()); @@ -5651,7 +5818,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a m_mousePressed = true; m_selectionInitiationState = HaveNotStartedSelection; -@@ -849,8 +848,6 @@ VisiblePosition EventHandler::selectionExtentRespectingEditingBoundary(const Vis +@@ -861,8 +860,6 @@ VisiblePosition EventHandler::selectionExtentRespectingEditingBoundary(const Vis return adjustedTarget->renderer()->positionForPoint(LayoutPoint(selectionEndPoint), nullptr); } @@ -5660,9 +5827,9 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a #if !PLATFORM(IOS_FAMILY) bool EventHandler::supportsSelectionUpdatesOnMouseDrag() const -@@ -872,8 +869,10 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e +@@ -884,8 +881,10 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e - Ref protectedFrame(m_frame); + Ref protectedFrame(m_frame); +#if ENABLE(DRAG_SUPPORT) if (handleDrag(event, checkDragHysteresis)) @@ -5671,7 +5838,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a RefPtr targetNode = event.targetNode(); if (event.event().button() != LeftButton || !targetNode) -@@ -894,7 +893,9 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e +@@ -906,7 +905,9 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e ASSERT(mouseDownMayStartSelect() || m_mouseDownMayStartAutoscroll); #endif @@ -5681,7 +5848,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) { m_autoscrollController->startAutoscrollForSelection(renderer); -@@ -911,6 +912,8 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e +@@ -923,6 +924,8 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e return true; } @@ -5690,7 +5857,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const { // This is a pre-flight check of whether the event might lead to a drag being started. Be careful -@@ -942,6 +945,8 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const +@@ -954,6 +957,8 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const return targetElement && page->dragController().draggableElement(&m_frame, targetElement.get(), result.roundedPointInInnerNodeFrame(), state); } @@ -5699,7 +5866,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a void EventHandler::updateSelectionForMouseDrag() { if (!supportsSelectionUpdatesOnMouseDrag()) -@@ -1036,7 +1041,6 @@ void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResul +@@ -1062,7 +1067,6 @@ void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResul if (oldSelection != newSelection && ImageOverlay::isOverlayText(newSelection.start().containerNode()) && ImageOverlay::isOverlayText(newSelection.end().containerNode())) invalidateClick(); } @@ -5707,7 +5874,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a void EventHandler::lostMouseCapture() { -@@ -1084,9 +1088,7 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e +@@ -1110,9 +1114,7 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e // on the selection, the selection goes away. However, if we are // editing, place the caret. if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection @@ -5717,7 +5884,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a && m_frame.selection().isRange() && event.event().button() != RightButton) { VisibleSelection newSelection; -@@ -2054,10 +2056,8 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseE +@@ -2111,10 +2113,8 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseE swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), 0, platformMouseEvent, FireMouseOverOut::Yes); @@ -5728,7 +5895,7 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a return swallowEvent; } -@@ -4142,7 +4142,14 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr +@@ -4207,7 +4207,14 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr if (!m_frame.document()) return false; @@ -5744,31 +5911,33 @@ index 1cfb3665021ce207ea3b52ae970373416f466666..ca6977e66fb7a65a50b8be69fe9b154a auto hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No; if (dragState().shouldDispatchEvents) { -@@ -4619,7 +4626,8 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) - allTouchReleased = false; - } - -- for (auto& point : points) { -+ for (unsigned index = 0; index < points.size(); index++) { -+ auto& point = points[index]; - PlatformTouchPoint::State pointState = point.state(); - LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos()); +@@ -4892,11 +4899,6 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) + document.page()->pointerCaptureController().dispatchEventForTouchAtIndex( + *touchTarget, cancelEvent, index, !index, *document.windowProxy(), { 0, 0 }); + } +- +- // FIXME: Pass the touch delta for pointermove events by remembering the position per pointerID similar to +- // Apple's m_touchLastGlobalPositionAndDeltaMap +- document.page()->pointerCaptureController().dispatchEventForTouchAtIndex( +- *pointerTarget, event, index, !index, *document.windowProxy(), { 0, 0 }); + #endif -@@ -4746,6 +4754,9 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) + if (&m_frame != targetFrame) { +@@ -4938,6 +4940,9 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) changedTouches[pointState].m_touches->append(WTFMove(touch)); changedTouches[pointState].m_targets.add(touchTarget); } + document.page()->pointerCaptureController().dispatchEventForTouchAtIndex( -+ *touchTarget, event, index, index == 0, *document.windowProxy()); ++ *touchTarget, event, index, index == 0, *document.windowProxy(), IntPoint::zero()); + } m_touchPressed = touches->length() > 0; if (allTouchReleased) diff --git a/Source/WebCore/page/EventHandler.h b/Source/WebCore/page/EventHandler.h -index 556cab9e978d31d23563fd5d5325bdb2470c2213..a232efeaf334b58301154dd93eb406d89f8995d2 100644 +index 7ab1b7513cf878700ee960bbbbf76dda37fcb16e..d186f310bf01de85e19f540b01bfe133a2456c6f 100644 --- a/Source/WebCore/page/EventHandler.h +++ b/Source/WebCore/page/EventHandler.h -@@ -136,9 +136,7 @@ public: +@@ -138,9 +138,7 @@ public: WEBCORE_EXPORT VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection&, const LayoutPoint&, Node*); @@ -5778,9 +5947,9 @@ index 556cab9e978d31d23563fd5d5325bdb2470c2213..a232efeaf334b58301154dd93eb406d8 #if ENABLE(PAN_SCROLLING) void didPanScrollStart(); -@@ -394,10 +392,8 @@ private: - bool startKeyboardScrollAnimationOnEnclosingScrollableContainer(ScrollDirection, ScrollGranularity, Node*); - bool focusedScrollableAreaUsesScrollSnap(); +@@ -405,10 +403,8 @@ private: + bool startKeyboardScrollAnimationOnRenderBoxAndItsAncestors(ScrollDirection, ScrollGranularity, RenderBox*, bool isKeyRepeat); + bool startKeyboardScrollAnimationOnEnclosingScrollableContainer(ScrollDirection, ScrollGranularity, Node*, bool isKeyRepeat); -#if ENABLE(DRAG_SUPPORT) bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&, CheckDragHysteresis = ShouldCheckDragHysteresis); @@ -5789,7 +5958,7 @@ index 556cab9e978d31d23563fd5d5325bdb2470c2213..a232efeaf334b58301154dd93eb406d8 WEBCORE_EXPORT bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&); -@@ -497,10 +493,8 @@ private: +@@ -510,10 +506,8 @@ private: void defaultTabEventHandler(KeyboardEvent&); void defaultArrowEventHandler(FocusDirection, KeyboardEvent&); @@ -5800,7 +5969,7 @@ index 556cab9e978d31d23563fd5d5325bdb2470c2213..a232efeaf334b58301154dd93eb406d8 // The following are called at the beginning of handleMouseUp and handleDrag. // If they return true it indicates that they have consumed the event. -@@ -508,9 +502,10 @@ private: +@@ -521,9 +515,10 @@ private: #if ENABLE(DRAG_SUPPORT) bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&); @@ -5812,60 +5981,148 @@ index 556cab9e978d31d23563fd5d5325bdb2470c2213..a232efeaf334b58301154dd93eb406d8 enum class SetOrClearLastScrollbar { Clear, Set }; void updateLastScrollbarUnderMouse(Scrollbar*, SetOrClearLastScrollbar); -@@ -602,8 +597,8 @@ private: +@@ -616,8 +611,8 @@ private: Timer m_autoHideCursorTimer; #endif -#if ENABLE(DRAG_SUPPORT) LayoutPoint m_dragStartPosition; +#if ENABLE(DRAG_SUPPORT) + std::optional m_dragStartSelection; RefPtr m_dragTarget; bool m_mouseDownMayStartDrag { false }; - bool m_dragMayStartSelectionInstead { false }; -diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp -index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a99391e8a745 100644 ---- a/Source/WebCore/page/Frame.cpp -+++ b/Source/WebCore/page/Frame.cpp -@@ -39,6 +39,7 @@ +diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp +index d62d41b79f148cee977447f740bd6a768b159b0c..2d16d7243788ef876487d741caddc4a71cb5425f 100644 +--- a/Source/WebCore/page/FrameSnapshotting.cpp ++++ b/Source/WebCore/page/FrameSnapshotting.cpp +@@ -109,7 +109,7 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& + // Other paint behaviors are set by paintContentsForSnapshot. + frame.view()->setPaintBehavior(paintBehavior); + +- float scaleFactor = frame.page()->deviceScaleFactor(); ++ float scaleFactor = options.flags.contains(SnapshotFlags::OmitDeviceScaleFactor) ? 1 : frame.page()->deviceScaleFactor(); + + if (frame.page()->delegatesScaling()) + scaleFactor *= frame.page()->pageScaleFactor(); +@@ -124,7 +124,13 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& + if (!buffer) + return nullptr; + ++#if !PLATFORM(MAC) ++ buffer->context().scale(scaleFactor); ++#endif ++ + buffer->context().translate(-imageRect.location()); ++ if (coordinateSpace != LocalFrameView::ViewCoordinates) ++ buffer->context().scale(1 / frame.page()->pageScaleFactor()); + + if (!clipRects.isEmpty()) { + Path clipPath; +@@ -133,7 +139,10 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& + buffer->context().clipPath(clipPath); + } + +- frame.view()->paintContentsForSnapshot(buffer->context(), imageRect, shouldIncludeSelection, coordinateSpace); ++ FloatRect fr = imageRect; ++ if (coordinateSpace != LocalFrameView::ViewCoordinates) ++ fr.scale(frame.page()->pageScaleFactor()); ++ frame.view()->paintContentsForSnapshot(buffer->context(), enclosingIntRect(fr), shouldIncludeSelection, coordinateSpace); + return buffer; + } + +diff --git a/Source/WebCore/page/FrameSnapshotting.h b/Source/WebCore/page/FrameSnapshotting.h +index 5f85bb24166b1c1805323fcbb34144be3191643b..09d2782e3961d70b9483a77e0c12923bc58860d7 100644 +--- a/Source/WebCore/page/FrameSnapshotting.h ++++ b/Source/WebCore/page/FrameSnapshotting.h +@@ -44,7 +44,7 @@ class ImageBuffer; + class LocalFrame; + class Node; + +-enum class SnapshotFlags : uint8_t { ++enum class SnapshotFlags : uint16_t { + ExcludeSelectionHighlighting = 1 << 0, + PaintSelectionOnly = 1 << 1, + InViewCoordinates = 1 << 2, +@@ -53,6 +53,7 @@ enum class SnapshotFlags : uint8_t { + PaintEverythingExcludingSelection = 1 << 5, + PaintWithIntegralScaleFactor = 1 << 6, + Shareable = 1 << 7, ++ OmitDeviceScaleFactor = 1 << 8, + }; + + struct SnapshotOptions { +diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp +index 81bd9a039ff42ed2ce7c651bae1890b7498539fb..9e3675205598ad773ba4f96aa75098af267c4d3e 100644 +--- a/Source/WebCore/page/History.cpp ++++ b/Source/WebCore/page/History.cpp +@@ -31,6 +31,7 @@ + #include "FrameLoader.h" + #include "HistoryController.h" + #include "HistoryItem.h" ++#include "InspectorInstrumentation.h" + #include "LocalFrame.h" + #include "LocalFrameLoaderClient.h" + #include "Logging.h" +@@ -274,6 +275,7 @@ ExceptionOr History::stateObjectAdded(RefPtr&& data + + if (!urlString.isEmpty()) + frame->document()->updateURLForPushOrReplaceState(fullURL); ++ InspectorInstrumentation::didNavigateWithinPage(*frame); + + if (stateObjectType == StateObjectType::Push) { + frame->loader().history().pushState(WTFMove(data), title, fullURL.string()); +diff --git a/Source/WebCore/page/LocalFrame.cpp b/Source/WebCore/page/LocalFrame.cpp +index 9dcbd3964008c12be7a472008fd4b2d3dc5f9fce..478a9562600b001e45b399b7a2a2fbae7d170f8b 100644 +--- a/Source/WebCore/page/LocalFrame.cpp ++++ b/Source/WebCore/page/LocalFrame.cpp +@@ -40,6 +40,7 @@ #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" +#include "ComposedTreeIterator.h" - #include "DOMWindow.h" + #include "DocumentLoader.h" #include "DocumentTimelinesController.h" #include "DocumentType.h" -@@ -73,6 +74,7 @@ - #include "NavigationScheduler.h" +@@ -57,6 +58,7 @@ + #include "FrameSelection.h" + #include "GraphicsContext.h" + #include "GraphicsLayer.h" ++#include "HTMLAreaElement.h" + #include "HTMLFormControlElement.h" + #include "HTMLFormElement.h" + #include "HTMLFrameElementBase.h" +@@ -74,6 +76,7 @@ + #include "Logging.h" #include "Navigator.h" #include "NodeList.h" +#include "NodeRenderStyle.h" #include "NodeTraversal.h" #include "Page.h" #include "ProcessWarming.h" -@@ -189,6 +191,7 @@ Frame::Frame(Page& page, HTMLFrameOwnerElement* ownerElement, UniqueRef&& frameLoad - void Frame::init() + void LocalFrame::init() { + InspectorInstrumentation::frameAttached(this); m_loader->init(); } -@@ -373,7 +376,7 @@ void Frame::orientationChanged() - int Frame::orientation() const +@@ -374,7 +378,7 @@ void LocalFrame::orientationChanged() + IntDegrees LocalFrame::orientation() const { - if (m_page) -- return m_page->chrome().client().deviceOrientation(); -+ return m_page->orientation(); + if (auto* page = this->page()) +- return page->chrome().client().deviceOrientation(); ++ return page->orientation(); return 0; } #endif // ENABLE(ORIENTATION_EVENTS) -@@ -1170,6 +1173,362 @@ DataDetectionResultsStorage& Frame::dataDetectionResults() +@@ -1176,6 +1180,362 @@ DataDetectionResultsStorage& LocalFrame::dataDetectionResults() #endif +#if !PLATFORM(IOS_FAMILY) + -+void Frame::betterApproximateNode(const IntPoint& testPoint, const NodeQualifier& nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect) ++void LocalFrame::betterApproximateNode(const IntPoint& testPoint, const NodeQualifier& nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect) +{ + IntRect candidateRect; + constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly }; @@ -5894,7 +6151,7 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + bestRect = candidateRect; +} + -+bool Frame::hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult& hitTestResult, IntPoint& center) ++bool LocalFrame::hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult& hitTestResult, IntPoint& center) +{ + if (!m_doc || !m_doc->renderView()) + return false; @@ -5909,7 +6166,7 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + return true; +} + -+Node* Frame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, ShouldApproximate shouldApproximate, ShouldFindRootEditableElement shouldFindRootEditableElement) ++Node* LocalFrame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, ShouldApproximate shouldApproximate, ShouldFindRootEditableElement shouldFindRootEditableElement) +{ + adjustedViewportLocation = viewportLocation; + @@ -5951,7 +6208,7 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + }; + + Node* originalApproximateNode = approximateNode; -+ for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) { ++ for (unsigned n = 0; n < std::size(testOffsets); n += 2) { + IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); + IntPoint testPoint = testCenter + testOffset; + @@ -5994,7 +6251,7 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + IntRect testRect(testCenter, IntSize()); + testRect.inflate(searchRadius); + int currentTestRadius = 0; -+ for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) { ++ for (unsigned n = 0; n < std::size(testOffsets); n += 2) { + IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); + IntPoint testPoint = testCenter + testOffset; + int testRadius = std::max(abs(testOffset.width()), abs(testOffset.height())); @@ -6021,7 +6278,7 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + return approximateNode; +} + -+Node* Frame::deepestNodeAtLocation(const FloatPoint& viewportLocation) ++Node* LocalFrame::deepestNodeAtLocation(const FloatPoint& viewportLocation) +{ + IntPoint center; + HitTestResult hitTestResult; @@ -6057,7 +6314,7 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + return node.willRespondToMouseClickEvents() || node.willRespondToMouseMoveEvents() || nodeIsMouseFocusable(node); +} + -+Node* Frame::approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) ++Node* LocalFrame::approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + // This function is only used for UIWebView. + auto&& ancestorRespondingToClickEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { @@ -6147,12 +6404,12 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + }; +} + -+Node* Frame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* securityOrigin) ++Node* LocalFrame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* securityOrigin) +{ + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(securityOrigin), ShouldApproximate::Yes); +} + -+Node* Frame::nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) ++Node* LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + auto&& ancestorRespondingToDoubleClickEvent = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) @@ -6179,12 +6436,12 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToDoubleClickEvent), ShouldApproximate::Yes); +} + -+Node* Frame::nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) ++Node* LocalFrame::nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(), ShouldApproximate::Yes, ShouldFindRootEditableElement::No); +} + -+Node* Frame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation) ++Node* LocalFrame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation) +{ + auto&& ancestorRespondingToScrollWheelEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) @@ -6222,11 +6479,30 @@ index 2d1133a87e56315d531f8d6e72c6c6a4c86c126b..571265e1b7ec906af8217cfaa008a993 } // namespace WebCore #undef FRAME_RELEASE_LOG_ERROR -diff --git a/Source/WebCore/page/Frame.h b/Source/WebCore/page/Frame.h -index 856ff374f367332ca5ab10a46bff825b8bcb159b..24bbbcd6b51a9ae27c72a0810c97678afb6b018c 100644 ---- a/Source/WebCore/page/Frame.h -+++ b/Source/WebCore/page/Frame.h -@@ -113,8 +113,8 @@ enum { +diff --git a/Source/WebCore/page/LocalFrame.h b/Source/WebCore/page/LocalFrame.h +index dcb779a5605d9cff6e0fb195a5e0c9e3b7bd4269..6ecb28dc92137845d112ac59d58df36c386f5712 100644 +--- a/Source/WebCore/page/LocalFrame.h ++++ b/Source/WebCore/page/LocalFrame.h +@@ -28,8 +28,10 @@ + #pragma once + + #include "AdjustViewSizeOrNot.h" ++#include "DOMPasteAccess.h" + #include "Document.h" + #include "Frame.h" ++#include "IntDegrees.h" + #include "ScrollTypes.h" + #include "UserScriptTypes.h" + #include +@@ -69,7 +71,6 @@ namespace WebCore { + class Color; + class LocalDOMWindow; + class DataDetectionResultsStorage; +-class Document; + class Editor; + class Element; + class EventHandler; +@@ -108,8 +109,8 @@ enum { }; enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll }; @@ -6234,9 +6510,9 @@ index 856ff374f367332ca5ab10a46bff825b8bcb159b..24bbbcd6b51a9ae27c72a0810c97678a #endif +using NodeQualifier = Function; - // FIXME: Rename Frame to LocalFrame and AbstractFrame to Frame. - class Frame final : public AbstractFrame { -@@ -220,10 +220,6 @@ public: + class LocalFrame final : public Frame { + public: +@@ -201,10 +202,6 @@ public: WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults(); #endif @@ -6247,7 +6523,7 @@ index 856ff374f367332ca5ab10a46bff825b8bcb159b..24bbbcd6b51a9ae27c72a0810c97678a WEBCORE_EXPORT Node* deepestNodeAtLocation(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* = nullptr); WEBCORE_EXPORT Node* nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); -@@ -231,6 +227,10 @@ public: +@@ -212,6 +209,10 @@ public: WEBCORE_EXPORT Node* nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); @@ -6258,7 +6534,7 @@ index 856ff374f367332ca5ab10a46bff825b8bcb159b..24bbbcd6b51a9ae27c72a0810c97678a WEBCORE_EXPORT NSArray *wordsInCurrentParagraph() const; WEBCORE_EXPORT CGRect renderRectForPoint(CGPoint, bool* isReplaced, float* fontSize) const; -@@ -298,6 +298,7 @@ public: +@@ -279,6 +280,7 @@ public: WEBCORE_EXPORT FloatSize screenSize() const; void setOverrideScreenSize(FloatSize&&); @@ -6266,15 +6542,15 @@ index 856ff374f367332ca5ab10a46bff825b8bcb159b..24bbbcd6b51a9ae27c72a0810c97678a void selfOnlyRef(); void selfOnlyDeref(); -@@ -336,7 +337,6 @@ private: +@@ -313,7 +315,6 @@ private: #if ENABLE(DATA_DETECTION) std::unique_ptr m_dataDetectionResults; #endif -#if PLATFORM(IOS_FAMILY) void betterApproximateNode(const IntPoint& testPoint, const NodeQualifier&, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect); bool hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult&, IntPoint& center); - -@@ -344,6 +344,7 @@ private: + +@@ -321,6 +322,7 @@ private: enum class ShouldFindRootEditableElement : bool { No, Yes }; Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier&, ShouldApproximate, ShouldFindRootEditableElement = ShouldFindRootEditableElement::Yes); @@ -6282,97 +6558,21 @@ index 856ff374f367332ca5ab10a46bff825b8bcb159b..24bbbcd6b51a9ae27c72a0810c97678a void setTimersPausedInternal(bool); ViewportArguments m_viewportArguments; -diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp -index 4e524dcb9f03fcc0e50919b16448be6b0421b5da..b566f02589bac9c3259a63db94a3108bbcbff554 100644 ---- a/Source/WebCore/page/FrameSnapshotting.cpp -+++ b/Source/WebCore/page/FrameSnapshotting.cpp -@@ -107,7 +107,7 @@ RefPtr snapshotFrameRectWithClip(Frame& frame, const IntRect& image - // Other paint behaviors are set by paintContentsForSnapshot. - frame.view()->setPaintBehavior(paintBehavior); - -- float scaleFactor = frame.page()->deviceScaleFactor(); -+ float scaleFactor = options.flags.contains(SnapshotFlags::OmitDeviceScaleFactor) ? 1 : frame.page()->deviceScaleFactor(); - - if (frame.page()->delegatesScaling()) - scaleFactor *= frame.page()->pageScaleFactor(); -@@ -122,7 +122,13 @@ RefPtr snapshotFrameRectWithClip(Frame& frame, const IntRect& image - if (!buffer) - return nullptr; - -+#if !PLATFORM(MAC) -+ buffer->context().scale(scaleFactor); -+#endif -+ - buffer->context().translate(-imageRect.location()); -+ if (coordinateSpace != FrameView::ViewCoordinates) -+ buffer->context().scale(1 / frame.page()->pageScaleFactor()); - - if (!clipRects.isEmpty()) { - Path clipPath; -@@ -131,7 +137,10 @@ RefPtr snapshotFrameRectWithClip(Frame& frame, const IntRect& image - buffer->context().clipPath(clipPath); - } - -- frame.view()->paintContentsForSnapshot(buffer->context(), imageRect, shouldIncludeSelection, coordinateSpace); -+ FloatRect fr = imageRect; -+ if (coordinateSpace != FrameView::ViewCoordinates) -+ fr.scale(frame.page()->pageScaleFactor()); -+ frame.view()->paintContentsForSnapshot(buffer->context(), enclosingIntRect(fr), shouldIncludeSelection, coordinateSpace); - return buffer; - } - -diff --git a/Source/WebCore/page/FrameSnapshotting.h b/Source/WebCore/page/FrameSnapshotting.h -index bb1bc2ffd02177718a77c5534e66bed55232e660..1eaff1702c30b337d4a8f5a804a9a4b134e1b111 100644 ---- a/Source/WebCore/page/FrameSnapshotting.h -+++ b/Source/WebCore/page/FrameSnapshotting.h -@@ -44,7 +44,7 @@ class IntRect; - class ImageBuffer; - class Node; - --enum class SnapshotFlags : uint8_t { -+enum class SnapshotFlags : uint16_t { - ExcludeSelectionHighlighting = 1 << 0, - PaintSelectionOnly = 1 << 1, - InViewCoordinates = 1 << 2, -@@ -53,6 +53,7 @@ enum class SnapshotFlags : uint8_t { - PaintEverythingExcludingSelection = 1 << 5, - PaintWithIntegralScaleFactor = 1 << 6, - Shareable = 1 << 7, -+ OmitDeviceScaleFactor = 1 << 8, - }; - - struct SnapshotOptions { -diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp -index a782c3be51ca113a52482c5a10583c8fa64724ef..1d82dff81be5c5492efb3bfe77d2f259c2f2b5db 100644 ---- a/Source/WebCore/page/History.cpp -+++ b/Source/WebCore/page/History.cpp -@@ -33,6 +33,7 @@ - #include "FrameLoaderClient.h" - #include "HistoryController.h" - #include "HistoryItem.h" -+#include "InspectorInstrumentation.h" - #include "Logging.h" - #include "NavigationScheduler.h" - #include "Page.h" -@@ -260,6 +261,7 @@ ExceptionOr History::stateObjectAdded(RefPtr&& data - - if (!urlString.isEmpty()) - frame->document()->updateURLForPushOrReplaceState(fullURL); -+ InspectorInstrumentation::didNavigateWithinPage(*frame); - - if (stateObjectType == StateObjectType::Push) { - frame->loader().history().pushState(WTFMove(data), title, fullURL.string()); diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp -index d633760e91b4074533a1a33109cb470ae654f66a..d4a00fbfd76c0301ceb3b02ac3378d90e7e2d1ae 100644 +index 89c9ad91a677a3da71afaa35f7f9822596c871f5..773cb8c0f9250e9243df2ac6977c9343d9468528 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp -@@ -484,6 +484,37 @@ void Page::setOverrideViewportArguments(const std::optional& +@@ -517,6 +517,45 @@ void Page::setOverrideViewportArguments(const std::optional& document->updateViewportArguments(); } +FloatSize Page::screenSize() +{ -+ return m_overrideScreenSize.value_or(screenRect(mainFrame().view()).size()); ++ auto* localMainFrame = dynamicDowncast(mainFrame()); ++ RefPtr frameView = localMainFrame ? localMainFrame->view() : nullptr; ++ if (!frameView) ++ return { }; ++ return m_overrideScreenSize.value_or(screenRect(frameView.get()).size()); +} + +void Page::setOverrideScreenSize(std::optional size) @@ -6381,7 +6581,8 @@ index d633760e91b4074533a1a33109cb470ae654f66a..d4a00fbfd76c0301ceb3b02ac3378d90 + return; + + m_overrideScreenSize = size; -+ if (auto* document = mainFrame().document()) ++ auto* localMainFrame = dynamicDowncast(mainFrame()); ++ if (auto* document = localMainFrame ? localMainFrame->document() : nullptr) + document->updateViewportArguments(); +} + @@ -6397,25 +6598,17 @@ index d633760e91b4074533a1a33109cb470ae654f66a..d4a00fbfd76c0301ceb3b02ac3378d90 + return; + + m_overrideOrientation = orientation; -+ mainFrame().orientationChanged(); ++ ++ auto* localMainFrame = dynamicDowncast(mainFrame()); ++ if (localMainFrame) ++ localMainFrame->orientationChanged(); +} +#endif + ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { -@@ -1373,10 +1404,6 @@ void Page::didCommitLoad() - m_isEditableRegionEnabled = false; - #endif - --#if HAVE(OS_DARK_MODE_SUPPORT) -- setUseDarkAppearanceOverride(std::nullopt); --#endif -- - resetSeenPlugins(); - resetSeenMediaEngines(); - -@@ -3430,6 +3457,16 @@ void Page::setUseDarkAppearanceOverride(std::optional valueOverride) +@@ -3687,6 +3726,26 @@ void Page::setUseDarkAppearanceOverride(std::optional valueOverride) #endif } @@ -6428,15 +6621,25 @@ index d633760e91b4074533a1a33109cb470ae654f66a..d4a00fbfd76c0301ceb3b02ac3378d90 + + appearanceDidChange(); +} ++ ++void Page::setUseForcedColorsOverride(std::optional valueOverride) ++{ ++ if (valueOverride == m_useForcedColorsOverride) ++ return; ++ ++ m_useForcedColorsOverride = valueOverride; ++ ++ appearanceDidChange(); ++} + void Page::setFullscreenInsets(const FloatBoxExtent& insets) { if (insets == m_fullscreenInsets) diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h -index fcb1b65103388ab6ed15b38e1bb4a91472f37d57..67232845466df8d819f4dea296ae5dd712083fb1 100644 +index 0d1c45acfce092af08d7f8489b5d8c97a33ced13..b841ebb198e258b0498fcf33cdc63b96178dee5a 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h -@@ -285,6 +285,9 @@ public: +@@ -311,6 +311,9 @@ public: const std::optional& overrideViewportArguments() const { return m_overrideViewportArguments; } WEBCORE_EXPORT void setOverrideViewportArguments(const std::optional&); @@ -6446,10 +6649,10 @@ index fcb1b65103388ab6ed15b38e1bb4a91472f37d57..67232845466df8d819f4dea296ae5dd7 static void refreshPlugins(bool reload); WEBCORE_EXPORT PluginData& pluginData(); void clearPluginData(); -@@ -339,6 +342,10 @@ public: - DragCaretController& dragCaretController() const { return *m_dragCaretController; } +@@ -369,6 +372,10 @@ public: #if ENABLE(DRAG_SUPPORT) - DragController& dragController() const { return *m_dragController; } + DragController& dragController() { return m_dragController.get(); } + const DragController& dragController() const { return m_dragController.get(); } +#if PLATFORM(MAC) + void setDragPasteboardName(const String& pasteboardName) { m_overrideDragPasteboardName = pasteboardName; } + const String& overrideDragPasteboardName() { return m_overrideDragPasteboardName; } @@ -6457,16 +6660,18 @@ index fcb1b65103388ab6ed15b38e1bb4a91472f37d57..67232845466df8d819f4dea296ae5dd7 #endif FocusController& focusController() const { return *m_focusController; } #if ENABLE(CONTEXT_MENUS) -@@ -506,6 +513,8 @@ public: +@@ -538,6 +545,10 @@ public: WEBCORE_EXPORT void effectiveAppearanceDidChange(bool useDarkAppearance, bool useElevatedUserInterfaceLevel); bool defaultUseDarkAppearance() const { return m_useDarkAppearance; } void setUseDarkAppearanceOverride(std::optional); + std::optional useReducedMotionOverride() const { return m_useReducedMotionOverride; } + void setUseReducedMotionOverride(std::optional); ++ std::optional useForcedColorsOverride() const { return m_useForcedColorsOverride; } ++ void setUseForcedColorsOverride(std::optional); #if ENABLE(TEXT_AUTOSIZING) float textAutosizingWidth() const { return m_textAutosizingWidth; } -@@ -916,6 +925,11 @@ public: +@@ -974,6 +985,11 @@ public: WEBCORE_EXPORT void setInteractionRegionsEnabled(bool); #endif @@ -6478,25 +6683,26 @@ index fcb1b65103388ab6ed15b38e1bb4a91472f37d57..67232845466df8d819f4dea296ae5dd7 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) DeviceOrientationUpdateProvider* deviceOrientationUpdateProvider() const { return m_deviceOrientationUpdateProvider.get(); } #endif -@@ -1037,6 +1051,9 @@ private: +@@ -1112,6 +1128,9 @@ private: #if ENABLE(DRAG_SUPPORT) - const std::unique_ptr m_dragController; + UniqueRef m_dragController; +#if PLATFORM(MAC) + String m_overrideDragPasteboardName; +#endif #endif - const std::unique_ptr m_focusController; + std::unique_ptr m_focusController; #if ENABLE(CONTEXT_MENUS) -@@ -1116,6 +1133,7 @@ private: +@@ -1193,6 +1212,8 @@ private: bool m_useElevatedUserInterfaceLevel { false }; bool m_useDarkAppearance { false }; std::optional m_useDarkAppearanceOverride; + std::optional m_useReducedMotionOverride; ++ std::optional m_useForcedColorsOverride; #if ENABLE(TEXT_AUTOSIZING) float m_textAutosizingWidth { 0 }; -@@ -1293,6 +1311,11 @@ private: +@@ -1371,6 +1392,11 @@ private: #endif std::optional m_overrideViewportArguments; @@ -6509,10 +6715,10 @@ index fcb1b65103388ab6ed15b38e1bb4a91472f37d57..67232845466df8d819f4dea296ae5dd7 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) RefPtr m_deviceOrientationUpdateProvider; diff --git a/Source/WebCore/page/PageConsoleClient.cpp b/Source/WebCore/page/PageConsoleClient.cpp -index 0c51d8cac09c17b5d1bb05847410a873a4eb503b..ad35630d5a519d2f82ac0d509a04639b4d7838b2 100644 +index 6fe30e064c50097f90b06ac7facbd0717d6a873b..81e3e8c19771fc6e0fbed5d55303517b7fbd2dca 100644 --- a/Source/WebCore/page/PageConsoleClient.cpp +++ b/Source/WebCore/page/PageConsoleClient.cpp -@@ -447,4 +447,10 @@ void PageConsoleClient::screenshot(JSC::JSGlobalObject* lexicalGlobalObject, Ref +@@ -429,4 +429,10 @@ void PageConsoleClient::screenshot(JSC::JSGlobalObject* lexicalGlobalObject, Ref addMessage(makeUnique(MessageSource::ConsoleAPI, MessageType::Image, MessageLevel::Log, dataURL, WTFMove(arguments), lexicalGlobalObject, 0, timestamp)); } @@ -6536,94 +6742,104 @@ index 9a6549a792bf95f6d5671289bc58be259ec73732..03a6ceb14a18b3b74e8544a98fb85841 Page& m_page; }; diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp -index 88c3ca9610ca27e2bfa8d548597170b990990897..21de65f197804a31bbc0bf1a1098579c5dc2bfd7 100644 +index bd147a1fee46d2f228c115230f8d071dc303756c..b06dce53e787d95c6b89c01511084f95175764b7 100644 --- a/Source/WebCore/page/PointerCaptureController.cpp +++ b/Source/WebCore/page/PointerCaptureController.cpp @@ -195,7 +195,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi return capturingData && capturingData->preventsCompatibilityMouseEvents; } --#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName) { for (RefPtr currentNode = target; currentNode; currentNode = currentNode->parentInComposedTree()) { -@@ -476,7 +476,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint +@@ -474,7 +474,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint capturingData->pendingTargetOverride = nullptr; capturingData->state = CapturingData::State::Cancelled; --#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) capturingData->previousTarget = nullptr; #endif diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h -index 8c911ca663507b61640a4e29245dabe79573c420..08cdd2bfea9f5ac19c8cc39dc80032e140828ca4 100644 +index 9ec307bf796452e21c695116d1f678e1d9916709..b47ed65e85cf9cbb0d32d6199a9b1c1c0681dfcb 100644 --- a/Source/WebCore/page/PointerCaptureController.h +++ b/Source/WebCore/page/PointerCaptureController.h @@ -57,7 +57,7 @@ public: RefPtr pointerEventForMouseEvent(const MouseEvent&, PointerID, const String& pointerType); --#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) - void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&); + void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&, const IntPoint&); #endif -@@ -77,7 +77,7 @@ private: +@@ -77,12 +77,12 @@ private: RefPtr pendingTargetOverride; RefPtr targetOverride; --#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) RefPtr previousTarget; #endif bool hasAnyElement() const { + return pendingTargetOverride || targetOverride +-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) ++#if ENABLE(TOUCH_EVENTS) + || previousTarget + #endif + ; diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp -index a204ceb7d50a08631dd6e90cd11a2202571e4d76..af8cce6a1732fd7455ff362961e0ebcd71f6f459 100644 +index 3161bc20838183906a01e85f0c1feedc82f34ce7..64f5ae86238b2621f5d1895eaae2b6077ab82a4a 100644 --- a/Source/WebCore/page/Screen.cpp +++ b/Source/WebCore/page/Screen.cpp -@@ -102,6 +102,8 @@ int Screen::availLeft() const +@@ -110,6 +110,9 @@ int Screen::availLeft() const + if (isLoadingInHeadlessMode(*frame)) return 0; - if (DeprecatedGlobalSettings::webAPIStatisticsEnabled()) - ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailLeft); + + if (frame->hasScreenSizeOverride()) + return 0; ++ return static_cast(screenAvailableRect(frame->view()).x()); } -@@ -112,6 +114,8 @@ int Screen::availTop() const +@@ -125,6 +128,9 @@ int Screen::availTop() const + if (isLoadingInHeadlessMode(*frame)) return 0; - if (DeprecatedGlobalSettings::webAPIStatisticsEnabled()) - ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailTop); + + if (frame->hasScreenSizeOverride()) + return 0; ++ return static_cast(screenAvailableRect(frame->view()).y()); } -@@ -122,6 +126,8 @@ unsigned Screen::availHeight() const - return 0; - if (DeprecatedGlobalSettings::webAPIStatisticsEnabled()) - ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailHeight); +@@ -140,6 +146,9 @@ int Screen::availHeight() const + if (isLoadingInHeadlessMode(*frame)) + return static_cast(frame->screenSize().height()); + + if (frame->hasScreenSizeOverride()) -+ return static_cast(frame->screenSize().height()); - return static_cast(screenAvailableRect(frame->view()).height()); ++ return static_cast(frame->screenSize().height()); ++ + return static_cast(screenAvailableRect(frame->view()).height()); } -@@ -132,6 +138,8 @@ unsigned Screen::availWidth() const - return 0; - if (DeprecatedGlobalSettings::webAPIStatisticsEnabled()) - ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailWidth); +@@ -155,6 +164,9 @@ int Screen::availWidth() const + if (isLoadingInHeadlessMode(*frame)) + return static_cast(frame->screenSize().width()); + + if (frame->hasScreenSizeOverride()) -+ return static_cast(frame->screenSize().width()); - return static_cast(screenAvailableRect(frame->view()).width()); ++ return static_cast(frame->screenSize().width()); ++ + return static_cast(screenAvailableRect(frame->view()).width()); } diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp -index 3cb3184dc359d5a6ad9159e5991e2309d0d0099b..4aaff93ba52e9ec097540e5a57140dca1bda2ec5 100644 +index 90e90260c6a653ade7cfda34b9a1079f18554589..bce4219f7d0fdbf6cfe43bded7c038e33020ad41 100644 --- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp -@@ -298,6 +298,8 @@ bool ContentSecurityPolicy::allowContentSecurityPolicySourceStarToMatchAnyProtoc +@@ -337,6 +337,8 @@ bool ContentSecurityPolicy::allowContentSecurityPolicySourceStarToMatchAnyProtoc template typename std::enable_if::value, bool>::type ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, Predicate&& predicate, Args&&... args) const { @@ -6632,7 +6848,7 @@ index 3cb3184dc359d5a6ad9159e5991e2309d0d0099b..4aaff93ba52e9ec097540e5a57140dca bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; for (auto& policy : m_policies) { if (policy->isReportOnly() != isReportOnly) -@@ -311,6 +313,8 @@ typename std::enable_if bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const { @@ -6641,7 +6857,7 @@ index 3cb3184dc359d5a6ad9159e5991e2309d0d0099b..4aaff93ba52e9ec097540e5a57140dca bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; bool isAllowed = true; for (auto& policy : m_policies) { -@@ -327,6 +331,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit +@@ -366,6 +370,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit template bool ContentSecurityPolicy::allPoliciesAllow(ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const { @@ -6652,7 +6868,7 @@ index 3cb3184dc359d5a6ad9159e5991e2309d0d0099b..4aaff93ba52e9ec097540e5a57140dca if (const ContentSecurityPolicyDirective* violatedDirective = (policy.get()->*predicate)(std::forward(args)...)) { diff --git a/Source/WebCore/page/wpe/DragControllerWPE.cpp b/Source/WebCore/page/wpe/DragControllerWPE.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..2549355fc55ca55d2b6917dbfd05999f0e5607b3 +index 0000000000000000000000000000000000000000..803239911006cfb3b03ea911c003f2d233f67600 --- /dev/null +++ b/Source/WebCore/page/wpe/DragControllerWPE.cpp @@ -0,0 +1,80 @@ @@ -6730,17 +6946,17 @@ index 0000000000000000000000000000000000000000..2549355fc55ca55d2b6917dbfd05999f + +void DragController::declareAndWriteDragImage(DataTransfer& dataTransfer, Element& element, const URL& url, const String& label) +{ -+ Frame* frame = element.document().frame(); ++ auto* frame = element.document().frame(); + ASSERT(frame); + frame->editor().writeImageToPasteboard(dataTransfer.pasteboard(), element, url, label); +} + +} diff --git a/Source/WebCore/platform/Cairo.cmake b/Source/WebCore/platform/Cairo.cmake -index 1fb0e9d5cee3b3df4ee1e96eb8d75016ad687fc5..497bd34cc97e2d20c9d6982a8d92d852451743cd 100644 +index e5f739288d77ed77c32fc538371637aea8370b7f..bc4c3cb723f733b8fd9683e15c91e13c89c3c426 100644 --- a/Source/WebCore/platform/Cairo.cmake +++ b/Source/WebCore/platform/Cairo.cmake -@@ -16,6 +16,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS +@@ -17,6 +17,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/cairo/ImageBufferCairoBackend.h platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.h platform/graphics/cairo/ImageBufferCairoSurfaceBackend.h @@ -6749,10 +6965,10 @@ index 1fb0e9d5cee3b3df4ee1e96eb8d75016ad687fc5..497bd34cc97e2d20c9d6982a8d92d852 ) diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h -index 6600dfa7b189e15fab7fb796f66ef1a79dcd22f3..4c0bc485ca92614efca23a5a2da871b77d5285d3 100644 +index c77ddd17643628a87c0245ee2ea3ba417d40bc23..c5179ff48e57cdcfbe709a10bae517ff2b9bdc17 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h -@@ -48,7 +48,7 @@ typedef void* DragDataRef; +@@ -47,7 +47,7 @@ typedef void* DragDataRef; #elif PLATFORM(WIN) typedef struct IDataObject* DragDataRef; @@ -6761,8 +6977,28 @@ index 6600dfa7b189e15fab7fb796f66ef1a79dcd22f3..4c0bc485ca92614efca23a5a2da871b7 namespace WebCore { class SelectionData; } +@@ -92,8 +92,8 @@ public: + // is initialized by the decoder and not in the constructor. + DragData() = default; + #if PLATFORM(WIN) +- WEBCORE_EXPORT DragData(const DragDataMap&, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet = { }, std::optional pageID = std::nullopt); +- const DragDataMap& dragDataMap(); ++ WEBCORE_EXPORT DragData(const DragDataMap&, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet = { }, OptionSet = anyDragDestinationAction(), std::optional pageID = std::nullopt); ++ WEBCORE_EXPORT const DragDataMap& dragDataMap() const; + void getDragFileDescriptorData(int& size, String& pathname); + void getDragFileContentData(int size, void* dataBlob); + #endif +@@ -140,7 +140,7 @@ private: + String m_pasteboardName; + #endif + #if PLATFORM(WIN) +- DragDataMap m_dragDataMap; ++ mutable DragDataMap m_dragDataMap; + #endif + bool m_disallowFileAccess { false }; + }; diff --git a/Source/WebCore/platform/DragImage.cpp b/Source/WebCore/platform/DragImage.cpp -index 9e97dd5f689e6a1a90c9069445dc3f4b8c45e840..cc3ddc3e6d656a91c5ed58e050483d37e36d015a 100644 +index 550600c6f370af1b71a896d4fa3ef5a871a48c19..35d125361b7fa892cf863352bf0bd7131325ff38 100644 --- a/Source/WebCore/platform/DragImage.cpp +++ b/Source/WebCore/platform/DragImage.cpp @@ -279,7 +279,7 @@ DragImage::~DragImage() @@ -6775,7 +7011,7 @@ index 9e97dd5f689e6a1a90c9069445dc3f4b8c45e840..cc3ddc3e6d656a91c5ed58e050483d37 IntSize dragImageSize(DragImageRef) { diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h -index 6c8bff431b593b2443e411381f634e417f71cf06..c48473c936e9f7d997db8006770ae1488e1b2a1f 100644 +index 39f37fc92f9be35cd3164b8a10b063fe270610ea..13523a3ca41e8ae264ba4b0d823a72208f2fc077 100644 --- a/Source/WebCore/platform/Pasteboard.h +++ b/Source/WebCore/platform/Pasteboard.h @@ -44,7 +44,7 @@ OBJC_CLASS NSString; @@ -6787,25 +7023,7 @@ index 6c8bff431b593b2443e411381f634e417f71cf06..c48473c936e9f7d997db8006770ae148 #include "SelectionData.h" #endif -@@ -92,16 +92,12 @@ struct PasteboardWebContent { - Vector clientTypes; - Vector> clientData; - #endif --#if PLATFORM(GTK) -+#if PLATFORM(GTK) || PLATFORM(WPE) - String contentOrigin; - bool canSmartCopyOrDelete; - String text; - String markup; - #endif --#if USE(LIBWPE) -- String text; -- String markup; --#endif - }; - - struct PasteboardURL { -@@ -110,7 +106,7 @@ struct PasteboardURL { +@@ -108,7 +108,7 @@ struct PasteboardURL { #if PLATFORM(MAC) String userVisibleForm; #endif @@ -6814,7 +7032,7 @@ index 6c8bff431b593b2443e411381f634e417f71cf06..c48473c936e9f7d997db8006770ae148 String markup; #endif }; -@@ -200,6 +196,11 @@ public: +@@ -193,6 +193,11 @@ public: #endif #endif @@ -6826,8 +7044,8 @@ index 6c8bff431b593b2443e411381f634e417f71cf06..c48473c936e9f7d997db8006770ae148 #if PLATFORM(WIN) explicit Pasteboard(std::unique_ptr&&, IDataObject*); explicit Pasteboard(std::unique_ptr&&, WCDataObject*); -@@ -266,6 +267,12 @@ public: - static std::unique_ptr createForGlobalSelection(std::unique_ptr&&); +@@ -260,6 +265,12 @@ public: + int64_t changeCount() const; #endif +#if PLATFORM(WPE) @@ -6839,16 +7057,16 @@ index 6c8bff431b593b2443e411381f634e417f71cf06..c48473c936e9f7d997db8006770ae148 #if PLATFORM(IOS_FAMILY) explicit Pasteboard(std::unique_ptr&&, int64_t changeCount); explicit Pasteboard(std::unique_ptr&&, const String& pasteboardName); -@@ -300,6 +307,7 @@ public: +@@ -296,6 +307,7 @@ public: COMPtr dataObject() const { return m_dataObject; } - void setExternalDataObject(IDataObject*); + WEBCORE_EXPORT void setExternalDataObject(IDataObject*); const DragDataMap& dragDataMap() const { return m_dragDataMap; } + WEBCORE_EXPORT DragDataMap createDragDataMap(); void writeURLToWritableDataObject(const URL&, const String&); COMPtr writableDataObject() const { return m_writableDataObject; } void writeImageToDataObject(Element&, const URL&); // FIXME: Layering violation. -@@ -351,6 +359,10 @@ private: - String m_name; +@@ -348,6 +360,10 @@ private: + int64_t m_changeCount { 0 }; #endif +#if PLATFORM(WPE) @@ -6858,7 +7076,7 @@ index 6c8bff431b593b2443e411381f634e417f71cf06..c48473c936e9f7d997db8006770ae148 #if PLATFORM(COCOA) String m_pasteboardName; int64_t m_changeCount; -@@ -366,6 +378,7 @@ private: +@@ -363,6 +379,7 @@ private: COMPtr m_dataObject; COMPtr m_writableDataObject; DragDataMap m_dragDataMap; @@ -6867,7 +7085,7 @@ index 6c8bff431b593b2443e411381f634e417f71cf06..c48473c936e9f7d997db8006770ae148 }; diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h -index 1d3edd9585338828c7074fd8389e437c16c42d92..0f4b5b074f6c95919a09567bd1338577c0930627 100644 +index deef18898ade8424c670fd809d04c448f5ab4558..52302ec6ebb1e760b5c87f1c344c17af81055699 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -134,6 +134,7 @@ namespace WebCore { @@ -6887,7 +7105,7 @@ index 1d3edd9585338828c7074fd8389e437c16c42d92..0f4b5b074f6c95919a09567bd1338577 #endif diff --git a/Source/WebCore/platform/PlatformScreen.cpp b/Source/WebCore/platform/PlatformScreen.cpp -index ba50b688ab6d0bae5d199fa0bac4b7e2004baf81..9963c0526c0a6d48c7c910ad81f5cab37cec2be7 100644 +index ba50b688ab6d0bae5d199fa0bac4b7e2004baf81..f27481c6039ed2450209179b4ed08d9d09842cd3 100644 --- a/Source/WebCore/platform/PlatformScreen.cpp +++ b/Source/WebCore/platform/PlatformScreen.cpp @@ -25,6 +25,7 @@ @@ -6898,7 +7116,7 @@ index ba50b688ab6d0bae5d199fa0bac4b7e2004baf81..9963c0526c0a6d48c7c910ad81f5cab3 #if PLATFORM(COCOA) -@@ -72,3 +73,16 @@ const ScreenData* screenData(PlatformDisplayID screenDisplayID) +@@ -72,3 +73,25 @@ const ScreenData* screenData(PlatformDisplayID screenDisplayID) } // namespace WebCore #endif // PLATFORM(COCOA) @@ -6906,24 +7124,35 @@ index ba50b688ab6d0bae5d199fa0bac4b7e2004baf81..9963c0526c0a6d48c7c910ad81f5cab3 +#if ENABLE(TOUCH_EVENTS) +namespace WebCore { + ++static std::optional screenHasTouchDeviceOverride = std::nullopt; ++void setScreenHasTouchDeviceOverride(bool value) { ++ screenHasTouchDeviceOverride = value; ++} ++ +bool screenHasTouchDevice() { -+ return DeprecatedGlobalSettings::touchEventsEnabled(); ++ if (screenHasTouchDeviceOverride) ++ return screenHasTouchDeviceOverride.value(); ++ return platformScreenHasTouchDevice(); +} +bool screenIsTouchPrimaryInputDevice() { -+ return DeprecatedGlobalSettings::isTouchPrimaryInputDevice(); ++ if (screenHasTouchDeviceOverride) ++ return screenHasTouchDeviceOverride.value(); ++ return platformScreenIsTouchPrimaryInputDevice(); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/PlatformScreen.h b/Source/WebCore/platform/PlatformScreen.h -index 44799e0b2a93cbcf25f4315d62a3d95896c02f3d..29277223448a0936a16f975970ab60d739b000cd 100644 +index 44799e0b2a93cbcf25f4315d62a3d95896c02f3d..ec593ea30f6e45c355f5d6806290f2462729ed8f 100644 --- a/Source/WebCore/platform/PlatformScreen.h +++ b/Source/WebCore/platform/PlatformScreen.h -@@ -151,12 +151,14 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); +@@ -151,15 +151,20 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); #endif #if ENABLE(TOUCH_EVENTS) -#if PLATFORM(GTK) || PLATFORM(WPE) ++WEBCORE_EXPORT void setScreenHasTouchDeviceOverride(bool); ++ WEBCORE_EXPORT bool screenHasTouchDevice(); WEBCORE_EXPORT bool screenIsTouchPrimaryInputDevice(); +#if PLATFORM(GTK) || PLATFORM(WPE) @@ -6937,121 +7166,25 @@ index 44799e0b2a93cbcf25f4315d62a3d95896c02f3d..29277223448a0936a16f975970ab60d7 #endif #endif -diff --git a/Source/WebCore/platform/ScrollableArea.h b/Source/WebCore/platform/ScrollableArea.h -index 15e75c74d437b962dfffcafa9c086491064e1f15..2b4b682b087c645cdfd02997658e07a423bb9c2d 100644 ---- a/Source/WebCore/platform/ScrollableArea.h -+++ b/Source/WebCore/platform/ScrollableArea.h -@@ -103,7 +103,7 @@ public: - void stopKeyboardScrollAnimation(); ++ + } // namespace WebCore - #if ENABLE(TOUCH_EVENTS) -- virtual bool handleTouchEvent(const PlatformTouchEvent&); -+ WEBCORE_EXPORT virtual bool handleTouchEvent(const PlatformTouchEvent&); - #endif + namespace WTF { +diff --git a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp +index 6016d84a982356c6c89d8719158346fd181dc0f6..572be8257134f190aed7befd548120fc6041b37c 100644 +--- a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp ++++ b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp +@@ -43,7 +43,7 @@ - #if PLATFORM(IOS_FAMILY) -diff --git a/Source/WebCore/platform/SourcesGLib.txt b/Source/WebCore/platform/SourcesGLib.txt -index 53f48ba8ad99364680457daf4dcbae632360be12..8825859d561113f14ba6ef8d860c5202d2fbd253 100644 ---- a/Source/WebCore/platform/SourcesGLib.txt -+++ b/Source/WebCore/platform/SourcesGLib.txt -@@ -33,6 +33,7 @@ platform/glib/LowPowerModeNotifierGLib.cpp - platform/glib/RemoteCommandListenerGLib.cpp - platform/glib/SharedBufferGlib.cpp - platform/glib/UserAgentGLib.cpp -+platform/glib/PlatformSpeechSynthesizerGLib.cpp - - platform/network/glib/DNSResolveQueueGLib.cpp - platform/network/glib/NetworkStateNotifierGLib.cpp -diff --git a/Source/WebCore/platform/glib/PlatformSpeechSynthesizerGLib.cpp b/Source/WebCore/platform/glib/PlatformSpeechSynthesizerGLib.cpp -new file mode 100644 -index 0000000000000000000000000000000000000000..f0c3a183e5bc44bdfa4201e0db2067b41bf51580 ---- /dev/null -+++ b/Source/WebCore/platform/glib/PlatformSpeechSynthesizerGLib.cpp -@@ -0,0 +1,68 @@ -+/* -+ * Copyright (C) 2013 Apple Inc. All rights reserved. -+ * -+ * 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 APPLE INC. ``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 APPLE INC. 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 "PlatformSpeechSynthesizer.h" -+ -+#if ENABLE(SPEECH_SYNTHESIS) -+ -+namespace WebCore { -+ -+PlatformSpeechSynthesizer::PlatformSpeechSynthesizer(PlatformSpeechSynthesizerClient* client) -+ : m_speechSynthesizerClient(client) -+{ -+} -+ -+PlatformSpeechSynthesizer::~PlatformSpeechSynthesizer() -+{ -+} -+ -+void PlatformSpeechSynthesizer::initializeVoiceList() -+{ -+} -+ -+void PlatformSpeechSynthesizer::pause() -+{ -+} -+ -+void PlatformSpeechSynthesizer::resume() -+{ -+} -+ -+void PlatformSpeechSynthesizer::speak(RefPtr&& utterance) -+{ -+} -+ -+void PlatformSpeechSynthesizer::cancel() -+{ -+} -+ -+void PlatformSpeechSynthesizer::resetState() -+{ -+} -+ -+} // namespace WebCore -+ -+#endif // ENABLE(SPEECH_SYNTHESIS) -diff --git a/Source/WebCore/platform/graphics/FontCascade.h b/Source/WebCore/platform/graphics/FontCascade.h -index 7eab503aba753ba11a67417e809bc24e5cdb1eae..891e928b4c992acee19cf29cfa3f3a35734a814e 100644 ---- a/Source/WebCore/platform/graphics/FontCascade.h -+++ b/Source/WebCore/platform/graphics/FontCascade.h -@@ -310,7 +310,8 @@ private: - return true; - if (textRenderingMode == TextRenderingMode::OptimizeSpeed) - return false; --#if PLATFORM(COCOA) || USE(FREETYPE) -+ // WIN: quick fix for https://bugs.webkit.org/show_bug.cgi?id=201213 -+#if PLATFORM(COCOA) || USE(FREETYPE) || PLATFORM(WIN) - return true; - #else - return false; + namespace WebCore { + +-static const unsigned scrollbarSize = 21; ++static const unsigned scrollbarSize = 0; + static const unsigned scrollbarBorderSize = 1; + static const unsigned thumbBorderSize = 1; + static const unsigned overlayThumbSize = 3; diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp -index 97f733ef9af5558ef7375ab2b74c8d4c6e6d8502..cd201b0155a4e12576c2bd1af8b45c4be1101763 100644 +index ba4211130b222abe1cba86e9eedf525940f317a0..f2289378791bc76a5bc82ba89876c3ed6aa645e3 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp @@ -48,6 +48,13 @@ @@ -7170,21 +7303,8 @@ index b60f9a64bacc8282860da6de299b75aeb295b9b5..55bd017c03c6478ca334bd5ef164160f namespace WebCore { -diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp -index ce40cc903f98688cbd2da28c0f0ed6660ce38b52..808e5e68f6abafc3a200f6c2d7cd12c9f34be473 100644 ---- a/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp -+++ b/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp -@@ -27,7 +27,7 @@ - #include "config.h" - #include "GraphicsContextGLOpenGL.h" - --#if ENABLE(WEBGL) && USE(OPENGL) -+#if !PLATFORM(WIN) && ENABLE(WEBGL) && USE(OPENGL) - - #include "ByteArrayPixelBuffer.h" - #include "ExtensionsGLOpenGL.h" diff --git a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp -index 6d6820fc22f9a7102bbdad6c4b5e3e7e9645f66c..f44797b8c197bf1b3daaa9b59dad2a8e250c4791 100644 +index 2a5c4edc93f19897648351181f4187b464ad1a62..32b74aadea83ce7f5ddb6010b45b901d34b0e870 100644 --- a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp +++ b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp @@ -170,6 +170,33 @@ static Vector stringIndicesFromClusters(const Vector& clusters, @@ -7231,7 +7351,7 @@ index 6d6820fc22f9a7102bbdad6c4b5e3e7e9645f66c..f44797b8c197bf1b3daaa9b59dad2a8e // Determine the string for this item. const UChar* str = cp + items[i].iCharPos; diff --git a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp -index dd5fb8634277baea92be6ecaf6d2fbc7ce7ee9f0..9aa9e4d923d487cd4003e7396ebe61c7df51057d 100644 +index 23f7caefeb0fdfd47d05b8bbc0f949d0b772dc15..d89d5395c7c5eddeaa3aebae8ae3fcc07964856e 100644 --- a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp @@ -37,8 +37,10 @@ @@ -7245,7 +7365,7 @@ index dd5fb8634277baea92be6ecaf6d2fbc7ce7ee9f0..9aa9e4d923d487cd4003e7396ebe61c7 namespace WebCore { -@@ -1294,6 +1296,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(unsigned keycode) +@@ -1302,6 +1304,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(unsigned keycode) } @@ -7493,10 +7613,10 @@ index dd5fb8634277baea92be6ecaf6d2fbc7ce7ee9f0..9aa9e4d923d487cd4003e7396ebe61c7 { switch (val) { diff --git a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp -index 80958ba565a877224d0ed37e4e4057b4be0dde24..eca42bf5181bc4a95efca9c9c3f5ce0f987fea43 100644 +index d16c5990bd872a76b9ea01a25a1a0f8035977cb2..b438aaa1063d61321f16942e47ecc85b6927e071 100644 --- a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp -@@ -224,7 +224,7 @@ bool screenSupportsExtendedColor(Widget*) +@@ -225,7 +225,7 @@ bool screenSupportsExtendedColor(Widget*) } #if ENABLE(TOUCH_EVENTS) @@ -7505,7 +7625,7 @@ index 80958ba565a877224d0ed37e4e4057b4be0dde24..eca42bf5181bc4a95efca9c9c3f5ce0f { auto* display = gdk_display_get_default(); if (!display) -@@ -234,7 +234,7 @@ bool screenHasTouchDevice() +@@ -235,7 +235,7 @@ bool screenHasTouchDevice() return seat ? gdk_seat_get_capabilities(seat) & GDK_SEAT_CAPABILITY_TOUCH : true; } @@ -7515,7 +7635,7 @@ index 80958ba565a877224d0ed37e4e4057b4be0dde24..eca42bf5181bc4a95efca9c9c3f5ce0f auto* display = gdk_display_get_default(); if (!display) diff --git a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp -index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b92a8e7838 100644 +index ae439e30f1fb239d18e1164e8896dfb272c75673..eddcb9bda783fcdcbf9f924d4eaa6cc78dd54395 100644 --- a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp @@ -32,6 +32,10 @@ @@ -7529,7 +7649,51 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b9 namespace WebCore { std::unique_ptr Pasteboard::createForCopyAndPaste(std::unique_ptr&& context) -@@ -73,6 +77,16 @@ String Pasteboard::readOrigin() +@@ -52,9 +56,28 @@ bool Pasteboard::hasData() + return !types.isEmpty(); + } + +-Vector Pasteboard::typesSafeForBindings(const String&) ++Vector Pasteboard::typesSafeForBindings(const String& origin) + { +- notImplemented(); ++ if (m_selectionData) { ++ ListHashSet types; ++ if (auto* buffer = m_selectionData->customData()) { ++ auto customData = PasteboardCustomData::fromSharedBuffer(*buffer); ++ if (customData.origin() == origin) { ++ for (auto& type : customData.orderedTypes()) ++ types.add(type); ++ } ++ } ++ ++ if (m_selectionData->hasText()) ++ types.add("text/plain"_s); ++ if (m_selectionData->hasMarkup()) ++ types.add("text/html"_s); ++ if (m_selectionData->hasURIList()) ++ types.add("text/uri-list"_s); ++ ++ return copyToVector(types); ++ } ++ + return { }; + } + +@@ -67,23 +90,55 @@ Vector Pasteboard::typesForLegacyUnsafeBindings() + + String Pasteboard::readOrigin() + { +- notImplemented(); // webkit.org/b/177633: [GTK] Move to new Pasteboard API ++ if (m_selectionData) { ++ if (auto* buffer = m_selectionData->customData()) ++ return PasteboardCustomData::fromSharedBuffer(*buffer).origin(); ++ ++ return { }; ++ } ++ + return { }; + } String Pasteboard::readString(const String& type) { @@ -7543,11 +7707,23 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b9 + return { }; + } + - return platformStrategies()->pasteboardStrategy()->readStringFromPasteboard(0, type, name(), context()); + return platformStrategies()->pasteboardStrategy()->readStringFromPasteboard(0, type, name(), context()); + } + +-String Pasteboard::readStringInCustomData(const String&) ++String Pasteboard::readStringInCustomData(const String& type) + { ++ if (m_selectionData) { ++ if (auto* buffer = m_selectionData->customData()) ++ return PasteboardCustomData::fromSharedBuffer(*buffer).readStringInCustomData(type); ++ ++ return { }; ++ } ++ + notImplemented(); + return { }; } -@@ -84,6 +98,15 @@ String Pasteboard::readStringInCustomData(const String&) - void Pasteboard::writeString(const String& type, const String& text) { + if (m_selectionData) { @@ -7562,7 +7738,7 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b9 platformStrategies()->pasteboardStrategy()->writeToPasteboard(type, text); } -@@ -111,7 +134,12 @@ void Pasteboard::read(PasteboardFileReader&, std::optional) +@@ -111,7 +166,12 @@ void Pasteboard::read(PasteboardFileReader&, std::optional) void Pasteboard::write(const PasteboardURL& url) { @@ -7576,7 +7752,7 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b9 } void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&) -@@ -119,8 +147,16 @@ void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&) +@@ -119,8 +179,16 @@ void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&) notImplemented(); } @@ -7594,7 +7770,7 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b9 } void Pasteboard::write(const PasteboardBuffer&) -@@ -129,7 +165,14 @@ void Pasteboard::write(const PasteboardBuffer&) +@@ -129,7 +197,13 @@ void Pasteboard::write(const PasteboardBuffer&) void Pasteboard::write(const PasteboardWebContent& content) { @@ -7603,14 +7779,33 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b9 + m_selectionData->clearAll(); + m_selectionData->setText(content.text); + m_selectionData->setMarkup(content.markup); -+ m_selectionData->setCanSmartReplace(content.canSmartCopyOrDelete); + } else { + platformStrategies()->pasteboardStrategy()->writeToPasteboard(content); + } } Pasteboard::FileContentState Pasteboard::fileContentState() -@@ -160,6 +203,35 @@ void Pasteboard::write(const Color&) +@@ -152,14 +226,54 @@ void Pasteboard::writePlainText(const String& text, SmartReplaceOption) + writeString("text/plain;charset=utf-8"_s, text); + } + +-void Pasteboard::writeCustomData(const Vector&) ++void Pasteboard::writeCustomData(const Vector& data) + { ++ if (m_selectionData) { ++ if (!data.isEmpty()) { ++ const auto& customData = data[0]; ++ customData.forEachPlatformString([this] (auto& type, auto& string) { ++ writeString(type, string); ++ }); ++ if (customData.hasSameOriginCustomData() || !customData.origin().isEmpty()) ++ m_selectionData->setCustomData(customData.createSharedBuffer()); ++ } ++ return; ++ } + } + + void Pasteboard::write(const Color&) { } @@ -7647,7 +7842,7 @@ index ae439e30f1fb239d18e1164e8896dfb272c75673..c004d77c162f87701278fa1ada9200b9 #endif // USE(LIBWPE) diff --git a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp -index a724f126f8f389d46ba5c1a941eef76fdc59c94c..aa40f6c3ee81213074639cce1d18eb21c6e204f4 100644 +index b7ddcc524def62c6be6bdf9cd5c8db3ed7368c99..0206c6adf63952ff843b46cc81203065f5f41e94 100644 --- a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp @@ -30,8 +30,10 @@ @@ -7661,7 +7856,7 @@ index a724f126f8f389d46ba5c1a941eef76fdc59c94c..aa40f6c3ee81213074639cce1d18eb21 namespace WebCore { -@@ -1291,6 +1293,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(unsigned keycode) +@@ -1305,6 +1307,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(unsigned keycode) return 0; } @@ -8012,11 +8207,24 @@ index 93db57fd75b8fcac1a745f62294e27c97e040ab0..02411ac6bb361c2677c269945f665e0a } Vector PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String&) const +diff --git a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h +index 0552842dbe3f3a2c12a504178f5a8ca977e1c4db..2ef3b1b459d8a9b4e86b4556feeb4f0737f05c54 100644 +--- a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h ++++ b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/LibWebRTCProviderGStreamer.h +@@ -31,6 +31,8 @@ + #include "GStreamerVideoEncoderFactory.h" + #include "LibWebRTCProvider.h" + ++#include "LibWebRTCProvider.h" ++ + namespace WebCore { + + class WEBCORE_EXPORT LibWebRTCProviderGStreamer : public LibWebRTCProvider { diff --git a/Source/WebCore/platform/network/HTTPHeaderMap.cpp b/Source/WebCore/platform/network/HTTPHeaderMap.cpp -index f169677e661510b225b899c79b68d040179a097a..420e101c7bb7a49b5c644076a8a2ffab2282d758 100644 +index 35ade40b37f0c476815535541118f9246ed199cd..2bd1444f9a5e9a14ab3d6acbc020434e1f55ede1 100644 --- a/Source/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/Source/WebCore/platform/network/HTTPHeaderMap.cpp -@@ -229,8 +229,11 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value) +@@ -235,8 +235,11 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value) auto index = m_commonHeaders.findIf([&](auto& header) { return header.key == name; }); @@ -8030,10 +8238,10 @@ index f169677e661510b225b899c79b68d040179a097a..420e101c7bb7a49b5c644076a8a2ffab m_commonHeaders.append(CommonHeader { name, value }); } diff --git a/Source/WebCore/platform/network/NetworkStorageSession.h b/Source/WebCore/platform/network/NetworkStorageSession.h -index cad5fdc361c1ae84f56e0c8cba754ede9b70450f..64ba38b5a05202ae2ec5ec4d244177a7b169e569 100644 +index 20f53a73e854e739a3289af2ee8fa979b5397460..db0c94f1b37b7930e9c95b5677705eadca595ccc 100644 --- a/Source/WebCore/platform/network/NetworkStorageSession.h +++ b/Source/WebCore/platform/network/NetworkStorageSession.h -@@ -156,6 +156,8 @@ public: +@@ -154,6 +154,8 @@ public: NetworkingContext* context() const; #endif @@ -8042,28 +8250,59 @@ index cad5fdc361c1ae84f56e0c8cba754ede9b70450f..64ba38b5a05202ae2ec5ec4d244177a7 WEBCORE_EXPORT HTTPCookieAcceptPolicy cookieAcceptPolicy() const; WEBCORE_EXPORT void setCookie(const Cookie&); WEBCORE_EXPORT void setCookies(const Vector&, const URL&, const URL& mainDocumentURL); +diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp +index 1c8c44d16ab8bb361d416ba1e5c1f0145327e07f..4c28fa8a267403a834918576a3c679f354f0f9c4 100644 +--- a/Source/WebCore/platform/network/ResourceResponseBase.cpp ++++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp +@@ -74,6 +74,7 @@ ResourceResponseBase::ResourceResponseBase(std::optionalm_httpStatusText : AtomString { }) + , m_httpVersion(data ? data->m_httpVersion : AtomString { }) + , m_httpHeaderFields(data ? data->m_httpHeaderFields : HTTPHeaderMap { }) ++ , m_httpRequestHeaderFields(data ? data->m_httpRequestHeaderFields : HTTPHeaderMap { }) + , m_networkLoadMetrics(data ? data->m_networkLoadMetrics : Box { }) + , m_certificateInfo(data ? data->m_certificateInfo : std::nullopt) + , m_httpStatusCode(data ? data->m_httpStatusCode : 0) +@@ -890,6 +891,7 @@ std::optional ResourceResponseBase::getRespo + m_httpStatusText, + m_httpVersion, + m_httpHeaderFields, ++ m_httpRequestHeaderFields, + m_networkLoadMetrics, + + m_httpStatusCode, diff --git a/Source/WebCore/platform/network/ResourceResponseBase.h b/Source/WebCore/platform/network/ResourceResponseBase.h -index cd8cde01d0bbb527983cee06f1759ff35bea2f9a..c87610f9a3386d518b3cf8529a42d61dbac200b1 100644 +index a2a0e57218fc14c7ead18bfe93330e9ddc260f36..ecfbd8538223ad08e64bb99fe976d2a1ab44a36d 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.h +++ b/Source/WebCore/platform/network/ResourceResponseBase.h -@@ -224,6 +224,8 @@ public: - - WEBCORE_EXPORT static ResourceResponse dataURLResponse(const URL&, const DataURLDecoder::Result&); - +@@ -127,6 +127,7 @@ public: + AtomString m_httpStatusText; + AtomString m_httpVersion; + HTTPHeaderMap m_httpHeaderFields; ++ HTTPHeaderMap m_httpRequestHeaderFields; + Box m_networkLoadMetrics; + + short m_httpStatusCode; +@@ -320,6 +321,11 @@ protected: + AtomString m_httpStatusText; + AtomString m_httpVersion; + HTTPHeaderMap m_httpHeaderFields; ++ ++public: + HTTPHeaderMap m_httpRequestHeaderFields; + - protected: - enum InitLevel { - Uninitialized, -@@ -303,6 +305,7 @@ void ResourceResponseBase::encode(Encoder& encoder) const ++protected: + Box m_networkLoadMetrics; + + mutable std::optional m_certificateInfo; +@@ -368,6 +374,7 @@ void ResourceResponseBase::encode(Encoder& encoder) const encoder << m_httpStatusText; encoder << m_httpVersion; encoder << m_httpHeaderFields; + encoder << m_httpRequestHeaderFields; - // We don't want to put the networkLoadMetrics info - // into the disk cache, because we will never use the old info. -@@ -375,6 +378,12 @@ bool ResourceResponseBase::decode(Decoder& decoder, ResourceResponseBase& respon + encoder << m_httpStatusCode; + encoder << m_certificateInfo; +@@ -437,6 +444,12 @@ bool ResourceResponseBase::decode(Decoder& decoder, ResourceResponseBase& respon return false; response.m_httpHeaderFields = WTFMove(*httpHeaderFields); @@ -8073,14 +8312,14 @@ index cd8cde01d0bbb527983cee06f1759ff35bea2f9a..c87610f9a3386d518b3cf8529a42d61d + return false; + response.m_httpRequestHeaderFields = WTFMove(*httpRequestHeaderFields); + - // The networkLoadMetrics info is only send over IPC and not stored in disk cache. - if constexpr (Decoder::isIPCDecoder) { - std::optional> networkLoadMetrics; + std::optional httpStatusCode; + decoder >> httpStatusCode; + if (!httpStatusCode) diff --git a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm -index a32a938cceed433559c00e15c72f6a47465ec575..1759e5d76989670705100cb3427a79b5ce35b761 100644 +index df4dcc2be66c6a9b5167133e8bcbf40122f38008..70fe07087e8145398c1b38aa3d439c5c7a144e05 100644 --- a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm +++ b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm -@@ -479,6 +479,22 @@ void NetworkStorageSession::setCookiesFromDOM(const URL& firstParty, const SameS +@@ -481,6 +481,22 @@ void NetworkStorageSession::setCookiesFromDOM(const URL& firstParty, const SameS END_BLOCK_OBJC_EXCEPTIONS } @@ -8104,7 +8343,7 @@ index a32a938cceed433559c00e15c72f6a47465ec575..1759e5d76989670705100cb3427a79b5 { ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies)); diff --git a/Source/WebCore/platform/network/curl/CookieJarDB.h b/Source/WebCore/platform/network/curl/CookieJarDB.h -index dd0553966d670c398bb352730905def8a0a3f289..0622f8a2d217365cfa4ceb1b4cab58b898835f92 100644 +index 7788bfea8bb631c51fe858b29cc33e43347cbfab..ad9f347ce55cbea4374a45d3c65f8e11bd7a00f4 100644 --- a/Source/WebCore/platform/network/curl/CookieJarDB.h +++ b/Source/WebCore/platform/network/curl/CookieJarDB.h @@ -72,7 +72,7 @@ public: @@ -8184,23 +8423,23 @@ index d94ff4f9169a6c0b5adb9719f5506d0fb80e6f89..3f955607764d028807d150619bf7f49e return streamID; diff --git a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h -index 0c39c90aac884fca48849388acc1b42bad16d620..dd8e50686c348b46d5ae92fd67a31eb0cbdb014f 100644 +index 423a2f825e7c3090fbdab8d2963ad1b45b71af9a..dfa43d953dda13ba9ab6a928bc6c7b2758267d7f 100644 --- a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h +++ b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h @@ -38,7 +38,7 @@ public: CurlStreamScheduler(); virtual ~CurlStreamScheduler(); -- CurlStreamID createStream(const URL&, CurlStream::Client&); -+ CurlStreamID createStream(const URL&, bool ignoreCertificateErrors, CurlStream::Client&); - void destroyStream(CurlStreamID); - void send(CurlStreamID, UniqueArray&&, size_t); +- WEBCORE_EXPORT CurlStreamID createStream(const URL&, CurlStream::Client&); ++ WEBCORE_EXPORT CurlStreamID createStream(const URL&, bool ignoreCertificateErrors, CurlStream::Client&); + WEBCORE_EXPORT void destroyStream(CurlStreamID); + WEBCORE_EXPORT void send(CurlStreamID, UniqueArray&&, size_t); diff --git a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp -index 1b93415110a77d443d951890095c31fdadf889e9..b7682f0a2539b1a98c23e5391ec255f169768b32 100644 +index 6f4684a843d58cb107030bc461767bc069fea0b9..ff4b6b3a1fbe4c41ba0bfb389d887ecba7af6ebd 100644 --- a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp +++ b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp -@@ -118,6 +118,12 @@ void NetworkStorageSession::setCookieAcceptPolicy(CookieAcceptPolicy policy) con +@@ -131,6 +131,12 @@ void NetworkStorageSession::setCookieAcceptPolicy(CookieAcceptPolicy policy) con cookieDatabase().setAcceptPolicy(policy); } @@ -8213,52 +8452,8 @@ index 1b93415110a77d443d951890095c31fdadf889e9..b7682f0a2539b1a98c23e5391ec255f1 HTTPCookieAcceptPolicy NetworkStorageSession::cookieAcceptPolicy() const { switch (cookieDatabase().acceptPolicy()) { -diff --git a/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h b/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h -index 950cd1b1ac6800212e8192b5cb53e69b34409111..58b1f55543f1bdcfc8e6b19b06633c0c4c45095a 100644 ---- a/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h -+++ b/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h -@@ -44,7 +44,7 @@ class StorageSessionProvider; - - class SocketStreamHandleImpl : public SocketStreamHandle, public CurlStream::Client { - public: -- static Ref create(const URL& url, SocketStreamHandleClient& client, PAL::SessionID, const String&, SourceApplicationAuditToken&&, const StorageSessionProvider* provider, bool) { return adoptRef(*new SocketStreamHandleImpl(url, client, provider)); } -+ static Ref create(const URL& url, SocketStreamHandleClient& client, PAL::SessionID, const String&, SourceApplicationAuditToken&&, const StorageSessionProvider* provider, bool ignoreCertificateErrors) { return adoptRef(*new SocketStreamHandleImpl(url, ignoreCertificateErrors, client, provider)); } - - virtual ~SocketStreamHandleImpl(); - -@@ -53,7 +53,7 @@ public: - WEBCORE_EXPORT void platformClose() final; - - private: -- WEBCORE_EXPORT SocketStreamHandleImpl(const URL&, SocketStreamHandleClient&, const StorageSessionProvider*); -+ WEBCORE_EXPORT SocketStreamHandleImpl(const URL&, bool ignoreCertificateErrors, SocketStreamHandleClient&, const StorageSessionProvider*); - - size_t bufferedAmount() final; - std::optional platformSendInternal(const uint8_t*, size_t); -diff --git a/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp b/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp -index e106d2e9c4bdf2f099c34d61270ab1ab12e1b1bc..d1ffe11e4fc2a0bece55c4a70f4d1eef28c4dadb 100644 ---- a/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp -+++ b/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp -@@ -44,7 +44,7 @@ - - namespace WebCore { - --SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandleClient& client, const StorageSessionProvider* provider) -+SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, bool ignoreCertificateErrors, SocketStreamHandleClient& client, const StorageSessionProvider* provider) - : SocketStreamHandle(url, client) - , m_storageSessionProvider(provider) - , m_scheduler(CurlContext::singleton().streamScheduler()) -@@ -53,7 +53,7 @@ SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandl - if (m_url.protocolIs("wss"_s) && DeprecatedGlobalSettings::allowsAnySSLCertificate()) - CurlContext::singleton().sslHandle().setIgnoreSSLErrors(true); - -- m_streamID = m_scheduler.createStream(m_url, *this); -+ m_streamID = m_scheduler.createStream(m_url, ignoreCertificateErrors, *this); - } - - SocketStreamHandleImpl::~SocketStreamHandleImpl() diff --git a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp -index 1c91f93595ab4362409762530880878e3804c2b8..8848c9d880f341d4a0de089ff0ddc1d0fdde5ea4 100644 +index ad7471cbd809b2c9b8bedeab15ead1f9d824b8e3..07ce9246c343d18602b31481f6df0c8603d15ba2 100644 --- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp +++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp @@ -410,6 +410,30 @@ void NetworkStorageSession::setCookie(const Cookie& cookie) @@ -8293,7 +8488,7 @@ index 1c91f93595ab4362409762530880878e3804c2b8..8848c9d880f341d4a0de089ff0ddc1d0 { GUniquePtr targetCookie(cookie.toSoupCookie()); diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp -index fdde3ee4f109b35c5b6766450a5aa3fd56619199..6d960bee81c15d0415c04616bb7715390a9a83e6 100644 +index 8456841cafdaf4d99be5b490afc67e28b03a8b42..51be5ab0fccca21aea4ccc7acf6c9f49b5577e4f 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -39,6 +39,7 @@ @@ -8329,22 +8524,40 @@ index c50799b63e05adbe32bae3535d786c7d268f980f..9cf1cc7ec4eaae22947f80ba272dfae2 HGLOBAL createGlobalData(const String&); HGLOBAL createGlobalData(const Vector&); diff --git a/Source/WebCore/platform/win/DragDataWin.cpp b/Source/WebCore/platform/win/DragDataWin.cpp -index 207572d157ba2173c045e01da8f9b83b034c047e..6590bd36b23bdcbc947b191d2c011414655dfd68 100644 +index 7bdb180c89bf3fe9d48098318d3b7503b8fd6279..296a3b2b82733b27272acb51ab4f883decfbaf14 100644 --- a/Source/WebCore/platform/win/DragDataWin.cpp +++ b/Source/WebCore/platform/win/DragDataWin.cpp +@@ -40,7 +40,7 @@ + + namespace WebCore { + +-DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet flags, std::optional pageID) ++DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet flags, OptionSet dragDestinationAction, std::optional pageID) + : m_clientPosition(clientPosition) + , m_globalPosition(globalPosition) + , m_platformDragData(0) @@ -48,6 +48,7 @@ DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, cons , m_applicationFlags(flags) , m_pageID(pageID) , m_dragDataMap(data) -+ , m_dragDestinationActionMask(anyDragDestinationAction()) ++ , m_dragDestinationActionMask(dragDestinationAction) { } +@@ -63,7 +64,7 @@ bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const + || (filenamePolicy == ConvertFilenames && (m_dragDataMap.contains(filenameWFormat()->cfFormat) || m_dragDataMap.contains(filenameFormat()->cfFormat))); + } + +-const DragDataMap& DragData::dragDataMap() ++const DragDataMap& DragData::dragDataMap() const + { + if (!m_dragDataMap.isEmpty() || !m_platformDragData) + return m_dragDataMap; diff --git a/Source/WebCore/platform/win/KeyEventWin.cpp b/Source/WebCore/platform/win/KeyEventWin.cpp -index 05a0d1256a136982507b732c7852bbece201b513..f2c00eca40fbf3a88780610228f60ba6f8c1f441 100644 +index 6350161d8c2cd0832f68883b98615e7c52630c75..f20f5c90459ec160e990eccf902cb0281a7e4526 100644 --- a/Source/WebCore/platform/win/KeyEventWin.cpp +++ b/Source/WebCore/platform/win/KeyEventWin.cpp -@@ -239,10 +239,16 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM code, LPARAM keyData, +@@ -242,10 +242,16 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM code, LPARAM keyData, { } @@ -8354,7 +8567,7 @@ index 05a0d1256a136982507b732c7852bbece201b513..f2c00eca40fbf3a88780610228f60ba6 - // No KeyDown events on Windows to disambiguate. - ASSERT_NOT_REACHED(); + m_type = type; -+ if (type == PlatformEvent::RawKeyDown) { ++ if (type == PlatformEvent::Type::RawKeyDown) { + m_text = String(); + m_unmodifiedText = String(); + } else { @@ -8363,9 +8576,9 @@ index 05a0d1256a136982507b732c7852bbece201b513..f2c00eca40fbf3a88780610228f60ba6 + } } - bool PlatformKeyboardEvent::currentCapsLockState() + OptionSet PlatformKeyboardEvent::currentStateOfModifierKeys() diff --git a/Source/WebCore/platform/win/PasteboardWin.cpp b/Source/WebCore/platform/win/PasteboardWin.cpp -index cff81b5ce4fdd771b7c4daab1570187de262efce..a990de0a7177bf1e48ea53f1be6444f410f2bbc6 100644 +index c4aea7f4acf1d81d064156addf8fbfebda0ced76..478bf6c806d107642f7f91debe388e7ef91ddd65 100644 --- a/Source/WebCore/platform/win/PasteboardWin.cpp +++ b/Source/WebCore/platform/win/PasteboardWin.cpp @@ -1129,7 +1129,21 @@ void Pasteboard::writeCustomData(const Vector& data) @@ -8416,20 +8629,6 @@ index cff81b5ce4fdd771b7c4daab1570187de262efce..a990de0a7177bf1e48ea53f1be6444f4 +} + } // namespace WebCore -diff --git a/Source/WebCore/platform/win/ScrollbarThemeWin.cpp b/Source/WebCore/platform/win/ScrollbarThemeWin.cpp -index e89ec9d83d8abc141938716f24eaba061a085af3..6005d02b9bf20ef2cbf9382fdf50c863952c8db5 100644 ---- a/Source/WebCore/platform/win/ScrollbarThemeWin.cpp -+++ b/Source/WebCore/platform/win/ScrollbarThemeWin.cpp -@@ -114,8 +114,7 @@ static int scrollbarThicknessInPixels() - - int ScrollbarThemeWin::scrollbarThickness(ScrollbarControlSize, ScrollbarExpansionState) - { -- float inverseScaleFactor = 1.0f / deviceScaleFactorForWindow(0); -- return clampTo(inverseScaleFactor * scrollbarThicknessInPixels()); -+ return 0; - } - - void ScrollbarThemeWin::themeChanged() diff --git a/Source/WebCore/platform/wpe/DragDataWPE.cpp b/Source/WebCore/platform/wpe/DragDataWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07fb260a5203167fdf94a552949394bb73ca8c61 @@ -8525,7 +8724,7 @@ index 0000000000000000000000000000000000000000..07fb260a5203167fdf94a552949394bb +} diff --git a/Source/WebCore/platform/wpe/DragImageWPE.cpp b/Source/WebCore/platform/wpe/DragImageWPE.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..e77e6db7a93a9dfcaad3866eb445edf4ebfe33b5 +index 0000000000000000000000000000000000000000..3aedd4bdfacd4d66552346bec8211efaeff1993c --- /dev/null +++ b/Source/WebCore/platform/wpe/DragImageWPE.cpp @@ -0,0 +1,73 @@ @@ -8590,7 +8789,7 @@ index 0000000000000000000000000000000000000000..e77e6db7a93a9dfcaad3866eb445edf4 + return nullptr; +} + -+DragImageRef createDragImageForLink(Element&, URL&, const String&, TextIndicatorData&, FontRenderingMode, float) ++DragImageRef createDragImageForLink(Element&, URL&, const String&, TextIndicatorData&, float) +{ + notImplemented(); + return nullptr; @@ -8623,7 +8822,7 @@ index bbdd1ce76241d933ada9c43fabae4912cbfa64e1..e6ae01a77350c519b203f6ed2910f638 } diff --git a/Source/WebCore/platform/wpe/SelectionData.cpp b/Source/WebCore/platform/wpe/SelectionData.cpp new file mode 100644 -index 0000000000000000000000000000000000000000..2a461c25464ec787513369527743671d34f56709 +index 0000000000000000000000000000000000000000..463651fa9ccf106a0fdd75db1aa747b4f760c06e --- /dev/null +++ b/Source/WebCore/platform/wpe/SelectionData.cpp @@ -0,0 +1,134 @@ @@ -8684,7 +8883,7 @@ index 0000000000000000000000000000000000000000..2a461c25464ec787513369527743671d + // from the URI list. + bool setURL = hasURL(); + for (auto& line : uriListString.split('\n')) { -+ line = line.stripWhiteSpace(); ++ line = line.stripLeadingAndTrailingCharacters(deprecatedIsSpaceOrNewline); + if (line.isEmpty()) + continue; + if (line[0] == '#') @@ -8850,10 +9049,10 @@ index 0000000000000000000000000000000000000000..cf2b51f6f02837a1106f4d999f2f130e + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp -index fcd984f4ec4646da9cc9920f9447b1ce0e96456d..8fea25dbf3cd74992dd2f3b8907c691f3fe2e6a8 100644 +index 6cf00050808db44c0cca58ee6a10ae617b8d3e1e..4a2bc192b03c8f16c49b469d9f354db8dc8110ed 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp -@@ -212,13 +212,13 @@ void RenderTextControl::layoutExcludedChildren(bool relayoutChildren) +@@ -227,13 +227,13 @@ void RenderTextControl::layoutExcludedChildren(bool relayoutChildren) } } @@ -8869,7 +9068,7 @@ index fcd984f4ec4646da9cc9920f9447b1ce0e96456d..8fea25dbf3cd74992dd2f3b8907c691f { auto innerText = innerTextElement(); diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h -index fac9402820702989bf72ed2425678bfb82bd6523..40b5a6441d22714fd370ce1a7c2f534e6e7510f5 100644 +index 4aec4c8060348ed41d04a1b1b576f15643db4364..801a5515e4fd3f52e48bdb411ae5d028b6ca0700 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -36,9 +36,9 @@ public: @@ -8906,53 +9105,20 @@ index 1d8488e0d36288e09cd5662bd7f770ade95dfee3..dee07f87b47d62d4ef8ede45824bdb2f WorkerOrWorkletGlobalScope& m_globalScope; }; -diff --git a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in -index 2081154f90fac8f7b9f7c6061cf5dc6da1af44b5..e7c6071a6f2e05e76e0fd1cb4661ebd32a5bb3fd 100644 ---- a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in -+++ b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in -@@ -26,13 +26,13 @@ - messages -> WebCookieManager NotRefCounted { - void GetHostnamesWithCookies(PAL::SessionID sessionID) -> (Vector hostnames) - void DeleteCookiesForHostnames(PAL::SessionID sessionID, Vector hostnames) -> () -- void DeleteAllCookies(PAL::SessionID sessionID) -> () - - void SetCookie(PAL::SessionID sessionID, Vector cookie) -> () - void SetCookies(PAL::SessionID sessionID, Vector cookies, URL url, URL mainDocumentURL) -> () - void GetAllCookies(PAL::SessionID sessionID) -> (Vector cookies) - void GetCookies(PAL::SessionID sessionID, URL url) -> (Vector cookies) - void DeleteCookie(PAL::SessionID sessionID, struct WebCore::Cookie cookie) -> () -+ void DeleteAllCookies(PAL::SessionID sessionID) -> () - void DeleteAllCookiesModifiedSince(PAL::SessionID sessionID, WallTime time) -> () - - void SetHTTPCookieAcceptPolicy(enum:uint8_t WebCore::HTTPCookieAcceptPolicy policy) -> () diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp -index 24e9d0eecb5730ad96c625b114b9c7360adcac52..e0b0218bbf37222fc581d19d6ec3f688445aa9c5 100644 +index 242dc0292659abe638dbefc6918bed92c7e436e2..4c9e1af501d24a1c76415443293623ad813e8dbc 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp -@@ -83,6 +83,11 @@ - #include - #include +@@ -88,6 +88,8 @@ -+#if PLATFORM(COCOA) + #if PLATFORM(COCOA) + #include +#include "NetworkDataTaskCocoa.h" +#include "NetworkSessionCocoa.h" -+#endif -+ - #if ENABLE(APPLE_PAY_REMOTE_UI) - #include "WebPaymentCoordinatorProxyMessages.h" - #endif -@@ -486,6 +491,10 @@ void NetworkConnectionToWebProcess::createSocketStream(URL&& url, String cachePa - if (auto* session = networkSession()) - acceptInsecureCertificates = session->shouldAcceptInsecureCertificatesForWebSockets(); #endif -+ if (auto* session = networkSession()) { -+ if (session->ignoreCertificateErrors()) -+ acceptInsecureCertificates = true; -+ } - m_networkSocketStreams.add(identifier, NetworkSocketStream::create(m_networkProcess.get(), WTFMove(url), m_sessionID, cachePartition, identifier, m_connection, WTFMove(token), acceptInsecureCertificates)); - } -@@ -1030,6 +1039,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) + #if ENABLE(APPLE_PAY_REMOTE_UI) +@@ -1023,6 +1025,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) #endif } @@ -8964,41 +9130,41 @@ index 24e9d0eecb5730ad96c625b114b9c7360adcac52..e0b0218bbf37222fc581d19d6ec3f688 + networkStorageSession->setCookiesFromResponse(firstParty, sameSiteInfo, url, setCookieValue); +} + - #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) + #if ENABLE(TRACKING_PREVENTION) void NetworkConnectionToWebProcess::removeStorageAccessForFrame(FrameIdentifier frameID, PageIdentifier pageID) { diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h -index 35deb0171bee03d36acd1abad195e9450a54d6fc..90c118158c336763c98132abdded326d9339d8ff 100644 +index dcf3ed999b0197d99a5ef6217fb13166e5714ac3..9f42dccb69145a9c4f6efbf12e3b25236727a28f 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h -@@ -312,6 +312,8 @@ private: +@@ -313,6 +313,8 @@ private: void clearPageSpecificData(WebCore::PageIdentifier); + void setCookieFromResponse(const URL& firstParty, const WebCore::SameSiteInfo&, const URL& url, const String& setCookieValue); + - #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) + #if ENABLE(TRACKING_PREVENTION) void removeStorageAccessForFrame(WebCore::FrameIdentifier, WebCore::PageIdentifier); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in -index 77597632a0e3f5dbac4ed45312c401496cf2387d..c3861e47242b15234101ca02a83f2766c8220de2 100644 +index 178a5009f929a4a7c0b6d4f6b9ce313fbdf40b9e..812c7288a0efa2c685ed91f1fefaf90997c8de1e 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in -@@ -66,6 +66,8 @@ messages -> NetworkConnectionToWebProcess LegacyReceiver { +@@ -65,6 +65,8 @@ messages -> NetworkConnectionToWebProcess LegacyReceiver { ClearPageSpecificData(WebCore::PageIdentifier pageID); + SetCookieFromResponse(URL firstParty, struct WebCore::SameSiteInfo sameSiteInfo, URL url, String setCookieValue); + - #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) + #if ENABLE(TRACKING_PREVENTION) RemoveStorageAccessForFrame(WebCore::FrameIdentifier frameID, WebCore::PageIdentifier pageID); LogUserInteraction(WebCore::RegistrableDomain domain) diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp -index a85a915ce9223070249618944691ae5f4a701126..3d5560f75f064bba89861789cb7fda4288f67e4f 100644 +index 23f9ba7a180081c95bc6b9810b2e18972788d9d6..6f90e47099c1cc99ae6b6132acd198014e4f9a6b 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkProcess.cpp -@@ -531,6 +531,12 @@ void NetworkProcess::destroySession(PAL::SessionID sessionID) - m_sessionsControlledByAutomation.remove(sessionID); +@@ -633,6 +633,12 @@ void NetworkProcess::registrableDomainsExemptFromWebsiteDataDeletion(PAL::Sessio + completionHandler({ }); } +void NetworkProcess::setIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignore) @@ -9007,14 +9173,14 @@ index a85a915ce9223070249618944691ae5f4a701126..3d5560f75f064bba89861789cb7fda42 + networkSession->setIgnoreCertificateErrors(ignore); +} + - #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) + #if ENABLE(TRACKING_PREVENTION) void NetworkProcess::dumpResourceLoadStatistics(PAL::SessionID sessionID, CompletionHandler&& completionHandler) { diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h -index 79529bec31b56db31d9501f763cb7d0ea0255e71..5a7c9b1982560c226526574033d28af4176ae4a8 100644 +index 1012b158f53e77ab80b6a921290fb8c7bb976391..82bbe98a551f934faaf4cd665b898cfc1ebda480 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkProcess.h -@@ -36,6 +36,7 @@ +@@ -37,6 +37,7 @@ #include "QuotaIncreaseRequestIdentifier.h" #include "RTCDataChannelRemoteManagerProxy.h" #include "SandboxExtension.h" @@ -9022,7 +9188,7 @@ index 79529bec31b56db31d9501f763cb7d0ea0255e71..5a7c9b1982560c226526574033d28af4 #include "WebPageProxyIdentifier.h" #include "WebResourceLoadStatisticsStore.h" #include "WebsiteData.h" -@@ -82,6 +83,7 @@ class SessionID; +@@ -84,6 +85,7 @@ class SessionID; namespace WebCore { class CertificateInfo; @@ -9030,33 +9196,34 @@ index 79529bec31b56db31d9501f763cb7d0ea0255e71..5a7c9b1982560c226526574033d28af4 class CurlProxySettings; class ProtectionSpace; class NetworkStorageSession; -@@ -201,6 +203,8 @@ public: - - void addWebsiteDataStore(WebsiteDataStoreParameters&&); +@@ -207,6 +209,9 @@ public: + void registrableDomainsWithLastAccessedTime(PAL::SessionID, CompletionHandler>)>&&); + void registrableDomainsExemptFromWebsiteDataDeletion(PAL::SessionID, CompletionHandler)>&&); ++ + void setIgnoreCertificateErrors(PAL::SessionID, bool); + - #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) + #if ENABLE(TRACKING_PREVENTION) void clearPrevalentResource(PAL::SessionID, RegistrableDomain&&, CompletionHandler&&); void clearUserInteraction(PAL::SessionID, RegistrableDomain&&, CompletionHandler&&); diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in -index 72b4a17928321402f4234e0fa60f92659d6617a1..fd0a7b05935a13caf102b69ee9ac3548420ff812 100644 +index 1590992ea4d62ac5dd49ef2e29a980a3c028b343..ede7220f254538a870281b07e1673cd04dd44817 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in -@@ -77,6 +77,8 @@ messages -> NetworkProcess LegacyReceiver { +@@ -79,6 +79,8 @@ messages -> NetworkProcess LegacyReceiver { - PreconnectTo(PAL::SessionID sessionID, WebKit::WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, URL url, String userAgent, enum:uint8_t WebCore::StoredCredentialsPolicy storedCredentialsPolicy, enum:bool std::optional isNavigatingToAppBoundDomain, enum:bool WebKit::LastNavigationWasAppInitiated lastNavigationWasAppInitiated); + PreconnectTo(PAL::SessionID sessionID, WebKit::WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, WebCore::ResourceRequest request, enum:uint8_t WebCore::StoredCredentialsPolicy storedCredentialsPolicy, std::optional isNavigatingToAppBoundDomain); + SetIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignoreTLSErrors) + - #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) + #if ENABLE(TRACKING_PREVENTION) ClearPrevalentResource(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () ClearUserInteraction(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () diff --git a/Source/WebKit/NetworkProcess/NetworkSession.h b/Source/WebKit/NetworkProcess/NetworkSession.h -index b60aeda86f298c1501a659af54a6416c04d66afc..ec6a7eeefc50d7fb6a3e32d235546eb5994b0b8c 100644 +index 69fe24f09138eecff8633acfe4a532c73f800187..08d284b8e8462657f2d58ea44777669f322d2002 100644 --- a/Source/WebKit/NetworkProcess/NetworkSession.h +++ b/Source/WebKit/NetworkProcess/NetworkSession.h -@@ -192,6 +192,9 @@ public: +@@ -204,6 +204,9 @@ public: void lowMemoryHandler(WTF::Critical); @@ -9064,9 +9231,9 @@ index b60aeda86f298c1501a659af54a6416c04d66afc..ec6a7eeefc50d7fb6a3e32d235546eb5 + bool ignoreCertificateErrors() { return m_ignoreCertificateErrors; } + #if ENABLE(SERVICE_WORKER) - void addSoftUpdateLoader(std::unique_ptr&& loader) { m_softUpdateLoaders.add(WTFMove(loader)); } void removeSoftUpdateLoader(ServiceWorkerSoftUpdateLoader* loader) { m_softUpdateLoaders.remove(loader); } -@@ -276,6 +279,7 @@ protected: + void addNavigationPreloaderTask(ServiceWorkerFetchTask&); +@@ -320,6 +323,7 @@ protected: bool m_privateClickMeasurementDebugModeEnabled { false }; std::optional m_ephemeralMeasurement; bool m_isRunningEphemeralMeasurementTest { false }; @@ -9075,10 +9242,10 @@ index b60aeda86f298c1501a659af54a6416c04d66afc..ec6a7eeefc50d7fb6a3e32d235546eb5 HashSet> m_keptAliveLoads; diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm -index d8eeb6c27a92134728ffada573a1f140e303c727..9ddddb0796cc00d7eea060b11919711446a39586 100644 +index cfe2b53558564ca9de52c01a2182900960ce1fad..b5a09289d597cf2af265ee357be4749c98de1561 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm -@@ -720,7 +720,7 @@ void NetworkSessionCocoa::setClientAuditToken(const WebCore::AuthenticationChall +@@ -751,7 +751,7 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didRece if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { sessionCocoa->setClientAuditToken(challenge); @@ -9087,7 +9254,7 @@ index d8eeb6c27a92134728ffada573a1f140e303c727..9ddddb0796cc00d7eea060b119197114 return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); NSURLSessionTaskTransactionMetrics *metrics = task._incompleteTaskMetrics.transactionMetrics.lastObject; -@@ -964,6 +964,13 @@ ALLOW_DEPRECATED_DECLARATIONS_END +@@ -1092,6 +1092,13 @@ ALLOW_DEPRECATED_DECLARATIONS_END resourceResponse.setDeprecatedNetworkLoadMetrics(WebCore::copyTimingData(taskMetrics, networkDataTask->networkLoadMetrics())); @@ -9102,27 +9269,90 @@ index d8eeb6c27a92134728ffada573a1f140e303c727..9ddddb0796cc00d7eea060b119197114 #if !LOG_DISABLED LOG(NetworkSession, "%llu didReceiveResponse completionHandler (%d)", taskIdentifier, policyAction); diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp -index d1fac29ff7fb628b8994642eb9b7a35cad9ad37f..5f2068c1d6deff4792d974714d75b204958e9a42 100644 +index ed3b63e49436fa7d84a07cf6bd2d1042b75c5833..20484b326d23b5eac610cf2da37e9623655cb8eb 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp -@@ -84,6 +84,8 @@ NetworkDataTaskCurl::NetworkDataTaskCurl(NetworkSession& session, NetworkDataTas - m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); - m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); +@@ -85,12 +85,20 @@ NetworkDataTaskCurl::NetworkDataTaskCurl(NetworkSession& session, NetworkDataTas + #endif + restrictRequestReferrerToOriginIfNeeded(request); + +- m_curlRequest = createCurlRequest(WTFMove(request)); +- if (!m_initialCredential.isEmpty()) { +- m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); +- m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); ++ if (request.url().protocolIsData()) { ++ DataURLDecoder::decode(request.url(), { }, [this, protectedThis = Ref { *this }](auto decodeResult) mutable { ++ didReadDataURL(WTFMove(decodeResult)); ++ }); ++ } else { ++ m_curlRequest = createCurlRequest(WTFMove(request)); ++ if (!m_initialCredential.isEmpty()) { ++ m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); ++ m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); ++ } ++ if (m_session->ignoreCertificateErrors()) ++ m_curlRequest->disableServerTrustEvaluation(); ++ m_curlRequest->start(); } -+ if (m_session->ignoreCertificateErrors()) -+ m_curlRequest->disableServerTrustEvaluation(); - m_curlRequest->start(); +- m_curlRequest->start(); } -@@ -160,6 +162,7 @@ void NetworkDataTaskCurl::curlDidReceiveResponse(CurlRequest& request, CurlRespo - m_response = ResourceResponse(receivedResponse); - m_response.setCertificateInfo(WTFMove(receivedResponse.certificateInfo)); + NetworkDataTaskCurl::~NetworkDataTaskCurl() +@@ -167,6 +175,7 @@ void NetworkDataTaskCurl::curlDidReceiveResponse(CurlRequest& request, CurlRespo + + updateNetworkLoadMetrics(receivedResponse.networkLoadMetrics); m_response.setDeprecatedNetworkLoadMetrics(Box::create(WTFMove(receivedResponse.networkLoadMetrics))); + m_response.m_httpRequestHeaderFields = request.resourceRequest().httpHeaderFields(); handleCookieHeaders(request.resourceRequest(), receivedResponse); -@@ -386,6 +389,8 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection() +@@ -284,6 +293,36 @@ bool NetworkDataTaskCurl::shouldRedirectAsGET(const ResourceRequest& request, bo + return false; + } + ++void NetworkDataTaskCurl::didReadDataURL(std::optional&& result) ++{ ++ if (state() == State::Canceling || state() == State::Completed) ++ return; ++ ++ m_dataURLResult = WTFMove(result); ++ m_response = ResourceResponse::dataURLResponse(firstRequest().url(), m_dataURLResult.value()); ++ invokeDidReceiveResponse(); ++} ++ ++void NetworkDataTaskCurl::downloadDataURL(Download& download) ++{ ++ if (!m_dataURLResult) { ++ deleteDownloadFile(); ++ download.didFail(internalError(firstRequest().url()), IPC::DataReference()); ++ return; ++ } ++ ++ if (-1 == FileSystem::writeToFile(m_downloadDestinationFile, static_cast(m_dataURLResult.value().data.data()), m_dataURLResult.value().data.size())) { ++ deleteDownloadFile(); ++ download.didFail(ResourceError(CURLE_WRITE_ERROR, m_response.url()), IPC::DataReference()); ++ return; ++ } ++ ++ download.didReceiveData(m_dataURLResult.value().data.size(), 0, 0); ++ FileSystem::closeFile(m_downloadDestinationFile); ++ m_downloadDestinationFile = FileSystem::invalidPlatformFileHandle; ++ download.didFinish(); ++} ++ + void NetworkDataTaskCurl::invokeDidReceiveResponse() + { + didReceiveResponse(ResourceResponse(m_response), NegotiatedLegacyTLS::No, PrivateRelayed::No, [this, protectedThis = Ref { *this }](PolicyAction policyAction) { +@@ -314,6 +353,8 @@ void NetworkDataTaskCurl::invokeDidReceiveResponse() + downloadPtr->didCreateDestination(m_pendingDownloadLocation); + if (m_curlRequest) + m_curlRequest->completeDidReceiveResponse(); ++ else if (firstRequest().url().protocolIsData()) ++ downloadDataURL(*downloadPtr); + break; + } + default: +@@ -397,6 +438,8 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection() m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); } @@ -9131,13 +9361,53 @@ index d1fac29ff7fb628b8994642eb9b7a35cad9ad37f..5f2068c1d6deff4792d974714d75b204 m_curlRequest->start(); if (m_state != State::Suspended) { +diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h +index 17131dda438f96bf4f9d9702248c5de61c51fc72..247605032eef3dcefe472f6fee413ad332c1e42f 100644 +--- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h ++++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h +@@ -28,6 +28,7 @@ + #include "NetworkDataTask.h" + #include "NetworkLoadParameters.h" + #include ++#include + #include + #include + #include +@@ -43,6 +44,8 @@ class SharedBuffer; + + namespace WebKit { + ++class Download; ++ + class NetworkDataTaskCurl final : public NetworkDataTask, public WebCore::CurlRequestClient { + public: + static Ref create(NetworkSession& session, NetworkDataTaskClient& client, const NetworkLoadParameters& parameters) +@@ -75,6 +78,9 @@ private: + void curlDidComplete(WebCore::CurlRequest&, WebCore::NetworkLoadMetrics&&) override; + void curlDidFailWithError(WebCore::CurlRequest&, WebCore::ResourceError&&, WebCore::CertificateInfo&&) override; + ++ void didReadDataURL(std::optional&&); ++ void downloadDataURL(Download&); ++ + void invokeDidReceiveResponse(); + + bool shouldRedirectAsGET(const WebCore::ResourceRequest&, bool crossOrigin); +@@ -111,6 +117,8 @@ private: + unsigned m_redirectCount { 0 }; + unsigned m_authFailureCount { 0 }; + ++ std::optional m_dataURLResult; ++ + FileSystem::PlatformFileHandle m_downloadDestinationFile { FileSystem::invalidPlatformFileHandle }; + + bool m_blockingCookies { false }; diff --git a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp -index 892d1b2541e218047c33e88a207aa56e36b7e6bc..04bf128418cce29926d53c1af682485f4162ba03 100644 +index c0e5e8654fac24ea968398bcd8008e35ccea02fd..7b8c41d0ebcef34d7ad5b6004075a219a7db9c22 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp -@@ -61,7 +61,7 @@ NetworkSessionCurl::~NetworkSessionCurl() +@@ -66,7 +66,7 @@ void NetworkSessionCurl::clearAlternativeServices(WallTime) - std::unique_ptr NetworkSessionCurl::createWebSocketTask(WebPageProxyIdentifier, NetworkSocketChannel& channel, const WebCore::ResourceRequest& request, const String& protocol, const WebCore::ClientOrigin&, bool) + std::unique_ptr NetworkSessionCurl::createWebSocketTask(WebPageProxyIdentifier, NetworkSocketChannel& channel, const WebCore::ResourceRequest& request, const String& protocol, const WebCore::ClientOrigin&, bool, bool, OptionSet) { - return makeUnique(channel, request, protocol); + return makeUnique(channel, request, protocol, ignoreCertificateErrors()); @@ -9145,10 +9415,10 @@ index 892d1b2541e218047c33e88a207aa56e36b7e6bc..04bf128418cce29926d53c1af682485f } // namespace WebKit diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp -index 2c14f606108b1942a5a84ddc833055bea95a37d3..d14839aef6cfca76c3f385651bc3ef3c5af951b2 100644 +index 40e466a49926c304695e0e86c57fbfeef80ceec1..3210765c6a8327b17849530cf13808c187b667ea 100644 --- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp -@@ -33,7 +33,7 @@ +@@ -34,7 +34,7 @@ namespace WebKit { @@ -9157,7 +9427,7 @@ index 2c14f606108b1942a5a84ddc833055bea95a37d3..d14839aef6cfca76c3f385651bc3ef3c : m_channel(channel) , m_request(request.isolatedCopy()) , m_protocol(protocol) -@@ -42,7 +42,7 @@ WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, const WebCore::Resou +@@ -43,7 +43,7 @@ WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, const WebCore::Resou if (request.url().protocolIs("wss"_s) && WebCore::DeprecatedGlobalSettings::allowsAnySSLCertificate()) WebCore::CurlContext::singleton().sslHandle().setIgnoreSSLErrors(true); @@ -9167,10 +9437,10 @@ index 2c14f606108b1942a5a84ddc833055bea95a37d3..d14839aef6cfca76c3f385651bc3ef3c } diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h -index 2027a4b929fda90b34f46bf563846ca8d4553829..34bfbb236d5f16c8bb34920a2bb01c048d63ab5f 100644 +index c2e60f5ec6766e485996764bc240c18e8e747d85..20eb908199ea8735d38dfb27985fa2f3f8136181 100644 --- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h +++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h -@@ -45,7 +45,7 @@ struct SessionSet; +@@ -47,7 +47,7 @@ struct SessionSet; class WebSocketTask : public CanMakeWeakPtr, public WebCore::CurlStream::Client { WTF_MAKE_FAST_ALLOCATED; public: @@ -9180,10 +9450,10 @@ index 2027a4b929fda90b34f46bf563846ca8d4553829..34bfbb236d5f16c8bb34920a2bb01c04 void sendString(const IPC::DataReference&, CompletionHandler&&); diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp -index fb70fe2e30abc45508eac1ff7b6fa5b576c22917..6d6404a9fdacf1f5c5f108b860e0e577856b6bf3 100644 +index f2102d9dc78f9f51fc0e6dfb47564a29d7c1e2e2..f62c991b391a281aad8236f71234278081cac77e 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp -@@ -494,6 +494,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr&& inputStream) +@@ -471,6 +471,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr&& inputStream) m_networkLoadMetrics.failsTAOCheck = !passesTimingAllowOriginCheck(m_response, *origin); } @@ -9192,7 +9462,7 @@ index fb70fe2e30abc45508eac1ff7b6fa5b576c22917..6d6404a9fdacf1f5c5f108b860e0e577 dispatchDidReceiveResponse(); } -@@ -591,6 +593,8 @@ bool NetworkDataTaskSoup::acceptCertificate(GTlsCertificate* certificate, GTlsCe +@@ -568,6 +570,8 @@ bool NetworkDataTaskSoup::acceptCertificate(GTlsCertificate* certificate, GTlsCe { ASSERT(m_soupMessage); URL url = soupURIToURL(soup_message_get_uri(m_soupMessage.get())); @@ -9202,7 +9472,7 @@ index fb70fe2e30abc45508eac1ff7b6fa5b576c22917..6d6404a9fdacf1f5c5f108b860e0e577 if (!error) return true; diff --git a/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp -index ddb157400854dd30878a15879cd3b8c2c13f436f..9e952998a139b84ccb80f7e756343e4b1a49efcc 100644 +index 7726f1ad59430f11a11bbec0300fcc86b4654e41..cdccb0f1d72c5350b5eebc197eeae8f55119c932 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp @@ -109,6 +109,11 @@ static gboolean webSocketAcceptCertificateCallback(GTlsConnection* connection, G @@ -9230,7 +9500,7 @@ index ddb157400854dd30878a15879cd3b8c2c13f436f..9e952998a139b84ccb80f7e756343e4b + g_signal_connect(connection, "accept-certificate", G_CALLBACK(webSocketAcceptCertificateCallbackIgnoreTLSErrors), soupMessage); +} + - std::unique_ptr NetworkSessionSoup::createWebSocketTask(WebPageProxyIdentifier, NetworkSocketChannel& channel, const ResourceRequest& request, const String& protocol, const ClientOrigin&, bool) + std::unique_ptr NetworkSessionSoup::createWebSocketTask(WebPageProxyIdentifier, NetworkSocketChannel& channel, const ResourceRequest& request, const String& protocol, const ClientOrigin&, bool, bool, OptionSet) { GRefPtr soupMessage = request.createSoupMessage(blobRegistry()); @@ -127,14 +141,21 @@ std::unique_ptr NetworkSessionSoup::createWebSocketTask(WebPagePr @@ -9263,10 +9533,10 @@ index ddb157400854dd30878a15879cd3b8c2c13f436f..9e952998a139b84ccb80f7e756343e4b } return makeUnique(channel, request, soupSession(), soupMessage.get(), protocol); diff --git a/Source/WebKit/PlatformGTK.cmake b/Source/WebKit/PlatformGTK.cmake -index 0f5355b305602e855195c8832b5671f91f43f819..8dcae8e77dc5c08b5deca8ed8eadff9f90ae7cd3 100644 +index 5a85b8fd3f11e32d4cac091c3495c2a994f8a707..f81aebc35471525dd320e715e0e6d7988dfa0469 100644 --- a/Source/WebKit/PlatformGTK.cmake +++ b/Source/WebKit/PlatformGTK.cmake -@@ -489,6 +489,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES +@@ -307,6 +307,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GSTREAMER_PBUTILS_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} @@ -9275,8 +9545,8 @@ index 0f5355b305602e855195c8832b5671f91f43f819..8dcae8e77dc5c08b5deca8ed8eadff9f +# Playwright end ) - if (USE_WPE_RENDERER) -@@ -530,6 +533,9 @@ if (USE_LIBWEBRTC) + list(APPEND WebKit_INTERFACE_INCLUDE_DIRECTORIES +@@ -353,6 +356,9 @@ if (USE_LIBWEBRTC) list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES "${THIRDPARTY_DIR}/libwebrtc/Source/" "${THIRDPARTY_DIR}/libwebrtc/Source/webrtc" @@ -9286,8 +9556,8 @@ index 0f5355b305602e855195c8832b5671f91f43f819..8dcae8e77dc5c08b5deca8ed8eadff9f ) endif () -@@ -544,6 +550,12 @@ if (ENABLE_MEDIA_STREAM) - ) +@@ -396,6 +402,12 @@ else () + set(WebKitGTK_ENUM_HEADER_TEMPLATE ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitEnumTypesGtk3.h.in) endif () +# Playwright begin @@ -9297,29 +9567,29 @@ index 0f5355b305602e855195c8832b5671f91f43f819..8dcae8e77dc5c08b5deca8ed8eadff9f +# Playwright end + # To generate WebKitEnumTypes.h we want to use all installed headers, except WebKitEnumTypes.h itself. - set(WebKit2GTK_ENUM_GENERATION_HEADERS ${WebKit2GTK_INSTALLED_HEADERS}) - list(REMOVE_ITEM WebKit2GTK_ENUM_GENERATION_HEADERS ${WebKit2Gtk_DERIVED_SOURCES_DIR}/webkit/WebKitEnumTypes.h) + set(WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_INSTALLED_HEADERS}) + list(REMOVE_ITEM WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_DERIVED_SOURCES_DIR}/webkit/WebKitEnumTypes.h) diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake -index 10230e9bd3d4b5afc507178e35a61a9c84624238..d9d1becc4a0b801c06f25e194cac662f96b47576 100644 +index 783f72ed591d3a68426a8fd90f311f75ebc0b54d..9c2c707d61f1f71170a7bfb76b0e36318e012ddf 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake -@@ -197,6 +197,7 @@ set(WPE_API_INSTALLED_HEADERS - ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitOptionMenuItem.h - ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPermissionRequest.h - ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPlugin.h +@@ -203,6 +203,7 @@ set(WPE_API_INSTALLED_HEADERS + ${DERIVED_SOURCES_WPE_API_DIR}/WebKitEnumTypes.h + ${DERIVED_SOURCES_WPE_API_DIR}/WebKitVersion.h + ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitColor.h + ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPointerLockPermissionRequest.h - ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitPolicyDecision.h ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitRectangle.h - ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitResponsePolicyDecision.h -@@ -326,6 +327,7 @@ list(APPEND WebKit_INCLUDE_DIRECTORIES - "${WEBKIT_DIR}/UIProcess/Inspector/glib" + ${WEBKIT_DIR}/UIProcess/API/wpe/WebKitWebViewBackend.h + ) +@@ -367,6 +368,7 @@ list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES + "${WEBKIT_DIR}/UIProcess/Launcher/libwpe" "${WEBKIT_DIR}/UIProcess/Notifications/glib/" "${WEBKIT_DIR}/UIProcess/geoclue" + "${WEBKIT_DIR}/UIProcess/glib" "${WEBKIT_DIR}/UIProcess/gstreamer" "${WEBKIT_DIR}/UIProcess/linux" "${WEBKIT_DIR}/UIProcess/soup" -@@ -347,8 +349,17 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES +@@ -390,8 +392,17 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GIO_UNIX_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} @@ -9338,10 +9608,10 @@ index 10230e9bd3d4b5afc507178e35a61a9c84624238..d9d1becc4a0b801c06f25e194cac662f Cairo::Cairo Freetype::Freetype diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake -index feb39b35c1bd873c646da76aa762e40680f96533..9188b2fd6561727504fb5f14185d00d245cc98cf 100644 +index ba7b7c9343e98d06f7479b9631977f122c476fa5..23c91e860e93380a77d3719fba1ccc85aa61a7a2 100644 --- a/Source/WebKit/PlatformWin.cmake +++ b/Source/WebKit/PlatformWin.cmake -@@ -64,8 +64,12 @@ list(APPEND WebKit_SOURCES +@@ -91,8 +91,12 @@ list(APPEND WebKit_SOURCES UIProcess/wc/DrawingAreaProxyWC.cpp @@ -9354,16 +9624,19 @@ index feb39b35c1bd873c646da76aa762e40680f96533..9188b2fd6561727504fb5f14185d00d2 UIProcess/win/WebPageProxyWin.cpp UIProcess/win/WebPopupMenuProxyWin.cpp UIProcess/win/WebProcessPoolWin.cpp -@@ -84,6 +88,7 @@ list(APPEND WebKit_SOURCES - WebProcess/MediaCache/WebMediaKeyStorageManager.cpp +@@ -113,6 +117,7 @@ list(APPEND WebKit_SOURCES + WebProcess/WebCoreSupport/curl/WebFrameNetworkingContext.cpp WebProcess/WebCoreSupport/win/WebPopupMenuWin.cpp + WebProcess/WebCoreSupport/win/WebDragClientWin.cpp WebProcess/WebPage/AcceleratedSurface.cpp -@@ -137,6 +142,72 @@ list(APPEND WebKit_MESSAGES_IN_FILES - GPUProcess/graphics/wc/RemoteWCLayerTreeHost +@@ -173,8 +178,84 @@ list(APPEND WebKit_MESSAGES_IN_FILES + + list(APPEND WebKit_PRIVATE_LIBRARIES + comctl32 ++ ${LIBVPX_CUSTOM_LIBRARY} ) +# Playwright begin @@ -9376,7 +9649,7 @@ index feb39b35c1bd873c646da76aa762e40680f96533..9188b2fd6561727504fb5f14185d00d2 + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" +) + -+list(APPEND WebKit_SOURCES ++set(vpxutils_SOURCES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvwriter.cc" @@ -9430,19 +9703,20 @@ index feb39b35c1bd873c646da76aa762e40680f96533..9188b2fd6561727504fb5f14185d00d2 + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/video_common.cc" +) ++ ++add_library(vpxutils STATIC ${vpxutils_SOURCES}) ++ ++target_include_directories(vpxutils PRIVATE ++ "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" ++ "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" ++) ++ ++target_link_libraries(WebKit PRIVATE vpxutils) +# Playwright end + - set(WebKitCommonIncludeDirectories ${WebKit_INCLUDE_DIRECTORIES}) - set(WebKitCommonSystemIncludeDirectories ${WebKit_SYSTEM_INCLUDE_DIRECTORIES}) - -@@ -197,6 +268,7 @@ if (${WTF_PLATFORM_WIN_CAIRO}) - OpenSSL::SSL - mfuuid.lib - strmiids.lib -+ ${LIBVPX_CUSTOM_LIBRARY} - ) - endif () - + list(APPEND WebProcess_SOURCES + WebProcess/EntryPoint/win/WebProcessMain.cpp + ) diff --git a/Source/WebKit/Shared/API/c/wpe/WebKit.h b/Source/WebKit/Shared/API/c/wpe/WebKit.h index caf67e1dece5b727e43eba780e70814f8fdb0f63..740150d2589d6e16a516daa3bf6ef899ac538c99 100644 --- a/Source/WebKit/Shared/API/c/wpe/WebKit.h @@ -9456,7 +9730,7 @@ index caf67e1dece5b727e43eba780e70814f8fdb0f63..740150d2589d6e16a516daa3bf6ef899 #include #include diff --git a/Source/WebKit/Shared/NativeWebKeyboardEvent.h b/Source/WebKit/Shared/NativeWebKeyboardEvent.h -index ee8cac1c980039c4a36de5501ab7f135e710d06b..deae2be9e720ff76186ecea89920dfc39c4f186a 100644 +index 7164af8d347828ba80bcb52fd6ca814401157f2b..9ba0e32717d9b4cb01f3f43898aa402ad0bd6913 100644 --- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h +++ b/Source/WebKit/Shared/NativeWebKeyboardEvent.h @@ -33,6 +33,7 @@ @@ -9467,20 +9741,20 @@ index ee8cac1c980039c4a36de5501ab7f135e710d06b..deae2be9e720ff76186ecea89920dfc3 #endif #if PLATFORM(GTK) -@@ -65,19 +66,35 @@ public: +@@ -66,19 +67,35 @@ public: #if USE(APPKIT) // FIXME: Share iOS's HandledByInputMethod enum here instead of passing a boolean. NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, bool replacesSoftSpace, const Vector&); -+ NativeWebKeyboardEvent(Type type, 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 modifiers, WallTime timestamp, Vector&& commands) ++ NativeWebKeyboardEvent(WebEventType type, 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 modifiers, WallTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands)) + { + } #elif PLATFORM(GTK) NativeWebKeyboardEvent(const NativeWebKeyboardEvent&); - NativeWebKeyboardEvent(GdkEvent*, const String&, Vector&& commands); + NativeWebKeyboardEvent(GdkEvent*, const String&, bool isAutoRepeat, Vector&& commands); NativeWebKeyboardEvent(const String&, std::optional>&&, std::optional&&); - NativeWebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, Vector&& commands, bool isKeypad, OptionSet); -+ NativeWebKeyboardEvent(Type type, 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 modifiers, WallTime timestamp, Vector&& commands) + NativeWebKeyboardEvent(WebEventType, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, Vector&& commands, bool isAutoRepeat, bool isKeypad, OptionSet); ++ NativeWebKeyboardEvent(WebEventType type, 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 modifiers, WallTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands)) + { + } @@ -9489,14 +9763,14 @@ index ee8cac1c980039c4a36de5501ab7f135e710d06b..deae2be9e720ff76186ecea89920dfc3 NativeWebKeyboardEvent(::WebEvent *, HandledByInputMethod); #elif USE(LIBWPE) enum class HandledByInputMethod : bool { No, Yes }; - NativeWebKeyboardEvent(struct wpe_input_keyboard_event*, const String&, HandledByInputMethod, std::optional>&&, std::optional&&); -+ NativeWebKeyboardEvent(Type type, 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 modifiers, WallTime timestamp) + NativeWebKeyboardEvent(struct wpe_input_keyboard_event*, const String&, bool isAutoRepeat, HandledByInputMethod, std::optional>&&, std::optional&&); ++ NativeWebKeyboardEvent(WebEventType type, 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 modifiers, WallTime timestamp) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp) + { + } #elif PLATFORM(WIN) NativeWebKeyboardEvent(HWND, UINT message, WPARAM, LPARAM, Vector&& pendingCharEvents); -+ NativeWebKeyboardEvent(Type type, 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 modifiers, WallTime timestamp) ++ NativeWebKeyboardEvent(WebEventType type, 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 modifiers, WallTime timestamp) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp) + { + } @@ -9504,26 +9778,26 @@ index ee8cac1c980039c4a36de5501ab7f135e710d06b..deae2be9e720ff76186ecea89920dfc3 #if USE(APPKIT) diff --git a/Source/WebKit/Shared/NativeWebMouseEvent.h b/Source/WebKit/Shared/NativeWebMouseEvent.h -index fef57e34be6ed7592187c3e1fd73c989bf79da1a..e35612e9b88877627802df18e9084e7f4022e629 100644 +index c586d2775021a9e164dc36b1732e1a2dadc986a0..ffb79428fe2de5af626bf3a9ad49545380a8e85d 100644 --- a/Source/WebKit/Shared/NativeWebMouseEvent.h +++ b/Source/WebKit/Shared/NativeWebMouseEvent.h -@@ -78,6 +78,11 @@ public: +@@ -79,6 +79,11 @@ public: NativeWebMouseEvent(HWND, UINT message, WPARAM, LPARAM, bool); #endif +#if PLATFORM(GTK) || USE(LIBWPE) || PLATFORM(WIN) -+ NativeWebMouseEvent(Type type, Button button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet modifiers, WallTime timestamp) -+ : WebMouseEvent(type, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount, modifiers, timestamp) { } ++ 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 modifiers, WallTime timestamp) ++ : WebMouseEvent({type, modifiers, timestamp}, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount) { } +#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 f2f3979fcac9dfd97d0e0ead600fe35eb8defd40..ac91412e1a96bdf521b1890a66e465dc54293d31 100644 +index 072a1f359bd50060da6a347fa06b72d89086825d..ca1b11ccc6241dfc3948910115df966b742d1af8 100644 --- a/Source/WebKit/Shared/NativeWebWheelEvent.h +++ b/Source/WebKit/Shared/NativeWebWheelEvent.h -@@ -67,7 +67,8 @@ public: +@@ -65,7 +65,8 @@ public: #elif PLATFORM(WIN) NativeWebWheelEvent(HWND, UINT message, WPARAM, LPARAM); #endif @@ -9533,12 +9807,25 @@ index f2f3979fcac9dfd97d0e0ead600fe35eb8defd40..ac91412e1a96bdf521b1890a66e465dc #if USE(APPKIT) NSEvent* nativeEvent() const { return m_nativeEvent.get(); } #elif PLATFORM(GTK) +diff --git a/Source/WebKit/Shared/Pasteboard.serialization.in b/Source/WebKit/Shared/Pasteboard.serialization.in +index 72ad2880160a374e8fa663e561d59becf9d2f36d..372ae6953199245fe4fc55a49813c7cae868f8b3 100644 +--- a/Source/WebKit/Shared/Pasteboard.serialization.in ++++ b/Source/WebKit/Shared/Pasteboard.serialization.in +@@ -75,7 +75,7 @@ header: + #if PLATFORM(MAC) + String userVisibleForm + #endif +-#if PLATFORM(GTK) ++#if PLATFORM(GTK) || PLATFORM(WPE) + String markup + #endif + }; diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp -index d8d0a639b6578d384f483ef636d3e16c51fe98fe..9cffd80bfdb19d6b131a393cc56755efb325599c 100644 +index c69d19020998f5897dc0041c4c5c45784ffebb90..cf2a613f6469d8153826ce1ac6c5a8f4733f6c2a 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp -@@ -124,6 +124,10 @@ - #include +@@ -192,6 +192,10 @@ + #include #endif +#if PLATFORM(WPE) @@ -9548,88 +9835,30 @@ index d8d0a639b6578d384f483ef636d3e16c51fe98fe..9cffd80bfdb19d6b131a393cc56755ef // FIXME: Seems like we could use std::tuple to cut down the code below a lot! namespace IPC { -@@ -1298,6 +1302,9 @@ void ArgumentCoder::encode(Encoder& encoder, const WindowFeature - encoder << windowFeatures.resizable; - encoder << windowFeatures.fullscreen; - encoder << windowFeatures.dialog; -+ encoder << windowFeatures.noopener; -+ encoder << windowFeatures.noreferrer; -+ encoder << windowFeatures.additionalFeatures; - } - - bool ArgumentCoder::decode(Decoder& decoder, WindowFeatures& windowFeatures) -@@ -1326,6 +1333,12 @@ bool ArgumentCoder::decode(Decoder& decoder, WindowFeatures& win - return false; - if (!decoder.decode(windowFeatures.dialog)) - return false; -+ if (!decoder.decode(windowFeatures.noopener)) -+ return false; -+ if (!decoder.decode(windowFeatures.noreferrer)) -+ return false; -+ if (!decoder.decode(windowFeatures.additionalFeatures)) -+ return false; - return true; - } - -@@ -1339,6 +1352,11 @@ void ArgumentCoder::encode(Encoder& encoder, const DragData& dragData) +diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +index fc050ff2eec654ad1c5319ba35fe2e00bb003140..b14c129107e868daa7a536be543cd2b78148f422 100644 +--- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in ++++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +@@ -1929,6 +1929,9 @@ class WebCore::AuthenticationChallenge { + class WebCore::DragData { #if PLATFORM(COCOA) - encoder << dragData.pasteboardName(); - encoder << dragData.fileNames(); + String pasteboardName(); +#endif +#if PLATFORM(WIN) -+ DragData dragDataCopy = dragData; -+ HashMap> hash = dragDataCopy.dragDataMap(); -+ encoder << hash; ++ WebCore::DragDataMap dragDataMap(); #endif - encoder << dragData.dragDestinationActionMask(); - encoder << dragData.pageID(); -@@ -1362,9 +1380,16 @@ bool ArgumentCoder::decode(Decoder& decoder, DragData& dragData) - if (!decoder.decode(applicationFlags)) - return false; - -+#if PLATFORM(WIN) -+ DragDataMap dragDataMap; -+ if (!decoder.decode(dragDataMap)) -+ return false; -+#else - String pasteboardName; -- Vector fileNames; -+#endif -+ - #if PLATFORM(COCOA) -+ Vector fileNames; - if (!decoder.decode(pasteboardName)) - return false; - -@@ -1380,8 +1405,14 @@ bool ArgumentCoder::decode(Decoder& decoder, DragData& dragData) - if (!decoder.decode(pageID)) - return false; - -+#if PLATFORM(WIN) -+ dragData = DragData(dragDataMap, clientPosition, globalPosition, draggingSourceOperationMask, applicationFlags, pageID); -+#else - dragData = DragData(pasteboardName, clientPosition, globalPosition, draggingSourceOperationMask, applicationFlags, dragDestinationActionMask, pageID); -+#endif -+#if PLATFORM(COCOA) - dragData.setFileNames(fileNames); -+#endif - - return true; - } -diff --git a/Source/WebKit/Shared/WebEvent.h b/Source/WebKit/Shared/WebEvent.h -index 3ae6504779d3917a79f69f32b58260afeda270b4..72d44c33953cc13bf2ed7c762b4f9a7b88571b56 100644 ---- a/Source/WebKit/Shared/WebEvent.h -+++ b/Source/WebKit/Shared/WebEvent.h -@@ -31,6 +31,7 @@ - - #include - #include -+#include - #include - #include - + WebCore::IntPoint clientPosition(); + WebCore::IntPoint globalPosition(); +@@ -2427,6 +2430,7 @@ enum class WebCore::ResourceLoadPriority : uint8_t { + AtomString m_httpStatusText; + AtomString m_httpVersion; + WebCore::HTTPHeaderMap m_httpHeaderFields; ++ WebCore::HTTPHeaderMap m_httpRequestHeaderFields; + Box m_networkLoadMetrics; + + short m_httpStatusCode; diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp -index 3679736973ebc06771c7d94591909688f28a70b4..8df0a8e223551e2ee73e816adcb3b31153c54eb5 100644 +index a80efd294086ea1bd3b1e9dc805491ff5230962f..17d9d5461ae47a122160f10b7fdcb662f06bea7a 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.cpp +++ b/Source/WebKit/Shared/WebKeyboardEvent.cpp @@ -35,6 +35,7 @@ WebKeyboardEvent::WebKeyboardEvent() @@ -9639,12 +9868,12 @@ index 3679736973ebc06771c7d94591909688f28a70b4..8df0a8e223551e2ee73e816adcb3b311 + #if USE(APPKIT) - WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector& commands, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) -@@ -56,6 +57,24 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& - ASSERT(isKeyboardEventType(type)); + WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector& commands, bool isAutoRepeat, bool isKeypad, bool isSystemKey) +@@ -56,6 +57,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S + ASSERT(isKeyboardEventType(type())); } -+WebKeyboardEvent::WebKeyboardEvent(Type type, 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 modifiers, WallTime timestamp, Vector&& commands) ++WebKeyboardEvent::WebKeyboardEvent(WebEventType type, 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 modifiers, WallTime timestamp, Vector&& commands) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) @@ -9664,12 +9893,12 @@ index 3679736973ebc06771c7d94591909688f28a70b4..8df0a8e223551e2ee73e816adcb3b311 + #elif PLATFORM(GTK) - WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&& preeditUnderlines, std::optional&& preeditSelectionRange, Vector&& commands, bool isKeypad, OptionSet modifiers, WallTime timestamp) -@@ -79,6 +98,24 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& - ASSERT(isKeyboardEventType(type)); + WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&& preeditUnderlines, std::optional&& preeditSelectionRange, Vector&& commands, bool isAutoRepeat, bool isKeypad) +@@ -79,6 +98,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S + ASSERT(isKeyboardEventType(type())); } -+WebKeyboardEvent::WebKeyboardEvent(Type type, 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 modifiers, WallTime timestamp, Vector&& commands) ++WebKeyboardEvent::WebKeyboardEvent(WebEventType type, 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 modifiers, WallTime timestamp, Vector&& commands) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) @@ -9689,14 +9918,14 @@ index 3679736973ebc06771c7d94591909688f28a70b4..8df0a8e223551e2ee73e816adcb3b311 + #elif PLATFORM(IOS_FAMILY) - WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) -@@ -142,6 +179,27 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& + WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey) +@@ -142,6 +179,27 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S #endif +#if PLATFORM(WIN) || USE(LIBWPE) + -+WebKeyboardEvent::WebKeyboardEvent(Type type, 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 modifiers, WallTime timestamp) ++WebKeyboardEvent::WebKeyboardEvent(WebEventType type, 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 modifiers, WallTime timestamp) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) @@ -9719,45 +9948,45 @@ index 3679736973ebc06771c7d94591909688f28a70b4..8df0a8e223551e2ee73e816adcb3b311 { } diff --git a/Source/WebKit/Shared/WebKeyboardEvent.h b/Source/WebKit/Shared/WebKeyboardEvent.h -index 1817691d3e12ddec8169248c791826cc13b057e3..cdc90eda23ed5ba20ee78a02c0dd632be4bc615a 100644 +index 7840e34e303873e771150f242f57e621ebbb78a3..c3cea2e0506bcf5c25815b06d35dbdb5dc58edb7 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.h +++ b/Source/WebKit/Shared/WebKeyboardEvent.h @@ -43,14 +43,18 @@ public: #if USE(APPKIT) - WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector&, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); -+ WebKeyboardEvent(Type, 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, WallTime timestamp, Vector&& commands); + WebKeyboardEvent(WebEvent&&, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector&, bool isAutoRepeat, bool isKeypad, bool isSystemKey); ++ 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, WallTime timestamp, Vector&& commands); #elif PLATFORM(GTK) - WebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&&, std::optional&&, Vector&& commands, bool isKeypad, OptionSet, WallTime timestamp); -+ WebKeyboardEvent(Type, 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, WallTime timestamp, Vector&& commands); + WebKeyboardEvent(WebEvent&&, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&&, std::optional&&, Vector&& commands, bool isAutoRepeat, bool isKeypad); ++ 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, WallTime timestamp, Vector&& commands); #elif PLATFORM(IOS_FAMILY) - WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); + WebKeyboardEvent(WebEvent&&, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey); #elif USE(LIBWPE) - WebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&&, std::optional&&, bool isKeypad, OptionSet, WallTime timestamp); -+ WebKeyboardEvent(Type, 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, WallTime timestamp); + WebKeyboardEvent(WebEvent&&, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&&, std::optional&&, bool isAutoRepeat, bool isKeypad); ++ 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, WallTime timestamp); #else - WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); -+ WebKeyboardEvent(Type, 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, WallTime timestamp); + WebKeyboardEvent(WebEvent&&, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey); ++ 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, WallTime timestamp); #endif const String& text() const { return m_text; } diff --git a/Source/WebKit/Shared/WebMouseEvent.h b/Source/WebKit/Shared/WebMouseEvent.h -index cf2adc382b3f59890c43a54b6c28bab2c4a965c6..998e96ec8c997bd1b51434c77e73e9420f5ebaa7 100644 +index a7862db2df45ac3ab8ba5c7dee7d9d0c5641c27b..149d8cc4ef277ebdfc3bb27be7d52f5cd2baffa7 100644 --- a/Source/WebKit/Shared/WebMouseEvent.h +++ b/Source/WebKit/Shared/WebMouseEvent.h -@@ -62,6 +62,7 @@ public: +@@ -73,6 +73,7 @@ public: - Button button() const { return static_cast