mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
27 Commits
printing-r
...
v30.0.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a47b724c99 | ||
|
|
ee4bbb5851 | ||
|
|
b713e34947 | ||
|
|
b39f36496d | ||
|
|
d16f1d52e8 | ||
|
|
d3b182f8b9 | ||
|
|
35099d9289 | ||
|
|
b45f579eda | ||
|
|
64c031f264 | ||
|
|
058c6b4af7 | ||
|
|
333ee6d51a | ||
|
|
e7300ad4c8 | ||
|
|
58ee15905b | ||
|
|
036e8502e0 | ||
|
|
17856cf91a | ||
|
|
56dfcc5468 | ||
|
|
105acec227 | ||
|
|
174aedf54c | ||
|
|
47deb401b0 | ||
|
|
7331e5dfb1 | ||
|
|
a55f23979e | ||
|
|
4a727c6a72 | ||
|
|
fd8eec3585 | ||
|
|
ef40e551cf | ||
|
|
532039ea2c | ||
|
|
25b0212fe6 | ||
|
|
310598c43d |
@@ -75,6 +75,10 @@ executors:
|
||||
resource_class: << parameters.size >>
|
||||
|
||||
# Electron Runners
|
||||
apple-silicon:
|
||||
resource_class: electronjs/macos-arm64
|
||||
machine: true
|
||||
|
||||
linux-arm:
|
||||
resource_class: electronjs/aks-linux-arm-test
|
||||
docker:
|
||||
@@ -2294,10 +2298,8 @@ jobs:
|
||||
- electron-tests:
|
||||
artifact-key: darwin-x64
|
||||
|
||||
darwin-testing-arm64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.m1.medium.gen1
|
||||
darwin-testing-arm64-tests:
|
||||
executor: apple-silicon
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
@@ -2321,9 +2323,7 @@ jobs:
|
||||
artifact-key: mas-x64
|
||||
|
||||
mas-testing-arm64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.m1.medium.gen1
|
||||
executor: apple-silicon
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
"onCreateCommand": ".devcontainer/on-create-command.sh",
|
||||
"updateContentCommand": ".devcontainer/update-content-command.sh",
|
||||
"workspaceFolder": "/workspaces/gclient/src/electron",
|
||||
"forwardPorts": [6080, 5901],
|
||||
"forwardPorts": [8088, 6080, 5901],
|
||||
"portsAttributes": {
|
||||
"8088": {
|
||||
"label": "Goma Control Panel",
|
||||
"onAutoForward": "silent"
|
||||
},
|
||||
"6080": {
|
||||
"label": "VNC web client (noVNC)",
|
||||
"onAutoForward": "silent"
|
||||
|
||||
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@@ -11,9 +11,6 @@ DEPS @electron/wg-upgrades
|
||||
/docs/breaking-changes.md @electron/wg-releases
|
||||
/npm/ @electron/wg-releases
|
||||
/script/release @electron/wg-releases
|
||||
appveyor.yml @electron/wg-releases
|
||||
appveyor-bake.yml @electron/wg-releases
|
||||
appveyor-woa.yml @electron/wg-releases
|
||||
|
||||
# Security WG
|
||||
/lib/browser/devtools.ts @electron/wg-security
|
||||
|
||||
18
.github/workflows/issue-labeled.yml
vendored
18
.github/workflows/issue-labeled.yml
vendored
@@ -8,24 +8,6 @@ permissions: # added using https://github.com/step-security/secure-workflows
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
issue-labeled-with-status:
|
||||
name: status/{confirmed,reviewed} label added
|
||||
if: github.event.label.name == 'status/confirmed' || github.event.label.name == 'status/reviewed'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Set status
|
||||
uses: dsanders11/project-actions/edit-item@82e99438bd44a14ad18d92d036dbc25cbfb9a8c4 # v1.2.0
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
project-number: 90
|
||||
field: Status
|
||||
field-value: ✅ Triaged
|
||||
issue-labeled-blocked:
|
||||
name: blocked/* label added
|
||||
if: startsWith(github.event.label.name, 'blocked/')
|
||||
|
||||
41
.github/workflows/issue-opened.yml
vendored
41
.github/workflows/issue-opened.yml
vendored
@@ -25,44 +25,3 @@ jobs:
|
||||
field-value: ${{ github.event.issue.user.login }}
|
||||
project-number: 90
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
set-labels:
|
||||
if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- run: npm install mdast-util-from-markdown@2.0.0 unist-util-select@5.1.0
|
||||
- name: Add labels
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
env:
|
||||
ISSUE_BODY: ${{ github.event.issue.body }}
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
const { fromMarkdown } = await import('${{ github.workspace }}/node_modules/mdast-util-from-markdown/index.js');
|
||||
const { select } = await import('${{ github.workspace }}/node_modules/unist-util-select/index.js');
|
||||
|
||||
const [ owner, repo ] = '${{ github.repository }}'.split('/');
|
||||
const issue_number = ${{ github.event.issue.number }};
|
||||
|
||||
const tree = fromMarkdown(process.env.ISSUE_BODY);
|
||||
|
||||
const labels = [];
|
||||
|
||||
const gistUrl = select('heading:has(> text[value="Testcase Gist URL"]) + paragraph > text', tree)?.value.trim();
|
||||
if (gistUrl !== undefined && gistUrl.startsWith('https://gist.github.com/')) {
|
||||
labels.push('has-repro-gist');
|
||||
}
|
||||
|
||||
if (labels.length) {
|
||||
await github.rest.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
labels,
|
||||
});
|
||||
}
|
||||
|
||||
41
.github/workflows/update_appveyor_image.yml
vendored
41
.github/workflows/update_appveyor_image.yml
vendored
@@ -6,23 +6,22 @@ on:
|
||||
schedule:
|
||||
- cron: '0 8 * * 1-5' # runs 8:00 every business day (see https://crontab.guru)
|
||||
|
||||
permissions: {}
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
bake-appveyor-image:
|
||||
name: Bake AppVeyor Image
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write # to create a new PR with updated Appveyor images
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.APPVEYOR_UPDATER_GH_APP_CREDS }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
- name: Yarn install
|
||||
run: |
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
@@ -50,24 +49,26 @@ jobs:
|
||||
diff -w -B appveyor.yml appveyor2.yml > appveyor.diff || true
|
||||
patch -f appveyor.yml < appveyor.diff
|
||||
rm appveyor2.yml appveyor.diff
|
||||
git add appveyor.yml
|
||||
- name: (Optionally) Generate Commit Diff for WOA
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
run: |
|
||||
diff -w -B appveyor-woa.yml appveyor-woa2.yml > appveyor-woa.diff || true
|
||||
patch -f appveyor-woa.yml < appveyor-woa.diff
|
||||
rm appveyor-woa2.yml appveyor-woa.diff
|
||||
git add appveyor-woa.yml
|
||||
- name: (Optionally) Commit to Branch
|
||||
- name: (Optionally) Commit and Pull Request
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
uses: dsanders11/github-app-commit-action@1dd0a2d22c564461d3f598b6858856e8842d7a16 # v1.1.0
|
||||
uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 # v6.0.0
|
||||
with:
|
||||
message: 'build: update appveyor image to latest version'
|
||||
ref: bump-appveyor-image
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
- name: (Optionally) Create Pull Request
|
||||
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
|
||||
run: |
|
||||
printf "This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}.\n\nNotes: none" | gh pr create --head bump-appveyor-image --label no-backport --label semver/none --title 'build: update appveyor image to latest version' --body-file=-
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: 'build: update appveyor image to latest version'
|
||||
committer: GitHub <noreply@github.com>
|
||||
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
|
||||
signoff: false
|
||||
branch: bump-appveyor-image
|
||||
delete-branch: true
|
||||
reviewers: electron/wg-releases
|
||||
title: 'build: update appveyor image to latest version'
|
||||
labels: semver/none,no-backport
|
||||
body: |
|
||||
This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}.
|
||||
Notes: none
|
||||
|
||||
@@ -1,17 +1,3 @@
|
||||
{
|
||||
"extends": "@electron/lint-roller/configs/markdownlint.json",
|
||||
"no-angle-brackets": true,
|
||||
"no-inline-html": {
|
||||
"allowed_elements": [
|
||||
"br",
|
||||
"details",
|
||||
"img",
|
||||
"li",
|
||||
"summary",
|
||||
"ul",
|
||||
"unknown",
|
||||
"Tabs",
|
||||
"TabItem",
|
||||
]
|
||||
}
|
||||
"extends": "@electron/lint-roller/configs/markdownlint.json"
|
||||
}
|
||||
|
||||
8
BUILD.gn
8
BUILD.gn
@@ -475,7 +475,6 @@ source_set("electron_lib") {
|
||||
"//net:extras",
|
||||
"//net:net_resources",
|
||||
"//printing/buildflags",
|
||||
"//services/device/public/cpp/bluetooth:bluetooth",
|
||||
"//services/device/public/cpp/geolocation",
|
||||
"//services/device/public/cpp/hid",
|
||||
"//services/device/public/mojom",
|
||||
@@ -503,7 +502,6 @@ source_set("electron_lib") {
|
||||
"//ui/native_theme",
|
||||
"//ui/shell_dialogs",
|
||||
"//ui/views",
|
||||
"//ui/views/controls/webview",
|
||||
"//v8",
|
||||
"//v8:v8_libplatform",
|
||||
]
|
||||
@@ -639,6 +637,7 @@ source_set("electron_lib") {
|
||||
"//ui/gtk:gtk_config",
|
||||
"//ui/linux:linux_ui",
|
||||
"//ui/linux:linux_ui_factory",
|
||||
"//ui/views/controls/webview",
|
||||
"//ui/wm",
|
||||
]
|
||||
if (ozone_platform_x11) {
|
||||
@@ -667,6 +666,7 @@ source_set("electron_lib") {
|
||||
deps += [
|
||||
"//components/crash/core/app:crash_export_thunks",
|
||||
"//ui/native_theme:native_theme_browser",
|
||||
"//ui/views/controls/webview",
|
||||
"//ui/wm",
|
||||
"//ui/wm/public",
|
||||
]
|
||||
@@ -700,8 +700,6 @@ source_set("electron_lib") {
|
||||
sources += [
|
||||
"shell/browser/printing/print_view_manager_electron.cc",
|
||||
"shell/browser/printing/print_view_manager_electron.h",
|
||||
"shell/browser/printing/printing_utils.cc",
|
||||
"shell/browser/printing/printing_utils.h",
|
||||
"shell/renderer/printing/print_render_frame_helper_delegate.cc",
|
||||
"shell/renderer/printing/print_render_frame_helper_delegate.h",
|
||||
]
|
||||
@@ -858,7 +856,7 @@ if (is_mac) {
|
||||
if (is_asan) {
|
||||
# crashpad_handler requires the ASan runtime at its @executable_path.
|
||||
sources += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ]
|
||||
public_deps += [ "//build/config/sanitizers:copy_sanitizer_runtime" ]
|
||||
public_deps += [ "//build/config/sanitizers:copy_asan_runtime" ]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,4 +112,4 @@ and more can be found on the [Community page](https://www.electronjs.org/communi
|
||||
|
||||
[MIT](https://github.com/electron/electron/blob/main/LICENSE)
|
||||
|
||||
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://trademark-policy.openjsf.org/).
|
||||
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf).
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-124.0.6359.0
|
||||
image: e-123.0.6312.5
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-124.0.6359.0
|
||||
image: e-123.0.6312.5
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
|
||||
@@ -32,7 +32,7 @@ In most cases, you should do everything in the `ready` event handler.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `launchInfo` Record\<string, any\> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
|
||||
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
|
||||
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
|
||||
@@ -970,7 +970,7 @@ app.setJumpList([
|
||||
|
||||
### `app.requestSingleInstanceLock([additionalData])`
|
||||
|
||||
* `additionalData` Record\<any, any\> (optional) - A JSON object containing additional data to send to the first instance.
|
||||
* `additionalData` Record<any, any> (optional) - A JSON object containing additional data to send to the first instance.
|
||||
|
||||
Returns `boolean`
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ The `autoUpdater` object has the following methods:
|
||||
|
||||
* `options` Object
|
||||
* `url` string
|
||||
* `headers` Record\<string, string\> (optional) _macOS_ - HTTP request headers.
|
||||
* `headers` Record<string, string> (optional) _macOS_ - HTTP request headers.
|
||||
* `serverType` string (optional) _macOS_ - Can be `json` or `default`, see the [Squirrel.Mac][squirrel-mac]
|
||||
README for more information.
|
||||
|
||||
|
||||
@@ -656,7 +656,7 @@ Closes the currently open [Quick Look][quick-look] panel.
|
||||
|
||||
#### `win.setBounds(bounds[, animate])`
|
||||
|
||||
* `bounds` Partial\<[Rectangle](structures/rectangle.md)\>
|
||||
* `bounds` Partial<[Rectangle](structures/rectangle.md)>
|
||||
* `animate` boolean (optional) _macOS_
|
||||
|
||||
Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values.
|
||||
|
||||
@@ -779,7 +779,7 @@ Closes the currently open [Quick Look][quick-look] panel.
|
||||
|
||||
#### `win.setBounds(bounds[, animate])`
|
||||
|
||||
* `bounds` Partial\<[Rectangle](structures/rectangle.md)\>
|
||||
* `bounds` Partial<[Rectangle](structures/rectangle.md)>
|
||||
* `animate` boolean (optional) _macOS_
|
||||
|
||||
Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values.
|
||||
@@ -1215,7 +1215,7 @@ win.loadURL('http://localhost:8000/post', {
|
||||
|
||||
* `filePath` string
|
||||
* `options` Object (optional)
|
||||
* `query` Record\<string, string\> (optional) - Passed to `url.format()`.
|
||||
* `query` Record<string, string> (optional) - Passed to `url.format()`.
|
||||
* `search` string (optional) - Passed to `url.format()`.
|
||||
* `hash` string (optional) - Passed to `url.format()`.
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ following properties:
|
||||
method.
|
||||
* `url` string (optional) - The request URL. Must be provided in the absolute
|
||||
form with the protocol scheme specified as http or https.
|
||||
* `headers` Record\<string, string | string[]\> (optional) - Headers to be sent
|
||||
with the request.
|
||||
* `session` Session (optional) - The [`Session`](session.md) instance with
|
||||
which the request is associated.
|
||||
* `partition` string (optional) - The name of the [`partition`](session.md)
|
||||
@@ -160,7 +158,7 @@ Returns:
|
||||
* `statusCode` Integer
|
||||
* `method` string
|
||||
* `redirectUrl` string
|
||||
* `responseHeaders` Record\<string, string[]\>
|
||||
* `responseHeaders` Record<string, string[]>
|
||||
|
||||
Emitted when the server returns a redirect response (e.g. 301 Moved
|
||||
Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will
|
||||
|
||||
@@ -59,14 +59,14 @@ The `crashReporter` module has the following methods:
|
||||
number of crashes uploaded to 1/hour. Default is `false`.
|
||||
* `compress` boolean (optional) - If true, crash reports will be compressed
|
||||
and uploaded with `Content-Encoding: gzip`. Default is `true`.
|
||||
* `extra` Record\<string, string\> (optional) - Extra string key/value
|
||||
* `extra` Record<string, string> (optional) - Extra string key/value
|
||||
annotations that will be sent along with crash reports that are generated
|
||||
in the main process. Only string values are supported. Crashes generated in
|
||||
child processes will not contain these extra
|
||||
parameters to crash reports generated from child processes, call
|
||||
[`addExtraParameter`](#crashreporteraddextraparameterkey-value) from the
|
||||
child process.
|
||||
* `globalExtra` Record\<string, string\> (optional) - Extra string key/value
|
||||
* `globalExtra` Record<string, string> (optional) - Extra string key/value
|
||||
annotations that will be sent along with any crash reports generated in any
|
||||
process. These annotations cannot be changed once the crash reporter has
|
||||
been started. If a key is present in both the global extra parameters and
|
||||
|
||||
@@ -72,7 +72,7 @@ Removes listeners of the specified `channel`.
|
||||
### `ipcMain.handle(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function\<Promise\<any\> | any\>
|
||||
* `listener` Function<Promise\<any> | any>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
* `...args` any[]
|
||||
|
||||
@@ -109,7 +109,7 @@ provided to the renderer process. Please refer to
|
||||
### `ipcMain.handleOnce(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function\<Promise\<any\> | any\>
|
||||
* `listener` Function<Promise\<any> | any>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
* `...args` any[]
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
## Class: NavigationHistory
|
||||
|
||||
> Manage a list of navigation entries, representing the user's browsing history within the application.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)<br />
|
||||
_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._
|
||||
|
||||
Each navigation entry corresponds to a specific page. The indexing system follows a sequential order, where the first available navigation entry is at index 0, representing the earliest visited page, and the latest navigation entry is at index N, representing the most recent page. Maintaining this ordered list of navigation entries enables seamless navigation both backward and forward through the user's browsing history.
|
||||
|
||||
### Instance Methods
|
||||
|
||||
#### `navigationHistory.getActiveIndex()`
|
||||
|
||||
Returns `Integer` - The index of the current page, from which we would go back/forward or reload.
|
||||
|
||||
#### `navigationHistory.getEntryAtIndex(index)`
|
||||
|
||||
* `index` Integer
|
||||
|
||||
Returns `Object`:
|
||||
|
||||
* `url` string - The URL of the navigation entry at the given index.
|
||||
* `title` string - The page title of the navigation entry at the given index.
|
||||
|
||||
If index is out of bounds (greater than history length or less than 0), null will be returned.
|
||||
|
||||
#### `navigationHistory.length()`
|
||||
|
||||
Returns `Integer` - History length.
|
||||
@@ -111,7 +111,7 @@ expect streaming responses.
|
||||
|
||||
* `scheme` string - scheme to handle, for example `https` or `my-app`. This is
|
||||
the bit before the `:` in a URL.
|
||||
* `handler` Function\<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise\<GlobalResponse\>\>
|
||||
* `handler` Function<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise<GlobalResponse>>
|
||||
* `request` [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
|
||||
Register a protocol handler for `scheme`. Requests made to URLs with this
|
||||
|
||||
@@ -27,7 +27,7 @@ The `pushNotification` module emits the following events:
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `userInfo` Record\<String, any\>
|
||||
* `userInfo` Record<String, any>
|
||||
|
||||
Emitted when the app receives a remote notification while running.
|
||||
See: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428430-application?language=objc
|
||||
|
||||
@@ -814,8 +814,6 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame.
|
||||
* `openExternal` - Request to open links in external applications.
|
||||
* `speaker-selection` - Request to enumerate and select audio output devices via the [speaker-selection permissions policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy/speaker-selection).
|
||||
* `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
|
||||
* `unknown` - An unrecognized permission request.
|
||||
* `callback` Function
|
||||
@@ -864,8 +862,6 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
|
||||
* `openExternal` - Open links in external applications.
|
||||
* `pointerLock` - Directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
|
||||
* `serial` - Read from and write to serial devices with the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API).
|
||||
* `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
|
||||
* `requestingOrigin` string - The origin URL of the permission check
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
@@ -1220,7 +1216,7 @@ Returns `Promise<Buffer>` - resolves with blob data.
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record\<string, string\> (optional) - HTTP request headers.
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url`.
|
||||
The API will generate a [DownloadItem](download-item.md) that can be accessed
|
||||
@@ -1428,37 +1424,6 @@ is emitted.
|
||||
Returns `string | null` - The absolute file system path where data for this
|
||||
session is persisted on disk. For in memory sessions this returns `null`.
|
||||
|
||||
#### `ses.clearData([options])`
|
||||
|
||||
* `options` Object (optional)
|
||||
* `dataTypes` String[] (optional) - The types of data to clear. By default, this will clear all types of data.
|
||||
* `backgroundFetch` - Background Fetch
|
||||
* `cache` - Cache
|
||||
* `cookies` - Cookies
|
||||
* `downloads` - Downloads
|
||||
* `fileSystems` - File Systems
|
||||
* `indexedDB` - IndexedDB
|
||||
* `localStorage` - Local Storage
|
||||
* `serviceWorkers` - Service Workers
|
||||
* `webSQL` - WebSQL
|
||||
* `origins` String[] (optional) - Clear data for only these origins. Cannot be used with `excludeOrigins`.
|
||||
* `excludeOrigins` String[] (optional) - Clear data for all origins except these ones. Cannot be used with `origins`.
|
||||
* `avoidClosingConnections` boolean (optional) - Skips deleting cookies that would close current network connections. (Default: `false`)
|
||||
* `originMatchingMode` String (optional) - The behavior for matching data to origins.
|
||||
* `third-parties-included` (default) - Storage is matched on origin in first-party contexts and top-level-site in third-party contexts.
|
||||
* `origin-in-all-contexts` - Storage is matched on origin only in all contexts.
|
||||
|
||||
Returns `Promise<void>` - resolves when all data has been cleared.
|
||||
|
||||
Clears various different types of data.
|
||||
|
||||
This method clears more types of data and is more thourough than the
|
||||
`clearStorageData` method.
|
||||
|
||||
**Note:** Cookies are stored at a broader scope than origins. When removing cookies and filtering by `origins` (or `excludeOrigins`), the cookies will be removed at the [registrable domain](https://url.spec.whatwg.org/#host-registrable-domain) level. For example, clearing cookies for the origin `https://really.specific.origin.example.com/` will end up clearing all cookies for `example.com`. Clearing cookies for the origin `https://my.website.example.co.uk/` will end up clearing all cookies for `example.co.uk`.
|
||||
|
||||
For more information, refer to Chromium's [`BrowsingDataRemover` interface](https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/browsing_data_remover.h).
|
||||
|
||||
### Instance Properties
|
||||
|
||||
The following properties are available on instances of `Session`:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# FilePathWithHeaders Object
|
||||
|
||||
* `path` string - The path to the file to send.
|
||||
* `headers` Record\<string, string\> (optional) - Additional headers to be sent.
|
||||
* `headers` Record<string, string> (optional) - Additional headers to be sent.
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
* `actionIdentifier` string - The identifier string of the action that the user selected.
|
||||
* `date` number - The delivery date of the notification.
|
||||
* `identifier` string - The unique identifier for this notification request.
|
||||
* `userInfo` Record\<string, any\> - A dictionary of custom information associated with the notification.
|
||||
* `userInfo` Record<string, any> - A dictionary of custom information associated with the notification.
|
||||
* `userText` string (optional) - The text entered or chosen by the user.
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
* `referrer` string
|
||||
* `method` string
|
||||
* `uploadData` [UploadData[]](upload-data.md) (optional)
|
||||
* `headers` Record\<string, string\>
|
||||
* `headers` Record<string, string>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
`"text/html"`. Setting `mimeType` would implicitly set the `content-type`
|
||||
header in response, but if `content-type` is already set in `headers`, the
|
||||
`mimeType` would be ignored.
|
||||
* `headers` Record\<string, string | string[]\> (optional) - An object containing the response headers. The
|
||||
* `headers` Record<string, string | string[]> (optional) - An object containing the response headers. The
|
||||
keys must be string, and values must be either string or Array of string.
|
||||
* `data` (Buffer | string | ReadableStream) (optional) - The response body. When
|
||||
returning stream as response, this is a Node.js readable stream representing
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
include in the trace. If not specified, trace all processes.
|
||||
* `histogram_names` string[] (optional) - a list of [histogram][] names to report
|
||||
with the trace.
|
||||
* `memory_dump_config` Record\<string, any\> (optional) - if the
|
||||
* `memory_dump_config` Record<string, any> (optional) - if the
|
||||
`disabled-by-default-memory-infra` category is enabled, this contains
|
||||
optional additional configuration for data collection. See the [Chromium
|
||||
memory-infra docs][memory-infra docs] for more information.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# WindowOpenHandlerResponse Object
|
||||
|
||||
* `action` string - Can be `allow` or `deny`. Controls whether new window should be created.
|
||||
* `overrideBrowserWindowOptions` BrowserWindowConstructorOptions (optional) - Allows customization of the created window.
|
||||
* `outlivesOpener` boolean (optional) - By default, child windows are closed when their opener is closed. This can be
|
||||
changed by specifying `outlivesOpener: true`, in which case the opened window will not be closed when its opener is closed.
|
||||
* `createWindow` (options: BrowserWindowConstructorOptions) => WebContents (optional) - If specified, will be called instead of `new BrowserWindow` to create the new child window and event [`did-create-window`](../web-contents.md#event-did-create-window) will not be emitted. Constructed child window should use passed `options` object. This can be used for example to have the new window open as a BrowserView instead of in a separate window.
|
||||
@@ -36,7 +36,7 @@ Returns `boolean` - Whether the Swipe between pages setting is on.
|
||||
### `systemPreferences.postNotification(event, userInfo[, deliverImmediately])` _macOS_
|
||||
|
||||
* `event` string
|
||||
* `userInfo` Record\<string, any\>
|
||||
* `userInfo` Record<string, any>
|
||||
* `deliverImmediately` boolean (optional) - `true` to post notifications immediately even when the subscribing app is inactive.
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
@@ -45,7 +45,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
### `systemPreferences.postLocalNotification(event, userInfo)` _macOS_
|
||||
|
||||
* `event` string
|
||||
* `userInfo` Record\<string, any\>
|
||||
* `userInfo` Record<string, any>
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
that contains the user information dictionary sent along with the notification.
|
||||
@@ -53,7 +53,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
### `systemPreferences.postWorkspaceNotification(event, userInfo)` _macOS_
|
||||
|
||||
* `event` string
|
||||
* `userInfo` Record\<string, any\>
|
||||
* `userInfo` Record<string, any>
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
that contains the user information dictionary sent along with the notification.
|
||||
@@ -63,7 +63,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
* `event` string | null
|
||||
* `callback` Function
|
||||
* `event` string
|
||||
* `userInfo` Record\<string, unknown\>
|
||||
* `userInfo` Record<string, unknown>
|
||||
* `object` string
|
||||
|
||||
Returns `number` - The ID of this subscription
|
||||
@@ -92,7 +92,7 @@ If `event` is null, the `NSDistributedNotificationCenter` doesn’t use it as cr
|
||||
* `event` string | null
|
||||
* `callback` Function
|
||||
* `event` string
|
||||
* `userInfo` Record\<string, unknown\>
|
||||
* `userInfo` Record<string, unknown>
|
||||
* `object` string
|
||||
|
||||
Returns `number` - The ID of this subscription
|
||||
@@ -107,7 +107,7 @@ If `event` is null, the `NSNotificationCenter` doesn’t use it as criteria for
|
||||
* `event` string | null
|
||||
* `callback` Function
|
||||
* `event` string
|
||||
* `userInfo` Record\<string, unknown\>
|
||||
* `userInfo` Record<string, unknown>
|
||||
* `object` string
|
||||
|
||||
Returns `number` - The ID of this subscription
|
||||
@@ -137,7 +137,7 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSWorkspace.
|
||||
|
||||
### `systemPreferences.registerDefaults(defaults)` _macOS_
|
||||
|
||||
* `defaults` Record\<string, string | boolean | number\> - a dictionary of (`key: value`) user defaults
|
||||
* `defaults` Record<string, string | boolean | number> - a dictionary of (`key: value`) user defaults
|
||||
|
||||
Add the specified defaults to your application's `NSUserDefaults`.
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ See [`window.open()`](window-open.md) for more details and how to use this in co
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event\<\>
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations.
|
||||
This property is always set to `false` for this event.
|
||||
@@ -270,7 +270,7 @@ Calling `event.preventDefault()` will prevent the navigation.
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event\<\>
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations.
|
||||
This property is always set to `false` for this event.
|
||||
@@ -300,7 +300,7 @@ Calling `event.preventDefault()` will prevent the navigation.
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event\<\>
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
@@ -324,7 +324,7 @@ Emitted when any frame (including main) starts navigating.
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event\<\>
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
@@ -355,7 +355,7 @@ redirect).
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event\<\>
|
||||
* `details` Event<>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
@@ -683,7 +683,7 @@ Emitted when media is paused or done playing.
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event\<\>
|
||||
* `event` Event<>
|
||||
* `audible` boolean - True if one or more frames or child `webContents` are emitting audio.
|
||||
|
||||
Emitted when media becomes audible or inaudible.
|
||||
@@ -900,7 +900,7 @@ Returns:
|
||||
* `webPreferences` [WebPreferences](structures/web-preferences.md) - The web preferences that will be used by the guest
|
||||
page. This object can be modified to adjust the preferences for the guest
|
||||
page.
|
||||
* `params` Record\<string, string\> - The other `<webview>` parameters such as the `src` URL.
|
||||
* `params` Record<string, string> - The other `<webview>` parameters such as the `src` URL.
|
||||
This object can be modified to adjust the parameters of the guest page.
|
||||
|
||||
Emitted when a `<webview>`'s web contents is being attached to this web
|
||||
@@ -1020,7 +1020,7 @@ win.webContents.loadURL('https://github.com', options)
|
||||
|
||||
* `filePath` string
|
||||
* `options` Object (optional)
|
||||
* `query` Record\<string, string\> (optional) - Passed to `url.format()`.
|
||||
* `query` Record<string, string> (optional) - Passed to `url.format()`.
|
||||
* `search` string (optional) - Passed to `url.format()`.
|
||||
* `hash` string (optional) - Passed to `url.format()`.
|
||||
|
||||
@@ -1051,7 +1051,7 @@ win.loadFile('src/index.html')
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record\<string, string\> (optional) - HTTP request headers.
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url` without navigating. The
|
||||
`will-download` event of `session` will be triggered.
|
||||
@@ -1288,7 +1288,7 @@ Ignore application menu shortcuts while this web contents is focused.
|
||||
|
||||
#### `contents.setWindowOpenHandler(handler)`
|
||||
|
||||
* `handler` Function\<[WindowOpenHandlerResponse](structures/window-open-handler-response.md)\>
|
||||
* `handler` Function<{action: 'deny'} | {action: 'allow', outlivesOpener?: boolean, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
|
||||
* `details` Object
|
||||
* `url` string - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
|
||||
* `frameName` string - Name of the window provided in `window.open()`
|
||||
@@ -1303,8 +1303,11 @@ Ignore application menu shortcuts while this web contents is focused.
|
||||
be set. If no post data is to be sent, the value will be `null`. Only defined
|
||||
when the window is being created by a form that set `target=_blank`.
|
||||
|
||||
Returns `WindowOpenHandlerResponse` - When set to `{ action: 'deny' }` cancels the creation of the new
|
||||
window. `{ action: 'allow' }` will allow the new window to be created.
|
||||
Returns `{action: 'deny'} | {action: 'allow', outlivesOpener?: boolean, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new
|
||||
window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window.
|
||||
By default, child windows are closed when their opener is closed. This can be
|
||||
changed by specifying `outlivesOpener: true`, in which case the opened window
|
||||
will not be closed when its opener is closed.
|
||||
Returning an unrecognized value such as a null, undefined, or an object
|
||||
without a recognized 'action' value will result in a console error and have
|
||||
the same effect as returning `{action: 'deny'}`.
|
||||
@@ -1315,26 +1318,6 @@ submitting a form with `<form target="_blank">`. See
|
||||
[`window.open()`](window-open.md) for more details and how to use this in
|
||||
conjunction with `did-create-window`.
|
||||
|
||||
An example showing how to customize the process of new `BrowserWindow` creation to be `BrowserView` attached to main window instead:
|
||||
|
||||
```js
|
||||
const { BrowserView, BrowserWindow } = require('electron')
|
||||
|
||||
const mainWindow = new BrowserWindow()
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
return {
|
||||
action: 'allow',
|
||||
createWindow: (options) => {
|
||||
const browserView = new BrowserView(options)
|
||||
mainWindow.addBrowserView(browserView)
|
||||
browserView.setBounds({ x: 0, y: 0, width: 640, height: 480 })
|
||||
return browserView.webContents
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### `contents.setAudioMuted(muted)`
|
||||
|
||||
* `muted` boolean
|
||||
@@ -1583,7 +1566,7 @@ Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/
|
||||
* `from` number - Index of the first page to print (0-based).
|
||||
* `to` number - Index of the last page to print (inclusive) (0-based).
|
||||
* `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
|
||||
* `dpi` Record\<string, number\> (optional)
|
||||
* `dpi` Record<string, number> (optional)
|
||||
* `horizontal` number (optional) - The horizontal dpi.
|
||||
* `vertical` number (optional) - The vertical dpi.
|
||||
* `header` string (optional) - string to be printed as page header.
|
||||
@@ -2223,10 +2206,6 @@ A `Integer` representing the unique ID of this WebContents. Each ID is unique am
|
||||
|
||||
A [`Session`](session.md) used by this webContents.
|
||||
|
||||
#### `contents.navigationHistory` _Readonly_
|
||||
|
||||
A [`NavigationHistory`](navigation-history.md) used by this webContents.
|
||||
|
||||
#### `contents.hostWebContents` _Readonly_
|
||||
|
||||
A [`WebContents`](web-contents.md) instance that might own this `WebContents`.
|
||||
|
||||
@@ -99,11 +99,11 @@ Some examples of valid `urls`:
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md) (optional)
|
||||
* `requestHeaders` Record\<string, string\>
|
||||
* `requestHeaders` Record<string, string>
|
||||
* `callback` Function
|
||||
* `beforeSendResponse` Object
|
||||
* `cancel` boolean (optional)
|
||||
* `requestHeaders` Record\<string, string | string[]\> (optional) - When provided, request will be made
|
||||
* `requestHeaders` Record<string, string | string[]> (optional) - When provided, request will be made
|
||||
with these headers.
|
||||
|
||||
The `listener` will be called with `listener(details, callback)` before sending
|
||||
@@ -126,7 +126,7 @@ The `callback` has to be called with a `response` object.
|
||||
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `requestHeaders` Record\<string, string\>
|
||||
* `requestHeaders` Record<string, string>
|
||||
|
||||
The `listener` will be called with `listener(details)` just before a request is
|
||||
going to be sent to the server, modifications of previous `onBeforeSendHeaders`
|
||||
@@ -148,11 +148,11 @@ response are visible by the time this listener is fired.
|
||||
* `timestamp` Double
|
||||
* `statusLine` string
|
||||
* `statusCode` Integer
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `callback` Function
|
||||
* `headersReceivedResponse` Object
|
||||
* `cancel` boolean (optional)
|
||||
* `responseHeaders` Record\<string, string | string[]\> (optional) - When provided, the server is assumed
|
||||
* `responseHeaders` Record<string, string | string[]> (optional) - When provided, the server is assumed
|
||||
to have responded with these headers.
|
||||
* `statusLine` string (optional) - Should be provided when overriding
|
||||
`responseHeaders` to change header status otherwise original response
|
||||
@@ -177,7 +177,7 @@ The `callback` has to be called with a `response` object.
|
||||
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `fromCache` boolean - Indicates whether the response was fetched from disk
|
||||
cache.
|
||||
* `statusCode` Integer
|
||||
@@ -207,7 +207,7 @@ and response headers are available.
|
||||
* `ip` string (optional) - The server IP address that the request was
|
||||
actually sent to.
|
||||
* `fromCache` boolean
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
|
||||
The `listener` will be called with `listener(details)` when a server initiated
|
||||
redirect is about to occur.
|
||||
@@ -226,7 +226,7 @@ redirect is about to occur.
|
||||
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `fromCache` boolean
|
||||
* `statusCode` Integer
|
||||
* `statusLine` string
|
||||
|
||||
@@ -287,7 +287,7 @@ e.g. the `http://` or `file://`.
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record\<string, string\> (optional) - HTTP request headers.
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url` without navigating.
|
||||
|
||||
@@ -580,7 +580,7 @@ Stops any `findInPage` request for the `webview` with the provided `action`.
|
||||
* `from` number - Index of the first page to print (0-based).
|
||||
* `to` number - Index of the last page to print (inclusive) (0-based).
|
||||
* `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
|
||||
* `dpi` Record\<string, number\> (optional)
|
||||
* `dpi` Record<string, number> (optional)
|
||||
* `horizontal` number (optional) - The horizontal dpi.
|
||||
* `vertical` number (optional) - The vertical dpi.
|
||||
* `header` string (optional) - string to be printed as page header.
|
||||
|
||||
@@ -1686,7 +1686,7 @@ folder
|
||||
└── file3
|
||||
```
|
||||
|
||||
In Electron <=6, this would return a `FileList` with a `File` object for:
|
||||
In Electron <=6, this would return a `FileList` with a `File` object for:
|
||||
|
||||
```console
|
||||
path/to/folder
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 4.2 MiB |
@@ -234,7 +234,7 @@ Notification) whereas camelCase modules are not instantiable (e.g. app, ipcRende
|
||||
<details><summary>Typed import aliases</summary>
|
||||
|
||||
For better type checking when writing TypeScript code, you can choose to import
|
||||
main process modules from `electron/main`.
|
||||
main process modules from <code>electron/main</code>.
|
||||
|
||||
```js
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
@@ -34,7 +34,6 @@ auto_filenames = {
|
||||
"docs/api/message-port-main.md",
|
||||
"docs/api/native-image.md",
|
||||
"docs/api/native-theme.md",
|
||||
"docs/api/navigation-history.md",
|
||||
"docs/api/net-log.md",
|
||||
"docs/api/net.md",
|
||||
"docs/api/notification.md",
|
||||
@@ -145,7 +144,6 @@ auto_filenames = {
|
||||
"docs/api/structures/web-preferences.md",
|
||||
"docs/api/structures/web-request-filter.md",
|
||||
"docs/api/structures/web-source.md",
|
||||
"docs/api/structures/window-open-handler-response.md",
|
||||
]
|
||||
|
||||
sandbox_bundle_deps = [
|
||||
|
||||
@@ -155,8 +155,12 @@ filenames = {
|
||||
"shell/browser/osr/osr_web_contents_view_mac.mm",
|
||||
"shell/browser/relauncher_mac.cc",
|
||||
"shell/browser/ui/certificate_trust_mac.mm",
|
||||
"shell/browser/ui/cocoa/delayed_native_view_host.h",
|
||||
"shell/browser/ui/cocoa/delayed_native_view_host.mm",
|
||||
"shell/browser/ui/cocoa/electron_bundle_mover.h",
|
||||
"shell/browser/ui/cocoa/electron_bundle_mover.mm",
|
||||
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h",
|
||||
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm",
|
||||
"shell/browser/ui/cocoa/electron_menu_controller.h",
|
||||
"shell/browser/ui/cocoa/electron_menu_controller.mm",
|
||||
"shell/browser/ui/cocoa/electron_native_widget_mac.h",
|
||||
@@ -183,6 +187,8 @@ filenames = {
|
||||
"shell/browser/ui/cocoa/window_buttons_proxy.mm",
|
||||
"shell/browser/ui/drag_util_mac.mm",
|
||||
"shell/browser/ui/file_dialog_mac.mm",
|
||||
"shell/browser/ui/inspectable_web_contents_view_mac.h",
|
||||
"shell/browser/ui/inspectable_web_contents_view_mac.mm",
|
||||
"shell/browser/ui/message_box_mac.mm",
|
||||
"shell/browser/ui/tray_icon_cocoa.h",
|
||||
"shell/browser/ui/tray_icon_cocoa.mm",
|
||||
@@ -198,7 +204,6 @@ filenames = {
|
||||
"shell/common/node_bindings_mac.cc",
|
||||
"shell/common/node_bindings_mac.h",
|
||||
"shell/common/platform_util_mac.mm",
|
||||
"shell/browser/ui/views/inspectable_web_contents_view_mac.mm",
|
||||
]
|
||||
|
||||
lib_sources_views = [
|
||||
@@ -213,6 +218,8 @@ filenames = {
|
||||
"shell/browser/ui/views/electron_views_delegate.h",
|
||||
"shell/browser/ui/views/frameless_view.cc",
|
||||
"shell/browser/ui/views/frameless_view.h",
|
||||
"shell/browser/ui/views/inspectable_web_contents_view_views.cc",
|
||||
"shell/browser/ui/views/inspectable_web_contents_view_views.h",
|
||||
"shell/browser/ui/views/menu_bar.cc",
|
||||
"shell/browser/ui/views/menu_bar.h",
|
||||
"shell/browser/ui/views/menu_delegate.cc",
|
||||
@@ -583,8 +590,6 @@ filenames = {
|
||||
"shell/common/gin_converters/hid_device_info_converter.h",
|
||||
"shell/common/gin_converters/image_converter.cc",
|
||||
"shell/common/gin_converters/image_converter.h",
|
||||
"shell/common/gin_converters/login_item_settings_converter.cc",
|
||||
"shell/common/gin_converters/login_item_settings_converter.h",
|
||||
"shell/common/gin_converters/media_converter.cc",
|
||||
"shell/common/gin_converters/media_converter.h",
|
||||
"shell/common/gin_converters/message_box_converter.cc",
|
||||
|
||||
@@ -433,15 +433,14 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
return p;
|
||||
};
|
||||
|
||||
WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => Electron.WindowOpenHandlerResponse) {
|
||||
WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => ({action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions, outlivesOpener?: boolean})) {
|
||||
this._windowOpenHandler = handler;
|
||||
};
|
||||
|
||||
WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event, details: Electron.HandlerDetails): {browserWindowConstructorOptions: BrowserWindowConstructorOptions | null, outlivesOpener: boolean, createWindow?: Electron.CreateWindowFunction} {
|
||||
WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event, details: Electron.HandlerDetails): {browserWindowConstructorOptions: BrowserWindowConstructorOptions | null, outlivesOpener: boolean} {
|
||||
const defaultResponse = {
|
||||
browserWindowConstructorOptions: null,
|
||||
outlivesOpener: false,
|
||||
createWindow: undefined
|
||||
outlivesOpener: false
|
||||
};
|
||||
if (!this._windowOpenHandler) {
|
||||
return defaultResponse;
|
||||
@@ -467,8 +466,7 @@ WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event,
|
||||
} else if (response.action === 'allow') {
|
||||
return {
|
||||
browserWindowConstructorOptions: typeof response.overrideBrowserWindowOptions === 'object' ? response.overrideBrowserWindowOptions : null,
|
||||
outlivesOpener: typeof response.outlivesOpener === 'boolean' ? response.outlivesOpener : false,
|
||||
createWindow: typeof response.createWindow === 'function' ? response.createWindow : undefined
|
||||
outlivesOpener: typeof response.outlivesOpener === 'boolean' ? response.outlivesOpener : false
|
||||
};
|
||||
} else {
|
||||
event.preventDefault();
|
||||
@@ -533,17 +531,6 @@ WebContents.prototype._init = function () {
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
// Add navigationHistory property which handles session history,
|
||||
// maintaining a list of navigation entries for backward and forward navigation.
|
||||
Object.defineProperty(this, 'navigationHistory', {
|
||||
value: {
|
||||
getActiveIndex: this._getActiveIndex.bind(this),
|
||||
length: this._historyLength.bind(this),
|
||||
getEntryAtIndex: this._getNavigationEntryAtIndex.bind(this)
|
||||
},
|
||||
writable: false
|
||||
});
|
||||
|
||||
// Dispatch IPC messages to the ipc module.
|
||||
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderToEvent(event, this);
|
||||
@@ -666,16 +653,13 @@ WebContents.prototype._init = function () {
|
||||
postData,
|
||||
overrideBrowserWindowOptions: options || {},
|
||||
windowOpenArgs: details,
|
||||
outlivesOpener: result.outlivesOpener,
|
||||
createWindow: result.createWindow
|
||||
outlivesOpener: result.outlivesOpener
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
|
||||
let windowOpenOutlivesOpenerOption: boolean = false;
|
||||
let createWindow: Electron.CreateWindowFunction | undefined;
|
||||
|
||||
this.on('-will-add-new-contents' as any, (event: Electron.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => {
|
||||
const postBody = postData ? {
|
||||
data: postData,
|
||||
@@ -700,7 +684,6 @@ WebContents.prototype._init = function () {
|
||||
|
||||
windowOpenOutlivesOpenerOption = result.outlivesOpener;
|
||||
windowOpenOverriddenOptions = result.browserWindowConstructorOptions;
|
||||
createWindow = result.createWindow;
|
||||
if (!event.defaultPrevented) {
|
||||
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
|
||||
// Allow setting of backgroundColor as a webPreference even though
|
||||
@@ -730,9 +713,6 @@ WebContents.prototype._init = function () {
|
||||
referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => {
|
||||
const overriddenOptions = windowOpenOverriddenOptions || undefined;
|
||||
const outlivesOpener = windowOpenOutlivesOpenerOption;
|
||||
const windowOpenFunction = createWindow;
|
||||
|
||||
createWindow = undefined;
|
||||
windowOpenOverriddenOptions = null;
|
||||
// false is the default
|
||||
windowOpenOutlivesOpenerOption = false;
|
||||
@@ -755,8 +735,7 @@ WebContents.prototype._init = function () {
|
||||
frameName,
|
||||
features: rawFeatures
|
||||
},
|
||||
outlivesOpener,
|
||||
createWindow: windowOpenFunction
|
||||
outlivesOpener
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,16 +16,16 @@ export type WindowOpenArgs = {
|
||||
features: string,
|
||||
}
|
||||
|
||||
const frameNamesToWindow = new Map<string, WebContents>();
|
||||
const registerFrameNameToGuestWindow = (name: string, webContents: WebContents) => frameNamesToWindow.set(name, webContents);
|
||||
const frameNamesToWindow = new Map<string, BrowserWindow>();
|
||||
const registerFrameNameToGuestWindow = (name: string, win: BrowserWindow) => frameNamesToWindow.set(name, win);
|
||||
const unregisterFrameName = (name: string) => frameNamesToWindow.delete(name);
|
||||
const getGuestWebContentsByFrameName = (name: string) => frameNamesToWindow.get(name);
|
||||
const getGuestWindowByFrameName = (name: string) => frameNamesToWindow.get(name);
|
||||
|
||||
/**
|
||||
* `openGuestWindow` is called to create and setup event handling for the new
|
||||
* window.
|
||||
*/
|
||||
export function openGuestWindow ({ embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs, outlivesOpener, createWindow }: {
|
||||
export function openGuestWindow ({ embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs, outlivesOpener }: {
|
||||
embedder: WebContents,
|
||||
guest?: WebContents,
|
||||
referrer: Referrer,
|
||||
@@ -34,8 +34,7 @@ export function openGuestWindow ({ embedder, guest, referrer, disposition, postD
|
||||
overrideBrowserWindowOptions?: BrowserWindowConstructorOptions,
|
||||
windowOpenArgs: WindowOpenArgs,
|
||||
outlivesOpener: boolean,
|
||||
createWindow?: Electron.CreateWindowFunction
|
||||
}): void {
|
||||
}): BrowserWindow | undefined {
|
||||
const { url, frameName, features } = windowOpenArgs;
|
||||
const { options: parsedOptions } = parseFeatures(features);
|
||||
const browserWindowOptions = {
|
||||
@@ -49,42 +48,17 @@ export function openGuestWindow ({ embedder, guest, referrer, disposition, postD
|
||||
// To spec, subsequent window.open calls with the same frame name (`target` in
|
||||
// spec parlance) will reuse the previous window.
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#apis-for-creating-and-navigating-browsing-contexts-by-name
|
||||
const existingWebContents = getGuestWebContentsByFrameName(frameName);
|
||||
if (existingWebContents) {
|
||||
if (existingWebContents.isDestroyed()) {
|
||||
const existingWindow = getGuestWindowByFrameName(frameName);
|
||||
if (existingWindow) {
|
||||
if (existingWindow.isDestroyed() || existingWindow.webContents.isDestroyed()) {
|
||||
// FIXME(t57ser): The webContents is destroyed for some reason, unregister the frame name
|
||||
unregisterFrameName(frameName);
|
||||
} else {
|
||||
existingWebContents.loadURL(url);
|
||||
return;
|
||||
existingWindow.loadURL(url);
|
||||
return existingWindow;
|
||||
}
|
||||
}
|
||||
|
||||
if (createWindow) {
|
||||
const webContents = createWindow({
|
||||
webContents: guest,
|
||||
...browserWindowOptions
|
||||
});
|
||||
|
||||
if (guest != null) {
|
||||
if (webContents !== guest) {
|
||||
throw new Error('Invalid webContents. Created window should be connected to webContents passed with options object.');
|
||||
}
|
||||
|
||||
webContents.loadURL(url, {
|
||||
httpReferrer: referrer,
|
||||
...(postData && {
|
||||
postData,
|
||||
extraHeaders: formatPostDataHeaders(postData as Electron.UploadRawData[])
|
||||
})
|
||||
});
|
||||
|
||||
handleWindowLifecycleEvents({ embedder, frameName, guest, outlivesOpener });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const window = new BrowserWindow({
|
||||
webContents: guest,
|
||||
...browserWindowOptions
|
||||
@@ -103,9 +77,11 @@ export function openGuestWindow ({ embedder, guest, referrer, disposition, postD
|
||||
});
|
||||
}
|
||||
|
||||
handleWindowLifecycleEvents({ embedder, frameName, guest: window.webContents, outlivesOpener });
|
||||
handleWindowLifecycleEvents({ embedder, frameName, guest: window, outlivesOpener });
|
||||
|
||||
embedder.emit('did-create-window', window, { url, frameName, options: browserWindowOptions, disposition, referrer, postData });
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,12 +92,12 @@ export function openGuestWindow ({ embedder, guest, referrer, disposition, postD
|
||||
*/
|
||||
const handleWindowLifecycleEvents = function ({ embedder, guest, frameName, outlivesOpener }: {
|
||||
embedder: WebContents,
|
||||
guest: WebContents,
|
||||
guest: BrowserWindow,
|
||||
frameName: string,
|
||||
outlivesOpener: boolean
|
||||
}) {
|
||||
const closedByEmbedder = function () {
|
||||
guest.removeListener('destroyed', closedByUser);
|
||||
guest.removeListener('closed', closedByUser);
|
||||
guest.destroy();
|
||||
};
|
||||
|
||||
@@ -134,11 +110,11 @@ const handleWindowLifecycleEvents = function ({ embedder, guest, frameName, outl
|
||||
if (!outlivesOpener) {
|
||||
embedder.once('current-render-view-deleted' as any, closedByEmbedder);
|
||||
}
|
||||
guest.once('destroyed', closedByUser);
|
||||
guest.once('closed', closedByUser);
|
||||
|
||||
if (frameName) {
|
||||
registerFrameNameToGuestWindow(frameName, guest);
|
||||
guest.once('destroyed', function () {
|
||||
guest.once('closed', function () {
|
||||
unregisterFrameName(frameName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,22 +209,6 @@ type ExtraURLLoaderOptions = {
|
||||
headers: Record<string, { name: string, value: string | string[] }>;
|
||||
allowNonHttpProtocols: boolean;
|
||||
}
|
||||
|
||||
function validateHeader (name: any, value: any): void {
|
||||
if (typeof name !== 'string') {
|
||||
throw new TypeError('`name` should be a string in setHeader(name, value)');
|
||||
}
|
||||
if (value == null) {
|
||||
throw new Error('`value` required in setHeader("' + name + '", value)');
|
||||
}
|
||||
if (!isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`);
|
||||
}
|
||||
if (!isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||
}
|
||||
}
|
||||
|
||||
function parseOptions (optionsIn: ClientRequestConstructorOptions | string): NodeJS.CreateURLLoaderOptions & ExtraURLLoaderOptions {
|
||||
// eslint-disable-next-line node/no-deprecated-api
|
||||
const options: any = typeof optionsIn === 'string' ? url.parse(optionsIn) : { ...optionsIn };
|
||||
@@ -291,7 +275,12 @@ function parseOptions (optionsIn: ClientRequestConstructorOptions | string): Nod
|
||||
};
|
||||
const headers: Record<string, string | string[]> = options.headers || {};
|
||||
for (const [name, value] of Object.entries(headers)) {
|
||||
validateHeader(name, value);
|
||||
if (!isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`);
|
||||
}
|
||||
if (!isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||
}
|
||||
const key = name.toLowerCase();
|
||||
urlLoaderOptions.headers[key] = { name, value };
|
||||
}
|
||||
@@ -362,10 +351,21 @@ export class ClientRequest extends Writable implements Electron.ClientRequest {
|
||||
}
|
||||
|
||||
setHeader (name: string, value: string) {
|
||||
if (typeof name !== 'string') {
|
||||
throw new TypeError('`name` should be a string in setHeader(name, value)');
|
||||
}
|
||||
if (value == null) {
|
||||
throw new Error('`value` required in setHeader("' + name + '", value)');
|
||||
}
|
||||
if (this._started || this._firstWrite) {
|
||||
throw new Error('Can\'t set headers after they are sent');
|
||||
}
|
||||
validateHeader(name, value);
|
||||
if (!isValidHeaderName(name)) {
|
||||
throw new Error(`Invalid header name: '${name}'`);
|
||||
}
|
||||
if (!isValidHeaderValue(value.toString())) {
|
||||
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||
}
|
||||
|
||||
const key = name.toLowerCase();
|
||||
this._urlLoaderOptions.headers[key] = { name, value };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Buffer } from 'buffer';
|
||||
import { Dirent, constants } from 'fs';
|
||||
import { constants } from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
|
||||
@@ -46,17 +46,7 @@ process._getOrCreateArchive = getOrCreateArchive;
|
||||
|
||||
const asarRe = /\.asar/i;
|
||||
|
||||
const {
|
||||
getValidatedPath,
|
||||
getOptions,
|
||||
getDirent
|
||||
} = __non_webpack_require__('internal/fs/utils');
|
||||
|
||||
const {
|
||||
validateBoolean,
|
||||
validateFunction
|
||||
} = __non_webpack_require__('internal/validators');
|
||||
|
||||
const { getValidatedPath } = __non_webpack_require__('internal/fs/utils');
|
||||
// In the renderer node internals use the node global URL but we do not set that to be
|
||||
// the global URL instance. We need to do instanceof checks against the internal URL impl
|
||||
const { URL: NodeURL } = __non_webpack_require__('internal/url');
|
||||
@@ -88,23 +78,6 @@ const gid = process.getgid?.() ?? 0;
|
||||
|
||||
const fakeTime = new Date();
|
||||
|
||||
function getDirents (p: string, { 0: names, 1: types }: any[][]): Dirent[] {
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
let type = types[i];
|
||||
const info = splitPath(path.join(p, names[i]));
|
||||
if (info.isAsar) {
|
||||
const archive = getOrCreateArchive(info.asarPath);
|
||||
if (!archive) continue;
|
||||
const stats = archive.stat(info.filePath);
|
||||
if (!stats) continue;
|
||||
type = stats.type;
|
||||
}
|
||||
names[i] = getDirent(p, names[i], type);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
enum AsarFileType {
|
||||
kFile = (constants as any).UV_DIRENT_FILE,
|
||||
kDirectory = (constants as any).UV_DIRENT_DIR,
|
||||
@@ -689,27 +662,13 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
return (encoding) ? buffer.toString(encoding) : buffer;
|
||||
};
|
||||
|
||||
type ReaddirOptions = { encoding: BufferEncoding | null; withFileTypes?: false, recursive?: false } | undefined | null;
|
||||
type ReaddirCallback = (err: NodeJS.ErrnoException | null, files: string[]) => void;
|
||||
|
||||
const { readdir } = fs;
|
||||
fs.readdir = function (pathArgument: string, options: ReaddirOptions, callback: ReaddirCallback) {
|
||||
callback = typeof options === 'function' ? options : callback;
|
||||
validateFunction(callback, 'callback');
|
||||
|
||||
options = getOptions(options);
|
||||
pathArgument = getValidatedPath(pathArgument);
|
||||
|
||||
if (options?.recursive != null) {
|
||||
validateBoolean(options?.recursive, 'options.recursive');
|
||||
}
|
||||
|
||||
if (options?.recursive) {
|
||||
nextTick(callback!, [null, readdirSyncRecursive(pathArgument, options)]);
|
||||
return;
|
||||
}
|
||||
|
||||
fs.readdir = function (pathArgument: string, options?: { encoding?: string | null; withFileTypes?: boolean } | null, callback?: Function) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
if (!pathInfo.isAsar) return readdir.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
@@ -746,62 +705,12 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
nextTick(callback!, [null, files]);
|
||||
};
|
||||
|
||||
const { readdir: readdirPromise } = require('fs').promises;
|
||||
fs.promises.readdir = async function (pathArgument: string, options: ReaddirOptions) {
|
||||
options = getOptions(options);
|
||||
pathArgument = getValidatedPath(pathArgument);
|
||||
fs.promises.readdir = util.promisify(fs.readdir);
|
||||
|
||||
if (options?.recursive != null) {
|
||||
validateBoolean(options?.recursive, 'options.recursive');
|
||||
}
|
||||
|
||||
if (options?.recursive) {
|
||||
return readdirRecursive(pathArgument, options);
|
||||
}
|
||||
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return readdirPromise(pathArgument, options);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) {
|
||||
return Promise.reject(createError(AsarError.INVALID_ARCHIVE, { asarPath }));
|
||||
}
|
||||
|
||||
const files = archive.readdir(filePath);
|
||||
if (!files) {
|
||||
return Promise.reject(createError(AsarError.NOT_FOUND, { asarPath, filePath }));
|
||||
}
|
||||
|
||||
if (options?.withFileTypes) {
|
||||
const dirents = [];
|
||||
for (const file of files) {
|
||||
const childPath = path.join(filePath, file);
|
||||
const stats = archive.stat(childPath);
|
||||
if (!stats) {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath: childPath });
|
||||
}
|
||||
dirents.push(new fs.Dirent(file, stats.type));
|
||||
}
|
||||
return Promise.resolve(dirents);
|
||||
}
|
||||
|
||||
return Promise.resolve(files);
|
||||
};
|
||||
type ReaddirSyncOptions = { encoding: BufferEncoding | null; withFileTypes?: false };
|
||||
|
||||
const { readdirSync } = fs;
|
||||
fs.readdirSync = function (pathArgument: string, options: ReaddirOptions) {
|
||||
options = getOptions(options);
|
||||
pathArgument = getValidatedPath(pathArgument);
|
||||
|
||||
if (options?.recursive != null) {
|
||||
validateBoolean(options?.recursive, 'options.recursive');
|
||||
}
|
||||
|
||||
if (options?.recursive) {
|
||||
return readdirSyncRecursive(pathArgument, options);
|
||||
}
|
||||
|
||||
fs.readdirSync = function (pathArgument: string, options: ReaddirSyncOptions | BufferEncoding | null) {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return readdirSync.apply(this, arguments);
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
@@ -816,7 +725,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
}
|
||||
|
||||
if (options?.withFileTypes) {
|
||||
if (options && (options as ReaddirSyncOptions).withFileTypes) {
|
||||
const dirents = [];
|
||||
for (const file of files) {
|
||||
const childPath = path.join(filePath, file);
|
||||
@@ -832,8 +741,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
return files;
|
||||
};
|
||||
|
||||
const binding = internalBinding('fs');
|
||||
const { internalModuleReadJSON, kUsePromises } = binding;
|
||||
const { internalModuleReadJSON } = internalBinding('fs');
|
||||
internalBinding('fs').internalModuleReadJSON = (pathArgument: string) => {
|
||||
const pathInfo = splitPath(pathArgument);
|
||||
if (!pathInfo.isAsar) return internalModuleReadJSON(pathArgument);
|
||||
@@ -879,187 +787,6 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
return (stats.type === AsarFileType.kDirectory) ? 1 : 0;
|
||||
};
|
||||
|
||||
async function readdirRecursive (originalPath: string, options: ReaddirOptions) {
|
||||
const result: any[] = [];
|
||||
|
||||
const pathInfo = splitPath(originalPath);
|
||||
let queue: [string, string[]][] = [];
|
||||
const withFileTypes = Boolean(options?.withFileTypes);
|
||||
|
||||
let initialItem = [];
|
||||
if (pathInfo.isAsar) {
|
||||
const archive = getOrCreateArchive(pathInfo.asarPath);
|
||||
if (!archive) return result;
|
||||
const files = archive.readdir(pathInfo.filePath);
|
||||
if (!files) return result;
|
||||
|
||||
// If we're in an asar dir, we need to ensure the result is in the same format as the
|
||||
// native call to readdir withFileTypes i.e. an array of arrays.
|
||||
initialItem = files;
|
||||
if (withFileTypes) {
|
||||
initialItem = [
|
||||
[...initialItem], initialItem.map((p: string) => {
|
||||
return internalBinding('fs').internalModuleStat(path.join(originalPath, p));
|
||||
})
|
||||
];
|
||||
}
|
||||
} else {
|
||||
initialItem = await binding.readdir(
|
||||
path.toNamespacedPath(originalPath),
|
||||
options!.encoding,
|
||||
withFileTypes,
|
||||
kUsePromises
|
||||
);
|
||||
}
|
||||
|
||||
queue = [[originalPath, initialItem]];
|
||||
|
||||
if (withFileTypes) {
|
||||
while (queue.length > 0) {
|
||||
// @ts-expect-error this is a valid array destructure assignment.
|
||||
const { 0: pathArg, 1: readDir } = queue.pop();
|
||||
for (const dirent of getDirents(pathArg, readDir)) {
|
||||
result.push(dirent);
|
||||
if (dirent.isDirectory()) {
|
||||
const direntPath = path.join(pathArg, dirent.name);
|
||||
const info = splitPath(direntPath);
|
||||
let readdirResult;
|
||||
if (info.isAsar) {
|
||||
const archive = getOrCreateArchive(info.asarPath);
|
||||
if (!archive) continue;
|
||||
const files = archive.readdir(info.filePath);
|
||||
if (!files) continue;
|
||||
|
||||
readdirResult = [
|
||||
[...files], files.map((p: string) => {
|
||||
return internalBinding('fs').internalModuleStat(path.join(direntPath, p));
|
||||
})
|
||||
];
|
||||
} else {
|
||||
readdirResult = await binding.readdir(
|
||||
direntPath,
|
||||
options!.encoding,
|
||||
true,
|
||||
kUsePromises
|
||||
);
|
||||
}
|
||||
queue.push([direntPath, readdirResult]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (queue.length > 0) {
|
||||
// @ts-expect-error this is a valid array destructure assignment.
|
||||
const { 0: pathArg, 1: readDir } = queue.pop();
|
||||
for (const ent of readDir) {
|
||||
const direntPath = path.join(pathArg, ent);
|
||||
const stat = internalBinding('fs').internalModuleStat(direntPath);
|
||||
result.push(path.relative(originalPath, direntPath));
|
||||
|
||||
if (stat === 1) {
|
||||
const subPathInfo = splitPath(direntPath);
|
||||
let item = [];
|
||||
if (subPathInfo.isAsar) {
|
||||
const archive = getOrCreateArchive(subPathInfo.asarPath);
|
||||
if (!archive) return;
|
||||
const files = archive.readdir(subPathInfo.filePath);
|
||||
if (!files) return result;
|
||||
item = files;
|
||||
} else {
|
||||
item = await binding.readdir(
|
||||
path.toNamespacedPath(direntPath),
|
||||
options!.encoding,
|
||||
false,
|
||||
kUsePromises
|
||||
);
|
||||
}
|
||||
queue.push([direntPath, item]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function readdirSyncRecursive (basePath: string, options: ReaddirOptions) {
|
||||
const withFileTypes = Boolean(options!.withFileTypes);
|
||||
const encoding = options!.encoding;
|
||||
|
||||
const readdirResults: string[] = [];
|
||||
const pathsQueue = [basePath];
|
||||
|
||||
function read (pathArg: string) {
|
||||
let readdirResult;
|
||||
|
||||
const pathInfo = splitPath(pathArg);
|
||||
if (pathInfo.isAsar) {
|
||||
const { asarPath, filePath } = pathInfo;
|
||||
const archive = getOrCreateArchive(asarPath);
|
||||
if (!archive) return;
|
||||
|
||||
readdirResult = archive.readdir(filePath);
|
||||
if (!readdirResult) return;
|
||||
// If we're in an asar dir, we need to ensure the result is in the same format as the
|
||||
// native call to readdir withFileTypes i.e. an array of arrays.
|
||||
if (withFileTypes) {
|
||||
readdirResult = [
|
||||
[...readdirResult], readdirResult.map((p: string) => {
|
||||
return internalBinding('fs').internalModuleStat(path.join(pathArg, p));
|
||||
})
|
||||
];
|
||||
}
|
||||
} else {
|
||||
readdirResult = binding.readdir(
|
||||
path.toNamespacedPath(pathArg),
|
||||
encoding,
|
||||
withFileTypes
|
||||
);
|
||||
}
|
||||
|
||||
if (readdirResult === undefined) return;
|
||||
|
||||
if (withFileTypes) {
|
||||
const length = readdirResult[0].length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const resultPath = path.join(pathArg, readdirResult[0][i]);
|
||||
const info = splitPath(resultPath);
|
||||
|
||||
let type = readdirResult[1][i];
|
||||
if (info.isAsar) {
|
||||
const archive = getOrCreateArchive(info.asarPath);
|
||||
if (!archive) return;
|
||||
const stats = archive.stat(info.filePath);
|
||||
if (!stats) continue;
|
||||
type = stats.type;
|
||||
}
|
||||
|
||||
const dirent = getDirent(pathArg, readdirResult[0][i], type);
|
||||
|
||||
readdirResults.push(dirent);
|
||||
if (dirent.isDirectory()) {
|
||||
pathsQueue.push(path.join(dirent.path, dirent.name));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < readdirResult.length; i++) {
|
||||
const resultPath = path.join(pathArg, readdirResult[i]);
|
||||
const relativeResultPath = path.relative(basePath, resultPath);
|
||||
const stat = internalBinding('fs').internalModuleStat(resultPath);
|
||||
|
||||
readdirResults.push(relativeResultPath);
|
||||
if (stat === 1) pathsQueue.push(resultPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < pathsQueue.length; i++) {
|
||||
read(pathsQueue[i]);
|
||||
}
|
||||
|
||||
return readdirResults;
|
||||
}
|
||||
|
||||
// Calling mkdir for directory inside asar archive should throw ENOTDIR
|
||||
// error, but on Windows it throws ENOENT.
|
||||
if (process.platform === 'win32') {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"@electron/docs-parser": "^1.2.0",
|
||||
"@electron/fiddle-core": "^1.0.4",
|
||||
"@electron/github-app-auth": "^2.0.0",
|
||||
"@electron/lint-roller": "^1.12.1",
|
||||
"@electron/lint-roller": "^1.9.0",
|
||||
"@electron/typescript-definitions": "^8.15.2",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@primer/octicons": "^10.0.0",
|
||||
@@ -49,7 +49,7 @@
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"eslint-plugin-unicorn": "^46.0.1",
|
||||
"events": "^3.2.0",
|
||||
"express": "^4.19.2",
|
||||
"express": "^4.16.4",
|
||||
"folder-hash": "^2.1.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"got": "^11.8.5",
|
||||
|
||||
@@ -34,22 +34,64 @@ index 69e759c3b34692beac06ceeddf4b3f1637fb7788..42d0da7f936626aa8bb90057723deeaa
|
||||
}
|
||||
|
||||
diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc
|
||||
index 0d8a53178e8d509a573ffdaadf2c4cec670522ac..b6fa337b2f5f445f38ef521613702af320df82cb 100644
|
||||
index 0d8a53178e8d509a573ffdaadf2c4cec670522ac..8e7f9b92beb317888a5a3acb3bc2fa29f283ff03 100644
|
||||
--- a/chrome/browser/printing/print_job.cc
|
||||
+++ b/chrome/browser/printing/print_job.cc
|
||||
@@ -100,9 +100,7 @@ PrefService* GetPrefsForWebContents(content::WebContents* web_contents) {
|
||||
// TODO(thestig): Figure out why crbug.com/1083911 occurred, which is likely
|
||||
// because `web_contents` was null. As a result, this section has many more
|
||||
// pointer checks to avoid crashing.
|
||||
- content::BrowserContext* context =
|
||||
- web_contents ? web_contents->GetBrowserContext() : nullptr;
|
||||
- return context ? Profile::FromBrowserContext(context)->GetPrefs() : nullptr;
|
||||
+ return nullptr;
|
||||
@@ -96,6 +96,7 @@ bool PrintWithReducedRasterization(PrefService* prefs) {
|
||||
return base::FeatureList::IsEnabled(features::kPrintWithReducedRasterization);
|
||||
}
|
||||
|
||||
content::WebContents* GetWebContents(content::GlobalRenderFrameHostId rfh_id) {
|
||||
+#if 0
|
||||
PrefService* GetPrefsForWebContents(content::WebContents* web_contents) {
|
||||
// TODO(thestig): Figure out why crbug.com/1083911 occurred, which is likely
|
||||
// because `web_contents` was null. As a result, this section has many more
|
||||
@@ -110,6 +111,7 @@ content::WebContents* GetWebContents(content::GlobalRenderFrameHostId rfh_id) {
|
||||
auto* rfh = content::RenderFrameHost::FromID(rfh_id);
|
||||
return rfh ? content::WebContents::FromRenderFrameHost(rfh) : nullptr;
|
||||
}
|
||||
+#endif
|
||||
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
@@ -150,10 +152,8 @@ void PrintJob::Initialize(std::unique_ptr<PrinterQuery> query,
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
pdf_page_mapping_ = PageNumber::GetPages(settings->ranges(), page_count);
|
||||
- PrefService* prefs = GetPrefsForWebContents(GetWebContents(rfh_id_));
|
||||
- if (prefs && prefs->IsManagedPreference(prefs::kPdfUseSkiaRendererEnabled)) {
|
||||
- use_skia_ = prefs->GetBoolean(prefs::kPdfUseSkiaRendererEnabled);
|
||||
- }
|
||||
+ // TODO(codebytere): should we enable this later?
|
||||
+ use_skia_ = false;
|
||||
#endif
|
||||
|
||||
auto new_doc = base::MakeRefCounted<PrintedDocument>(std::move(settings),
|
||||
@@ -404,8 +404,10 @@ void PrintJob::StartPdfToEmfConversion(
|
||||
|
||||
const PrintSettings& settings = document()->settings();
|
||||
|
||||
+#if 0
|
||||
PrefService* prefs = GetPrefsForWebContents(GetWebContents(rfh_id_));
|
||||
- bool print_with_reduced_rasterization = PrintWithReducedRasterization(prefs);
|
||||
+#endif
|
||||
+ bool print_with_reduced_rasterization = PrintWithReducedRasterization(nullptr);
|
||||
|
||||
using RenderMode = PdfRenderSettings::Mode;
|
||||
RenderMode mode = print_with_reduced_rasterization
|
||||
@@ -497,8 +499,10 @@ void PrintJob::StartPdfToPostScriptConversion(
|
||||
if (ps_level2) {
|
||||
mode = PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2;
|
||||
} else {
|
||||
+#if 0
|
||||
PrefService* prefs = GetPrefsForWebContents(GetWebContents(rfh_id_));
|
||||
- mode = PrintWithPostScriptType42Fonts(prefs)
|
||||
+#endif
|
||||
+ mode = PrintWithPostScriptType42Fonts(nullptr)
|
||||
? PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3_WITH_TYPE42_FONTS
|
||||
: PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3;
|
||||
}
|
||||
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
|
||||
index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b895705a2 100644
|
||||
index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..427a045c310109475b83a229637f4d09b1e78450 100644
|
||||
--- a/chrome/browser/printing/print_view_manager_base.cc
|
||||
+++ b/chrome/browser/printing/print_view_manager_base.cc
|
||||
@@ -23,7 +23,9 @@
|
||||
@@ -137,12 +179,13 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
}
|
||||
|
||||
PrintViewManagerBase::~PrintViewManagerBase() {
|
||||
@@ -202,12 +228,16 @@ void PrintViewManagerBase::DisableThirdPartyBlocking() {
|
||||
@@ -202,12 +228,17 @@ void PrintViewManagerBase::DisableThirdPartyBlocking() {
|
||||
}
|
||||
#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
|
||||
|
||||
-bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) {
|
||||
+bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh,
|
||||
+ bool silent,
|
||||
+ base::Value::Dict settings,
|
||||
+ CompletionCallback callback) {
|
||||
if (!StartPrintCommon(rfh)) {
|
||||
@@ -152,11 +195,11 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
- GetPrintRenderFrame(rfh)->PrintRequestedPages();
|
||||
+ callback_ = std::move(callback);
|
||||
+
|
||||
+ GetPrintRenderFrame(rfh)->PrintRequestedPages(std::move(settings));
|
||||
+ GetPrintRenderFrame(rfh)->PrintRequestedPages(silent, std::move(settings));
|
||||
|
||||
for (auto& observer : GetTestObservers()) {
|
||||
observer.OnPrintNow(rfh);
|
||||
@@ -336,12 +366,13 @@ void PrintViewManagerBase::OnDidUpdatePrintableArea(
|
||||
@@ -336,12 +367,13 @@ void PrintViewManagerBase::OnDidUpdatePrintableArea(
|
||||
}
|
||||
PRINTER_LOG(EVENT) << "Paper printable area updated for vendor id "
|
||||
<< print_settings->requested_media().vendor_id;
|
||||
@@ -171,7 +214,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
base::Value::Dict job_settings,
|
||||
std::unique_ptr<PrintSettings> print_settings,
|
||||
UpdatePrintSettingsCallback callback) {
|
||||
@@ -349,7 +380,8 @@ void PrintViewManagerBase::CompleteUpdatePrintSettings(
|
||||
@@ -349,7 +381,8 @@ void PrintViewManagerBase::CompleteUpdatePrintSettings(
|
||||
settings->pages = GetPageRangesFromJobSettings(job_settings);
|
||||
settings->params = mojom::PrintParams::New();
|
||||
RenderParamsFromPrintSettings(*print_settings, settings->params.get());
|
||||
@@ -181,7 +224,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
if (!PrintMsgPrintParamsIsValid(*settings->params)) {
|
||||
mojom::PrinterType printer_type = static_cast<mojom::PrinterType>(
|
||||
*job_settings.FindInt(kSettingPrinterType));
|
||||
@@ -361,6 +393,10 @@ void PrintViewManagerBase::CompleteUpdatePrintSettings(
|
||||
@@ -361,6 +394,10 @@ void PrintViewManagerBase::CompleteUpdatePrintSettings(
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,7 +235,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
set_cookie(settings->params->document_cookie);
|
||||
std::move(callback).Run(std::move(settings));
|
||||
}
|
||||
@@ -647,11 +683,12 @@ void PrintViewManagerBase::DidPrintDocument(
|
||||
@@ -647,11 +684,12 @@ void PrintViewManagerBase::DidPrintDocument(
|
||||
void PrintViewManagerBase::GetDefaultPrintSettings(
|
||||
GetDefaultPrintSettingsCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
@@ -206,7 +249,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
content::RenderFrameHost* render_frame_host = GetCurrentTargetFrame();
|
||||
if (base::FeatureList::IsEnabled(kCheckPrintRfhIsActive) &&
|
||||
!render_frame_host->IsActive()) {
|
||||
@@ -710,10 +747,12 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
@@ -710,10 +748,12 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
base::Value::Dict job_settings,
|
||||
UpdatePrintSettingsCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
@@ -219,7 +262,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
|
||||
std::optional<int> printer_type_value =
|
||||
job_settings.FindInt(kSettingPrinterType);
|
||||
@@ -724,6 +763,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
@@ -724,6 +764,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
|
||||
mojom::PrinterType printer_type =
|
||||
static_cast<mojom::PrinterType>(*printer_type_value);
|
||||
@@ -227,7 +270,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
if (printer_type != mojom::PrinterType::kExtension &&
|
||||
printer_type != mojom::PrinterType::kPdf &&
|
||||
printer_type != mojom::PrinterType::kLocal) {
|
||||
@@ -743,6 +783,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
@@ -743,6 +784,7 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
if (value > 0)
|
||||
job_settings.Set(kSettingRasterizePdfDpi, value);
|
||||
}
|
||||
@@ -235,7 +278,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
|
||||
std::unique_ptr<PrintSettings> print_settings =
|
||||
PrintSettingsFromJobSettings(job_settings);
|
||||
@@ -762,7 +803,21 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
@@ -762,7 +804,21 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +301,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
// TODO(crbug.com/1424368): Remove this if the printable areas can be made
|
||||
// fully available from `PrintBackend::GetPrinterSemanticCapsAndDefaults()`
|
||||
// for in-browser queries.
|
||||
@@ -784,8 +839,6 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
@@ -784,8 +840,6 @@ void PrintViewManagerBase::UpdatePrintSettings(
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -267,7 +310,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
}
|
||||
|
||||
void PrintViewManagerBase::SetAccessibilityTree(
|
||||
@@ -801,7 +854,7 @@ void PrintViewManagerBase::SetAccessibilityTree(
|
||||
@@ -801,7 +855,7 @@ void PrintViewManagerBase::SetAccessibilityTree(
|
||||
void PrintViewManagerBase::IsPrintingEnabled(
|
||||
IsPrintingEnabledCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
@@ -276,7 +319,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
}
|
||||
|
||||
void PrintViewManagerBase::ScriptedPrint(mojom::ScriptedPrintParamsPtr params,
|
||||
@@ -852,6 +905,7 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie,
|
||||
@@ -852,6 +906,7 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie,
|
||||
|
||||
PrintManager::PrintingFailed(cookie, reason);
|
||||
|
||||
@@ -284,7 +327,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
// `PrintingFailed()` can occur because asynchronous compositing results
|
||||
// don't complete until after a print job has already failed and been
|
||||
// destroyed. In such cases the error notification to the user will
|
||||
@@ -861,7 +915,7 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie,
|
||||
@@ -861,7 +916,7 @@ void PrintViewManagerBase::PrintingFailed(int32_t cookie,
|
||||
print_job_->document()->cookie() == cookie) {
|
||||
ShowPrintErrorDialogForGenericError();
|
||||
}
|
||||
@@ -293,7 +336,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
ReleasePrinterQuery();
|
||||
}
|
||||
|
||||
@@ -873,15 +927,24 @@ void PrintViewManagerBase::RemoveTestObserver(TestObserver& observer) {
|
||||
@@ -873,15 +928,24 @@ void PrintViewManagerBase::RemoveTestObserver(TestObserver& observer) {
|
||||
test_observers_.RemoveObserver(&observer);
|
||||
}
|
||||
|
||||
@@ -318,7 +361,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
}
|
||||
|
||||
void PrintViewManagerBase::RenderFrameDeleted(
|
||||
@@ -933,7 +996,12 @@ void PrintViewManagerBase::OnJobDone() {
|
||||
@@ -933,7 +997,12 @@ void PrintViewManagerBase::OnJobDone() {
|
||||
// Printing is done, we don't need it anymore.
|
||||
// print_job_->is_job_pending() may still be true, depending on the order
|
||||
// of object registration.
|
||||
@@ -332,7 +375,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
ReleasePrintJob();
|
||||
}
|
||||
|
||||
@@ -942,9 +1010,10 @@ void PrintViewManagerBase::OnCanceling() {
|
||||
@@ -942,9 +1011,10 @@ void PrintViewManagerBase::OnCanceling() {
|
||||
}
|
||||
|
||||
void PrintViewManagerBase::OnFailed() {
|
||||
@@ -344,7 +387,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
TerminatePrintJob(true);
|
||||
}
|
||||
|
||||
@@ -954,7 +1023,7 @@ bool PrintViewManagerBase::RenderAllMissingPagesNow() {
|
||||
@@ -954,7 +1024,7 @@ bool PrintViewManagerBase::RenderAllMissingPagesNow() {
|
||||
|
||||
// Is the document already complete?
|
||||
if (print_job_->document() && print_job_->document()->IsComplete()) {
|
||||
@@ -353,7 +396,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1007,7 +1076,10 @@ bool PrintViewManagerBase::SetupNewPrintJob(
|
||||
@@ -1007,7 +1077,10 @@ bool PrintViewManagerBase::SetupNewPrintJob(
|
||||
|
||||
// Disconnect the current `print_job_`.
|
||||
auto weak_this = weak_ptr_factory_.GetWeakPtr();
|
||||
@@ -365,7 +408,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
if (!weak_this)
|
||||
return false;
|
||||
|
||||
@@ -1027,7 +1099,7 @@ bool PrintViewManagerBase::SetupNewPrintJob(
|
||||
@@ -1027,7 +1100,7 @@ bool PrintViewManagerBase::SetupNewPrintJob(
|
||||
#endif
|
||||
print_job_->AddObserver(*this);
|
||||
|
||||
@@ -374,7 +417,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1095,6 +1167,11 @@ void PrintViewManagerBase::ReleasePrintJob() {
|
||||
@@ -1095,6 +1168,11 @@ void PrintViewManagerBase::ReleasePrintJob() {
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -386,7 +429,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
if (!print_job_)
|
||||
return;
|
||||
|
||||
@@ -1102,7 +1179,7 @@ void PrintViewManagerBase::ReleasePrintJob() {
|
||||
@@ -1102,7 +1180,7 @@ void PrintViewManagerBase::ReleasePrintJob() {
|
||||
// printing_rfh_ should only ever point to a RenderFrameHost with a live
|
||||
// RenderFrame.
|
||||
DCHECK(rfh->IsRenderFrameLive());
|
||||
@@ -395,7 +438,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
}
|
||||
|
||||
print_job_->RemoveObserver(*this);
|
||||
@@ -1144,7 +1221,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
|
||||
@@ -1144,7 +1222,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
|
||||
}
|
||||
|
||||
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
|
||||
@@ -404,7 +447,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
return true;
|
||||
|
||||
if (!cookie) {
|
||||
@@ -1298,6 +1375,8 @@ void PrintViewManagerBase::CompleteScriptedPrint(
|
||||
@@ -1298,6 +1376,8 @@ void PrintViewManagerBase::CompleteScriptedPrint(
|
||||
auto callback_wrapper = base::BindOnce(
|
||||
&PrintViewManagerBase::ScriptedPrintReply, weak_ptr_factory_.GetWeakPtr(),
|
||||
std::move(callback), render_process_host->GetID());
|
||||
@@ -413,7 +456,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
|
||||
DisableThirdPartyBlocking();
|
||||
#endif
|
||||
@@ -1312,7 +1391,7 @@ void PrintViewManagerBase::CompleteScriptedPrint(
|
||||
@@ -1312,7 +1392,7 @@ void PrintViewManagerBase::CompleteScriptedPrint(
|
||||
params->expected_pages_count, params->has_selection, params->margin_type,
|
||||
params->is_scripted, !render_process_host->IsPdf(),
|
||||
base::BindOnce(&OnDidScriptedPrint, queue_, std::move(printer_query),
|
||||
@@ -423,7 +466,7 @@ index 301a4a47fb4dfb6007c2214b04ffdff744cc3043..168b7b773996a621fbbebea08933317b
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS)
|
||||
diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h
|
||||
index 24a2bc8b26462e6cafbcd5eb89e838b73266ec70..0399e0bafa51d7b02d4dd05e6df8b48fc51d7457 100644
|
||||
index 24a2bc8b26462e6cafbcd5eb89e838b73266ec70..402aab3b14e6987bde0e22e6c82ac438d465330a 100644
|
||||
--- a/chrome/browser/printing/print_view_manager_base.h
|
||||
+++ b/chrome/browser/printing/print_view_manager_base.h
|
||||
@@ -49,6 +49,8 @@ class PrinterQuery;
|
||||
@@ -435,18 +478,19 @@ index 24a2bc8b26462e6cafbcd5eb89e838b73266ec70..0399e0bafa51d7b02d4dd05e6df8b48f
|
||||
// Base class for managing the print commands for a WebContents.
|
||||
class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
public:
|
||||
@@ -82,7 +84,9 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
@@ -82,7 +84,10 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
// Prints the current document immediately. Since the rendering is
|
||||
// asynchronous, the actual printing will not be completed on the return of
|
||||
// this function. Returns false if printing is impossible at the moment.
|
||||
- virtual bool PrintNow(content::RenderFrameHost* rfh);
|
||||
+ virtual bool PrintNow(content::RenderFrameHost* rfh,
|
||||
+ bool silent = true,
|
||||
+ base::Value::Dict settings = {},
|
||||
+ CompletionCallback callback = {});
|
||||
|
||||
// Like PrintNow(), but for the node under the context menu, instead of the
|
||||
// entire frame.
|
||||
@@ -136,8 +140,10 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
@@ -136,8 +141,10 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
void IsPrintingEnabled(IsPrintingEnabledCallback callback) override;
|
||||
void ScriptedPrint(mojom::ScriptedPrintParamsPtr params,
|
||||
ScriptedPrintCallback callback) override;
|
||||
@@ -457,7 +501,7 @@ index 24a2bc8b26462e6cafbcd5eb89e838b73266ec70..0399e0bafa51d7b02d4dd05e6df8b48f
|
||||
|
||||
// Adds and removes observers for `PrintViewManagerBase` events. The order in
|
||||
// which notifications are sent to observers is undefined. Observers must be
|
||||
@@ -145,6 +151,14 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
@@ -145,6 +152,14 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
void AddTestObserver(TestObserver& observer);
|
||||
void RemoveTestObserver(TestObserver& observer);
|
||||
|
||||
@@ -472,7 +516,7 @@ index 24a2bc8b26462e6cafbcd5eb89e838b73266ec70..0399e0bafa51d7b02d4dd05e6df8b48f
|
||||
protected:
|
||||
explicit PrintViewManagerBase(content::WebContents* web_contents);
|
||||
|
||||
@@ -268,6 +282,7 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
@@ -268,6 +283,7 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
bool success);
|
||||
#endif
|
||||
void CompleteUpdatePrintSettings(
|
||||
@@ -480,7 +524,7 @@ index 24a2bc8b26462e6cafbcd5eb89e838b73266ec70..0399e0bafa51d7b02d4dd05e6df8b48f
|
||||
base::Value::Dict job_settings,
|
||||
std::unique_ptr<PrintSettings> print_settings,
|
||||
UpdatePrintSettingsCallback callback);
|
||||
@@ -362,8 +377,11 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
@@ -362,8 +378,11 @@ class PrintViewManagerBase : public PrintManager, public PrintJob::Observer {
|
||||
// The current RFH that is printing with a system printing dialog.
|
||||
raw_ptr<content::RenderFrameHost> printing_rfh_ = nullptr;
|
||||
|
||||
@@ -521,6 +565,32 @@ index 418f53b0db3a2b2624298fca5628aacdd2a99c94..4a110fda692e16ec887cb90c6a2fa611
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
diff --git a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc
|
||||
index ac54519f611f719470c4b7a139a58f489884ede2..89055b6df74389560b6c5884a511897a36425b7b 100644
|
||||
--- a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc
|
||||
+++ b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.cc
|
||||
@@ -21,7 +21,7 @@ FakePrintRenderFrame::FakePrintRenderFrame(
|
||||
|
||||
FakePrintRenderFrame::~FakePrintRenderFrame() = default;
|
||||
|
||||
-void FakePrintRenderFrame::PrintRequestedPages() {}
|
||||
+void FakePrintRenderFrame::PrintRequestedPages(bool /*silent*/, ::base::Value::Dict /*settings*/) {}
|
||||
|
||||
void FakePrintRenderFrame::PrintWithParams(mojom::PrintPagesParamsPtr params,
|
||||
PrintWithParamsCallback callback) {
|
||||
diff --git a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h
|
||||
index 1e8f7bedaf679ee19788bf181b33e5d574d1f863..8be77b57580621bf659a6a2a63a2be94a2301c70 100644
|
||||
--- a/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h
|
||||
+++ b/chrome/browser/ui/webui/print_preview/fake_print_render_frame.h
|
||||
@@ -25,7 +25,7 @@ class FakePrintRenderFrame : public mojom::PrintRenderFrame {
|
||||
|
||||
private:
|
||||
// printing::mojom::PrintRenderFrame:
|
||||
- void PrintRequestedPages() override;
|
||||
+ void PrintRequestedPages(bool silent, ::base::Value::Dict settings) override;
|
||||
void PrintWithParams(mojom::PrintPagesParamsPtr params,
|
||||
PrintWithParamsCallback callback) override;
|
||||
void PrintForSystemDialog() override;
|
||||
diff --git a/components/printing/browser/print_manager.cc b/components/printing/browser/print_manager.cc
|
||||
index 21c81377d32ae8d4185598a7eba88ed1d2063ef0..0767f4e9369e926b1cea99178c1a1975941f1765 100644
|
||||
--- a/components/printing/browser/print_manager.cc
|
||||
@@ -547,7 +617,7 @@ index ca71560874a0189068dd11fbc039f5673bf6bd96..a8551d95e64da2afbc1685b2df8f1fc3
|
||||
mojom::PrintFailureReason reason) override;
|
||||
|
||||
diff --git a/components/printing/common/print.mojom b/components/printing/common/print.mojom
|
||||
index 4ecdb28904fac480cf102fffdff24ae008ac88cf..0d7d20c1a7920b1961585b345d30d9969411ca9e 100644
|
||||
index 4ecdb28904fac480cf102fffdff24ae008ac88cf..e8150c95fafd83d7e2fe1f472a35acec3ca6e391 100644
|
||||
--- a/components/printing/common/print.mojom
|
||||
+++ b/components/printing/common/print.mojom
|
||||
@@ -302,7 +302,7 @@ union PrintWithParamsResult {
|
||||
@@ -555,7 +625,7 @@ index 4ecdb28904fac480cf102fffdff24ae008ac88cf..0d7d20c1a7920b1961585b345d30d996
|
||||
// Tells the RenderFrame to switch the CSS to print media type, render every
|
||||
// requested page, and then switch back the CSS to display media type.
|
||||
- PrintRequestedPages();
|
||||
+ PrintRequestedPages(mojo_base.mojom.DictionaryValue settings);
|
||||
+ PrintRequestedPages(bool silent, mojo_base.mojom.DictionaryValue settings);
|
||||
|
||||
// Requests the frame to be printed with specified parameters. This is used
|
||||
// to programmatically produce PDF by request from the browser (e.g. over
|
||||
@@ -570,7 +640,7 @@ index 4ecdb28904fac480cf102fffdff24ae008ac88cf..0d7d20c1a7920b1961585b345d30d996
|
||||
PrintingFailed(int32 cookie, PrintFailureReason reason);
|
||||
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
|
||||
index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e0bc57369 100644
|
||||
index a0ec654b13f82d9c5ff4eb838585485a59c45924..e24f2e209e547685daf18570c0a8a95306c72e2d 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.cc
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.cc
|
||||
@@ -47,6 +47,7 @@
|
||||
@@ -594,7 +664,7 @@ index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e
|
||||
|
||||
- Print(web_frame, blink::WebNode(), PrintRequestType::kScripted);
|
||||
+ Print(web_frame, blink::WebNode(), PrintRequestType::kScripted,
|
||||
+ base::Value::Dict() /* new_settings */);
|
||||
+ false /* silent */, base::Value::Dict() /* new_settings */);
|
||||
if (!weak_this) {
|
||||
return;
|
||||
}
|
||||
@@ -603,7 +673,7 @@ index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e
|
||||
}
|
||||
|
||||
-void PrintRenderFrameHelper::PrintRequestedPages() {
|
||||
+void PrintRenderFrameHelper::PrintRequestedPages(base::Value::Dict settings) {
|
||||
+void PrintRenderFrameHelper::PrintRequestedPages(bool silent, base::Value::Dict settings) {
|
||||
ScopedIPC scoped_ipc(weak_ptr_factory_.GetWeakPtr());
|
||||
if (ipc_nesting_level_ > kAllowedIpcDepthForPrint)
|
||||
return;
|
||||
@@ -612,20 +682,21 @@ index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e
|
||||
auto plugin = delegate_->GetPdfElement(frame);
|
||||
|
||||
- Print(frame, plugin, PrintRequestType::kRegular);
|
||||
+ Print(frame, plugin, PrintRequestType::kRegular, std::move(settings));
|
||||
+ Print(frame, plugin, PrintRequestType::kRegular, silent, std::move(settings));
|
||||
|
||||
if (render_frame_gone_) {
|
||||
return;
|
||||
@@ -1371,7 +1372,7 @@ void PrintRenderFrameHelper::PrintForSystemDialog() {
|
||||
@@ -1371,7 +1372,8 @@ void PrintRenderFrameHelper::PrintForSystemDialog() {
|
||||
}
|
||||
|
||||
Print(frame, print_preview_context_.source_node(),
|
||||
- PrintRequestType::kRegular);
|
||||
+ PrintRequestType::kRegular, base::Value::Dict());
|
||||
+ PrintRequestType::kRegular, false,
|
||||
+ base::Value::Dict());
|
||||
if (render_frame_gone_) {
|
||||
return;
|
||||
}
|
||||
@@ -1434,6 +1435,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) {
|
||||
@@ -1434,6 +1436,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) {
|
||||
if (ipc_nesting_level_ > kAllowedIpcDepthForPrint)
|
||||
return;
|
||||
|
||||
@@ -634,27 +705,28 @@ index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e
|
||||
print_preview_context_.OnPrintPreview();
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
||||
@@ -2011,7 +2014,7 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
|
||||
@@ -2011,7 +2015,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
|
||||
}
|
||||
|
||||
Print(duplicate_node.GetDocument().GetFrame(), duplicate_node,
|
||||
- PrintRequestType::kRegular);
|
||||
+ PrintRequestType::kRegular, base::Value::Dict());
|
||||
+ PrintRequestType::kRegular, false /* silent */,
|
||||
+ base::Value::Dict() /* new_settings */);
|
||||
// Check if `this` is still valid.
|
||||
if (!weak_this) {
|
||||
return;
|
||||
@@ -2027,17 +2030,19 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
|
||||
@@ -2027,17 +2032,19 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
|
||||
|
||||
void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
|
||||
const blink::WebNode& node,
|
||||
- PrintRequestType print_request_type) {
|
||||
+ PrintRequestType print_request_type,
|
||||
+ bool silent,
|
||||
+ base::Value::Dict settings) {
|
||||
// If still not finished with earlier print request simply ignore.
|
||||
if (prep_frame_view_)
|
||||
return;
|
||||
|
||||
+ bool silent = settings.FindBool("silent").value_or(false);
|
||||
FrameReference frame_ref(frame);
|
||||
|
||||
- if (!InitPrintSettings(frame, node)) {
|
||||
@@ -666,7 +738,7 @@ index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e
|
||||
DidFinishPrinting(PrintingResult::kFailPrintInit);
|
||||
return;
|
||||
}
|
||||
@@ -2058,8 +2063,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
|
||||
@@ -2058,8 +2065,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
|
||||
print_pages_params_->params->print_scaling_option;
|
||||
|
||||
auto self = weak_ptr_factory_.GetWeakPtr();
|
||||
@@ -683,7 +755,7 @@ index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e
|
||||
// Check if `this` is still valid.
|
||||
if (!self)
|
||||
return;
|
||||
@@ -2317,25 +2329,33 @@ void PrintRenderFrameHelper::IPCProcessed() {
|
||||
@@ -2317,25 +2331,33 @@ void PrintRenderFrameHelper::IPCProcessed() {
|
||||
}
|
||||
|
||||
bool PrintRenderFrameHelper::InitPrintSettings(blink::WebLocalFrame* frame,
|
||||
@@ -724,7 +796,7 @@ index a0ec654b13f82d9c5ff4eb838585485a59c45924..01381687ee4e4c4096c0407ffc211c3e
|
||||
}
|
||||
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h
|
||||
index b0ac94751454bd16b4e9bfdc071e2623813133ec..74809543b8c1030494638a58c6d27ee69e2867b2 100644
|
||||
index b0ac94751454bd16b4e9bfdc071e2623813133ec..271bd9949a802a370b3619340f3364df14c7fe4a 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.h
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.h
|
||||
@@ -245,7 +245,7 @@ class PrintRenderFrameHelper
|
||||
@@ -732,21 +804,22 @@ index b0ac94751454bd16b4e9bfdc071e2623813133ec..74809543b8c1030494638a58c6d27ee6
|
||||
|
||||
// printing::mojom::PrintRenderFrame:
|
||||
- void PrintRequestedPages() override;
|
||||
+ void PrintRequestedPages(base::Value::Dict settings) override;
|
||||
+ void PrintRequestedPages(bool silent, base::Value::Dict settings) override;
|
||||
void PrintWithParams(mojom::PrintPagesParamsPtr params,
|
||||
PrintWithParamsCallback callback) override;
|
||||
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
|
||||
@@ -312,7 +312,8 @@ class PrintRenderFrameHelper
|
||||
@@ -312,7 +312,9 @@ class PrintRenderFrameHelper
|
||||
// WARNING: |this| may be gone after this method returns.
|
||||
void Print(blink::WebLocalFrame* frame,
|
||||
const blink::WebNode& node,
|
||||
- PrintRequestType print_request_type);
|
||||
+ PrintRequestType print_request_type,
|
||||
+ bool silent,
|
||||
+ base::Value::Dict settings);
|
||||
|
||||
// Notification when printing is done - signal tear-down/free resources.
|
||||
void DidFinishPrinting(PrintingResult result);
|
||||
@@ -322,7 +323,8 @@ class PrintRenderFrameHelper
|
||||
@@ -322,7 +324,8 @@ class PrintRenderFrameHelper
|
||||
// Initialize print page settings with default settings.
|
||||
// Used only for native printing workflow.
|
||||
bool InitPrintSettings(blink::WebLocalFrame* frame,
|
||||
|
||||
@@ -33,6 +33,7 @@ fix_assert_module_in_the_renderer_process.patch
|
||||
fix_add_trusted_space_and_trusted_lo_space_to_the_v8_heap.patch
|
||||
win_process_avoid_assert_after_spawning_store_app_4152.patch
|
||||
chore_remove_use_of_deprecated_kmaxlength.patch
|
||||
fix_missing_include_for_node_extern.patch
|
||||
feat_optionally_prevent_calling_v8_enablewebassemblytraphandler.patch
|
||||
build_only_create_cppgc_heap_on_non-32_bit_platforms.patch
|
||||
fix_-wshadow_error_in_uvwasi_c.patch
|
||||
@@ -46,4 +47,3 @@ build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch
|
||||
fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
|
||||
src_preload_function_for_environment.patch
|
||||
deprecate_vector_v8_local_in_v8.patch
|
||||
fs_fix_wtf-8_decoding_issue.patch
|
||||
|
||||
@@ -87,18 +87,10 @@ index 895ff3a5948add3513700ecc2f32fce4c2fbe4eb..3182a5e4aad2ba0be2b6769edb696b81
|
||||
|
||||
MaybeLocal<Value> ModuleWrap::SyntheticModuleEvaluationStepsCallback(
|
||||
diff --git a/src/module_wrap.h b/src/module_wrap.h
|
||||
index e17048357feca2419087621ed280de30882a90bc..63682be31ce00a3bf7b9be909cac4b7f9ec02a8e 100644
|
||||
index e17048357feca2419087621ed280de30882a90bc..061117dc3182d63e35d7e99ffd95801f96356322 100644
|
||||
--- a/src/module_wrap.h
|
||||
+++ b/src/module_wrap.h
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "base_object.h"
|
||||
+#include "node.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
@@ -31,7 +32,14 @@ enum HostDefinedOptions : int {
|
||||
@@ -31,7 +31,14 @@ enum HostDefinedOptions : int {
|
||||
kLength = 9,
|
||||
};
|
||||
|
||||
@@ -114,7 +106,7 @@ index e17048357feca2419087621ed280de30882a90bc..63682be31ce00a3bf7b9be909cac4b7f
|
||||
public:
|
||||
enum InternalFields {
|
||||
kModuleSlot = BaseObject::kInternalFieldCount,
|
||||
@@ -68,6 +76,8 @@ class ModuleWrap : public BaseObject {
|
||||
@@ -68,6 +75,8 @@ class ModuleWrap : public BaseObject {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -123,7 +115,7 @@ index e17048357feca2419087621ed280de30882a90bc..63682be31ce00a3bf7b9be909cac4b7f
|
||||
private:
|
||||
ModuleWrap(Realm* realm,
|
||||
v8::Local<v8::Object> object,
|
||||
@@ -102,7 +112,6 @@ class ModuleWrap : public BaseObject {
|
||||
@@ -102,7 +111,6 @@ class ModuleWrap : public BaseObject {
|
||||
v8::Local<v8::String> specifier,
|
||||
v8::Local<v8::FixedArray> import_attributes,
|
||||
v8::Local<v8::Module> referrer);
|
||||
|
||||
26
patches/node/fix_missing_include_for_node_extern.patch
Normal file
26
patches/node/fix_missing_include_for_node_extern.patch
Normal file
@@ -0,0 +1,26 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Wed, 15 Nov 2023 12:25:39 +0100
|
||||
Subject: fix: missing include for NODE_EXTERN
|
||||
|
||||
At some point it seems that node.h was removed from the include chain,
|
||||
causing the following error:
|
||||
|
||||
../../third_party/electron_node/src/module_wrap.h:33:1: error: unknown type name 'NODE_EXTERN'
|
||||
33 | NODE_EXTERN v8::MaybeLocal<v8::Promise> ImportModuleDynamically(
|
||||
| ^
|
||||
|
||||
This should be upstreamed.
|
||||
|
||||
diff --git a/src/module_wrap.h b/src/module_wrap.h
|
||||
index 061117dc3182d63e35d7e99ffd95801f96356322..63682be31ce00a3bf7b9be909cac4b7f9ec02a8e 100644
|
||||
--- a/src/module_wrap.h
|
||||
+++ b/src/module_wrap.h
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "base_object.h"
|
||||
+#include "node.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Richard Lau <rlau@redhat.com>
|
||||
Date: Fri, 1 Mar 2024 19:15:40 +0000
|
||||
Subject: fs: fix WTF-8 decoding issue
|
||||
|
||||
Cherry-pick of libuv/libuv@d09441c
|
||||
|
||||
Refs: https://github.com/libuv/libuv/pull/2970
|
||||
Fixes: https://github.com/nodejs/node/issues/48673
|
||||
|
||||
We forgot to mask off the high bits from the first byte, so we ended up
|
||||
always failing the subsequent range check.
|
||||
|
||||
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
|
||||
index fc209c54f470edaa031009979061cff071cbf66d..4fc13b04bdae5bd9e2627027a10c534c2d9675dc 100644
|
||||
--- a/deps/uv/src/win/fs.c
|
||||
+++ b/deps/uv/src/win/fs.c
|
||||
@@ -176,9 +176,11 @@ static int32_t fs__decode_wtf8_char(const char** input) {
|
||||
if ((b4 & 0xC0) != 0x80)
|
||||
return -1; /* invalid: not a continuation byte */
|
||||
code_point = (code_point << 6) | (b4 & 0x3F);
|
||||
- if (b1 <= 0xF4)
|
||||
+ if (b1 <= 0xF4) {
|
||||
+ code_point &= 0x1FFFFF;
|
||||
if (code_point <= 0x10FFFF)
|
||||
return code_point; /* four-byte character */
|
||||
+ }
|
||||
|
||||
/* code point too large */
|
||||
return -1;
|
||||
@@ -13,7 +13,7 @@ THREEWAY = "ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES" in os.environ
|
||||
def apply_patches(target):
|
||||
repo = target.get('repo')
|
||||
if not os.path.exists(repo):
|
||||
warnings.warn(f'repo not found: {repo}')
|
||||
warnings.warn('repo not found: %s' % repo)
|
||||
return
|
||||
patch_dir = target.get('patch_dir')
|
||||
git.import_patches(
|
||||
|
||||
@@ -13,13 +13,13 @@ def stop():
|
||||
DBusTestCase.stop_dbus(DBusTestCase.session_bus_pid)
|
||||
|
||||
def start():
|
||||
with sys.stdout if is_verbose_mode() \
|
||||
else open(os.devnull, 'w', encoding='utf-8') as log:
|
||||
DBusTestCase.start_system_bus()
|
||||
DBusTestCase.spawn_server_template('logind', None, log)
|
||||
log = sys.stdout if is_verbose_mode() else open(os.devnull, 'w')
|
||||
|
||||
DBusTestCase.start_session_bus()
|
||||
DBusTestCase.spawn_server_template('notification_daemon', None, log)
|
||||
DBusTestCase.start_system_bus()
|
||||
DBusTestCase.spawn_server_template('logind', None, log)
|
||||
|
||||
DBusTestCase.start_session_bus()
|
||||
DBusTestCase.spawn_server_template('notification_daemon', None, log)
|
||||
|
||||
if __name__ == '__main__':
|
||||
start()
|
||||
|
||||
@@ -11,7 +11,7 @@ from lib import git
|
||||
def export_patches(target, dry_run):
|
||||
repo = target.get('repo')
|
||||
if not os.path.exists(repo):
|
||||
warnings.warn(f'repo not found: {repo}')
|
||||
warnings.warn('repo not found: %s' % repo)
|
||||
return
|
||||
git.export_patches(
|
||||
dry_run=dry_run,
|
||||
|
||||
@@ -29,15 +29,15 @@ def run_node_configure(target_cpu):
|
||||
|
||||
def read_node_config_gypi():
|
||||
config_gypi = os.path.join(NODE_DIR, 'config.gypi')
|
||||
with open(config_gypi, 'r', encoding='utf-8') as file_in:
|
||||
content = file_in.read()
|
||||
with open(config_gypi, 'r') as f:
|
||||
content = f.read()
|
||||
return ast.literal_eval(content)
|
||||
|
||||
def read_electron_args():
|
||||
all_gn = os.path.join(ELECTRON_DIR, 'build', 'args', 'all.gn')
|
||||
args = {}
|
||||
with open(all_gn, 'r', encoding='utf-8') as file_in:
|
||||
for line in file_in:
|
||||
with open(all_gn, 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
m = re.match('([\w_]+) = (.+)', line)
|
||||
@@ -62,8 +62,8 @@ def main(target_file, target_cpu):
|
||||
# Used by certain versions of node-gyp.
|
||||
v['build_v8_with_gn'] = 'false'
|
||||
|
||||
with open(target_file, 'w+', encoding='utf-8') as file_out:
|
||||
file_out.write(pprint.pformat(config, indent=2))
|
||||
with open(target_file, 'w+') as f:
|
||||
f.write(pprint.pformat(config, indent=2))
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1], sys.argv[2]))
|
||||
|
||||
@@ -4,7 +4,7 @@ import zipfile
|
||||
import sys
|
||||
|
||||
def main(zip_path, manifest_out):
|
||||
with open(manifest_out, 'w', encoding='utf-8') as manifest, \
|
||||
with open(manifest_out, 'w') as manifest, \
|
||||
zipfile.ZipFile(zip_path, 'r', allowZip64=True) as z:
|
||||
for name in sorted(z.namelist()):
|
||||
manifest.write(name + '\n')
|
||||
|
||||
@@ -8,8 +8,7 @@ NMV = None
|
||||
if len(sys.argv) > 3:
|
||||
NMV = sys.argv[3]
|
||||
|
||||
with open(node_version_file, 'r', encoding='utf-8') as in_file, \
|
||||
open(out_file, 'w', encoding='utf-8') as out_file:
|
||||
with open(node_version_file, 'r') as in_file, open(out_file, 'w') as out_file:
|
||||
changed = False
|
||||
contents = in_file.read()
|
||||
new_contents = re.sub(
|
||||
|
||||
@@ -43,7 +43,7 @@ def get_zip_name(name, version, suffix=''):
|
||||
arch = get_target_arch()
|
||||
if arch == 'arm':
|
||||
arch += 'v7l'
|
||||
zip_name = f'{name}-{version}-{get_platform_key()}-{arch}'
|
||||
zip_name = '{0}-{1}-{2}-{3}'.format(name, version, get_platform_key(), arch)
|
||||
if suffix:
|
||||
zip_name += '-' + suffix
|
||||
return zip_name + '.zip'
|
||||
|
||||
@@ -72,10 +72,13 @@ def am(repo, patch_data, threeway=False, directory=None, exclude=None,
|
||||
root_args += ['-c', 'user.email=' + committer_email]
|
||||
root_args += ['-c', 'commit.gpgsign=false']
|
||||
command = ['git'] + root_args + ['am'] + args
|
||||
with subprocess.Popen(command, stdin=subprocess.PIPE) as proc:
|
||||
proc.communicate(patch_data.encode('utf-8'))
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(f"Command {command} returned {proc.returncode}")
|
||||
proc = subprocess.Popen(
|
||||
command,
|
||||
stdin=subprocess.PIPE)
|
||||
proc.communicate(patch_data.encode('utf-8'))
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError("Command {} returned {}".format(command,
|
||||
proc.returncode))
|
||||
|
||||
|
||||
def import_patches(repo, ref=UPSTREAM_HEAD, **kwargs):
|
||||
@@ -226,19 +229,19 @@ def export_patches(repo, out_dir,
|
||||
dry_run=False, grep=None):
|
||||
if not os.path.exists(repo):
|
||||
sys.stderr.write(
|
||||
f"Skipping patches in {repo} because it does not exist.\n"
|
||||
"Skipping patches in {} because it does not exist.\n".format(repo)
|
||||
)
|
||||
return
|
||||
if patch_range is None:
|
||||
patch_range, n_patches = guess_base_commit(repo, ref)
|
||||
msg = f"Exporting {n_patches} patches in {repo} since {patch_range[0:7]}\n"
|
||||
sys.stderr.write(msg)
|
||||
patch_range, num_patches = guess_base_commit(repo, ref)
|
||||
sys.stderr.write("Exporting {} patches in {} since {}\n".format(
|
||||
num_patches, repo, patch_range[0:7]))
|
||||
patch_data = format_patch(repo, patch_range)
|
||||
patches = split_patches(patch_data)
|
||||
if grep:
|
||||
olen = len(patches)
|
||||
patches = filter_patches(patches, grep)
|
||||
sys.stderr.write(f"Exporting {len(patches)} of {olen} patches\n")
|
||||
sys.stderr.write("Exporting {} of {} patches\n".format(len(patches), olen))
|
||||
|
||||
try:
|
||||
os.mkdir(out_dir)
|
||||
@@ -253,8 +256,7 @@ def export_patches(repo, out_dir,
|
||||
for patch in patches:
|
||||
filename = get_file_name(patch)
|
||||
filepath = posixpath.join(out_dir, filename)
|
||||
with io.open(filepath, 'rb') as inp:
|
||||
existing_patch = str(inp.read(), 'utf-8')
|
||||
existing_patch = str(io.open(filepath, 'rb').read(), 'utf-8')
|
||||
formatted_patch = join_patch(patch)
|
||||
if formatted_patch != existing_patch:
|
||||
bad_patches.append(filename)
|
||||
|
||||
@@ -65,7 +65,7 @@ class Platform:
|
||||
return Platform.WINDOWS
|
||||
|
||||
raise AssertionError(
|
||||
f"unexpected current platform '{platform}'")
|
||||
"unexpected current platform '{}'".format(platform))
|
||||
|
||||
@staticmethod
|
||||
def get_all():
|
||||
@@ -101,19 +101,19 @@ class TestsList():
|
||||
# First check that all names are present in the config.
|
||||
for binary_name in binaries:
|
||||
if binary_name not in self.tests:
|
||||
msg = f"binary {binary_name} not found in config '{self.config_path}'"
|
||||
raise Exception(msg)
|
||||
raise Exception("binary {0} not found in config '{1}'".format(
|
||||
binary_name, self.config_path))
|
||||
|
||||
# Respect the "platform" setting.
|
||||
for binary_name in binaries:
|
||||
if not self.__platform_supports(binary_name):
|
||||
host = Platform.get_current()
|
||||
errmsg = f"binary {binary_name} cannot run on {host}. Check the config"
|
||||
raise Exception(errmsg)
|
||||
raise Exception(
|
||||
"binary {0} cannot be run on {1}, check the config".format(
|
||||
binary_name, Platform.get_current()))
|
||||
|
||||
suite_returncode = sum(
|
||||
self.__run(binary, output_dir, verbosity, disabled_tests_policy)
|
||||
for binary in binaries)
|
||||
[self.__run(binary, output_dir, verbosity, disabled_tests_policy)
|
||||
for binary in binaries])
|
||||
return suite_returncode
|
||||
|
||||
def run_all(self, output_dir=None, verbosity=Verbosity.CHATTY,
|
||||
@@ -134,7 +134,7 @@ class TestsList():
|
||||
|
||||
@staticmethod
|
||||
def __get_config_data(config_path):
|
||||
with open(config_path, 'r', encoding='utf-8') as stream:
|
||||
with open(config_path, 'r') as stream:
|
||||
return yaml.load(stream)
|
||||
|
||||
@staticmethod
|
||||
@@ -146,7 +146,7 @@ class TestsList():
|
||||
if isinstance(value, str):
|
||||
return {value: None}
|
||||
|
||||
raise AssertionError(f"unexpected shorthand type: {type(value)}")
|
||||
raise AssertionError("unexpected shorthand type: {}".format(type(value)))
|
||||
|
||||
@staticmethod
|
||||
def __make_a_list(value):
|
||||
@@ -166,7 +166,7 @@ class TestsList():
|
||||
return [list_item for key in value for list_item in value[key]]
|
||||
|
||||
raise AssertionError(
|
||||
f"unexpected type for list merging: {type(value)}")
|
||||
"unexpected type for list merging: {}".format(type(value)))
|
||||
|
||||
def __platform_supports(self, binary_name):
|
||||
return Platform.get_current() in self.tests[binary_name]['platforms']
|
||||
@@ -194,7 +194,8 @@ class TestsList():
|
||||
|
||||
for platform in platforms:
|
||||
assert Platform.is_valid(platform), \
|
||||
f"Unsupported platform {platform}, check {binary_name} config"
|
||||
"platform '{0}' is not supported, check {1} config" \
|
||||
.format(platform, binary_name)
|
||||
|
||||
test_data['platforms'] = platforms
|
||||
|
||||
@@ -230,7 +231,7 @@ class TestsList():
|
||||
if output_dir is None:
|
||||
return None
|
||||
|
||||
return os.path.join(output_dir, f"results_{binary_name}.xml")
|
||||
return os.path.join(output_dir, "results_{}.xml".format(binary_name))
|
||||
|
||||
|
||||
class TestBinary():
|
||||
@@ -247,40 +248,50 @@ class TestBinary():
|
||||
gtest_output = TestBinary.__get_gtest_output(output_file_path)
|
||||
|
||||
args = [self.binary_path, gtest_filter, gtest_output]
|
||||
stdout, stderr = TestBinary.__get_stdout_and_stderr(verbosity)
|
||||
|
||||
returncode = 0
|
||||
|
||||
with open(os.devnull, "w", encoding='utf-8') as devnull:
|
||||
stdout = stderr = None
|
||||
if Verbosity.le(verbosity, Verbosity.ERRORS):
|
||||
stdout = devnull
|
||||
if verbosity == Verbosity.SILENT:
|
||||
stderr = devnull
|
||||
|
||||
try:
|
||||
returncode = subprocess.call(args, stdout=stdout, stderr=stderr)
|
||||
except Exception as exception:
|
||||
if Verbosity.ge(verbosity, Verbosity.ERRORS):
|
||||
print(f"An error occurred while running '{self.binary_path}':",
|
||||
'\n', exception, file=sys.stderr)
|
||||
returncode = 1
|
||||
try:
|
||||
returncode = subprocess.call(args, stdout=stdout, stderr=stderr)
|
||||
except Exception as exception:
|
||||
if Verbosity.ge(verbosity, Verbosity.ERRORS):
|
||||
print("An error occurred while running '{}':".format(self.binary_path),
|
||||
'\n', exception, file=sys.stderr)
|
||||
returncode = 1
|
||||
|
||||
return returncode
|
||||
|
||||
@staticmethod
|
||||
def __get_gtest_filter(included_tests, excluded_tests):
|
||||
included_str = TestBinary.__list_tests(included_tests)
|
||||
excluded_str = TestBinary.__list_tests(excluded_tests)
|
||||
return f"--gtest_filter={included_str}-{excluded_str}"
|
||||
included_tests_string = TestBinary.__list_tests(included_tests)
|
||||
excluded_tests_string = TestBinary.__list_tests(excluded_tests)
|
||||
|
||||
gtest_filter = "--gtest_filter={}-{}".format(included_tests_string,
|
||||
excluded_tests_string)
|
||||
return gtest_filter
|
||||
|
||||
@staticmethod
|
||||
def __get_gtest_output(output_file_path):
|
||||
if output_file_path is None:
|
||||
return ""
|
||||
return f"--gtest_output={TestBinary.output_format}:{output_file_path}"
|
||||
gtest_output = ""
|
||||
if output_file_path is not None:
|
||||
gtest_output = "--gtest_output={0}:{1}".format(TestBinary.output_format,
|
||||
output_file_path)
|
||||
return gtest_output
|
||||
|
||||
@staticmethod
|
||||
def __list_tests(tests):
|
||||
if tests is None:
|
||||
return ''
|
||||
return ':'.join(tests)
|
||||
|
||||
@staticmethod
|
||||
def __get_stdout_and_stderr(verbosity):
|
||||
stdout = stderr = None
|
||||
|
||||
if Verbosity.le(verbosity, Verbosity.ERRORS):
|
||||
devnull = open(os.devnull, 'w')
|
||||
stdout = devnull
|
||||
if verbosity == Verbosity.SILENT:
|
||||
stderr = devnull
|
||||
|
||||
return (stdout, stderr)
|
||||
|
||||
@@ -21,8 +21,8 @@ def read_patch(patch_dir, patch_filename):
|
||||
for l in f.readlines():
|
||||
line_has_correct_start = l.startswith('diff -') or l.startswith('---')
|
||||
if not added_patch_location and line_has_correct_start:
|
||||
ret.append(f'{PATCH_DIR_PREFIX}{patch_dir}\n')
|
||||
ret.append(f'{PATCH_FILENAME_PREFIX}{patch_filename}\n')
|
||||
ret.append('{}{}\n'.format(PATCH_DIR_PREFIX, patch_dir))
|
||||
ret.append('{}{}\n'.format(PATCH_FILENAME_PREFIX, patch_filename))
|
||||
added_patch_location = True
|
||||
ret.append(l)
|
||||
return ''.join(ret)
|
||||
@@ -31,8 +31,8 @@ def read_patch(patch_dir, patch_filename):
|
||||
def patch_from_dir(patch_dir):
|
||||
"""Read a directory of patches into a format suitable for passing to
|
||||
'git am'"""
|
||||
with open(os.path.join(patch_dir, ".patches"), encoding='utf-8') as file_in:
|
||||
patch_list = [line.rstrip('\n') for line in file_in.readlines()]
|
||||
with open(os.path.join(patch_dir, ".patches")) as f:
|
||||
patch_list = [l.rstrip('\n') for l in f.readlines()]
|
||||
|
||||
return ''.join([
|
||||
read_patch(patch_dir, patch_filename)
|
||||
|
||||
@@ -35,8 +35,9 @@ def scoped_cwd(path):
|
||||
|
||||
def download(text, url, path):
|
||||
safe_mkdir(os.path.dirname(path))
|
||||
with open(path, 'wb') as local_file, urlopen(url) as web_file:
|
||||
print(f"Downloading {url} to {path}")
|
||||
with open(path, 'wb') as local_file:
|
||||
print("Downloading %s to %s" % (url, path))
|
||||
web_file = urlopen(url)
|
||||
info = web_file.info()
|
||||
if hasattr(info, 'getheader'):
|
||||
file_size = int(info.getheaders("Content-Length")[0])
|
||||
@@ -57,11 +58,11 @@ def download(text, url, path):
|
||||
|
||||
if not ci:
|
||||
percent = downloaded_size * 100. / file_size
|
||||
status = f"\r{text} {downloaded_size:10d} [{percent:3.1f}%]"
|
||||
status = "\r%s %10d [%3.1f%%]" % (text, downloaded_size, percent)
|
||||
print(status, end=' ')
|
||||
|
||||
if ci:
|
||||
print(f"{text} done.")
|
||||
print("%s done." % (text))
|
||||
else:
|
||||
print()
|
||||
return path
|
||||
@@ -73,16 +74,15 @@ def make_zip(zip_file_path, files, dirs):
|
||||
allfiles = files + dirs
|
||||
execute(['zip', '-r', '-y', zip_file_path] + allfiles)
|
||||
else:
|
||||
with zipfile.ZipFile(zip_file_path, "w",
|
||||
zipfile.ZIP_DEFLATED,
|
||||
allowZip64=True) as zip_file:
|
||||
for filename in files:
|
||||
zip_file.write(filename, filename)
|
||||
for dirname in dirs:
|
||||
for root, _, filenames in os.walk(dirname):
|
||||
for f in filenames:
|
||||
zip_file.write(os.path.join(root, f))
|
||||
zip_file.close()
|
||||
zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED,
|
||||
allowZip64=True)
|
||||
for filename in files:
|
||||
zip_file.write(filename, filename)
|
||||
for dirname in dirs:
|
||||
for root, _, filenames in os.walk(dirname):
|
||||
for f in filenames:
|
||||
zip_file.write(os.path.join(root, f))
|
||||
zip_file.close()
|
||||
|
||||
|
||||
def rm_rf(path):
|
||||
@@ -128,8 +128,8 @@ def get_electron_branding():
|
||||
SOURCE_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
|
||||
branding_file_path = os.path.join(
|
||||
SOURCE_ROOT, 'shell', 'app', 'BRANDING.json')
|
||||
with open(branding_file_path, encoding='utf-8') as file_in:
|
||||
return json.load(file_in)
|
||||
with open(branding_file_path) as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
cached_electron_version = None
|
||||
@@ -173,14 +173,14 @@ def get_electron_exec():
|
||||
out_dir = get_out_dir()
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
return f'{out_dir}/Electron.app/Contents/MacOS/Electron'
|
||||
return '{0}/Electron.app/Contents/MacOS/Electron'.format(out_dir)
|
||||
if sys.platform == 'win32':
|
||||
return f'{out_dir}/electron.exe'
|
||||
return '{0}/electron.exe'.format(out_dir)
|
||||
if sys.platform == 'linux':
|
||||
return f'{out_dir}/electron'
|
||||
return '{0}/electron'.format(out_dir)
|
||||
|
||||
raise Exception(
|
||||
f"get_electron_exec: unexpected platform '{sys.platform}'")
|
||||
"get_electron_exec: unexpected platform '{0}'".format(sys.platform))
|
||||
|
||||
def get_buildtools_executable(name):
|
||||
buildtools = os.path.realpath(os.path.join(ELECTRON_DIR, '..', 'buildtools'))
|
||||
|
||||
@@ -120,10 +120,10 @@ const LINTERS = [{
|
||||
roots: ['script'],
|
||||
test: filename => filename.endsWith('.py'),
|
||||
run: (opts, filenames) => {
|
||||
const rcfile = path.join(DEPOT_TOOLS, 'pylintrc-2.17');
|
||||
const rcfile = path.join(DEPOT_TOOLS, 'pylintrc');
|
||||
const args = ['--rcfile=' + rcfile, ...filenames];
|
||||
const env = { PYTHONPATH: path.join(ELECTRON_ROOT, 'script'), ...process.env };
|
||||
spawnAndCheckExitCode('pylint-2.17', args, { env });
|
||||
spawnAndCheckExitCode('pylint-2.7', args, { env });
|
||||
}
|
||||
}, {
|
||||
key: 'javascript',
|
||||
|
||||
@@ -65,19 +65,19 @@ def parse_args():
|
||||
# 'config' must exist and be a file.
|
||||
args.config = os.path.abspath(args.config)
|
||||
if not os.path.isfile(args.config):
|
||||
parser.error(f"file '{args.config}' doesn't exist")
|
||||
parser.error("file '{}' doesn't exist".format(args.config))
|
||||
|
||||
# 'tests_dir' must exist and be a directory.
|
||||
if args.tests_dir is not None:
|
||||
args.tests_dir = os.path.abspath(args.tests_dir)
|
||||
if not os.path.isdir(args.tests_dir):
|
||||
parser.error(f"directory '{args.tests_dir}' doesn't exist")
|
||||
parser.error("directory '{}' doesn't exist".format(args.tests_dir))
|
||||
|
||||
# 'output_dir' must exist and be a directory.
|
||||
if args.output_dir is not None:
|
||||
args.output_dir = os.path.abspath(args.output_dir)
|
||||
if not os.path.isdir(args.output_dir):
|
||||
parser.error(f"directory '{args.output_dir}' doesn't exist")
|
||||
parser.error("directory '{}' doesn't exist".format(args.output_dir))
|
||||
|
||||
return args
|
||||
|
||||
@@ -99,7 +99,7 @@ def main():
|
||||
return tests_list.run_all(args.output_dir, args.verbosity,
|
||||
args.disabled_tests_policy)
|
||||
|
||||
raise AssertionError(f"unexpected command '{args.command}'")
|
||||
raise AssertionError("unexpected command '{}'".format(args.command))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -77,8 +77,8 @@ def set_mtimes(patches_config, mtime):
|
||||
|
||||
mtime_cache[file_path] = mtime
|
||||
|
||||
for file_path, file_mtime in mtime_cache.items():
|
||||
os.utime(file_path, (file_mtime, file_mtime))
|
||||
for file_path in mtime_cache:
|
||||
os.utime(file_path, (mtime_cache[file_path], mtime_cache[file_path]))
|
||||
|
||||
|
||||
def main():
|
||||
@@ -131,17 +131,17 @@ def main():
|
||||
if args.operation == "generate":
|
||||
try:
|
||||
# Cache file may exist from a previously aborted sync. Reuse it.
|
||||
with open(args.cache_file, mode='r', encoding='utf-8') as fin:
|
||||
json.load(fin) # Make sure it's not an empty file
|
||||
with open(args.cache_file, mode="r") as f:
|
||||
json.load(f) # Make sure it's not an empty file
|
||||
print("Using existing mtime cache for patches")
|
||||
return 0
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
with open(args.cache_file, mode="w", encoding='utf-8') as fin:
|
||||
with open(args.cache_file, mode="w") as f:
|
||||
mtime_cache = generate_cache(json.load(args.patches_config))
|
||||
json.dump(mtime_cache, fin, indent=2)
|
||||
json.dump(mtime_cache, f, indent=2)
|
||||
except Exception:
|
||||
print(
|
||||
"ERROR: failed to generate mtime cache for patches",
|
||||
@@ -155,8 +155,8 @@ def main():
|
||||
return 0 # Cache file may not exist, fail more gracefully
|
||||
|
||||
try:
|
||||
with open(args.cache_file, mode='r', encoding='utf-8') as file_in:
|
||||
apply_mtimes(json.load(file_in))
|
||||
with open(args.cache_file, mode="r") as f:
|
||||
apply_mtimes(json.load(f))
|
||||
|
||||
if not args.preserve_cache:
|
||||
os.remove(args.cache_file)
|
||||
|
||||
@@ -3,18 +3,9 @@ if (!process.env.CI) require('dotenv-safe').load();
|
||||
const assert = require('node:assert');
|
||||
const got = require('got');
|
||||
|
||||
const { Octokit } = require('@octokit/rest');
|
||||
const octokit = new Octokit({
|
||||
auth: process.env.ELECTRON_GITHUB_TOKEN
|
||||
});
|
||||
|
||||
const BUILD_APPVEYOR_URL = 'https://ci.appveyor.com/api/builds';
|
||||
const CIRCLECI_PIPELINE_URL = 'https://circleci.com/api/v2/project/gh/electron/electron/pipeline';
|
||||
const GH_ACTIONS_PIPELINE_URL = 'https://github.com/electron/electron/actions';
|
||||
const GH_ACTIONS_API_URL = '/repos/electron/electron/actions';
|
||||
|
||||
const CIRCLECI_WAIT_TIME = process.env.CIRCLECI_WAIT_TIME || 30000;
|
||||
const GH_ACTIONS_WAIT_TIME = process.env.GH_ACTIONS_WAIT_TIME || 30000;
|
||||
|
||||
const appVeyorJobs = {
|
||||
'electron-x64': 'electron-x64-release',
|
||||
@@ -32,14 +23,6 @@ const circleCIPublishIndividualArches = {
|
||||
'linux-publish': ['arm', 'arm64', 'x64']
|
||||
};
|
||||
|
||||
const ghActionsPublishWorkflows = [
|
||||
'macos-publish'
|
||||
];
|
||||
|
||||
const ghActionsPublishIndividualArches = {
|
||||
'macos-publish': ['osx-x64', 'mas-x64', 'osx-arm64', 'mas-arm64']
|
||||
};
|
||||
|
||||
let jobRequestedCount = 0;
|
||||
|
||||
async function makeRequest ({ auth, username, password, url, headers, body, method }) {
|
||||
@@ -70,65 +53,6 @@ async function makeRequest ({ auth, username, password, url, headers, body, meth
|
||||
return JSON.parse(response.body);
|
||||
}
|
||||
|
||||
async function githubActionsCall (targetBranch, workflowName, options) {
|
||||
console.log(`Triggering GitHub Actions to run build job: ${workflowName} on branch: ${targetBranch} with release flag.`);
|
||||
const buildRequest = {
|
||||
branch: targetBranch,
|
||||
parameters: {}
|
||||
};
|
||||
if (options.ghRelease) {
|
||||
buildRequest.parameters['upload-to-storage'] = '0';
|
||||
} else {
|
||||
buildRequest.parameters['upload-to-storage'] = '1';
|
||||
}
|
||||
buildRequest.parameters[`run-${workflowName}`] = true;
|
||||
if (options.arch) {
|
||||
const validArches = ghActionsPublishIndividualArches[workflowName];
|
||||
assert(validArches.includes(options.arch), `Unknown GitHub Actions architecture "${options.arch}". Valid values are ${JSON.stringify(validArches)}`);
|
||||
buildRequest.parameters['macos-publish-arch-limit'] = options.arch;
|
||||
}
|
||||
|
||||
jobRequestedCount++;
|
||||
try {
|
||||
const commits = await octokit.repos.listCommits({
|
||||
owner: 'electron',
|
||||
repo: 'electron',
|
||||
sha: targetBranch,
|
||||
per_page: 5
|
||||
});
|
||||
if (!commits.data.length) {
|
||||
console.error('Could not fetch most recent commits for GitHub Actions, returning early');
|
||||
}
|
||||
|
||||
await octokit.request(`POST ${GH_ACTIONS_API_URL}/workflows/${workflowName}.yml/dispatches`, {
|
||||
ref: buildRequest.branch,
|
||||
inputs: {
|
||||
...buildRequest.parameters
|
||||
},
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
});
|
||||
|
||||
const runNumber = await getGitHubActionsRun(workflowName, commits.data[0].sha);
|
||||
if (runNumber === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`GitHub Actions release build pipeline ${runNumber} for ${workflowName} triggered.`);
|
||||
const runUrl = `${GH_ACTIONS_PIPELINE_URL}/runs/${runNumber}`;
|
||||
|
||||
if (options.runningPublishWorkflows) {
|
||||
console.log(`GitHub Actions release workflow request for ${workflowName} successful. Check ${runUrl} for status.`);
|
||||
} else {
|
||||
console.log(`GitHub Actions release build workflow running at ${GH_ACTIONS_PIPELINE_URL}/runs/${runNumber} for ${workflowName}.`);
|
||||
console.log(`GitHub Actions release build request for ${workflowName} successful. Check ${runUrl} for status.`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Error calling GitHub Actions: ', err);
|
||||
}
|
||||
}
|
||||
|
||||
async function circleCIcall (targetBranch, workflowName, options) {
|
||||
console.log(`Triggering CircleCI to run build job: ${workflowName} on branch: ${targetBranch} with release flag.`);
|
||||
const buildRequest = {
|
||||
@@ -243,59 +167,6 @@ async function getCircleCIJobNumber (workflowId) {
|
||||
return jobNumber;
|
||||
}
|
||||
|
||||
async function getGitHubActionsRun (workflowId, headCommit) {
|
||||
let runNumber = 0;
|
||||
let actionRun;
|
||||
while (runNumber === 0) {
|
||||
const actionsRuns = await octokit.request(`GET ${GH_ACTIONS_API_URL}/workflows/${workflowId}.yml/runs`, {
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
});
|
||||
if (!actionsRuns.data.workflow_runs.length) {
|
||||
console.log(`No current workflow_runs found for ${workflowId}, response was: ${actionsRuns.data.workflow_runs}`);
|
||||
runNumber = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (const run of actionsRuns.data.workflow_runs) {
|
||||
if (run.head_sha === headCommit) {
|
||||
console.log(`GitHub Actions run ${run.html_url} found for ${headCommit}, waiting on status.`);
|
||||
actionRun = run;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actionRun) {
|
||||
switch (actionRun.status) {
|
||||
case 'in_progress':
|
||||
case 'pending':
|
||||
case 'queued':
|
||||
case 'requested':
|
||||
case 'waiting': {
|
||||
if (actionRun.id && !isNaN(actionRun.id)) {
|
||||
console.log(`GitHub Actions run ${actionRun.status} for ${actionRun.html_url}.`);
|
||||
runNumber = actionRun.id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'action_required':
|
||||
case 'cancelled':
|
||||
case 'failure':
|
||||
case 'skipped':
|
||||
case 'timed_out':
|
||||
case 'failed': {
|
||||
console.log(`Error workflow run returned a status of ${actionRun.status} for ${actionRun.html_url}`);
|
||||
runNumber = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, GH_ACTIONS_WAIT_TIME));
|
||||
}
|
||||
}
|
||||
return runNumber;
|
||||
}
|
||||
|
||||
async function circleCIRequest (url, method, requestBody) {
|
||||
const requestOpts = {
|
||||
username: process.env.CIRCLE_TOKEN,
|
||||
@@ -323,6 +194,18 @@ async function circleCIRequest (url, method, requestBody) {
|
||||
});
|
||||
}
|
||||
|
||||
function buildAppVeyor (targetBranch, options) {
|
||||
const validJobs = Object.keys(appVeyorJobs);
|
||||
if (options.job) {
|
||||
assert(validJobs.includes(options.job), `Unknown AppVeyor CI job name: ${options.job}. Valid values are: ${validJobs}.`);
|
||||
callAppVeyor(targetBranch, options.job, options);
|
||||
} else {
|
||||
for (const job of validJobs) {
|
||||
callAppVeyor(targetBranch, job, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function callAppVeyor (targetBranch, job, options) {
|
||||
console.log(`Triggering AppVeyor to run build job: ${job} on branch: ${targetBranch} with release flag.`);
|
||||
const environmentVariables = {
|
||||
@@ -369,18 +252,6 @@ async function callAppVeyor (targetBranch, job, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function buildAppVeyor (targetBranch, options) {
|
||||
const validJobs = Object.keys(appVeyorJobs);
|
||||
if (options.job) {
|
||||
assert(validJobs.includes(options.job), `Unknown AppVeyor CI job name: ${options.job}. Valid values are: ${validJobs}.`);
|
||||
callAppVeyor(targetBranch, options.job, options);
|
||||
} else {
|
||||
for (const job of validJobs) {
|
||||
callAppVeyor(targetBranch, job, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildCircleCI (targetBranch, options) {
|
||||
if (options.job) {
|
||||
assert(circleCIPublishWorkflows.includes(options.job), `Unknown CircleCI workflow name: ${options.job}. Valid values are: ${circleCIPublishWorkflows}.`);
|
||||
@@ -394,19 +265,6 @@ function buildCircleCI (targetBranch, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function buildGHActions (targetBranch, options) {
|
||||
if (options.job) {
|
||||
assert(ghActionsPublishWorkflows.includes(options.job), `Unknown GitHub Actions workflow name: ${options.job}. Valid values are: ${ghActionsPublishWorkflows}.`);
|
||||
githubActionsCall(targetBranch, options.job, options);
|
||||
} else {
|
||||
assert(!options.arch, 'Cannot provide a single architecture while building all workflows, please specify a single workflow via --workflow');
|
||||
options.runningPublishWorkflows = true;
|
||||
for (const job of ghActionsPublishWorkflows) {
|
||||
githubActionsCall(targetBranch, job, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runRelease (targetBranch, options) {
|
||||
if (options.ci) {
|
||||
switch (options.ci) {
|
||||
@@ -414,10 +272,6 @@ function runRelease (targetBranch, options) {
|
||||
buildCircleCI(targetBranch, options);
|
||||
break;
|
||||
}
|
||||
case 'GitHubActions': {
|
||||
buildGHActions(targetBranch, options);
|
||||
break;
|
||||
}
|
||||
case 'AppVeyor': {
|
||||
buildAppVeyor(targetBranch, options);
|
||||
break;
|
||||
@@ -430,8 +284,6 @@ function runRelease (targetBranch, options) {
|
||||
} else {
|
||||
buildCircleCI(targetBranch, options);
|
||||
buildAppVeyor(targetBranch, options);
|
||||
// TODO(vertedinde): Enable GH Actions in defaults when ready
|
||||
// buildGHActions(targetBranch, options);
|
||||
}
|
||||
console.log(`${jobRequestedCount} jobs were requested.`);
|
||||
}
|
||||
@@ -445,7 +297,7 @@ if (require.main === module) {
|
||||
const targetBranch = args._[0];
|
||||
if (args._.length < 1) {
|
||||
console.log(`Trigger CI to build release builds of electron.
|
||||
Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=CircleCI|AppVeyor|GitHubActions]
|
||||
Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=CircleCI|AppVeyor]
|
||||
[--ghRelease] [--circleBuildNum=xxx] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH
|
||||
`);
|
||||
process.exit(0);
|
||||
|
||||
@@ -32,8 +32,9 @@ def get_content(retry_count = 5):
|
||||
headers={"Authorization" : authToken}
|
||||
)
|
||||
|
||||
with urlopen(request) as resp:
|
||||
proposed_content = resp.read()
|
||||
proposed_content = urlopen(
|
||||
request
|
||||
).read()
|
||||
|
||||
if is_json(proposed_content):
|
||||
return proposed_content
|
||||
|
||||
@@ -29,7 +29,7 @@ def main():
|
||||
]
|
||||
|
||||
if args.target_dir is None:
|
||||
store_artifact(directory, f'headers/dist/{args.version}',
|
||||
store_artifact(directory, 'headers/dist/{0}'.format(args.version),
|
||||
checksums)
|
||||
else:
|
||||
copy_files(checksums, args.target_dir)
|
||||
@@ -51,10 +51,10 @@ def parse_args():
|
||||
|
||||
def get_files_list(version):
|
||||
return [
|
||||
{ "filename": f'node-{version}.tar.gz', "required": True },
|
||||
{ "filename": f'node-{version}-headers.tar.gz', "required": True },
|
||||
{ "filename": f'iojs-{version}.tar.gz', "required": True },
|
||||
{ "filename": f'iojs-{version}-headers.tar.gz', "required": True },
|
||||
{ "filename": 'node-{0}.tar.gz'.format(version), "required": True },
|
||||
{ "filename": 'node-{0}-headers.tar.gz'.format(version), "required": True },
|
||||
{ "filename": 'iojs-{0}.tar.gz'.format(version), "required": True },
|
||||
{ "filename": 'iojs-{0}-headers.tar.gz'.format(version), "required": True },
|
||||
{ "filename": 'node.lib', "required": False },
|
||||
{ "filename": 'x64/node.lib', "required": False },
|
||||
{ "filename": 'win-x86/iojs.lib', "required": False },
|
||||
@@ -91,8 +91,8 @@ def create_checksum(algorithm, directory, filename, files):
|
||||
lines.append(h.hexdigest() + ' ' + os.path.relpath(path, directory))
|
||||
|
||||
checksum_file = os.path.join(directory, filename)
|
||||
with open(checksum_file, 'w', encoding='utf-8') as fout:
|
||||
fout.write('\n'.join(lines) + '\n')
|
||||
with open(checksum_file, 'w') as f:
|
||||
f.write('\n'.join(lines) + '\n')
|
||||
return checksum_file
|
||||
|
||||
def copy_files(source_files, output_dir):
|
||||
|
||||
@@ -45,9 +45,9 @@ def upload_node(version):
|
||||
versioned_header_tar = header_tar.format(version)
|
||||
shutil.copy2(generated_tar, os.path.join(GEN_DIR, versioned_header_tar))
|
||||
|
||||
store_artifact(GEN_DIR, f'headers/dist/{version}',
|
||||
store_artifact(GEN_DIR, 'headers/dist/{0}'.format(version),
|
||||
glob.glob('node-*.tar.gz'))
|
||||
store_artifact(GEN_DIR, f'headers/dist/{version}',
|
||||
store_artifact(GEN_DIR, 'headers/dist/{0}'.format(version),
|
||||
glob.glob('iojs-*.tar.gz'))
|
||||
|
||||
if PLATFORM == 'win32':
|
||||
@@ -73,13 +73,13 @@ def upload_node(version):
|
||||
shutil.copy2(electron_lib, v4_node_lib)
|
||||
|
||||
# Upload the node.lib.
|
||||
store_artifact(DIST_DIR, f'headers/dist/{version}', [node_lib])
|
||||
store_artifact(DIST_DIR, 'headers/dist/{0}'.format(version), [node_lib])
|
||||
|
||||
# Upload the iojs.lib.
|
||||
store_artifact(DIST_DIR, f'headers/dist/{version}', [iojs_lib])
|
||||
store_artifact(DIST_DIR, 'headers/dist/{0}'.format(version), [iojs_lib])
|
||||
|
||||
# Upload the v4 node.lib.
|
||||
store_artifact(DIST_DIR, f'headers/dist/{version}',
|
||||
store_artifact(DIST_DIR, 'headers/dist/{0}'.format(version),
|
||||
[v4_node_lib])
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ PRODUCT_NAME = get_electron_branding()['product_name']
|
||||
SYMBOLS_DIR = os.path.join(RELEASE_DIR, 'breakpad_symbols')
|
||||
|
||||
PDB_LIST = [
|
||||
os.path.join(RELEASE_DIR, f'{PROJECT_NAME}.exe.pdb')
|
||||
os.path.join(RELEASE_DIR, '{0}.exe.pdb'.format(PROJECT_NAME))
|
||||
]
|
||||
|
||||
PDB_LIST += glob.glob(os.path.join(RELEASE_DIR, '*.dll.pdb'))
|
||||
@@ -80,14 +80,8 @@ def main():
|
||||
|
||||
|
||||
def run_symstore(pdb, dest, product):
|
||||
for attempt in range(2):
|
||||
try:
|
||||
execute(['symstore', 'add', '/r', '/f', pdb, '/s', dest, '/t', product])
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"An error occurred while adding '{pdb}' to SymStore: {str(e)}")
|
||||
if attempt == 0:
|
||||
print("Retrying...")
|
||||
execute(['symstore', 'add', '/r', '/f', pdb, '/s', dest, '/t', product])
|
||||
|
||||
|
||||
def upload_symbols(files):
|
||||
store_artifact(SYMBOLS_DIR, 'symbols',
|
||||
|
||||
@@ -53,8 +53,9 @@ def main():
|
||||
|
||||
build_version = get_electron_build_version()
|
||||
if not ELECTRON_VERSION.startswith(build_version):
|
||||
errmsg = f"Tag ({ELECTRON_VERSION}) should match build ({build_version})\n"
|
||||
sys.stderr.write(errmsg)
|
||||
error = 'Tag name ({0}) should match build version ({1})\n'.format(
|
||||
ELECTRON_VERSION, build_version)
|
||||
sys.stderr.write(error)
|
||||
sys.stderr.flush()
|
||||
return 1
|
||||
|
||||
@@ -343,7 +344,8 @@ def upload_electron(release, file_path, args):
|
||||
# if upload_to_storage is set, skip github upload.
|
||||
# todo (vertedinde): migrate this variable to upload_to_storage
|
||||
if args.upload_to_storage:
|
||||
key_prefix = f'release-builds/{args.version}_{args.upload_timestamp}'
|
||||
key_prefix = 'release-builds/{0}_{1}'.format(args.version,
|
||||
args.upload_timestamp)
|
||||
store_artifact(os.path.dirname(file_path), key_prefix, [file_path])
|
||||
upload_sha256_checksum(args.version, file_path, key_prefix)
|
||||
return
|
||||
@@ -356,30 +358,30 @@ def upload_electron(release, file_path, args):
|
||||
|
||||
|
||||
def upload_io_to_github(release, filename, filepath, version):
|
||||
print(f'Uploading {filename} to GitHub')
|
||||
print('Uploading %s to GitHub' % \
|
||||
(filename))
|
||||
script_path = os.path.join(
|
||||
ELECTRON_DIR, 'script', 'release', 'uploaders', 'upload-to-github.ts')
|
||||
with subprocess.Popen([TS_NODE, script_path, filepath,
|
||||
filename, str(release['id']), version],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT) as upload_process:
|
||||
if is_verbose_mode():
|
||||
for c in iter(lambda: upload_process.stdout.read(1), b""):
|
||||
sys.stdout.buffer.write(c)
|
||||
sys.stdout.flush()
|
||||
upload_process = subprocess.Popen([TS_NODE, script_path, filepath, filename,
|
||||
str(release['id']), version], stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
if is_verbose_mode():
|
||||
for c in iter(lambda: upload_process.stdout.read(1), b""):
|
||||
sys.stdout.buffer.write(c)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def upload_sha256_checksum(version, file_path, key_prefix=None):
|
||||
checksum_path = f'{file_path}.sha256sum'
|
||||
checksum_path = '{}.sha256sum'.format(file_path)
|
||||
if key_prefix is None:
|
||||
key_prefix = f'checksums-scratchpad/{version}'
|
||||
key_prefix = 'checksums-scratchpad/{0}'.format(version)
|
||||
sha256 = hashlib.sha256()
|
||||
with open(file_path, 'rb') as f:
|
||||
sha256.update(f.read())
|
||||
|
||||
filename = os.path.basename(file_path)
|
||||
with open(checksum_path, 'w', encoding='utf-8') as checksum:
|
||||
checksum.write(f'{sha256.hexdigest()} *{filename}')
|
||||
with open(checksum_path, 'w') as checksum:
|
||||
checksum.write('{} *{}'.format(sha256.hexdigest(), filename))
|
||||
store_artifact(os.path.dirname(checksum_path), key_prefix, [checksum_path])
|
||||
|
||||
|
||||
@@ -392,7 +394,7 @@ def get_release(version):
|
||||
release_env['NODE_NO_WARNINGS'] = '1'
|
||||
release_info = execute(['node', script_path, version], release_env)
|
||||
if is_verbose_mode():
|
||||
print(f'Release info for version: {version}:\n')
|
||||
print('Release info for version: {}:\n'.format(version))
|
||||
print(release_info)
|
||||
release = json.loads(release_info)
|
||||
return release
|
||||
|
||||
@@ -85,8 +85,8 @@ def make_diff(diff_file, original, reformatted):
|
||||
difflib.unified_diff(
|
||||
original,
|
||||
reformatted,
|
||||
fromfile=f'a/{diff_file}',
|
||||
tofile=f'b/{diff_file}',
|
||||
fromfile='a/{}'.format(diff_file),
|
||||
tofile='b/{}'.format(diff_file),
|
||||
n=3))
|
||||
|
||||
|
||||
@@ -111,7 +111,8 @@ def run_clang_format_diff_wrapper(args, file_name):
|
||||
raise
|
||||
except Exception as e:
|
||||
# pylint: disable=W0707
|
||||
raise UnexpectedError(f'{file_name}: {e.__class__.__name__}: {e}', e)
|
||||
raise UnexpectedError('{}: {}: {}'.format(
|
||||
file_name, e.__class__.__name__, e), e)
|
||||
|
||||
|
||||
def run_clang_format_diff(args, file_name):
|
||||
@@ -130,22 +131,25 @@ def run_clang_format_diff(args, file_name):
|
||||
print(" ".join(invocation))
|
||||
return [], []
|
||||
try:
|
||||
with subprocess.Popen(' '.join(invocation),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
shell=True) as proc:
|
||||
outs = list(proc.stdout.readlines())
|
||||
errs = list(proc.stderr.readlines())
|
||||
proc.wait()
|
||||
if proc.returncode:
|
||||
code = proc.returncode
|
||||
msg = f"clang-format exited with code {code}: '{file_name}'"
|
||||
raise DiffError(msg, errs)
|
||||
proc = subprocess.Popen(
|
||||
' '.join(invocation),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
shell=True)
|
||||
except OSError as exc:
|
||||
# pylint: disable=raise-missing-from
|
||||
cmd = subprocess.list2cmdline(invocation)
|
||||
raise DiffError(f"Command '{cmd}' failed to start: {exc}")
|
||||
# pylint: disable=W0707
|
||||
raise DiffError(
|
||||
"Command '{}' failed to start: {}".format(
|
||||
subprocess.list2cmdline(invocation), exc
|
||||
)
|
||||
)
|
||||
outs = list(proc.stdout.readlines())
|
||||
errs = list(proc.stderr.readlines())
|
||||
proc.wait()
|
||||
if proc.returncode:
|
||||
raise DiffError("clang-format exited with status {}: '{}'".format(
|
||||
proc.returncode, file_name), errs)
|
||||
if args.fix:
|
||||
return None, errs
|
||||
if sys.platform == 'win32':
|
||||
@@ -196,7 +200,7 @@ def print_trouble(prog, message, use_colors):
|
||||
error_text = 'error:'
|
||||
if use_colors:
|
||||
error_text = bold_red(error_text)
|
||||
print(f"{prog}: {error_text} {message}", file=sys.stderr)
|
||||
print("{}: {} {}".format(prog, error_text, message), file=sys.stderr)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -208,8 +212,8 @@ def main():
|
||||
default=get_buildtools_executable('clang-format'))
|
||||
parser.add_argument(
|
||||
'--extensions',
|
||||
help='comma-separated list of file extensions'
|
||||
f' (default: {DEFAULT_EXTENSIONS})',
|
||||
help='comma separated list of file extensions (default: {})'.format(
|
||||
DEFAULT_EXTENSIONS),
|
||||
default=DEFAULT_EXTENSIONS)
|
||||
parser.add_argument(
|
||||
'--fix',
|
||||
@@ -286,18 +290,18 @@ def main():
|
||||
|
||||
parse_files = []
|
||||
if args.changed:
|
||||
with subprocess.Popen(
|
||||
stdout = subprocess.Popen(
|
||||
"git diff --name-only --cached",
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
shell=True,
|
||||
universal_newlines=True
|
||||
) as child:
|
||||
for line in child.communicate()[0].split("\n"):
|
||||
file_name = line.rstrip()
|
||||
# don't check deleted files
|
||||
if os.path.isfile(file_name):
|
||||
parse_files.append(file_name)
|
||||
).communicate()[0].split("\n")
|
||||
for line in stdout:
|
||||
file_name = line.rstrip()
|
||||
# don't check deleted files
|
||||
if os.path.isfile(file_name):
|
||||
parse_files.append(file_name)
|
||||
|
||||
else:
|
||||
parse_files = args.files
|
||||
@@ -320,7 +324,6 @@ def main():
|
||||
njobs = min(len(files), njobs)
|
||||
|
||||
if not args.fix:
|
||||
# pylint: disable=consider-using-with
|
||||
patch_file = tempfile.NamedTemporaryFile(delete=False,
|
||||
prefix='electron-format-')
|
||||
|
||||
@@ -330,7 +333,6 @@ def main():
|
||||
it = (run_clang_format_diff_wrapper(args, file) for file in files)
|
||||
pool = None
|
||||
else:
|
||||
# pylint: disable=consider-using-with
|
||||
pool = multiprocessing.Pool(njobs)
|
||||
it = pool.imap_unordered(
|
||||
partial(run_clang_format_diff_wrapper, args), files)
|
||||
@@ -371,11 +373,8 @@ def main():
|
||||
patch_file.close()
|
||||
os.unlink(patch_file.name)
|
||||
else:
|
||||
print(
|
||||
'To patch these files, run:',
|
||||
f"$ git apply {patch_file.name}", sep='\n')
|
||||
filename=patch_file.name
|
||||
print(f"\nTo patch these files, run:\n$ git apply {filename}\n")
|
||||
print("\nTo patch these files, run:\n$ git apply {}\n"
|
||||
.format(patch_file.name))
|
||||
|
||||
return retcode
|
||||
|
||||
|
||||
@@ -7,6 +7,6 @@ target = sys.argv[2]
|
||||
|
||||
os.chdir(os.path.dirname(source))
|
||||
|
||||
with tarfile.open(name=os.path.basename(target), mode='w:gz') as tarball:
|
||||
tarball.add(os.path.relpath(source))
|
||||
tarball.close()
|
||||
tarball = tarfile.open(name=os.path.basename(target), mode='w:gz')
|
||||
tarball.add(os.path.relpath(source))
|
||||
tarball.close()
|
||||
|
||||
@@ -21,15 +21,14 @@ def main():
|
||||
|
||||
chromedriver_path = os.path.join(
|
||||
args.source_root, args.build_dir, chromedriver_name[sys.platform])
|
||||
with subprocess.Popen([chromedriver_path],
|
||||
stdout=subprocess.PIPE,
|
||||
universal_newlines=True) as proc:
|
||||
try:
|
||||
output = proc.stdout.readline()
|
||||
except KeyboardInterrupt:
|
||||
returncode = 0
|
||||
finally:
|
||||
proc.terminate()
|
||||
proc = subprocess.Popen([chromedriver_path],
|
||||
stdout=subprocess.PIPE, universal_newlines=True)
|
||||
try:
|
||||
output = proc.stdout.readline()
|
||||
except KeyboardInterrupt:
|
||||
returncode = 0
|
||||
finally:
|
||||
proc.terminate()
|
||||
|
||||
returncode = 0
|
||||
match = re.search(
|
||||
|
||||
@@ -24,10 +24,10 @@ def main():
|
||||
electron = os.path.join(app_path, 'Contents', 'MacOS', PRODUCT_NAME)
|
||||
ffmpeg_name = 'libffmpeg.dylib'
|
||||
ffmpeg_app_path = os.path.join(app_path, 'Contents', 'Frameworks',
|
||||
f'{PRODUCT_NAME} Framework.framework',
|
||||
'{0} Framework.framework'.format(PRODUCT_NAME),
|
||||
'Libraries')
|
||||
elif sys.platform == 'win32':
|
||||
electron = os.path.join(app_path, f'{PROJECT_NAME}.exe')
|
||||
electron = os.path.join(app_path, '{0}.exe'.format(PROJECT_NAME))
|
||||
ffmpeg_app_path = app_path
|
||||
ffmpeg_name = 'ffmpeg.dll'
|
||||
else:
|
||||
@@ -69,7 +69,7 @@ def create_app_copy(initial_app_path):
|
||||
+ '-no-proprietary-codecs')
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
app_name = f'{PRODUCT_NAME}.app'
|
||||
app_name = '{0}.app'.format(PRODUCT_NAME)
|
||||
initial_app_path = os.path.join(initial_app_path, app_name)
|
||||
app_path = os.path.join(app_path, app_name)
|
||||
|
||||
|
||||
@@ -26,9 +26,8 @@ def main():
|
||||
try:
|
||||
with scoped_cwd(app_path):
|
||||
if args.snapshot_files_dir is None:
|
||||
snapshot_filename = os.path.join(app_path, 'mksnapshot_args')
|
||||
with open(snapshot_filename, encoding='utf-8') as file_in:
|
||||
mkargs = file_in.read().splitlines()
|
||||
with open(os.path.join(app_path, 'mksnapshot_args')) as f:
|
||||
mkargs = f.read().splitlines()
|
||||
print('running: ' + ' '.join(mkargs + [ SNAPSHOT_SOURCE ]))
|
||||
subprocess.check_call(mkargs + [ SNAPSHOT_SOURCE ], cwd=app_path)
|
||||
print('ok mksnapshot successfully created snapshot_blob.bin.')
|
||||
@@ -42,7 +41,7 @@ def main():
|
||||
gen_binary = get_binary_path('v8_context_snapshot_generator', \
|
||||
app_path)
|
||||
genargs = [ gen_binary, \
|
||||
f'--output_file={context_snapshot_path}' ]
|
||||
'--output_file={0}'.format(context_snapshot_path) ]
|
||||
print('running: ' + ' '.join(genargs))
|
||||
subprocess.check_call(genargs)
|
||||
print('ok v8_context_snapshot_generator successfully created ' \
|
||||
@@ -60,15 +59,15 @@ def main():
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
bin_files = glob.glob(os.path.join(app_path, '*.bin'))
|
||||
app_dir = os.path.join(app_path, f'{PRODUCT_NAME}.app')
|
||||
app_dir = os.path.join(app_path, '{0}.app'.format(PRODUCT_NAME))
|
||||
electron = os.path.join(app_dir, 'Contents', 'MacOS', PRODUCT_NAME)
|
||||
bin_out_path = os.path.join(app_dir, 'Contents', 'Frameworks',
|
||||
f'{PROJECT_NAME} Framework.framework',
|
||||
'{0} Framework.framework'.format(PROJECT_NAME),
|
||||
'Resources')
|
||||
for bin_file in bin_files:
|
||||
shutil.copy2(bin_file, bin_out_path)
|
||||
elif sys.platform == 'win32':
|
||||
electron = os.path.join(app_path, f'{PROJECT_NAME}.exe')
|
||||
electron = os.path.join(app_path, '{0}.exe'.format(PROJECT_NAME))
|
||||
else:
|
||||
electron = os.path.join(app_path, PROJECT_NAME)
|
||||
|
||||
@@ -82,7 +81,7 @@ def main():
|
||||
except KeyboardInterrupt:
|
||||
print('Other error')
|
||||
returncode = 0
|
||||
print(f'Returning with error code: {returncode}')
|
||||
print('Returning with error code: {0}'.format(returncode))
|
||||
return returncode
|
||||
|
||||
|
||||
@@ -99,7 +98,7 @@ def create_app_copy(initial_app_path):
|
||||
|
||||
def get_binary_path(binary_name, root_path):
|
||||
if sys.platform == 'win32':
|
||||
binary_path = os.path.join(root_path, f'{binary_name}.exe')
|
||||
binary_path = os.path.join(root_path, '{0}.exe'.format(binary_name))
|
||||
else:
|
||||
binary_path = os.path.join(root_path, binary_name)
|
||||
return binary_path
|
||||
|
||||
@@ -4,7 +4,7 @@ import zipfile
|
||||
import sys
|
||||
|
||||
def main(zip_path, manifest_in):
|
||||
with open(manifest_in, 'r', encoding='utf-8') as manifest, \
|
||||
with open(manifest_in, 'r') as manifest, \
|
||||
zipfile.ZipFile(zip_path, 'r', allowZip64=True) as z:
|
||||
files_in_zip = set(z.namelist())
|
||||
files_in_manifest = {l.strip() for l in manifest.readlines()}
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "shell/browser/ui/cocoa/electron_bundle_mover.h"
|
||||
#endif
|
||||
|
||||
@@ -323,6 +324,80 @@ struct Converter<JumpListResult> {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
template <>
|
||||
struct Converter<Browser::LaunchItem> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
Browser::LaunchItem* out) {
|
||||
gin_helper::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
|
||||
dict.Get("name", &(out->name));
|
||||
dict.Get("path", &(out->path));
|
||||
dict.Get("args", &(out->args));
|
||||
dict.Get("scope", &(out->scope));
|
||||
dict.Get("enabled", &(out->enabled));
|
||||
return true;
|
||||
}
|
||||
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
Browser::LaunchItem val) {
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("name", val.name);
|
||||
dict.Set("path", val.path);
|
||||
dict.Set("args", val.args);
|
||||
dict.Set("scope", val.scope);
|
||||
dict.Set("enabled", val.enabled);
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct Converter<Browser::LoginItemSettings> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
Browser::LoginItemSettings* out) {
|
||||
gin_helper::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
|
||||
dict.Get("openAtLogin", &(out->open_at_login));
|
||||
dict.Get("openAsHidden", &(out->open_as_hidden));
|
||||
dict.Get("path", &(out->path));
|
||||
dict.Get("args", &(out->args));
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
dict.Get("name", &(out->name));
|
||||
dict.Get("enabled", &(out->enabled));
|
||||
#elif BUILDFLAG(IS_MAC)
|
||||
dict.Get("serviceName", &(out->service_name));
|
||||
dict.Get("type", &(out->type));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
Browser::LoginItemSettings val) {
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
dict.Set("launchItems", val.launch_items);
|
||||
dict.Set("executableWillLaunchAtLogin",
|
||||
val.executable_will_launch_at_login);
|
||||
#elif BUILDFLAG(IS_MAC)
|
||||
if (base::mac::MacOSMajorVersion() >= 13)
|
||||
dict.Set("status", val.status);
|
||||
#endif
|
||||
dict.Set("openAtLogin", val.open_at_login);
|
||||
dict.Set("openAsHidden", val.open_as_hidden);
|
||||
dict.Set("restoreState", val.restore_state);
|
||||
dict.Set("wasOpenedAtLogin", val.opened_at_login);
|
||||
dict.Set("wasOpenedAsHidden", val.opened_as_hidden);
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<content::CertificateRequestResultType> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
@@ -1141,8 +1216,8 @@ void App::SetAccessibilitySupportEnabled(gin_helper::ErrorThrower thrower,
|
||||
Browser::Get()->OnAccessibilitySupportChanged();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> App::GetLoginItemSettings(gin::Arguments* args) {
|
||||
LoginItemSettings options;
|
||||
Browser::LoginItemSettings App::GetLoginItemSettings(gin::Arguments* args) {
|
||||
Browser::LoginItemSettings options;
|
||||
args->GetNext(&options);
|
||||
return Browser::Get()->GetLoginItemSettings(options);
|
||||
}
|
||||
@@ -1206,7 +1281,7 @@ JumpListResult App::SetJumpList(v8::Local<v8::Value> val,
|
||||
if (!delete_jump_list &&
|
||||
!gin::ConvertFromV8(args->isolate(), val, &categories)) {
|
||||
gin_helper::ErrorThrower(args->isolate())
|
||||
.ThrowTypeError("Argument must be null or an array of categories");
|
||||
.ThrowError("Argument must be null or an array of categories");
|
||||
return JumpListResult::kArgumentError;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ class App : public ElectronBrowserClient::Delegate,
|
||||
bool IsAccessibilitySupportEnabled();
|
||||
void SetAccessibilitySupportEnabled(gin_helper::ErrorThrower thrower,
|
||||
bool enabled);
|
||||
v8::Local<v8::Value> GetLoginItemSettings(gin::Arguments* args);
|
||||
Browser::LoginItemSettings GetLoginItemSettings(gin::Arguments* args);
|
||||
#if BUILDFLAG(USE_NSS_CERTS)
|
||||
void ImportCertificate(gin_helper::ErrorThrower thrower,
|
||||
base::Value options,
|
||||
|
||||
@@ -117,6 +117,11 @@ BaseWindow::BaseWindow(gin_helper::Arguments* args,
|
||||
BaseWindow::~BaseWindow() {
|
||||
CloseImmediately();
|
||||
|
||||
// Destroy the native window in next tick because the native code might be
|
||||
// iterating all windows.
|
||||
base::SingleThreadTaskRunner::GetCurrentDefault()->DeleteSoon(
|
||||
FROM_HERE, window_.release());
|
||||
|
||||
// Remove global reference so the JS object can be garbage collected.
|
||||
self_ref_.Reset();
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
|
||||
WebContentsView::Create(isolate, web_preferences);
|
||||
DCHECK(web_contents_view.get());
|
||||
window_->AddDraggableRegionProvider(web_contents_view.get());
|
||||
web_contents_view_.Reset(isolate, web_contents_view.ToV8());
|
||||
|
||||
// Save a reference of the WebContents.
|
||||
gin::Handle<WebContents> web_contents =
|
||||
@@ -93,14 +92,7 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
|
||||
InitWithArgs(args);
|
||||
|
||||
// Install the content view after BaseWindow's JS code is initialized.
|
||||
// The WebContentsView is added a sibling of BaseWindow's contentView (before
|
||||
// it in the paint order) so that any views added to BrowserWindow's
|
||||
// contentView will be painted on top of the BrowserWindow's WebContentsView.
|
||||
// See https://github.com/electron/electron/pull/41256.
|
||||
// Note that |GetContentsView|, confusingly, does not refer to the same thing
|
||||
// as |BaseWindow::GetContentView|.
|
||||
window()->GetContentsView()->AddChildViewAt(web_contents_view->view(), 0);
|
||||
window()->GetContentsView()->DeprecatedLayoutImmediately();
|
||||
SetContentView(gin::CreateHandle<View>(isolate, web_contents_view.get()));
|
||||
|
||||
// Init window after everything has been setup.
|
||||
window()->InitFromOptions(options);
|
||||
|
||||
@@ -95,7 +95,6 @@ class BrowserWindow : public BaseWindow,
|
||||
base::CancelableRepeatingClosure window_unresponsive_closure_;
|
||||
|
||||
v8::Global<v8::Value> web_contents_;
|
||||
v8::Global<v8::Value> web_contents_view_;
|
||||
base::WeakPtr<api::WebContents> api_web_contents_;
|
||||
|
||||
base::WeakPtrFactory<BrowserWindow> weak_factory_{this};
|
||||
|
||||
@@ -12,12 +12,10 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "base/files/file_enumerator.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/scoped_observation.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/uuid.h"
|
||||
@@ -34,14 +32,11 @@
|
||||
#include "content/browser/code_cache/generated_code_cache_context.h" // nogncheck
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/browsing_data_filter_builder.h"
|
||||
#include "content/public/browser/browsing_data_remover.h"
|
||||
#include "content/public/browser/download_item_utils.h"
|
||||
#include "content/public/browser/download_manager_delegate.h"
|
||||
#include "content/public/browser/network_service_instance.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "gin/converter.h"
|
||||
#include "mojo/public/cpp/bindings/pending_remote.h"
|
||||
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
|
||||
#include "net/base/completion_repeating_callback.h"
|
||||
@@ -82,14 +77,12 @@
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/object_template_builder.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/common/process_util.h"
|
||||
#include "third_party/blink/public/common/storage_key/storage_key.h"
|
||||
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
@@ -110,8 +103,6 @@
|
||||
#endif
|
||||
|
||||
using content::BrowserThread;
|
||||
using content::BrowsingDataFilterBuilder;
|
||||
using content::BrowsingDataRemover;
|
||||
using content::StoragePartition;
|
||||
|
||||
namespace {
|
||||
@@ -123,23 +114,25 @@ struct ClearStorageDataOptions {
|
||||
};
|
||||
|
||||
uint32_t GetStorageMask(const std::vector<std::string>& storage_types) {
|
||||
static constexpr auto Lookup =
|
||||
base::MakeFixedFlatMap<std::string_view, uint32_t>(
|
||||
{{"cookies", StoragePartition::REMOVE_DATA_MASK_COOKIES},
|
||||
{"filesystem", StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS},
|
||||
{"indexdb", StoragePartition::REMOVE_DATA_MASK_INDEXEDDB},
|
||||
{"localstorage", StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE},
|
||||
{"shadercache", StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE},
|
||||
{"websql", StoragePartition::REMOVE_DATA_MASK_WEBSQL},
|
||||
{"serviceworkers",
|
||||
StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS},
|
||||
{"cachestorage", StoragePartition::REMOVE_DATA_MASK_CACHE_STORAGE}});
|
||||
|
||||
uint32_t storage_mask = 0;
|
||||
for (const auto& it : storage_types) {
|
||||
auto type = base::ToLowerASCII(it);
|
||||
if (Lookup.contains(type))
|
||||
storage_mask |= Lookup.at(type);
|
||||
if (type == "cookies")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES;
|
||||
else if (type == "filesystem")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
|
||||
else if (type == "indexdb")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
|
||||
else if (type == "localstorage")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
|
||||
else if (type == "shadercache")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
|
||||
else if (type == "websql")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL;
|
||||
else if (type == "serviceworkers")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
|
||||
else if (type == "cachestorage")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_CACHE_STORAGE;
|
||||
}
|
||||
return storage_mask;
|
||||
}
|
||||
@@ -156,204 +149,6 @@ uint32_t GetQuotaMask(const std::vector<std::string>& quota_types) {
|
||||
return quota_mask;
|
||||
}
|
||||
|
||||
constexpr BrowsingDataRemover::DataType kClearDataTypeAll = ~0ULL;
|
||||
constexpr BrowsingDataRemover::OriginType kClearOriginTypeAll =
|
||||
BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB |
|
||||
BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB;
|
||||
|
||||
constexpr auto kDataTypeLookup =
|
||||
base::MakeFixedFlatMap<std::string_view, BrowsingDataRemover::DataType>({
|
||||
{"backgroundFetch", BrowsingDataRemover::DATA_TYPE_BACKGROUND_FETCH},
|
||||
{"cache", BrowsingDataRemover::DATA_TYPE_CACHE |
|
||||
BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE},
|
||||
{"cookies", BrowsingDataRemover::DATA_TYPE_COOKIES},
|
||||
{"downloads", BrowsingDataRemover::DATA_TYPE_DOWNLOADS},
|
||||
{"fileSystems", BrowsingDataRemover::DATA_TYPE_FILE_SYSTEMS},
|
||||
{"indexedDB", BrowsingDataRemover::DATA_TYPE_INDEXED_DB},
|
||||
{"localStorage", BrowsingDataRemover::DATA_TYPE_LOCAL_STORAGE},
|
||||
{"serviceWorkers", BrowsingDataRemover::DATA_TYPE_SERVICE_WORKERS},
|
||||
{"webSQL", BrowsingDataRemover::DATA_TYPE_WEB_SQL},
|
||||
});
|
||||
|
||||
BrowsingDataRemover::DataType GetDataTypeMask(
|
||||
const std::vector<std::string>& data_types) {
|
||||
BrowsingDataRemover::DataType mask = 0u;
|
||||
for (const auto& type : data_types) {
|
||||
if (kDataTypeLookup.contains(type)) {
|
||||
mask |= kDataTypeLookup.at(type);
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetDataTypesFromMask(
|
||||
BrowsingDataRemover::DataType mask) {
|
||||
std::vector<std::string> results;
|
||||
for (const auto [type, flag] : kDataTypeLookup) {
|
||||
if (mask & flag) {
|
||||
results.emplace_back(type);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// Represents a task to clear browsing data for the `clearData` API method.
|
||||
//
|
||||
// This type manages its own lifetime, deleting itself once the task finishes
|
||||
// completely.
|
||||
class ClearDataTask {
|
||||
public:
|
||||
// Starts running a task. This function will return before the task is
|
||||
// finished, but will resolve or reject the |promise| when it finishes.
|
||||
static void Run(
|
||||
BrowsingDataRemover* remover,
|
||||
gin_helper::Promise<void> promise,
|
||||
BrowsingDataRemover::DataType data_type_mask,
|
||||
std::vector<url::Origin> origins,
|
||||
BrowsingDataFilterBuilder::Mode filter_mode,
|
||||
BrowsingDataFilterBuilder::OriginMatchingMode origin_matching_mode) {
|
||||
std::shared_ptr<ClearDataTask> task(new ClearDataTask(std::move(promise)));
|
||||
|
||||
// This method counts as an operation. This is important so we can call
|
||||
// `OnOperationFinished` at the end of this method as a fallback if all the
|
||||
// other operations finished while this method was still executing
|
||||
task->operations_running_ = 1;
|
||||
|
||||
// Cookies are scoped more broadly than other types of data, so if we are
|
||||
// filtering then we need to do it at the registrable domain level
|
||||
if (!origins.empty() &&
|
||||
data_type_mask & BrowsingDataRemover::DATA_TYPE_COOKIES) {
|
||||
data_type_mask &= ~BrowsingDataRemover::DATA_TYPE_COOKIES;
|
||||
|
||||
auto cookies_filter_builder =
|
||||
BrowsingDataFilterBuilder::Create(filter_mode);
|
||||
|
||||
for (const url::Origin& origin : origins) {
|
||||
std::string domain = GetDomainAndRegistry(
|
||||
origin,
|
||||
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
|
||||
if (domain.empty()) {
|
||||
domain = origin.host();
|
||||
}
|
||||
cookies_filter_builder->AddRegisterableDomain(domain);
|
||||
}
|
||||
|
||||
StartOperation(task, remover, BrowsingDataRemover::DATA_TYPE_COOKIES,
|
||||
std::move(cookies_filter_builder));
|
||||
}
|
||||
|
||||
// If cookies aren't the only data type and weren't handled above, then we
|
||||
// can start an operation that is scoped to origins
|
||||
if (data_type_mask) {
|
||||
auto filter_builder =
|
||||
BrowsingDataFilterBuilder::Create(filter_mode, origin_matching_mode);
|
||||
|
||||
for (auto const& origin : origins) {
|
||||
filter_builder->AddOrigin(origin);
|
||||
}
|
||||
|
||||
StartOperation(task, remover, data_type_mask, std::move(filter_builder));
|
||||
}
|
||||
|
||||
// This static method counts as an operation.
|
||||
task->OnOperationFinished(std::nullopt);
|
||||
}
|
||||
|
||||
private:
|
||||
// An individiual |content::BrowsingDataRemover::Remove...| operation as part
|
||||
// of a full |ClearDataTask|. This class manages its own lifetime, cleaning
|
||||
// itself up after the operation completes and notifies the task of the
|
||||
// result.
|
||||
class ClearDataOperation : public BrowsingDataRemover::Observer {
|
||||
public:
|
||||
static void Run(std::shared_ptr<ClearDataTask> task,
|
||||
BrowsingDataRemover* remover,
|
||||
BrowsingDataRemover::DataType data_type_mask,
|
||||
std::unique_ptr<BrowsingDataFilterBuilder> filter_builder) {
|
||||
auto* operation = new ClearDataOperation(task, remover);
|
||||
|
||||
remover->RemoveWithFilterAndReply(base::Time::Min(), base::Time::Max(),
|
||||
data_type_mask, kClearOriginTypeAll,
|
||||
std::move(filter_builder), operation);
|
||||
}
|
||||
|
||||
// BrowsingDataRemover::Observer:
|
||||
void OnBrowsingDataRemoverDone(
|
||||
BrowsingDataRemover::DataType failed_data_types) override {
|
||||
task_->OnOperationFinished(failed_data_types);
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
ClearDataOperation(std::shared_ptr<ClearDataTask> task,
|
||||
BrowsingDataRemover* remover)
|
||||
: task_(task) {
|
||||
observation_.Observe(remover);
|
||||
}
|
||||
|
||||
std::shared_ptr<ClearDataTask> task_;
|
||||
base::ScopedObservation<BrowsingDataRemover, BrowsingDataRemover::Observer>
|
||||
observation_{this};
|
||||
};
|
||||
|
||||
explicit ClearDataTask(gin_helper::Promise<void> promise)
|
||||
: promise_(std::move(promise)) {}
|
||||
|
||||
static void StartOperation(
|
||||
std::shared_ptr<ClearDataTask> task,
|
||||
BrowsingDataRemover* remover,
|
||||
BrowsingDataRemover::DataType data_type_mask,
|
||||
std::unique_ptr<BrowsingDataFilterBuilder> filter_builder) {
|
||||
// Track this operation
|
||||
task->operations_running_ += 1;
|
||||
|
||||
ClearDataOperation::Run(task, remover, data_type_mask,
|
||||
std::move(filter_builder));
|
||||
}
|
||||
|
||||
void OnOperationFinished(
|
||||
std::optional<BrowsingDataRemover::DataType> failed_data_types) {
|
||||
DCHECK_GT(operations_running_, 0);
|
||||
operations_running_ -= 1;
|
||||
|
||||
if (failed_data_types.has_value()) {
|
||||
failed_data_types_ |= failed_data_types.value();
|
||||
}
|
||||
|
||||
// If this is the last operation, then the task is finished
|
||||
if (operations_running_ == 0) {
|
||||
OnTaskFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void OnTaskFinished() {
|
||||
if (failed_data_types_ == 0ULL) {
|
||||
promise_.Resolve();
|
||||
} else {
|
||||
v8::Isolate* isolate = promise_.isolate();
|
||||
|
||||
v8::Local<v8::Value> failed_data_types_array =
|
||||
gin::ConvertToV8(isolate, GetDataTypesFromMask(failed_data_types_));
|
||||
|
||||
// Create a rich error object with extra detail about what data types
|
||||
// failed
|
||||
auto error = v8::Exception::Error(
|
||||
gin::StringToV8(isolate, "Failed to clear data"));
|
||||
error.As<v8::Object>()
|
||||
->Set(promise_.GetContext(),
|
||||
gin::StringToV8(isolate, "failedDataTypes"),
|
||||
failed_data_types_array)
|
||||
.Check();
|
||||
|
||||
promise_.Reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
int operations_running_ = 0;
|
||||
BrowsingDataRemover::DataType failed_data_types_ = 0ULL;
|
||||
gin_helper::Promise<void> promise_;
|
||||
};
|
||||
|
||||
base::Value::Dict createProxyConfig(ProxyPrefs::ProxyMode proxy_mode,
|
||||
std::string const& pac_url,
|
||||
std::string const& proxy_server,
|
||||
@@ -1306,89 +1101,6 @@ v8::Local<v8::Promise> Session::ClearCodeCaches(
|
||||
return handle;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Session::ClearData(gin_helper::ErrorThrower thrower,
|
||||
gin::Arguments* args) {
|
||||
auto* isolate = JavascriptEnvironment::GetIsolate();
|
||||
|
||||
BrowsingDataRemover::DataType data_type_mask = kClearDataTypeAll;
|
||||
std::vector<url::Origin> origins;
|
||||
BrowsingDataFilterBuilder::OriginMatchingMode origin_matching_mode =
|
||||
BrowsingDataFilterBuilder::OriginMatchingMode::kThirdPartiesIncluded;
|
||||
BrowsingDataFilterBuilder::Mode filter_mode =
|
||||
BrowsingDataFilterBuilder::Mode::kPreserve;
|
||||
|
||||
if (gin_helper::Dictionary options; args->GetNext(&options)) {
|
||||
if (std::vector<std::string> data_types;
|
||||
options.Get("dataTypes", &data_types)) {
|
||||
data_type_mask = GetDataTypeMask(data_types);
|
||||
}
|
||||
|
||||
if (bool avoid_closing_connections;
|
||||
options.Get("avoidClosingConnections", &avoid_closing_connections) &&
|
||||
avoid_closing_connections) {
|
||||
data_type_mask |=
|
||||
BrowsingDataRemover::DATA_TYPE_AVOID_CLOSING_CONNECTIONS;
|
||||
}
|
||||
|
||||
std::vector<GURL> origin_urls;
|
||||
{
|
||||
bool has_origins_key = options.Get("origins", &origin_urls);
|
||||
std::vector<GURL> exclude_origin_urls;
|
||||
bool has_exclude_origins_key =
|
||||
options.Get("excludeOrigins", &exclude_origin_urls);
|
||||
|
||||
if (has_origins_key && has_exclude_origins_key) {
|
||||
thrower.ThrowError(
|
||||
"Cannot provide both 'origins' and 'excludeOrigins'");
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
if (has_origins_key) {
|
||||
filter_mode = BrowsingDataFilterBuilder::Mode::kDelete;
|
||||
} else if (has_exclude_origins_key) {
|
||||
origin_urls = std::move(exclude_origin_urls);
|
||||
}
|
||||
}
|
||||
|
||||
if (!origin_urls.empty()) {
|
||||
origins.reserve(origin_urls.size());
|
||||
for (const GURL& origin_url : origin_urls) {
|
||||
auto origin = url::Origin::Create(origin_url);
|
||||
|
||||
// Opaque origins cannot be used with this API
|
||||
if (origin.opaque()) {
|
||||
thrower.ThrowError(
|
||||
base::StringPrintf("Invalid origin: '%s'",
|
||||
origin_url.possibly_invalid_spec().c_str()));
|
||||
return v8::Undefined(isolate);
|
||||
}
|
||||
|
||||
origins.push_back(std::move(origin));
|
||||
}
|
||||
}
|
||||
|
||||
if (std::string origin_matching_mode_string;
|
||||
options.Get("originMatchingMode", &origin_matching_mode_string)) {
|
||||
if (origin_matching_mode_string == "third-parties-included") {
|
||||
origin_matching_mode = BrowsingDataFilterBuilder::OriginMatchingMode::
|
||||
kThirdPartiesIncluded;
|
||||
} else if (origin_matching_mode_string == "origin-in-all-contexts") {
|
||||
origin_matching_mode =
|
||||
BrowsingDataFilterBuilder::OriginMatchingMode::kOriginInAllContexts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gin_helper::Promise<void> promise(isolate);
|
||||
v8::Local<v8::Promise> promise_handle = promise.GetHandle();
|
||||
|
||||
BrowsingDataRemover* remover = browser_context_->GetBrowsingDataRemover();
|
||||
ClearDataTask::Run(remover, std::move(promise), data_type_mask,
|
||||
std::move(origins), filter_mode, origin_matching_mode);
|
||||
|
||||
return promise_handle;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
base::Value Session::GetSpellCheckerLanguages() {
|
||||
return browser_context_->prefs()
|
||||
@@ -1658,7 +1370,6 @@ void Session::FillObjectTemplate(v8::Isolate* isolate,
|
||||
.SetMethod("getStoragePath", &Session::GetPath)
|
||||
.SetMethod("setCodeCachePath", &Session::SetCodeCachePath)
|
||||
.SetMethod("clearCodeCaches", &Session::ClearCodeCaches)
|
||||
.SetMethod("clearData", &Session::ClearData)
|
||||
.SetProperty("cookies", &Session::Cookies)
|
||||
.SetProperty("netLog", &Session::NetLog)
|
||||
.SetProperty("protocol", &Session::Protocol)
|
||||
|
||||
@@ -147,8 +147,6 @@ class Session : public gin::Wrappable<Session>,
|
||||
v8::Local<v8::Value> GetPath(v8::Isolate* isolate);
|
||||
void SetCodeCachePath(gin::Arguments* args);
|
||||
v8::Local<v8::Promise> ClearCodeCaches(const gin_helper::Dictionary& options);
|
||||
v8::Local<v8::Value> ClearData(gin_helper::ErrorThrower thrower,
|
||||
gin::Arguments* args);
|
||||
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
|
||||
base::Value GetSpellCheckerLanguages();
|
||||
void SetSpellCheckerLanguages(gin_helper::ErrorThrower thrower,
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
#include "mojo/public/cpp/system/platform_handle.h"
|
||||
#include "ppapi/buildflags/buildflags.h"
|
||||
#include "printing/buildflags/buildflags.h"
|
||||
#include "printing/print_job_constants.h"
|
||||
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
|
||||
#include "services/service_manager/public/cpp/interface_provider.h"
|
||||
#include "shell/browser/api/electron_api_browser_window.h"
|
||||
@@ -172,10 +173,10 @@
|
||||
#include "components/printing/browser/print_manager_utils.h"
|
||||
#include "components/printing/browser/print_to_pdf/pdf_print_result.h"
|
||||
#include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
|
||||
#include "printing/mojom/print.mojom.h" // nogncheck
|
||||
#include "printing/backend/print_backend.h" // nogncheck
|
||||
#include "printing/mojom/print.mojom.h" // nogncheck
|
||||
#include "printing/page_range.h"
|
||||
#include "shell/browser/printing/print_view_manager_electron.h"
|
||||
#include "shell/browser/printing/printing_utils.h"
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "printing/backend/win_helper.h"
|
||||
@@ -351,20 +352,6 @@ struct Converter<scoped_refptr<content::DevToolsAgentHost>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<content::NavigationEntry*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
content::NavigationEntry* entry) {
|
||||
if (!entry) {
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
gin_helper::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
dict.Set("url", entry->GetURL().spec());
|
||||
dict.Set("title", entry->GetTitleForDisplay());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gin
|
||||
|
||||
namespace electron::api {
|
||||
@@ -529,6 +516,96 @@ std::optional<base::TimeDelta> GetCursorBlinkInterval() {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
// This will return false if no printer with the provided device_name can be
|
||||
// found on the network. We need to check this because Chromium does not do
|
||||
// sanity checking of device_name validity and so will crash on invalid names.
|
||||
bool IsDeviceNameValid(const std::u16string& device_name) {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
base::apple::ScopedCFTypeRef<CFStringRef> new_printer_id(
|
||||
base::SysUTF16ToCFStringRef(device_name));
|
||||
PMPrinter new_printer = PMPrinterCreateFromPrinterID(new_printer_id.get());
|
||||
bool printer_exists = new_printer != nullptr;
|
||||
PMRelease(new_printer);
|
||||
return printer_exists;
|
||||
#else
|
||||
scoped_refptr<printing::PrintBackend> print_backend =
|
||||
printing::PrintBackend::CreateInstance(
|
||||
g_browser_process->GetApplicationLocale());
|
||||
return print_backend->IsValidPrinter(base::UTF16ToUTF8(device_name));
|
||||
#endif
|
||||
}
|
||||
|
||||
// This function returns a validated device name.
|
||||
// If the user passed one to webContents.print(), we check that it's valid and
|
||||
// return it or fail if the network doesn't recognize it. If the user didn't
|
||||
// pass a device name, we first try to return the system default printer. If one
|
||||
// isn't set, then pull all the printers and use the first one or fail if none
|
||||
// exist.
|
||||
std::pair<std::string, std::u16string> GetDeviceNameToUse(
|
||||
const std::u16string& device_name) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Blocking is needed here because Windows printer drivers are oftentimes
|
||||
// not thread-safe and have to be accessed on the UI thread.
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
#endif
|
||||
|
||||
if (!device_name.empty()) {
|
||||
if (!IsDeviceNameValid(device_name))
|
||||
return std::make_pair("Invalid deviceName provided", std::u16string());
|
||||
return std::make_pair(std::string(), device_name);
|
||||
}
|
||||
|
||||
scoped_refptr<printing::PrintBackend> print_backend =
|
||||
printing::PrintBackend::CreateInstance(
|
||||
g_browser_process->GetApplicationLocale());
|
||||
std::string printer_name;
|
||||
printing::mojom::ResultCode code =
|
||||
print_backend->GetDefaultPrinterName(printer_name);
|
||||
|
||||
// We don't want to return if this fails since some devices won't have a
|
||||
// default printer.
|
||||
if (code != printing::mojom::ResultCode::kSuccess)
|
||||
LOG(ERROR) << "Failed to get default printer name";
|
||||
|
||||
if (printer_name.empty()) {
|
||||
printing::PrinterList printers;
|
||||
if (print_backend->EnumeratePrinters(printers) !=
|
||||
printing::mojom::ResultCode::kSuccess)
|
||||
return std::make_pair("Failed to enumerate printers", std::u16string());
|
||||
if (printers.empty())
|
||||
return std::make_pair("No printers available on the network",
|
||||
std::u16string());
|
||||
|
||||
printer_name = printers.front().printer_name;
|
||||
}
|
||||
|
||||
return std::make_pair(std::string(), base::UTF8ToUTF16(printer_name));
|
||||
}
|
||||
|
||||
// Copied from
|
||||
// chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc:L36-L54
|
||||
scoped_refptr<base::TaskRunner> CreatePrinterHandlerTaskRunner() {
|
||||
// USER_VISIBLE because the result is displayed in the print preview dialog.
|
||||
#if !BUILDFLAG(IS_WIN)
|
||||
static constexpr base::TaskTraits kTraits = {
|
||||
base::MayBlock(), base::TaskPriority::USER_VISIBLE};
|
||||
#endif
|
||||
|
||||
#if defined(USE_CUPS)
|
||||
// CUPS is thread safe.
|
||||
return base::ThreadPool::CreateTaskRunner(kTraits);
|
||||
#elif BUILDFLAG(IS_WIN)
|
||||
// Windows drivers are likely not thread-safe and need to be accessed on the
|
||||
// UI thread.
|
||||
return content::GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE});
|
||||
#else
|
||||
// Be conservative on unsupported platforms.
|
||||
return base::ThreadPool::CreateSingleThreadTaskRunner(kTraits);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
struct UserDataLink : public base::SupportsUserData::Data {
|
||||
explicit UserDataLink(base::WeakPtr<WebContents> contents)
|
||||
: web_contents(contents) {}
|
||||
@@ -2483,11 +2560,6 @@ int WebContents::GetActiveIndex() const {
|
||||
return web_contents()->GetController().GetCurrentEntryIndex();
|
||||
}
|
||||
|
||||
content::NavigationEntry* WebContents::GetNavigationEntryAtIndex(
|
||||
int index) const {
|
||||
return web_contents()->GetController().GetEntryAtIndex(index);
|
||||
}
|
||||
|
||||
void WebContents::ClearHistory() {
|
||||
// In some rare cases (normally while there is no real history) we are in a
|
||||
// state where we can't prune navigation entries
|
||||
@@ -2861,6 +2933,7 @@ bool WebContents::IsCurrentlyAudible() {
|
||||
void WebContents::OnGetDeviceNameToUse(
|
||||
base::Value::Dict print_settings,
|
||||
printing::CompletionCallback print_callback,
|
||||
bool silent,
|
||||
// <error, device_name>
|
||||
std::pair<std::string, std::u16string> info) {
|
||||
// The content::WebContents might be already deleted at this point, and the
|
||||
@@ -2880,12 +2953,6 @@ void WebContents::OnGetDeviceNameToUse(
|
||||
// If the user has passed a deviceName use it, otherwise use default printer.
|
||||
print_settings.Set(printing::kSettingDeviceName, info.second);
|
||||
|
||||
if (!print_settings.FindInt(printing::kSettingDpiHorizontal)) {
|
||||
gfx::Size dpi = GetDefaultPrinterDPI(info.second);
|
||||
print_settings.Set(printing::kSettingDpiHorizontal, dpi.width());
|
||||
print_settings.Set(printing::kSettingDpiVertical, dpi.height());
|
||||
}
|
||||
|
||||
auto* print_view_manager =
|
||||
PrintViewManagerElectron::FromWebContents(web_contents());
|
||||
if (!print_view_manager)
|
||||
@@ -2896,7 +2963,7 @@ void WebContents::OnGetDeviceNameToUse(
|
||||
? focused_frame
|
||||
: web_contents()->GetPrimaryMainFrame();
|
||||
|
||||
print_view_manager->PrintNow(rfh, std::move(print_settings),
|
||||
print_view_manager->PrintNow(rfh, silent, std::move(print_settings),
|
||||
std::move(print_callback));
|
||||
}
|
||||
|
||||
@@ -2917,10 +2984,9 @@ void WebContents::Print(gin::Arguments* args) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set optional silent printing.
|
||||
// Set optional silent printing
|
||||
bool silent = false;
|
||||
options.Get("silent", &silent);
|
||||
settings.Set("silent", silent);
|
||||
|
||||
bool print_background = false;
|
||||
options.Get("printBackground", &print_background);
|
||||
@@ -3048,6 +3114,7 @@ void WebContents::Print(gin::Arguments* args) {
|
||||
|
||||
// Set custom dots per inch (dpi)
|
||||
gin_helper::Dictionary dpi_settings;
|
||||
int dpi = 72;
|
||||
if (options.Get("dpi", &dpi_settings)) {
|
||||
int horizontal = 72;
|
||||
dpi_settings.Get("horizontal", &horizontal);
|
||||
@@ -3055,13 +3122,16 @@ void WebContents::Print(gin::Arguments* args) {
|
||||
int vertical = 72;
|
||||
dpi_settings.Get("vertical", &vertical);
|
||||
settings.Set(printing::kSettingDpiVertical, vertical);
|
||||
} else {
|
||||
settings.Set(printing::kSettingDpiHorizontal, dpi);
|
||||
settings.Set(printing::kSettingDpiVertical, dpi);
|
||||
}
|
||||
|
||||
print_task_runner_->PostTaskAndReplyWithResult(
|
||||
FROM_HERE, base::BindOnce(&GetDeviceNameToUse, device_name),
|
||||
base::BindOnce(&WebContents::OnGetDeviceNameToUse,
|
||||
weak_factory_.GetWeakPtr(), std::move(settings),
|
||||
std::move(callback)));
|
||||
std::move(callback), silent));
|
||||
}
|
||||
|
||||
// Partially duplicated and modified from
|
||||
@@ -4283,11 +4353,9 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
|
||||
.SetMethod("goToOffset", &WebContents::GoToOffset)
|
||||
.SetMethod("canGoToIndex", &WebContents::CanGoToIndex)
|
||||
.SetMethod("goToIndex", &WebContents::GoToIndex)
|
||||
.SetMethod("_getActiveIndex", &WebContents::GetActiveIndex)
|
||||
.SetMethod("_getNavigationEntryAtIndex",
|
||||
&WebContents::GetNavigationEntryAtIndex)
|
||||
.SetMethod("_historyLength", &WebContents::GetHistoryLength)
|
||||
.SetMethod("getActiveIndex", &WebContents::GetActiveIndex)
|
||||
.SetMethod("clearHistory", &WebContents::ClearHistory)
|
||||
.SetMethod("length", &WebContents::GetHistoryLength)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
.SetMethod("forcefullyCrashRenderer",
|
||||
&WebContents::ForcefullyCrashRenderer)
|
||||
|
||||
@@ -194,7 +194,6 @@ class WebContents : public ExclusiveAccessContext,
|
||||
bool CanGoToIndex(int index) const;
|
||||
void GoToIndex(int index);
|
||||
int GetActiveIndex() const;
|
||||
content::NavigationEntry* GetNavigationEntryAtIndex(int index) const;
|
||||
void ClearHistory();
|
||||
int GetHistoryLength() const;
|
||||
const std::string GetWebRTCIPHandlingPolicy() const;
|
||||
@@ -236,6 +235,7 @@ class WebContents : public ExclusiveAccessContext,
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
void OnGetDeviceNameToUse(base::Value::Dict print_settings,
|
||||
printing::CompletionCallback print_callback,
|
||||
bool silent,
|
||||
// <error, device_name>
|
||||
std::pair<std::string, std::u16string> info);
|
||||
void Print(gin::Arguments* args);
|
||||
|
||||
@@ -24,14 +24,29 @@
|
||||
#include "ui/views/view_class_properties.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#include "shell/browser/ui/cocoa/delayed_native_view_host.h"
|
||||
#endif
|
||||
|
||||
namespace electron::api {
|
||||
|
||||
WebContentsView::WebContentsView(v8::Isolate* isolate,
|
||||
gin::Handle<WebContents> web_contents)
|
||||
: View(web_contents->inspectable_web_contents()->GetView()),
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
: View(new DelayedNativeViewHost(web_contents->inspectable_web_contents()
|
||||
->GetView()
|
||||
->GetNativeView())),
|
||||
#else
|
||||
: View(web_contents->inspectable_web_contents()->GetView()->GetView()),
|
||||
#endif
|
||||
web_contents_(isolate, web_contents.ToV8()),
|
||||
api_web_contents_(web_contents.get()) {
|
||||
#if !BUILDFLAG(IS_MAC)
|
||||
// On macOS the View is a newly-created |DelayedNativeViewHost| and it is our
|
||||
// responsibility to delete it. On other platforms the View is created and
|
||||
// managed by InspectableWebContents.
|
||||
set_delete_view(false);
|
||||
#endif
|
||||
view()->SetProperty(
|
||||
views::kFlexBehaviorKey,
|
||||
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
|
||||
|
||||
@@ -42,7 +42,6 @@ void FrameSubscriber::AttachToHost(content::RenderWidgetHost* host) {
|
||||
|
||||
// Create and configure the video capturer.
|
||||
gfx::Size size = GetRenderViewSize();
|
||||
DCHECK(!size.IsEmpty());
|
||||
video_capturer_ = host_->GetView()->CreateVideoCapturer();
|
||||
video_capturer_->SetResolutionConstraints(size, size, true);
|
||||
video_capturer_->SetAutoThrottlingEnabled(false);
|
||||
|
||||
@@ -27,16 +27,6 @@
|
||||
|
||||
namespace electron {
|
||||
|
||||
LoginItemSettings::LoginItemSettings() = default;
|
||||
LoginItemSettings::~LoginItemSettings() = default;
|
||||
LoginItemSettings::LoginItemSettings(const LoginItemSettings& other) = default;
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
LaunchItem::LaunchItem() = default;
|
||||
LaunchItem::~LaunchItem() = default;
|
||||
LaunchItem::LaunchItem(const LaunchItem& other) = default;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// Call |quit| after Chromium is fully started.
|
||||
@@ -53,6 +43,17 @@ void RunQuitClosure(base::OnceClosure quit) {
|
||||
|
||||
} // namespace
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
Browser::LaunchItem::LaunchItem() = default;
|
||||
Browser::LaunchItem::~LaunchItem() = default;
|
||||
Browser::LaunchItem::LaunchItem(const LaunchItem& other) = default;
|
||||
#endif
|
||||
|
||||
Browser::LoginItemSettings::LoginItemSettings() = default;
|
||||
Browser::LoginItemSettings::~LoginItemSettings() = default;
|
||||
Browser::LoginItemSettings::LoginItemSettings(const LoginItemSettings& other) =
|
||||
default;
|
||||
|
||||
Browser::Browser() {
|
||||
WindowList::AddObserver(this);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "gin/dictionary.h"
|
||||
#include "shell/browser/browser_observer.h"
|
||||
#include "shell/browser/window_list_observer.h"
|
||||
#include "shell/common/gin_converters/login_item_settings_converter.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
@@ -42,48 +41,6 @@ namespace electron {
|
||||
|
||||
class ElectronMenuModel;
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
struct LaunchItem {
|
||||
std::wstring name;
|
||||
std::wstring path;
|
||||
std::wstring scope;
|
||||
std::vector<std::wstring> args;
|
||||
bool enabled = true;
|
||||
|
||||
LaunchItem();
|
||||
~LaunchItem();
|
||||
LaunchItem(const LaunchItem&);
|
||||
};
|
||||
#endif
|
||||
|
||||
struct LoginItemSettings {
|
||||
bool open_at_login = false;
|
||||
bool open_as_hidden = false;
|
||||
bool restore_state = false;
|
||||
bool opened_at_login = false;
|
||||
bool opened_as_hidden = false;
|
||||
std::u16string path;
|
||||
std::vector<std::u16string> args;
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
std::string type = "mainAppService";
|
||||
std::string service_name;
|
||||
std::string status;
|
||||
#elif BUILDFLAG(IS_WIN)
|
||||
// used in browser::setLoginItemSettings
|
||||
bool enabled = true;
|
||||
std::wstring name;
|
||||
|
||||
// used in browser::getLoginItemSettings
|
||||
bool executable_will_launch_at_login = false;
|
||||
std::vector<LaunchItem> launch_items;
|
||||
#endif
|
||||
|
||||
LoginItemSettings();
|
||||
~LoginItemSettings();
|
||||
LoginItemSettings(const LoginItemSettings&);
|
||||
};
|
||||
|
||||
// This class is used for control application-wide operations.
|
||||
class Browser : public WindowListObserver {
|
||||
public:
|
||||
@@ -155,8 +112,50 @@ class Browser : public WindowListObserver {
|
||||
bool SetBadgeCount(std::optional<int> count);
|
||||
[[nodiscard]] int badge_count() const { return badge_count_; }
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
struct LaunchItem {
|
||||
std::wstring name;
|
||||
std::wstring path;
|
||||
std::wstring scope;
|
||||
std::vector<std::wstring> args;
|
||||
bool enabled = true;
|
||||
|
||||
LaunchItem();
|
||||
~LaunchItem();
|
||||
LaunchItem(const LaunchItem&);
|
||||
};
|
||||
#endif
|
||||
|
||||
// Set/Get the login item settings of the app
|
||||
struct LoginItemSettings {
|
||||
bool open_at_login = false;
|
||||
bool open_as_hidden = false;
|
||||
bool restore_state = false;
|
||||
bool opened_at_login = false;
|
||||
bool opened_as_hidden = false;
|
||||
std::u16string path;
|
||||
std::vector<std::u16string> args;
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
std::string type = "mainAppService";
|
||||
std::string service_name;
|
||||
std::string status;
|
||||
#elif BUILDFLAG(IS_WIN)
|
||||
// used in browser::setLoginItemSettings
|
||||
bool enabled = true;
|
||||
std::wstring name;
|
||||
|
||||
// used in browser::getLoginItemSettings
|
||||
bool executable_will_launch_at_login = false;
|
||||
std::vector<LaunchItem> launch_items;
|
||||
#endif
|
||||
|
||||
LoginItemSettings();
|
||||
~LoginItemSettings();
|
||||
LoginItemSettings(const LoginItemSettings&);
|
||||
};
|
||||
void SetLoginItemSettings(LoginItemSettings settings);
|
||||
v8::Local<v8::Value> GetLoginItemSettings(const LoginItemSettings& options);
|
||||
LoginItemSettings GetLoginItemSettings(const LoginItemSettings& options);
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
// Set the handler which decides whether to shutdown.
|
||||
|
||||
@@ -11,11 +11,9 @@
|
||||
#include "base/environment.h"
|
||||
#include "base/process/launch.h"
|
||||
#include "electron/electron_version.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "shell/common/application_info.h"
|
||||
#include "shell/common/gin_converters/login_item_settings_converter.h"
|
||||
#include "shell/common/thread_restrictions.h"
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
@@ -140,10 +138,9 @@ bool Browser::SetBadgeCount(std::optional<int> count) {
|
||||
|
||||
void Browser::SetLoginItemSettings(LoginItemSettings settings) {}
|
||||
|
||||
v8::Local<v8::Value> Browser::GetLoginItemSettings(
|
||||
Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
const LoginItemSettings& options) {
|
||||
LoginItemSettings settings;
|
||||
return gin::ConvertToV8(JavascriptEnvironment::GetIsolate(), settings);
|
||||
return LoginItemSettings();
|
||||
}
|
||||
|
||||
std::string Browser::GetExecutableFileVersion() const {
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "shell/common/api/electron_api_native_image.h"
|
||||
#include "shell/common/application_info.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
#include "shell/common/gin_converters/login_item_settings_converter.h"
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
@@ -89,8 +88,8 @@ bool CheckLoginItemStatus(bool* is_hidden) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LoginItemSettings GetLoginItemSettingsDeprecated() {
|
||||
LoginItemSettings settings;
|
||||
Browser::LoginItemSettings GetLoginItemSettingsDeprecated() {
|
||||
Browser::LoginItemSettings settings;
|
||||
settings.open_at_login = CheckLoginItemStatus(&settings.open_as_hidden);
|
||||
settings.restore_state = base::mac::WasLaunchedAsLoginItemRestoreState();
|
||||
settings.opened_at_login = base::mac::WasLaunchedAsLoginOrResumeItem();
|
||||
@@ -376,15 +375,13 @@ void Browser::ApplyForcedRTL() {
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Browser::GetLoginItemSettings(
|
||||
Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
const LoginItemSettings& options) {
|
||||
LoginItemSettings settings;
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
|
||||
if (options.type != "mainAppService" && options.service_name.empty()) {
|
||||
gin_helper::ErrorThrower(isolate).ThrowTypeError(
|
||||
"'name' is required when type is not mainAppService");
|
||||
return v8::Local<v8::Value>();
|
||||
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
|
||||
.ThrowTypeError("'name' is required when type is not mainAppService");
|
||||
return settings;
|
||||
}
|
||||
|
||||
#if IS_MAS_BUILD()
|
||||
@@ -411,7 +408,7 @@ v8::Local<v8::Value> Browser::GetLoginItemSettings(
|
||||
settings = settings_deprecated;
|
||||
}
|
||||
#endif
|
||||
return gin::ConvertToV8(isolate, settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
void Browser::SetLoginItemSettings(LoginItemSettings settings) {
|
||||
|
||||
@@ -30,19 +30,16 @@
|
||||
#include "shell/browser/api/electron_api_app.h"
|
||||
#include "shell/browser/badging/badge_manager.h"
|
||||
#include "shell/browser/electron_browser_main_parts.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/ui/message_box.h"
|
||||
#include "shell/browser/ui/win/jump_list.h"
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "shell/common/application_info.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
#include "shell/common/gin_converters/login_item_settings_converter.h"
|
||||
#include "shell/common/gin_helper/arguments.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/skia_util.h"
|
||||
#include "shell/common/thread_restrictions.h"
|
||||
#include "skia/ext/font_utils.h"
|
||||
#include "skia/ext/legacy_display_globals.h"
|
||||
#include "third_party/skia/include/core/SkCanvas.h"
|
||||
#include "third_party/skia/include/core/SkFont.h"
|
||||
@@ -156,12 +153,12 @@ bool FormatCommandLineString(std::wstring* exe,
|
||||
// a list of launchItem with matching paths to our application.
|
||||
// if a launchItem with a matching path also has a matching entry within the
|
||||
// startup_approved_key_path, set executable_will_launch_at_login to be `true`
|
||||
std::vector<LaunchItem> GetLoginItemSettingsHelper(
|
||||
std::vector<Browser::LaunchItem> GetLoginItemSettingsHelper(
|
||||
base::win::RegistryValueIterator* it,
|
||||
boolean* executable_will_launch_at_login,
|
||||
std::wstring scope,
|
||||
const LoginItemSettings& options) {
|
||||
std::vector<LaunchItem> launch_items;
|
||||
const Browser::LoginItemSettings& options) {
|
||||
std::vector<Browser::LaunchItem> launch_items;
|
||||
|
||||
base::FilePath lookup_exe_path;
|
||||
if (options.path.empty()) {
|
||||
@@ -185,7 +182,7 @@ std::vector<LaunchItem> GetLoginItemSettingsHelper(
|
||||
|
||||
// add launch item to vector if it has a matching path (case-insensitive)
|
||||
if (exe_match) {
|
||||
LaunchItem launch_item;
|
||||
Browser::LaunchItem launch_item;
|
||||
launch_item.name = it->Name();
|
||||
launch_item.path = registry_launch_path.value();
|
||||
launch_item.args = registry_launch_cmd.GetArgs();
|
||||
@@ -594,7 +591,7 @@ void Browser::UpdateBadgeContents(
|
||||
paint.reset();
|
||||
paint.setColor(kForegroundColor);
|
||||
|
||||
SkFont font = skia::DefaultFont();
|
||||
SkFont font;
|
||||
|
||||
SkRect bounds;
|
||||
int text_size = kMaxTextSize;
|
||||
@@ -658,7 +655,7 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) {
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Browser::GetLoginItemSettings(
|
||||
Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
const LoginItemSettings& options) {
|
||||
LoginItemSettings settings;
|
||||
std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
||||
@@ -677,7 +674,7 @@ v8::Local<v8::Value> Browser::GetLoginItemSettings(
|
||||
// if there exists a launch entry with property enabled=='true',
|
||||
// set executable_will_launch_at_login to 'true'.
|
||||
boolean executable_will_launch_at_login = false;
|
||||
std::vector<LaunchItem> launch_items;
|
||||
std::vector<Browser::LaunchItem> launch_items;
|
||||
base::win::RegistryValueIterator hkcu_iterator(HKEY_CURRENT_USER,
|
||||
keyPath.c_str());
|
||||
base::win::RegistryValueIterator hklm_iterator(HKEY_LOCAL_MACHINE,
|
||||
@@ -685,14 +682,16 @@ v8::Local<v8::Value> Browser::GetLoginItemSettings(
|
||||
|
||||
launch_items = GetLoginItemSettingsHelper(
|
||||
&hkcu_iterator, &executable_will_launch_at_login, L"user", options);
|
||||
std::vector<LaunchItem> launch_items_hklm = GetLoginItemSettingsHelper(
|
||||
&hklm_iterator, &executable_will_launch_at_login, L"machine", options);
|
||||
std::vector<Browser::LaunchItem> launch_items_hklm =
|
||||
GetLoginItemSettingsHelper(&hklm_iterator,
|
||||
&executable_will_launch_at_login, L"machine",
|
||||
options);
|
||||
launch_items.insert(launch_items.end(), launch_items_hklm.begin(),
|
||||
launch_items_hklm.end());
|
||||
|
||||
settings.executable_will_launch_at_login = executable_will_launch_at_login;
|
||||
settings.launch_items = launch_items;
|
||||
return gin::ConvertToV8(JavascriptEnvironment::GetIsolate(), settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
PCWSTR Browser::GetAppUserModelID() {
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "extensions/browser/api/scripting/scripting_utils.h"
|
||||
#include "extensions/browser/extension_api_frame_id_map.h"
|
||||
#include "extensions/browser/extension_file_task_runner.h"
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "extensions/browser/extension_system.h"
|
||||
#include "extensions/browser/extension_user_script_loader.h"
|
||||
#include "extensions/browser/extension_util.h"
|
||||
@@ -1062,17 +1061,6 @@ void ScriptingRegisterContentScriptsFunction::OnContentScriptFilesValidated(
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot proceed if the extension is uninstalled or unloaded in the middle
|
||||
// of validating its script files.
|
||||
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
|
||||
if (!extension() ||
|
||||
!registry->enabled_extensions().Contains(extension_id())) {
|
||||
// Note: a Respond() is not needed if the system is shutting down or if the
|
||||
// extension is no longer enabled.
|
||||
Release(); // Matches the `AddRef()` in `Run()`.
|
||||
return;
|
||||
}
|
||||
|
||||
auto error = std::move(result.second);
|
||||
auto scripts = std::move(result.first);
|
||||
ExtensionUserScriptLoader* loader =
|
||||
@@ -1318,17 +1306,6 @@ void ScriptingUpdateContentScriptsFunction::OnContentScriptFilesValidated(
|
||||
return;
|
||||
}
|
||||
|
||||
// We cannot proceed if the extension is uninstalled or unloaded in the middle
|
||||
// of validating its script files.
|
||||
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
|
||||
if (!extension() ||
|
||||
!registry->enabled_extensions().Contains(extension_id())) {
|
||||
// Note: a Respond() is not needed if the system is shutting down or if the
|
||||
// extension is no longer enabled.
|
||||
Release(); // Matches the `AddRef()` in `Run()`.
|
||||
return;
|
||||
}
|
||||
|
||||
auto error = std::move(result.second);
|
||||
auto scripts = std::move(result.first);
|
||||
ExtensionUserScriptLoader* loader =
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/dcheck_is_on.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
std::string EnablePlatformSpecificFeatures() {
|
||||
@@ -21,12 +19,8 @@ std::string EnablePlatformSpecificFeatures() {
|
||||
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
// kThumbnailCapturerMac,
|
||||
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
#if DCHECK_IS_ON()
|
||||
return "";
|
||||
#else
|
||||
return "ScreenCaptureKitPickerScreen,ScreenCaptureKitStreamPickerSonoma,"
|
||||
"ThumbnailCapturerMac:capture_mode/sc_screenshot_manager";
|
||||
#endif
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -242,7 +242,6 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
|
||||
params.bounds = bounds;
|
||||
params.delegate = this;
|
||||
params.type = views::Widget::InitParams::TYPE_WINDOW;
|
||||
params.headless_mode = true;
|
||||
params.native_widget =
|
||||
new ElectronNativeWidgetMac(this, windowType, styleMask, widget());
|
||||
widget()->Init(std::move(params));
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "content/public/browser/desktop_media_id.h"
|
||||
#include "shell/browser/api/electron_api_web_contents.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
||||
#include "shell/browser/ui/views/inspectable_web_contents_view_views.h"
|
||||
#include "shell/browser/ui/views/root_view.h"
|
||||
#include "shell/browser/web_contents_preferences.h"
|
||||
#include "shell/browser/web_view_manager.h"
|
||||
@@ -469,12 +469,12 @@ void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
|
||||
|
||||
void NativeWindowViews::SetContentView(views::View* view) {
|
||||
if (content_view()) {
|
||||
root_view_.GetMainView()->RemoveChildView(content_view());
|
||||
root_view_.RemoveChildView(content_view());
|
||||
}
|
||||
set_content_view(view);
|
||||
focused_view_ = view;
|
||||
root_view_.GetMainView()->AddChildView(content_view());
|
||||
root_view_.GetMainView()->DeprecatedLayoutImmediately();
|
||||
root_view_.AddChildView(content_view());
|
||||
root_view_.DeprecatedLayoutImmediately();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Close() {
|
||||
@@ -1664,7 +1664,7 @@ std::u16string NativeWindowViews::GetWindowTitle() const {
|
||||
}
|
||||
|
||||
views::View* NativeWindowViews::GetContentsView() {
|
||||
return root_view_.GetMainView();
|
||||
return &root_view_;
|
||||
}
|
||||
|
||||
bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
||||
@@ -1674,7 +1674,7 @@ bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
||||
}
|
||||
|
||||
views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
|
||||
return new NativeWindowClientView{widget, &root_view_, this};
|
||||
return new NativeWindowClientView{widget, GetContentsView(), this};
|
||||
}
|
||||
|
||||
std::unique_ptr<views::NonClientFrameView>
|
||||
|
||||
@@ -159,21 +159,21 @@ void LibnotifyNotification::Show(const NotificationOptions& options) {
|
||||
|
||||
void LibnotifyNotification::Dismiss() {
|
||||
if (!notification_) {
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
GError* error = nullptr;
|
||||
on_dismissing_ = true;
|
||||
libnotify_loader_.notify_notification_close(notification_, &error);
|
||||
if (error) {
|
||||
log_and_clear_error(error, "notify_notification_close");
|
||||
Destroy();
|
||||
}
|
||||
on_dismissing_ = false;
|
||||
}
|
||||
|
||||
void LibnotifyNotification::OnNotificationClosed(
|
||||
NotifyNotification* notification) {
|
||||
NotificationDismissed(!on_dismissing_);
|
||||
NotificationDismissed();
|
||||
}
|
||||
|
||||
void LibnotifyNotification::OnNotificationView(NotifyNotification* notification,
|
||||
|
||||
@@ -33,7 +33,6 @@ class LibnotifyNotification : public Notification {
|
||||
RAW_PTR_EXCLUSION NotifyNotification* notification_ = nullptr;
|
||||
|
||||
ScopedGSignal signal_;
|
||||
bool on_dismissing_ = false;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "content/browser/renderer_host/render_widget_host_delegate.h" // nogncheck
|
||||
#include "content/browser/renderer_host/render_widget_host_owner_delegate.h" // nogncheck
|
||||
#include "content/common/input/synthetic_gesture.h" // nogncheck
|
||||
#include "content/common/input/synthetic_gesture_target.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/context_factory.h"
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright (c) 2024 Microsoft, GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/printing/printing_utils.h"
|
||||
|
||||
#include "base/apple/scoped_typeref.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task/task_traits.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "printing/backend/print_backend.h" // nogncheck
|
||||
#include "printing/units.h"
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#elif BUILDFLAG(LINUX)
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
namespace electron {
|
||||
|
||||
gfx::Size GetDefaultPrinterDPI(const std::u16string& device_name) {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
return gfx::Size(printing::kDefaultMacDpi, printing::kDefaultMacDpi);
|
||||
#elif BUILDFLAG(IS_WIN)
|
||||
HDC hdc =
|
||||
CreateDC(L"WINSPOOL", base::as_wcstr(device_name), nullptr, nullptr);
|
||||
if (hdc == nullptr)
|
||||
return gfx::Size(kDefaultPdfDpi, kDefaultPdfDpi);
|
||||
|
||||
int dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
|
||||
int dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
|
||||
DeleteDC(hdc);
|
||||
|
||||
return gfx::Size(dpi_x, dpi_y);
|
||||
#else
|
||||
GtkPrintSettings* print_settings = gtk_print_settings_new();
|
||||
int dpi = gtk_print_settings_get_resolution(print_settings);
|
||||
g_object_unref(print_settings);
|
||||
return gfx::Size(dpi, dpi);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsDeviceNameValid(const std::u16string& device_name) {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
base::apple::ScopedCFTypeRef<CFStringRef> new_printer_id(
|
||||
base::SysUTF16ToCFStringRef(device_name));
|
||||
PMPrinter new_printer = PMPrinterCreateFromPrinterID(new_printer_id.get());
|
||||
bool printer_exists = new_printer != nullptr;
|
||||
PMRelease(new_printer);
|
||||
return printer_exists;
|
||||
#else
|
||||
scoped_refptr<printing::PrintBackend> print_backend =
|
||||
printing::PrintBackend::CreateInstance(
|
||||
g_browser_process->GetApplicationLocale());
|
||||
return print_backend->IsValidPrinter(base::UTF16ToUTF8(device_name));
|
||||
#endif
|
||||
}
|
||||
|
||||
std::pair<std::string, std::u16string> GetDeviceNameToUse(
|
||||
const std::u16string& device_name) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Blocking is needed here because Windows printer drivers are oftentimes
|
||||
// not thread-safe and have to be accessed on the UI thread.
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
#endif
|
||||
|
||||
if (!device_name.empty()) {
|
||||
if (!IsDeviceNameValid(device_name))
|
||||
return std::make_pair("Invalid deviceName provided", std::u16string());
|
||||
return std::make_pair(std::string(), device_name);
|
||||
}
|
||||
|
||||
scoped_refptr<printing::PrintBackend> print_backend =
|
||||
printing::PrintBackend::CreateInstance(
|
||||
g_browser_process->GetApplicationLocale());
|
||||
std::string printer_name;
|
||||
printing::mojom::ResultCode code =
|
||||
print_backend->GetDefaultPrinterName(printer_name);
|
||||
|
||||
// We don't want to return if this fails since some devices won't have a
|
||||
// default printer.
|
||||
if (code != printing::mojom::ResultCode::kSuccess)
|
||||
LOG(ERROR) << "Failed to get default printer name";
|
||||
|
||||
if (printer_name.empty()) {
|
||||
printing::PrinterList printers;
|
||||
if (print_backend->EnumeratePrinters(printers) !=
|
||||
printing::mojom::ResultCode::kSuccess)
|
||||
return std::make_pair("Failed to enumerate printers", std::u16string());
|
||||
if (printers.empty())
|
||||
return std::make_pair("No printers available on the network",
|
||||
std::u16string());
|
||||
|
||||
printer_name = printers.front().printer_name;
|
||||
}
|
||||
|
||||
return std::make_pair(std::string(), base::UTF8ToUTF16(printer_name));
|
||||
}
|
||||
|
||||
// Copied from
|
||||
// chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc:L36-L54
|
||||
scoped_refptr<base::TaskRunner> CreatePrinterHandlerTaskRunner() {
|
||||
// USER_VISIBLE because the result is displayed in the print preview dialog.
|
||||
#if !BUILDFLAG(IS_WIN)
|
||||
static constexpr base::TaskTraits kTraits = {
|
||||
base::MayBlock(), base::TaskPriority::USER_VISIBLE};
|
||||
#endif
|
||||
|
||||
#if defined(USE_CUPS)
|
||||
// CUPS is thread safe.
|
||||
return base::ThreadPool::CreateTaskRunner(kTraits);
|
||||
#elif BUILDFLAG(IS_WIN)
|
||||
// Windows drivers are likely not thread-safe and need to be accessed on the
|
||||
// UI thread.
|
||||
return content::GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE});
|
||||
#else
|
||||
// Be conservative on unsupported platforms.
|
||||
return base::ThreadPool::CreateSingleThreadTaskRunner(kTraits);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2024 Microsoft, GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_PRINTING_PRINTING_UTILS_H_
|
||||
#define ELECTRON_SHELL_BROWSER_PRINTING_PRINTING_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/task/task_runner.h"
|
||||
|
||||
namespace gfx {
|
||||
class Size;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
// This function returns the per-platform default printer's DPI.
|
||||
gfx::Size GetDefaultPrinterDPI(const std::u16string& device_name);
|
||||
|
||||
// This will return false if no printer with the provided device_name can be
|
||||
// found on the network. We need to check this because Chromium does not do
|
||||
// sanity checking of device_name validity and so will crash on invalid names.
|
||||
bool IsDeviceNameValid(const std::u16string& device_name);
|
||||
|
||||
// This function returns a validated device name.
|
||||
// If the user passed one to webContents.print(), we check that it's valid and
|
||||
// return it or fail if the network doesn't recognize it. If the user didn't
|
||||
// pass a device name, we first try to return the system default printer. If one
|
||||
// isn't set, then pull all the printers and use the first one or fail if none
|
||||
// exist.
|
||||
std::pair<std::string, std::u16string> GetDeviceNameToUse(
|
||||
const std::u16string& device_name);
|
||||
|
||||
// This function creates a task runner for use with printing tasks.
|
||||
scoped_refptr<base::TaskRunner> CreatePrinterHandlerTaskRunner();
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_PRINTING_PRINTING_UTILS_H_
|
||||
@@ -35,9 +35,7 @@ std::unique_ptr<content::SerialChooser> ElectronSerialDelegate::RunChooser(
|
||||
if (controller) {
|
||||
DeleteControllerForFrame(frame);
|
||||
}
|
||||
AddControllerForFrame(frame, std::move(filters),
|
||||
std::move(allowed_bluetooth_service_class_ids),
|
||||
std::move(callback));
|
||||
AddControllerForFrame(frame, std::move(filters), std::move(callback));
|
||||
|
||||
// Return a nullptr because the return value isn't used for anything, eg
|
||||
// there is no mechanism to cancel navigator.serial.requestPort(). The return
|
||||
@@ -108,14 +106,12 @@ SerialChooserController* ElectronSerialDelegate::ControllerForFrame(
|
||||
SerialChooserController* ElectronSerialDelegate::AddControllerForFrame(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
std::vector<blink::mojom::SerialPortFilterPtr> filters,
|
||||
std::vector<device::BluetoothUUID> allowed_bluetooth_service_class_ids,
|
||||
content::SerialChooser::Callback callback) {
|
||||
auto* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||
auto controller = std::make_unique<SerialChooserController>(
|
||||
render_frame_host, std::move(filters),
|
||||
std::move(allowed_bluetooth_service_class_ids), std::move(callback),
|
||||
web_contents, weak_factory_.GetWeakPtr());
|
||||
render_frame_host, std::move(filters), std::move(callback), web_contents,
|
||||
weak_factory_.GetWeakPtr());
|
||||
controller_map_.insert(
|
||||
std::make_pair(render_frame_host, std::move(controller)));
|
||||
return ControllerForFrame(render_frame_host);
|
||||
|
||||
@@ -67,7 +67,6 @@ class ElectronSerialDelegate : public content::SerialDelegate,
|
||||
SerialChooserController* AddControllerForFrame(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
std::vector<blink::mojom::SerialPortFilterPtr> filters,
|
||||
std::vector<device::BluetoothUUID> allowed_bluetooth_service_class_ids,
|
||||
content::SerialChooser::Callback callback);
|
||||
|
||||
base::ScopedObservation<SerialChooserContext,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user