mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
190 Commits
v30.0.0-ni
...
security/2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b12902c0a | ||
|
|
41b7c7e515 | ||
|
|
fe869081b3 | ||
|
|
914d8f373e | ||
|
|
0bd7092e74 | ||
|
|
5cdfdcdffb | ||
|
|
fc5ee6d319 | ||
|
|
0529300980 | ||
|
|
3a142b6c4f | ||
|
|
3fd34fc4b6 | ||
|
|
dcf12182b8 | ||
|
|
537e8c3bea | ||
|
|
3041c956ce | ||
|
|
c57f515e43 | ||
|
|
4b3d3a5f07 | ||
|
|
0b51976cd2 | ||
|
|
4e1f54087d | ||
|
|
d2ffa6fe31 | ||
|
|
f7bb17ebd1 | ||
|
|
f9ed0eaee4 | ||
|
|
8933e7e2a9 | ||
|
|
262f4d34cf | ||
|
|
b721d420d5 | ||
|
|
4517547f07 | ||
|
|
4f30f731ee | ||
|
|
3b81b7efbc | ||
|
|
acd34fdca9 | ||
|
|
84ecd700db | ||
|
|
cbc0f6720e | ||
|
|
8fbabeaca7 | ||
|
|
4c737147c3 | ||
|
|
5ebc741819 | ||
|
|
cd6ad4d1bb | ||
|
|
19f0abd62e | ||
|
|
9d4f8a06e8 | ||
|
|
a43014a410 | ||
|
|
803698e2c4 | ||
|
|
557cadddcb | ||
|
|
fe01ed750a | ||
|
|
7f26c72af6 | ||
|
|
7a3e587a1d | ||
|
|
bf14d05830 | ||
|
|
384642792e | ||
|
|
5bbac9ae30 | ||
|
|
0da6411d11 | ||
|
|
297be64122 | ||
|
|
1c47ba0a91 | ||
|
|
1cd7a71bb1 | ||
|
|
feb81b6841 | ||
|
|
a3d9e4be58 | ||
|
|
ec4683cd91 | ||
|
|
a02e0f0f02 | ||
|
|
97eee463fa | ||
|
|
ed9a12cba7 | ||
|
|
fe4d3a2484 | ||
|
|
ad9a90ec53 | ||
|
|
8647232c48 | ||
|
|
f9e28e3e50 | ||
|
|
3698f89205 | ||
|
|
238cc80cef | ||
|
|
3b025ec0c7 | ||
|
|
d2c14f1c6c | ||
|
|
0d3f50fc12 | ||
|
|
d3da708f5c | ||
|
|
e64c123d80 | ||
|
|
9ce58dd0ea | ||
|
|
4da7bff05f | ||
|
|
53a7faa029 | ||
|
|
d2177e4d08 | ||
|
|
07f50757a3 | ||
|
|
98283d1dae | ||
|
|
d0fdc28c0e | ||
|
|
99dd9e2138 | ||
|
|
c5a2873f8f | ||
|
|
1e34cdda96 | ||
|
|
880aee0aa7 | ||
|
|
c00489396b | ||
|
|
30587d9700 | ||
|
|
ede0ebcc73 | ||
|
|
5966b42ac5 | ||
|
|
33e61a19ef | ||
|
|
a90c5b1b08 | ||
|
|
06e01e5b76 | ||
|
|
96d053677d | ||
|
|
8fe14665a0 | ||
|
|
c9384a609e | ||
|
|
fd2620bda4 | ||
|
|
dc04802296 | ||
|
|
90ca4e5f80 | ||
|
|
5013150cfd | ||
|
|
2d9c5a62c6 | ||
|
|
23f690ffd0 | ||
|
|
8f4e94694e | ||
|
|
af47434dc8 | ||
|
|
8ab99e2d8e | ||
|
|
ffcccdcf37 | ||
|
|
ce2ac1c0c2 | ||
|
|
1c3feddef8 | ||
|
|
c779f19ee5 | ||
|
|
09fbee9998 | ||
|
|
69d371fc41 | ||
|
|
b6db80c1c4 | ||
|
|
b87cf56b09 | ||
|
|
bc40a1aa0c | ||
|
|
d8606efe94 | ||
|
|
523e0d4574 | ||
|
|
3b23911121 | ||
|
|
516cbfa29a | ||
|
|
5c71377f40 | ||
|
|
85db55516b | ||
|
|
e071faa31b | ||
|
|
53e1c63d69 | ||
|
|
b8917a03d6 | ||
|
|
b33bc21159 | ||
|
|
9bb821a818 | ||
|
|
432b89445f | ||
|
|
00a3c3c883 | ||
|
|
288ec2ed93 | ||
|
|
90ca228cdc | ||
|
|
aa4ea630f8 | ||
|
|
d6fedc20bc | ||
|
|
42a72df1e7 | ||
|
|
16764199a7 | ||
|
|
4113f9d6a6 | ||
|
|
7aff4bc1dd | ||
|
|
d5b0df6775 | ||
|
|
b4f66e5f79 | ||
|
|
fbab31a699 | ||
|
|
7bccdbcbdb | ||
|
|
d715090a36 | ||
|
|
31054d6d46 | ||
|
|
76859affbd | ||
|
|
f3224365cf | ||
|
|
4a24337b14 | ||
|
|
2312420deb | ||
|
|
a05c9bcfb9 | ||
|
|
25f52d5d32 | ||
|
|
1fefe25ed5 | ||
|
|
d92ffceafb | ||
|
|
6e1dc452f9 | ||
|
|
9daf416097 | ||
|
|
738e0b9664 | ||
|
|
370a2c702b | ||
|
|
3f85bd57a2 | ||
|
|
5c8b5ff811 | ||
|
|
7d7f390c93 | ||
|
|
0fc5e42018 | ||
|
|
1ff780d3dd | ||
|
|
dd142b0327 | ||
|
|
0df4312ded | ||
|
|
95e3df589f | ||
|
|
7441b812e4 | ||
|
|
12f4204824 | ||
|
|
b84beed666 | ||
|
|
ebeb8adaf4 | ||
|
|
d5433ec0cc | ||
|
|
8d49957c93 | ||
|
|
471c44c709 | ||
|
|
8f4e7bde5e | ||
|
|
94fdb02987 | ||
|
|
2377746413 | ||
|
|
2bb2ef92da | ||
|
|
c994eb8e13 | ||
|
|
a9d358e730 | ||
|
|
69e30e8d67 | ||
|
|
02dfdce54a | ||
|
|
bd304f7c9d | ||
|
|
c2524d762b | ||
|
|
0b1e1b1612 | ||
|
|
0d0340ec69 | ||
|
|
f0d42aed88 | ||
|
|
ddb1c784d0 | ||
|
|
33ae7cc786 | ||
|
|
cbd1b4486c | ||
|
|
40a13b649f | ||
|
|
5728d3b709 | ||
|
|
0778cc70bb | ||
|
|
f0c02568da | ||
|
|
3c01b58114 | ||
|
|
c257cc25a2 | ||
|
|
e1ec17d641 | ||
|
|
ce7e0afd0a | ||
|
|
f589b73dee | ||
|
|
44f29fc675 | ||
|
|
daf00de2ed | ||
|
|
877a3b9fe2 | ||
|
|
0bcaaca6bd | ||
|
|
8619bd5027 | ||
|
|
4875c9b645 | ||
|
|
f4979e3cd2 |
@@ -75,10 +75,6 @@ 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:
|
||||
@@ -264,9 +260,9 @@ step-depot-tools-get: &step-depot-tools-get
|
||||
index c305c248..e6e0fbdc 100755
|
||||
--- a/gclient.py
|
||||
+++ b/gclient.py
|
||||
@@ -735,7 +735,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
|
||||
if dep_type == 'cipd':
|
||||
@@ -783,7 +783,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
not condition or "non_git_source" not in condition):
|
||||
continue
|
||||
cipd_root = self.GetCipdRoot()
|
||||
- for package in dep_value.get('packages', []):
|
||||
+ packages = dep_value.get('packages', [])
|
||||
@@ -353,10 +349,10 @@ step-setup-rbe-for-build: &step-setup-rbe-for-build
|
||||
mkdir third_party
|
||||
# Pull down credential helper and print status
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath")
|
||||
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
|
||||
$HELPER login
|
||||
echo 'export RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $BASH_ENV
|
||||
echo 'export RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath)"` >> $BASH_ENV
|
||||
echo 'export RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $BASH_ENV
|
||||
echo 'export RBE_experimental_credentials_helper_args="print"' >> $BASH_ENV
|
||||
|
||||
step-restore-brew-cache: &step-restore-brew-cache
|
||||
@@ -2296,8 +2292,10 @@ jobs:
|
||||
- electron-tests:
|
||||
artifact-key: darwin-x64
|
||||
|
||||
darwin-testing-arm64-tests:
|
||||
executor: apple-silicon
|
||||
darwin-testing-arm64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.m1.medium.gen1
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
@@ -2321,7 +2319,9 @@ jobs:
|
||||
artifact-key: mas-x64
|
||||
|
||||
mas-testing-arm64-tests:
|
||||
executor: apple-silicon
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.m1.medium.gen1
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
|
||||
18
.github/workflows/branch-created.yml
vendored
18
.github/workflows/branch-created.yml
vendored
@@ -1,12 +1,6 @@
|
||||
name: Branch Created
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch-name:
|
||||
description: Branch name (e.g. `29-x-y`)
|
||||
required: true
|
||||
type: string
|
||||
create:
|
||||
|
||||
permissions: {}
|
||||
@@ -14,7 +8,7 @@ permissions: {}
|
||||
jobs:
|
||||
release-branch-created:
|
||||
name: Release Branch Created
|
||||
if: ${{ github.event_name == 'workflow_dispatch' || (github.event.ref_type == 'branch' && endsWith(github.event.ref, '-x-y') && !startsWith(github.event.ref, 'roller')) }}
|
||||
if: ${{ github.event.ref_type == 'branch' && endsWith(github.event.ref, '-x-y') && !startsWith(github.event.ref, 'roller') }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
@@ -24,10 +18,10 @@ jobs:
|
||||
- name: Determine Major Version
|
||||
id: check-major-version
|
||||
run: |
|
||||
if [[ ${{ github.event.inputs.branch-name || github.event.ref }} =~ ^([0-9]+)-x-y$ ]]; then
|
||||
if [[ ${{ github.event.ref }} =~ ^([0-9]+)-x-y$ ]]; then
|
||||
echo "MAJOR=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "Not a release branch: ${{ github.event.inputs.branch-name || github.event.ref }}"
|
||||
echo "Not a release branch: ${{ github.event.ref }}"
|
||||
fi
|
||||
- name: New Release Branch Tasks
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
@@ -99,9 +93,7 @@ jobs:
|
||||
project-number: 64
|
||||
# TODO - Set to public once GitHub fixes their GraphQL bug
|
||||
# public: true
|
||||
# TODO - Enable once GitHub doesn't require overly broad, read
|
||||
# and write permission for repo "Contents" to link
|
||||
# link-to-repository: electron/electron
|
||||
link-to-repository: electron/electron
|
||||
template-view: ${{ steps.generate-project-metadata.outputs.template-view }}
|
||||
title: ${{ steps.generate-project-metadata.outputs.major }}-x-y
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
@@ -116,10 +108,8 @@ jobs:
|
||||
id: find-prev-release-board
|
||||
with:
|
||||
title: ${{ steps.generate-project-metadata.outputs.prev-prev-major }}-x-y
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
- name: Close Previous Release Project Board
|
||||
if: ${{ steps.check-major-version.outputs.MAJOR }}
|
||||
uses: dsanders11/project-actions/close-project@3a81985616963f32fae17d1d1b406c631f3201a1 # v1.1.0
|
||||
with:
|
||||
project-number: ${{ steps.find-prev-release-board.outputs.number }}
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
{
|
||||
"extends": "@electron/lint-roller/configs/markdownlint.json"
|
||||
"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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
53
BUILD.gn
53
BUILD.gn
@@ -81,18 +81,11 @@ if (is_linux) {
|
||||
]
|
||||
}
|
||||
|
||||
# Generates electron_gtk_stubs.h header which contains
|
||||
# stubs for extracting function ptrs from the gtk library.
|
||||
# Function signatures for which stubs are required should be
|
||||
# declared in electron_gtk.sigs, currently this file contains
|
||||
# signatures for the functions used with native file chooser
|
||||
# implementation. In future, this file can be extended to contain
|
||||
# gtk4 stubs to switch gtk version in runtime.
|
||||
# Generates headers which contain stubs for extracting function ptrs
|
||||
# from the gtk library. Function signatures for which stubs are
|
||||
# required should be declared in the sig files.
|
||||
generate_stubs("electron_gtk_stubs") {
|
||||
sigs = [
|
||||
"shell/browser/ui/electron_gdk_pixbuf.sigs",
|
||||
"shell/browser/ui/electron_gtk.sigs",
|
||||
]
|
||||
sigs = [ "shell/browser/ui/electron_gdk_pixbuf.sigs" ]
|
||||
extra_header = "shell/browser/ui/electron_gtk.fragment"
|
||||
output_name = "electron_gtk_stubs"
|
||||
public_deps = [ "//ui/gtk:gtk_config" ]
|
||||
@@ -166,15 +159,6 @@ npm_action("build_electron_definitions") {
|
||||
outputs = [ "$target_gen_dir/tsc/typings/electron.d.ts" ]
|
||||
}
|
||||
|
||||
webpack_build("electron_asar_bundle") {
|
||||
deps = [ ":build_electron_definitions" ]
|
||||
|
||||
inputs = auto_filenames.asar_bundle_deps
|
||||
|
||||
config_file = "//electron/build/webpack/webpack.config.asar.js"
|
||||
out_file = "$target_gen_dir/js2c/asar_bundle.js"
|
||||
}
|
||||
|
||||
webpack_build("electron_browser_bundle") {
|
||||
deps = [ ":build_electron_definitions" ]
|
||||
|
||||
@@ -220,6 +204,15 @@ webpack_build("electron_isolated_renderer_bundle") {
|
||||
out_file = "$target_gen_dir/js2c/isolated_bundle.js"
|
||||
}
|
||||
|
||||
webpack_build("electron_node_bundle") {
|
||||
deps = [ ":build_electron_definitions" ]
|
||||
|
||||
inputs = auto_filenames.node_bundle_deps
|
||||
|
||||
config_file = "//electron/build/webpack/webpack.config.node.js"
|
||||
out_file = "$target_gen_dir/js2c/node_init.js"
|
||||
}
|
||||
|
||||
webpack_build("electron_utility_bundle") {
|
||||
deps = [ ":build_electron_definitions" ]
|
||||
|
||||
@@ -231,9 +224,9 @@ webpack_build("electron_utility_bundle") {
|
||||
|
||||
action("electron_js2c") {
|
||||
deps = [
|
||||
":electron_asar_bundle",
|
||||
":electron_browser_bundle",
|
||||
":electron_isolated_renderer_bundle",
|
||||
":electron_node_bundle",
|
||||
":electron_renderer_bundle",
|
||||
":electron_sandboxed_renderer_bundle",
|
||||
":electron_utility_bundle",
|
||||
@@ -242,9 +235,9 @@ action("electron_js2c") {
|
||||
]
|
||||
|
||||
sources = [
|
||||
"$target_gen_dir/js2c/asar_bundle.js",
|
||||
"$target_gen_dir/js2c/browser_init.js",
|
||||
"$target_gen_dir/js2c/isolated_bundle.js",
|
||||
"$target_gen_dir/js2c/node_init.js",
|
||||
"$target_gen_dir/js2c/renderer_init.js",
|
||||
"$target_gen_dir/js2c/sandbox_bundle.js",
|
||||
"$target_gen_dir/js2c/utility_init.js",
|
||||
@@ -473,6 +466,7 @@ 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",
|
||||
@@ -693,10 +687,19 @@ source_set("electron_lib") {
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_views_api) {
|
||||
sources += [
|
||||
"shell/browser/api/views/electron_api_image_view.cc",
|
||||
"shell/browser/api/views/electron_api_image_view.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (enable_printing) {
|
||||
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",
|
||||
]
|
||||
@@ -1461,8 +1464,10 @@ dist_zip("hunspell_dictionaries_zip") {
|
||||
}
|
||||
|
||||
copy("libcxx_headers") {
|
||||
sources = libcxx_headers + libcxx_licenses +
|
||||
[ "//buildtools/third_party/libc++/__config_site" ]
|
||||
sources = libcxx_headers + libcxx_licenses + [
|
||||
"//buildtools/third_party/libc++/__assertion_handler",
|
||||
"//buildtools/third_party/libc++/__config_site",
|
||||
]
|
||||
outputs = [ "$target_gen_dir/electron_libcxx_include/{{source_root_relative_dir}}/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
|
||||
4
DEPS
4
DEPS
@@ -2,9 +2,9 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'122.0.6236.2',
|
||||
'122.0.6261.156',
|
||||
'node_version':
|
||||
'v20.10.0',
|
||||
'v20.9.0',
|
||||
'nan_version':
|
||||
'e14bdcd1f72d62bca1d541b66da43130384ec213',
|
||||
'squirrel.mac_version':
|
||||
|
||||
@@ -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://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf).
|
||||
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://trademark-policy.openjsf.org/).
|
||||
|
||||
@@ -106,7 +106,7 @@ for:
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath({})"
|
||||
- ps: >-
|
||||
& $env:RECLIENT_HELPER login
|
||||
- ps: >-
|
||||
@@ -177,7 +177,12 @@ for:
|
||||
# built on CI.
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
- ps: |
|
||||
$manifest_file = "electron/script/zip_manifests/dist_zip.win.$env:TARGET_ARCH.manifest"
|
||||
python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip $manifest_file
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Zip contains files not listed in the manifest $manifest_file"
|
||||
}
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
|
||||
@@ -104,7 +104,7 @@ for:
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath({})"
|
||||
- ps: >-
|
||||
& $env:RECLIENT_HELPER login
|
||||
- ps: >-
|
||||
@@ -174,7 +174,12 @@ for:
|
||||
# built on CI.
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
- ps: |
|
||||
$manifest_file = "electron/script/zip_manifests/dist_zip.win.$env:TARGET_ARCH.manifest"
|
||||
python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip $manifest_file
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Zip contains files not listed in the manifest $manifest_file"
|
||||
}
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
|
||||
@@ -24,6 +24,10 @@ enable_printing = true
|
||||
angle_enable_vulkan_validation_layers = false
|
||||
dawn_enable_vulkan_validation_layers = false
|
||||
|
||||
# Removes dxc dll's that are only used experimentally.
|
||||
# See https://bugs.chromium.org/p/chromium/issues/detail?id=1474897
|
||||
dawn_use_built_dxc = false
|
||||
|
||||
# These are disabled because they cause the zip manifest to differ between
|
||||
# testing and release builds.
|
||||
# See https://chromium-review.googlesource.com/c/chromium/src/+/2774898.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'asar',
|
||||
alwaysHasNode: true,
|
||||
targetDeletesNodeGlobals: true
|
||||
});
|
||||
@@ -53,6 +53,12 @@ module.exports = ({
|
||||
|
||||
const ignoredModules = [];
|
||||
|
||||
if (defines.ENABLE_VIEWS_API === 'false') {
|
||||
ignoredModules.push(
|
||||
'@electron/internal/browser/api/views/image-view.js'
|
||||
);
|
||||
}
|
||||
|
||||
const plugins = [];
|
||||
|
||||
if (onlyPrintingGraph) {
|
||||
|
||||
4
build/webpack/webpack.config.node.js
Normal file
4
build/webpack/webpack.config.node.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'node',
|
||||
alwaysHasNode: true
|
||||
});
|
||||
@@ -9,9 +9,21 @@ buildflag_header("buildflags") {
|
||||
header = "buildflags.h"
|
||||
|
||||
flags = [
|
||||
"ENABLE_VIEWS_API=$enable_views_api",
|
||||
"ENABLE_PDF_VIEWER=$enable_pdf_viewer",
|
||||
"ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions",
|
||||
"ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker",
|
||||
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
|
||||
]
|
||||
|
||||
if (electron_vendor_version != "") {
|
||||
result = string_split(electron_vendor_version, ":")
|
||||
flags += [
|
||||
"HAS_VENDOR_VERSION=true",
|
||||
"VENDOR_VERSION_NAME=\"${result[0]}\"",
|
||||
"VENDOR_VERSION_VALUE=\"${result[1]}\"",
|
||||
]
|
||||
} else {
|
||||
flags += [ "HAS_VENDOR_VERSION=false" ]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
declare_args() {
|
||||
enable_views_api = true
|
||||
|
||||
enable_pdf_viewer = true
|
||||
|
||||
# Provide a fake location provider for mocking
|
||||
@@ -21,4 +23,10 @@ declare_args() {
|
||||
# Packagers and vendor builders should set this in gn args to avoid running
|
||||
# the script that reads git tag.
|
||||
override_electron_version = ""
|
||||
|
||||
# Define an extra item that will show in process.versions, the value must
|
||||
# be in the format of "key:value".
|
||||
# Packagers and vendor builders can set this in gn args to attach extra info
|
||||
# about the build in the binary.
|
||||
electron_vendor_version = ""
|
||||
}
|
||||
|
||||
@@ -242,6 +242,8 @@ static_library("chrome") {
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm",
|
||||
"//chrome/browser/media/webrtc/thumbnail_capturer_mac.h",
|
||||
"//chrome/browser/media/webrtc/thumbnail_capturer_mac.mm",
|
||||
"//chrome/browser/media/webrtc/window_icon_util_mac.mm",
|
||||
"//chrome/browser/platform_util_mac.mm",
|
||||
"//chrome/browser/process_singleton_mac.mm",
|
||||
|
||||
@@ -106,7 +106,7 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
|
||||
* [app](api/app.md)
|
||||
* [autoUpdater](api/auto-updater.md)
|
||||
* [BaseWindow](api/base-window.md)
|
||||
* [BrowserView](api/browser-view.md)
|
||||
* [BrowserWindow](api/browser-window.md)
|
||||
* [contentTracing](api/content-tracing.md)
|
||||
* [desktopCapturer](api/desktop-capturer.md)
|
||||
@@ -134,10 +134,8 @@ These individual tutorials expand on topics discussed in the guide above.
|
||||
* [TouchBar](api/touch-bar.md)
|
||||
* [Tray](api/tray.md)
|
||||
* [utilityProcess](api/utility-process.md)
|
||||
* [View](api/view.md)
|
||||
* [webContents](api/web-contents.md)
|
||||
* [webFrameMain](api/web-frame-main.md)
|
||||
* [WebContentsView](api/web-contents-view.md)
|
||||
|
||||
### Modules for the Renderer Process (Web Page):
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
Accelerators are strings that can contain multiple modifiers and a single key code,
|
||||
combined by the `+` character, and are used to define keyboard shortcuts
|
||||
throughout your application. Accelerators are case insensitive.
|
||||
throughout your application.
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -1261,7 +1261,7 @@ Returns `Object`:
|
||||
|
||||
* `openAtLogin` boolean - `true` if the app is set to open at login.
|
||||
* `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up.
|
||||
* `wasOpenedAtLogin` boolean _macOS_ _Deprecated_ - `true` if the app was opened at login automatically. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically.
|
||||
* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`.
|
||||
@@ -1468,6 +1468,24 @@ details.
|
||||
|
||||
**Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it when it is no longer needed.
|
||||
|
||||
### `app.setProxy(config)`
|
||||
|
||||
* `config` [ProxyConfig](structures/proxy-config.md)
|
||||
|
||||
Returns `Promise<void>` - Resolves when the proxy setting process is complete.
|
||||
|
||||
Sets the proxy settings for networks requests made without an associated [Session](session.md).
|
||||
Currently this will affect requests made with [Net](net.md) in the [utility process](../glossary.md#utility-process)
|
||||
and internal requests made by the runtime (ex: geolocation queries).
|
||||
|
||||
This method can only be called after app is ready.
|
||||
|
||||
#### `app.resolveProxy(url)`
|
||||
|
||||
* `url` URL
|
||||
|
||||
Returns `Promise<string>` - Resolves with the proxy information for `url` that will be used when attempting to make requests using [Net](net.md) in the [utility process](../glossary.md#utility-process).
|
||||
|
||||
## Properties
|
||||
|
||||
### `app.accessibilitySupportEnabled` _macOS_ _Windows_
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,5 @@
|
||||
# BrowserView
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
A `BrowserView` can be used to embed additional web content into a
|
||||
[`BrowserWindow`](browser-window.md). It is like a child window, except that it is positioned
|
||||
relative to its owning window. It is meant to be an alternative to the
|
||||
@@ -13,10 +9,6 @@ relative to its owning window. It is meant to be an alternative to the
|
||||
|
||||
> Create and control views.
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
This module cannot be used until the `ready` event of the `app`
|
||||
@@ -38,7 +30,7 @@ app.whenReady().then(() => {
|
||||
})
|
||||
```
|
||||
|
||||
### `new BrowserView([options])` _Experimental_ _Deprecated_
|
||||
### `new BrowserView([options])` _Experimental_
|
||||
|
||||
* `options` Object (optional)
|
||||
* `webPreferences` [WebPreferences](structures/web-preferences.md?inline) (optional) - Settings of web page's features.
|
||||
@@ -47,7 +39,7 @@ app.whenReady().then(() => {
|
||||
|
||||
Objects created with `new BrowserView` have the following properties:
|
||||
|
||||
#### `view.webContents` _Experimental_ _Deprecated_
|
||||
#### `view.webContents` _Experimental_
|
||||
|
||||
A [`WebContents`](web-contents.md) object owned by this view.
|
||||
|
||||
@@ -55,7 +47,7 @@ A [`WebContents`](web-contents.md) object owned by this view.
|
||||
|
||||
Objects created with `new BrowserView` have the following instance methods:
|
||||
|
||||
#### `view.setAutoResize(options)` _Experimental_ _Deprecated_
|
||||
#### `view.setAutoResize(options)` _Experimental_
|
||||
|
||||
* `options` Object
|
||||
* `width` boolean (optional) - If `true`, the view's width will grow and shrink together
|
||||
@@ -67,19 +59,19 @@ Objects created with `new BrowserView` have the following instance methods:
|
||||
* `vertical` boolean (optional) - If `true`, the view's y position and height will grow
|
||||
and shrink proportionally with the window. `false` by default.
|
||||
|
||||
#### `view.setBounds(bounds)` _Experimental_ _Deprecated_
|
||||
#### `view.setBounds(bounds)` _Experimental_
|
||||
|
||||
* `bounds` [Rectangle](structures/rectangle.md)
|
||||
|
||||
Resizes and moves the view to the supplied bounds relative to the window.
|
||||
|
||||
#### `view.getBounds()` _Experimental_ _Deprecated_
|
||||
#### `view.getBounds()` _Experimental_
|
||||
|
||||
Returns [`Rectangle`](structures/rectangle.md)
|
||||
|
||||
The `bounds` of this BrowserView instance as `Object`.
|
||||
|
||||
#### `view.setBackgroundColor(color)` _Experimental_ _Deprecated_
|
||||
#### `view.setBackgroundColor(color)` _Experimental_
|
||||
|
||||
* `color` string - Color in Hex, RGB, ARGB, HSL, HSLA or named CSS color format. The alpha channel is
|
||||
optional for the hex type.
|
||||
@@ -87,25 +79,25 @@ The `bounds` of this BrowserView instance as `Object`.
|
||||
Examples of valid `color` values:
|
||||
|
||||
* Hex
|
||||
* `#fff` (RGB)
|
||||
* `#ffff` (ARGB)
|
||||
* `#ffffff` (RRGGBB)
|
||||
* `#ffffffff` (AARRGGBB)
|
||||
* #fff (RGB)
|
||||
* #ffff (ARGB)
|
||||
* #ffffff (RRGGBB)
|
||||
* #ffffffff (AARRGGBB)
|
||||
* RGB
|
||||
* `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)`
|
||||
* e.g. `rgb(255, 255, 255)`
|
||||
* rgb\((\[\d]+),\s*(\[\d]+),\s*(\[\d]+)\)
|
||||
* e.g. rgb(255, 255, 255)
|
||||
* RGBA
|
||||
* `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)`
|
||||
* e.g. `rgba(255, 255, 255, 1.0)`
|
||||
* rgba\((\[\d]+),\s*(\[\d]+),\s*(\[\d]+),\s*(\[\d.]+)\)
|
||||
* e.g. rgba(255, 255, 255, 1.0)
|
||||
* HSL
|
||||
* `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)`
|
||||
* e.g. `hsl(200, 20%, 50%)`
|
||||
* hsl\((-?\[\d.]+),\s*(\[\d.]+)%,\s*(\[\d.]+)%\)
|
||||
* e.g. hsl(200, 20%, 50%)
|
||||
* HSLA
|
||||
* `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)`
|
||||
* e.g. `hsla(200, 20%, 50%, 0.5)`
|
||||
* hsla\((-?\[\d.]+),\s*(\[\d.]+)%,\s*(\[\d.]+)%,\s*(\[\d.]+)\)
|
||||
* e.g. hsla(200, 20%, 50%, 0.5)
|
||||
* Color name
|
||||
* Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148)
|
||||
* Similar to CSS Color Module Level 3 keywords, but case-sensitive.
|
||||
* e.g. `blueviolet` or `red`
|
||||
|
||||
**Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBAA` or `RGB`.
|
||||
**Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBA` or `RGA`.
|
||||
|
||||
@@ -98,8 +98,8 @@ The `child` window will always show on top of the `top` window.
|
||||
|
||||
## Modal windows
|
||||
|
||||
A modal window is a child window that disables parent window. To create a modal
|
||||
window, you have to set both the `parent` and `modal` options:
|
||||
A modal window is a child window that disables parent window, to create a modal
|
||||
window, you have to set both `parent` and `modal` options:
|
||||
|
||||
```js
|
||||
const { BrowserWindow } = require('electron')
|
||||
@@ -140,7 +140,7 @@ state is `hidden` in order to minimize power consumption.
|
||||
* On Linux the type of modal windows will be changed to `dialog`.
|
||||
* On Linux many desktop environments do not support hiding a modal window.
|
||||
|
||||
## Class: BrowserWindow extends `BaseWindow`
|
||||
## Class: BrowserWindow
|
||||
|
||||
> Create and control browser windows.
|
||||
|
||||
@@ -440,14 +440,10 @@ Returns `BrowserWindow | null` - The window that is focused in this application,
|
||||
Returns `BrowserWindow | null` - The window that owns the given `webContents`
|
||||
or `null` if the contents are not owned by a window.
|
||||
|
||||
#### `BrowserWindow.fromBrowserView(browserView)` _Deprecated_
|
||||
#### `BrowserWindow.fromBrowserView(browserView)`
|
||||
|
||||
* `browserView` [BrowserView](browser-view.md)
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
Returns `BrowserWindow | null` - The window that owns the given `browserView`. If the given view is not attached to any window, returns `null`.
|
||||
|
||||
#### `BrowserWindow.fromId(id)`
|
||||
@@ -779,7 +775,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 +1211,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()`.
|
||||
|
||||
@@ -1584,62 +1580,41 @@ machine has a touch bar.
|
||||
**Note:** The TouchBar API is currently experimental and may change or be
|
||||
removed in future Electron releases.
|
||||
|
||||
#### `win.setBrowserView(browserView)` _Experimental_ _Deprecated_
|
||||
#### `win.setBrowserView(browserView)` _Experimental_
|
||||
|
||||
* `browserView` [BrowserView](browser-view.md) | null - Attach `browserView` to `win`.
|
||||
If there are other `BrowserView`s attached, they will be removed from
|
||||
this window.
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
#### `win.getBrowserView()` _Experimental_ _Deprecated_
|
||||
#### `win.getBrowserView()` _Experimental_
|
||||
|
||||
Returns `BrowserView | null` - The `BrowserView` attached to `win`. Returns `null`
|
||||
if one is not attached. Throws an error if multiple `BrowserView`s are attached.
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
#### `win.addBrowserView(browserView)` _Experimental_ _Deprecated_
|
||||
#### `win.addBrowserView(browserView)` _Experimental_
|
||||
|
||||
* `browserView` [BrowserView](browser-view.md)
|
||||
|
||||
Replacement API for setBrowserView supporting work with multi browser views.
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
#### `win.removeBrowserView(browserView)` _Experimental_ _Deprecated_
|
||||
#### `win.removeBrowserView(browserView)` _Experimental_
|
||||
|
||||
* `browserView` [BrowserView](browser-view.md)
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
#### `win.setTopBrowserView(browserView)` _Experimental_ _Deprecated_
|
||||
#### `win.setTopBrowserView(browserView)` _Experimental_
|
||||
|
||||
* `browserView` [BrowserView](browser-view.md)
|
||||
|
||||
Raises `browserView` above other `BrowserView`s attached to `win`.
|
||||
Throws an error if `browserView` is not attached to `win`.
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
|
||||
#### `win.getBrowserViews()` _Experimental_ _Deprecated_
|
||||
#### `win.getBrowserViews()` _Experimental_
|
||||
|
||||
Returns `BrowserView[]` - a sorted by z-index array of all BrowserViews that have been attached
|
||||
with `addBrowserView` or `setBrowserView`. The top-most BrowserView is the last element of the array.
|
||||
|
||||
> **Note**
|
||||
> The `BrowserView` class is deprecated, and replaced by the new
|
||||
> [`WebContentsView`](web-contents-view.md) class.
|
||||
**Note:** The BrowserView API is currently experimental and may change or be
|
||||
removed in future Electron releases.
|
||||
|
||||
#### `win.setTitleBarOverlay(options)` _Windows_
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ 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)
|
||||
@@ -158,7 +160,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
|
||||
|
||||
@@ -174,7 +174,7 @@ dialog.showOpenDialog(mainWindow, {
|
||||
* `dontAddToRecent` _Windows_ - Do not add the item being saved to the recent documents list.
|
||||
* `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path.
|
||||
|
||||
Returns `string | undefined`, the path of the file chosen by the user; if the dialog is cancelled it returns `undefined`.
|
||||
Returns `string`, the path of the file chosen by the user; if the dialog is cancelled it returns an empty string.
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
@@ -207,7 +207,7 @@ The `filters` specifies an array of file types that can be displayed, see
|
||||
Returns `Promise<Object>` - Resolve with an object containing the following:
|
||||
|
||||
* `canceled` boolean - whether or not the dialog was canceled.
|
||||
* `filePath` string (optional) - If the dialog is canceled, this will be `undefined`.
|
||||
* `filePath` string - If the dialog is canceled, this will be an empty string.
|
||||
* `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present. (For return values, see [table here](#bookmarks-array).)
|
||||
|
||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||
|
||||
@@ -142,6 +142,11 @@ Setting this variable is the same as passing `--log-file`
|
||||
on the command line. For more info, see `--log-file` in [command-line
|
||||
switches](./command-line-switches.md#--log-filepath).
|
||||
|
||||
### `ELECTRON_DEBUG_DRAG_REGIONS`
|
||||
|
||||
Adds coloration to draggable regions on [`BrowserView`](./browser-view.md)s on macOS - draggable regions will be colored
|
||||
green and non-draggable regions will be colored red to aid debugging.
|
||||
|
||||
### `ELECTRON_DEBUG_NOTIFICATIONS`
|
||||
|
||||
Adds extra logs to [`Notification`](./notification.md) lifecycles on macOS to aid in debugging. Extra logging will be displayed when new Notifications are created or activated. They will also be displayed when common actions are taken: a notification is shown, dismissed, its button is clicked, or it is replied to.
|
||||
|
||||
@@ -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[]
|
||||
|
||||
|
||||
@@ -4,36 +4,41 @@
|
||||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
In Electron, for the APIs that take images, you can pass either file paths or
|
||||
`NativeImage` instances. An empty image will be used when `null` is passed.
|
||||
The `nativeImage` module provides a unified interface for manipulating
|
||||
system images. These can be handy if you want to provide multiple scaled
|
||||
versions of the same icon or take advantage of macOS [template images][template-image].
|
||||
|
||||
For example, when creating a tray or setting a window's icon, you can pass an
|
||||
image file path as a `string`:
|
||||
Electron APIs that take image files accept either file paths or
|
||||
`NativeImage` instances. An empty and transparent image will be used when `null` is passed.
|
||||
|
||||
```js
|
||||
For example, when creating a [Tray](../api/tray.md) or setting a [BrowserWindow](../api/browser-window.md)'s
|
||||
icon, you can either pass an image file path as a string:
|
||||
|
||||
```js title='Main Process'
|
||||
const { BrowserWindow, Tray } = require('electron')
|
||||
|
||||
const appIcon = new Tray('/Users/somebody/images/icon.png')
|
||||
const tray = new Tray('/Users/somebody/images/icon.png')
|
||||
const win = new BrowserWindow({ icon: '/Users/somebody/images/window.png' })
|
||||
console.log(appIcon, win)
|
||||
```
|
||||
|
||||
Or read the image from the clipboard, which returns a `NativeImage`:
|
||||
or generate a `NativeImage` instance from the same file:
|
||||
|
||||
```js
|
||||
const { clipboard, Tray } = require('electron')
|
||||
const image = clipboard.readImage()
|
||||
const appIcon = new Tray(image)
|
||||
console.log(appIcon)
|
||||
```js title='Main Process'
|
||||
const { BrowserWindow, nativeImage, Tray } = require('electron')
|
||||
|
||||
const trayIcon = nativeImage.createFromPath('/Users/somebody/images/icon.png')
|
||||
const appIcon = nativeImage.createFromPath('/Users/somebody/images/window.png')
|
||||
const tray = new Tray(trayIcon)
|
||||
const win = new BrowserWindow({ icon: appIcon })
|
||||
```
|
||||
|
||||
## Supported Formats
|
||||
|
||||
Currently `PNG` and `JPEG` image formats are supported. `PNG` is recommended
|
||||
because of its support for transparency and lossless compression.
|
||||
Currently, `PNG` and `JPEG` image formats are supported across all platforms.
|
||||
`PNG` is recommended because of its support for transparency and lossless compression.
|
||||
|
||||
On Windows, you can also load `ICO` icons from file paths. For best visual
|
||||
quality, it is recommended to include at least the following sizes in the:
|
||||
quality, we recommend including at least the following sizes:
|
||||
|
||||
* Small icon
|
||||
* 16x16 (100% DPI scale)
|
||||
@@ -47,22 +52,30 @@ quality, it is recommended to include at least the following sizes in the:
|
||||
* 64x64 (200% DPI scale)
|
||||
* 256x256
|
||||
|
||||
Check the _Size requirements_ section in [this article][icons].
|
||||
Check the _Icon Scaling_ section in the Windows [App Icon Construction][icons] reference.
|
||||
|
||||
[icons]: https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-icons
|
||||
[icons]: https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/app-icon-construction#icon-scaling
|
||||
|
||||
:::note
|
||||
|
||||
EXIF metadata is currently not supported and will not be taken into account during
|
||||
image encoding and decoding.
|
||||
|
||||
:::
|
||||
|
||||
## High Resolution Image
|
||||
|
||||
On platforms that have high-DPI support such as Apple Retina displays, you can
|
||||
append `@2x` after image's base filename to mark it as a high resolution image.
|
||||
On platforms that support high pixel density displays (such as Apple Retina),
|
||||
you can append `@2x` after image's base filename to mark it as a 2x scale
|
||||
high resolution image.
|
||||
|
||||
For example, if `icon.png` is a normal image that has standard resolution, then
|
||||
`icon@2x.png` will be treated as a high resolution image that has double DPI
|
||||
density.
|
||||
`icon@2x.png` will be treated as a high resolution image that has double
|
||||
Dots per Inch (DPI) density.
|
||||
|
||||
If you want to support displays with different DPI densities at the same time,
|
||||
you can put images with different sizes in the same folder and use the filename
|
||||
without DPI suffixes. For example:
|
||||
without DPI suffixes within Electron. For example:
|
||||
|
||||
```plaintext
|
||||
images/
|
||||
@@ -71,10 +84,9 @@ images/
|
||||
└── icon@3x.png
|
||||
```
|
||||
|
||||
```js
|
||||
```js title='Main Process'
|
||||
const { Tray } = require('electron')
|
||||
const appIcon = new Tray('/Users/somebody/images/icon.png')
|
||||
console.log(appIcon)
|
||||
const appTray = new Tray('/Users/somebody/images/icon.png')
|
||||
```
|
||||
|
||||
The following suffixes for DPI are also supported:
|
||||
@@ -91,27 +103,23 @@ The following suffixes for DPI are also supported:
|
||||
* `@4x`
|
||||
* `@5x`
|
||||
|
||||
## Template Image
|
||||
## Template Image _macOS_
|
||||
|
||||
Template images consist of black and an alpha channel.
|
||||
On macOS, [template images][template-image] consist of black and an alpha channel.
|
||||
Template images are not intended to be used as standalone images and are usually
|
||||
mixed with other content to create the desired final appearance.
|
||||
|
||||
The most common case is to use template images for a menu bar icon, so it can
|
||||
The most common case is to use template images for a menu bar (Tray) icon, so it can
|
||||
adapt to both light and dark menu bars.
|
||||
|
||||
**Note:** Template image is only supported on macOS.
|
||||
|
||||
To mark an image as a template image, its filename should end with the word
|
||||
`Template`. For example:
|
||||
|
||||
* `xxxTemplate.png`
|
||||
* `xxxTemplate@2x.png`
|
||||
To mark an image as a template image, its base filename should end with the word
|
||||
`Template` (e.g. `xxxTemplate.png`). You can also specify template images at
|
||||
different DPI densities (e.g. `xxxTemplate@2x.png`).
|
||||
|
||||
## Methods
|
||||
|
||||
The `nativeImage` module has the following methods, all of which return
|
||||
an instance of the `NativeImage` class:
|
||||
an instance of the [`NativeImage`](#class-nativeimage) class:
|
||||
|
||||
### `nativeImage.createEmpty()`
|
||||
|
||||
@@ -130,7 +138,7 @@ Note: The Windows implementation will ignore `size.height` and scale the height
|
||||
|
||||
### `nativeImage.createFromPath(path)`
|
||||
|
||||
* `path` string
|
||||
* `path` string - path to a file that we intend to construct an image out of.
|
||||
|
||||
Returns `NativeImage`
|
||||
|
||||
@@ -139,7 +147,7 @@ returns an empty image if the `path` does not exist, cannot be read, or is not
|
||||
a valid image.
|
||||
|
||||
```js
|
||||
const nativeImage = require('electron').nativeImage
|
||||
const { nativeImage } = require('electron')
|
||||
|
||||
const image = nativeImage.createFromPath('/Users/somebody/images/icon.png')
|
||||
console.log(image)
|
||||
@@ -176,7 +184,7 @@ Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or JP
|
||||
|
||||
Returns `NativeImage`
|
||||
|
||||
Creates a new `NativeImage` instance from `dataURL`.
|
||||
Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL][data-url] string.
|
||||
|
||||
### `nativeImage.createFromNamedImage(imageName[, hslShift])` _macOS_
|
||||
|
||||
@@ -185,14 +193,14 @@ Creates a new `NativeImage` instance from `dataURL`.
|
||||
|
||||
Returns `NativeImage`
|
||||
|
||||
Creates a new `NativeImage` instance from the NSImage that maps to the
|
||||
given image name. See [`System Icons`](https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/system-icons/)
|
||||
for a list of possible values.
|
||||
Creates a new `NativeImage` instance from the `NSImage` that maps to the
|
||||
given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388)
|
||||
documentation for a list of possible values.
|
||||
|
||||
The `hslShift` is applied to the image with the following rules:
|
||||
|
||||
* `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map
|
||||
to 0 and 360 on the hue color wheel (red).
|
||||
to 0 and 360 on the hue color wheel (red).
|
||||
* `hsl_shift[1]` (saturation): A saturation shift for the image, with the
|
||||
following key values:
|
||||
0 = remove all color.
|
||||
@@ -209,7 +217,9 @@ This means that `[-1, 0, 1]` will make the image completely white and
|
||||
|
||||
In some cases, the `NSImageName` doesn't match its string representation; one example of this is `NSFolderImageName`, whose string representation would actually be `NSFolder`. Therefore, you'll need to determine the correct string representation for your image before passing it in. This can be done with the following:
|
||||
|
||||
`echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test`
|
||||
```sh
|
||||
echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test
|
||||
```
|
||||
|
||||
where `SYSTEM_IMAGE_NAME` should be replaced with any value from [this list](https://developer.apple.com/documentation/appkit/nsimagename?language=objc).
|
||||
|
||||
@@ -250,7 +260,7 @@ data.
|
||||
* `options` Object (optional)
|
||||
* `scaleFactor` Number (optional) - Defaults to 1.0.
|
||||
|
||||
Returns `string` - The data URL of the image.
|
||||
Returns `string` - The [Data URL][data-url] of the image.
|
||||
|
||||
#### `image.getBitmap([options])`
|
||||
|
||||
@@ -266,7 +276,7 @@ current event loop tick; otherwise the data might be changed or destroyed.
|
||||
#### `image.getNativeHandle()` _macOS_
|
||||
|
||||
Returns `Buffer` - A [Buffer][buffer] that stores C pointer to underlying native handle of
|
||||
the image. On macOS, a pointer to `NSImage` instance would be returned.
|
||||
the image. On macOS, a pointer to `NSImage` instance is returned.
|
||||
|
||||
Notice that the returned pointer is a weak pointer to the underlying native
|
||||
image instead of a copy, so you _must_ ensure that the associated
|
||||
@@ -288,11 +298,11 @@ If `scaleFactor` is passed, this will return the size corresponding to the image
|
||||
|
||||
* `option` boolean
|
||||
|
||||
Marks the image as a template image.
|
||||
Marks the image as a macOS [template image][template-image].
|
||||
|
||||
#### `image.isTemplateImage()`
|
||||
|
||||
Returns `boolean` - Whether the image is a template image.
|
||||
Returns `boolean` - Whether the image is a macOS [template image][template-image].
|
||||
|
||||
#### `image.crop(rect)`
|
||||
|
||||
@@ -321,13 +331,13 @@ will be preserved in the resized image.
|
||||
|
||||
* `scaleFactor` Number (optional) - Defaults to 1.0.
|
||||
|
||||
Returns `Number` - The image's aspect ratio.
|
||||
Returns `Number` - The image's aspect ratio (width divided by height).
|
||||
|
||||
If `scaleFactor` is passed, this will return the aspect ratio corresponding to the image representation most closely matching the passed value.
|
||||
|
||||
#### `image.getScaleFactors()`
|
||||
|
||||
Returns `Number[]` - An array of all scale factors corresponding to representations for a given nativeImage.
|
||||
Returns `Number[]` - An array of all scale factors corresponding to representations for a given `NativeImage`.
|
||||
|
||||
#### `image.addRepresentation(options)`
|
||||
|
||||
@@ -342,15 +352,17 @@ Returns `Number[]` - An array of all scale factors corresponding to representati
|
||||
encoded PNG or JPEG image.
|
||||
|
||||
Add an image representation for a specific scale factor. This can be used
|
||||
to explicitly add different scale factor representations to an image. This
|
||||
to programmatically add different scale factor representations to an image. This
|
||||
can be called on empty images.
|
||||
|
||||
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
|
||||
|
||||
### Instance Properties
|
||||
|
||||
#### `nativeImage.isMacTemplateImage` _macOS_
|
||||
|
||||
A `boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template).
|
||||
A `boolean` property that determines whether the image is considered a [template image][template-image].
|
||||
|
||||
Please note that this property only has an effect on macOS.
|
||||
|
||||
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
|
||||
[data-url]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
|
||||
[template-image]: https://developer.apple.com/documentation/appkit/nsimage/1520017-template
|
||||
|
||||
29
docs/api/navigation-history.md
Normal file
29
docs/api/navigation-history.md
Normal file
@@ -0,0 +1,29 @@
|
||||
## 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
|
||||
|
||||
@@ -589,105 +589,15 @@ Writes any unwritten DOMStorage data to disk.
|
||||
|
||||
#### `ses.setProxy(config)`
|
||||
|
||||
* `config` Object
|
||||
* `mode` string (optional) - The proxy mode. Should be one of `direct`,
|
||||
`auto_detect`, `pac_script`, `fixed_servers` or `system`. If it's
|
||||
unspecified, it will be automatically determined based on other specified
|
||||
options.
|
||||
* `direct`
|
||||
In direct mode all connections are created directly, without any proxy involved.
|
||||
* `auto_detect`
|
||||
In auto_detect mode the proxy configuration is determined by a PAC script that can
|
||||
be downloaded at http://wpad/wpad.dat.
|
||||
* `pac_script`
|
||||
In pac_script mode the proxy configuration is determined by a PAC script that is
|
||||
retrieved from the URL specified in the `pacScript`. This is the default mode
|
||||
if `pacScript` is specified.
|
||||
* `fixed_servers`
|
||||
In fixed_servers mode the proxy configuration is specified in `proxyRules`.
|
||||
This is the default mode if `proxyRules` is specified.
|
||||
* `system`
|
||||
In system mode the proxy configuration is taken from the operating system.
|
||||
Note that the system mode is different from setting no proxy configuration.
|
||||
In the latter case, Electron falls back to the system settings
|
||||
only if no command-line options influence the proxy configuration.
|
||||
* `pacScript` string (optional) - The URL associated with the PAC file.
|
||||
* `proxyRules` string (optional) - Rules indicating which proxies to use.
|
||||
* `proxyBypassRules` string (optional) - Rules indicating which URLs should
|
||||
bypass the proxy settings.
|
||||
* `config` [ProxyConfig](structures/proxy-config.md)
|
||||
|
||||
Returns `Promise<void>` - Resolves when the proxy setting process is complete.
|
||||
|
||||
Sets the proxy settings.
|
||||
|
||||
When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules`
|
||||
option is ignored and `pacScript` configuration is applied.
|
||||
|
||||
You may need `ses.closeAllConnections` to close currently in flight connections to prevent
|
||||
pooled sockets using previous proxy from being reused by future requests.
|
||||
|
||||
The `proxyRules` has to follow the rules below:
|
||||
|
||||
```sh
|
||||
proxyRules = schemeProxies[";"<schemeProxies>]
|
||||
schemeProxies = [<urlScheme>"="]<proxyURIList>
|
||||
urlScheme = "http" | "https" | "ftp" | "socks"
|
||||
proxyURIList = <proxyURL>[","<proxyURIList>]
|
||||
proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and
|
||||
HTTP proxy `foopy2:80` for `ftp://` URLs.
|
||||
* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs.
|
||||
* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing
|
||||
over to `bar` if `foopy:80` is unavailable, and after that using no proxy.
|
||||
* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs.
|
||||
* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail
|
||||
over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable.
|
||||
* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no
|
||||
proxy if `foopy` is unavailable.
|
||||
* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use
|
||||
`socks4://foopy2` for all other URLs.
|
||||
|
||||
The `proxyBypassRules` is a comma separated list of rules described below:
|
||||
|
||||
* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]`
|
||||
|
||||
Match all hostnames that match the pattern HOSTNAME_PATTERN.
|
||||
|
||||
Examples:
|
||||
"foobar.com", "\*foobar.com", "\*.foobar.com", "\*foobar.com:99",
|
||||
"https://x.\*.y.com:99"
|
||||
|
||||
* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]`
|
||||
|
||||
Match a particular domain suffix.
|
||||
|
||||
Examples:
|
||||
".google.com", ".com", "http://.google.com"
|
||||
|
||||
* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]`
|
||||
|
||||
Match URLs which are IP address literals.
|
||||
|
||||
Examples:
|
||||
"127.0.1", "\[0:0::1]", "\[::1]", "http://\[::1]:99"
|
||||
|
||||
* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS`
|
||||
|
||||
Match any URL that is to an IP literal that falls between the
|
||||
given range. IP range is specified using CIDR notation.
|
||||
|
||||
Examples:
|
||||
"192.168.1.1/16", "fefe:13::abc/33".
|
||||
|
||||
* `<local>`
|
||||
|
||||
Match local addresses. The meaning of `<local>` is whether the
|
||||
host matches one of: "127.0.0.1", "::1", "localhost".
|
||||
|
||||
#### `ses.resolveHost(host, [options])`
|
||||
|
||||
* `host` string - Hostname to resolve.
|
||||
@@ -903,6 +813,8 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `pointerLock` - Request to 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.
|
||||
* `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.
|
||||
* `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
|
||||
@@ -951,6 +863,8 @@ 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.
|
||||
@@ -1305,7 +1219,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
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
# BaseWindowConstructorOptions Object
|
||||
|
||||
* `width` Integer (optional) - Window's width in pixels. Default is `800`.
|
||||
* `height` Integer (optional) - Window's height in pixels. Default is `600`.
|
||||
* `x` Integer (optional) - (**required** if y is used) Window's left offset from screen.
|
||||
Default is to center the window.
|
||||
* `y` Integer (optional) - (**required** if x is used) Window's top offset from screen.
|
||||
Default is to center the window.
|
||||
* `useContentSize` boolean (optional) - The `width` and `height` would be used as web
|
||||
page's size, which means the actual window's size will include window
|
||||
frame's size and be slightly larger. Default is `false`.
|
||||
* `center` boolean (optional) - Show window in the center of the screen. Default is `false`.
|
||||
* `minWidth` Integer (optional) - Window's minimum width. Default is `0`.
|
||||
* `minHeight` Integer (optional) - Window's minimum height. Default is `0`.
|
||||
* `maxWidth` Integer (optional) - Window's maximum width. Default is no limit.
|
||||
* `maxHeight` Integer (optional) - Window's maximum height. Default is no limit.
|
||||
* `resizable` boolean (optional) - Whether window is resizable. Default is `true`.
|
||||
* `movable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
movable. This is not implemented on Linux. Default is `true`.
|
||||
* `minimizable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
minimizable. This is not implemented on Linux. Default is `true`.
|
||||
* `maximizable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
maximizable. This is not implemented on Linux. Default is `true`.
|
||||
* `closable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
closable. This is not implemented on Linux. Default is `true`.
|
||||
* `focusable` boolean (optional) - Whether the window can be focused. Default is
|
||||
`true`. On Windows setting `focusable: false` also implies setting
|
||||
`skipTaskbar: true`. On Linux setting `focusable: false` makes the window
|
||||
stop interacting with wm, so the window will always stay on top in all
|
||||
workspaces.
|
||||
* `alwaysOnTop` boolean (optional) - Whether the window should always stay on top of
|
||||
other windows. Default is `false`.
|
||||
* `fullscreen` boolean (optional) - Whether the window should show in fullscreen. When
|
||||
explicitly set to `false` the fullscreen button will be hidden or disabled
|
||||
on macOS. Default is `false`.
|
||||
* `fullscreenable` boolean (optional) - Whether the window can be put into fullscreen
|
||||
mode. On macOS, also whether the maximize/zoom button should toggle full
|
||||
screen mode or maximize window. Default is `true`.
|
||||
* `simpleFullscreen` boolean (optional) _macOS_ - Use pre-Lion fullscreen on
|
||||
macOS. Default is `false`.
|
||||
* `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar.
|
||||
Default is `false`.
|
||||
* `hiddenInMissionControl` boolean (optional) _macOS_ - Whether window should be hidden when the user toggles into mission control.
|
||||
* `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`.
|
||||
* `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `<title>` is defined in the HTML file loaded by `loadURL()`, this property will be ignored.
|
||||
* `icon` ([NativeImage](../native-image.md) | string) (optional) - The window icon. On Windows it is
|
||||
recommended to use `ICO` icons to get best visual effects, you can also
|
||||
leave it undefined so the executable's icon will be used.
|
||||
* `show` boolean (optional) - Whether window should be shown when created. Default is
|
||||
`true`.
|
||||
* `frame` boolean (optional) - Specify `false` to create a
|
||||
[frameless window](../../tutorial/window-customization.md#create-frameless-windows). Default is `true`.
|
||||
* `parent` BaseWindow (optional) - Specify parent window. Default is `null`.
|
||||
* `modal` boolean (optional) - Whether this is a modal window. This only works when the
|
||||
window is a child window. Default is `false`.
|
||||
* `acceptFirstMouse` boolean (optional) _macOS_ - Whether clicking an
|
||||
inactive window will also click through to the web contents. Default is
|
||||
`false` on macOS. This option is not configurable on other platforms.
|
||||
* `disableAutoHideCursor` boolean (optional) - Whether to hide cursor when typing.
|
||||
Default is `false`.
|
||||
* `autoHideMenuBar` boolean (optional) - Auto hide the menu bar unless the `Alt`
|
||||
key is pressed. Default is `false`.
|
||||
* `enableLargerThanScreen` boolean (optional) _macOS_ - Enable the window to
|
||||
be resized larger than screen. Only relevant for macOS, as other OSes
|
||||
allow larger-than-screen windows by default. Default is `false`.
|
||||
* `backgroundColor` string (optional) - The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if `transparent` is set to `true`. Default is `#FFF` (white). See [win.setBackgroundColor](../browser-window.md#winsetbackgroundcolorbackgroundcolor) for more information.
|
||||
* `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`.
|
||||
* `opacity` number (optional) _macOS_ _Windows_ - Set the initial opacity of
|
||||
the window, between 0.0 (fully transparent) and 1.0 (fully opaque). This
|
||||
is only implemented on Windows and macOS.
|
||||
* `darkTheme` boolean (optional) - Forces using dark theme for the window, only works on
|
||||
some GTK+3 desktop environments. Default is `false`.
|
||||
* `transparent` boolean (optional) - Makes the window [transparent](../../tutorial/window-customization.md#create-transparent-windows).
|
||||
Default is `false`. On Windows, does not work unless the window is frameless.
|
||||
* `type` string (optional) - The type of window, default is normal window. See more about
|
||||
this below.
|
||||
* `visualEffectState` string (optional) _macOS_ - Specify how the material
|
||||
appearance should reflect window activity state on macOS. Must be used
|
||||
with the `vibrancy` property. Possible values are:
|
||||
* `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default.
|
||||
* `active` - The backdrop should always appear active.
|
||||
* `inactive` - The backdrop should always appear inactive.
|
||||
* `titleBarStyle` string (optional) _macOS_ _Windows_ - The style of window title bar.
|
||||
Default is `default`. Possible values are:
|
||||
* `default` - Results in the standard title bar for macOS or Windows respectively.
|
||||
* `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (“traffic lights”) in the top left. On Windows, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown.
|
||||
* `hiddenInset` _macOS_ - Only on macOS, results in a hidden title bar
|
||||
with an alternative look where the traffic light buttons are slightly
|
||||
more inset from the window edge.
|
||||
* `customButtonsOnHover` _macOS_ - Only on macOS, results in a hidden
|
||||
title bar and a full size content window, the traffic light buttons will
|
||||
display when being hovered over in the top left of the window.
|
||||
**Note:** This option is currently experimental.
|
||||
* `trafficLightPosition` [Point](point.md) (optional) _macOS_ -
|
||||
Set a custom position for the traffic light buttons in frameless windows.
|
||||
* `roundedCorners` boolean (optional) _macOS_ - Whether frameless window
|
||||
should have rounded corners on macOS. Default is `true`. Setting this property
|
||||
to `false` will prevent the window from being fullscreenable.
|
||||
* `thickFrame` boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on
|
||||
Windows, which adds standard window frame. Setting it to `false` will remove
|
||||
window shadow and window animations. Default is `true`.
|
||||
* `vibrancy` string (optional) _macOS_ - Add a type of vibrancy effect to
|
||||
the window, only on macOS. Can be `appearance-based`, `titlebar`, `selection`,
|
||||
`menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`,
|
||||
`tooltip`, `content`, `under-window`, or `under-page`.
|
||||
* `backgroundMaterial` string (optional) _Windows_ - Set the window's
|
||||
system-drawn background material, including behind the non-client area.
|
||||
Can be `auto`, `none`, `mica`, `acrylic` or `tabbed`. See [win.setBackgroundMaterial](../browser-window.md#winsetbackgroundmaterialmaterial-windows) for more information.
|
||||
* `zoomToPageWidth` boolean (optional) _macOS_ - Controls the behavior on
|
||||
macOS when option-clicking the green stoplight button on the toolbar or by
|
||||
clicking the Window > Zoom menu item. If `true`, the window will grow to
|
||||
the preferred width of the web page when zoomed, `false` will cause it to
|
||||
zoom to the width of the screen. This will also affect the behavior when
|
||||
calling `maximize()` directly. Default is `false`.
|
||||
* `tabbingIdentifier` string (optional) _macOS_ - Tab group name, allows
|
||||
opening the window as a native tab. Windows with the same
|
||||
tabbing identifier will be grouped together. This also adds a native new
|
||||
tab button to your window's tab bar and allows your `app` and window to
|
||||
receive the `new-window-for-tab` event.
|
||||
|
||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||
passing a size that does not follow size constraints to `setBounds`/`setSize` or
|
||||
to the constructor of `BrowserWindow`.
|
||||
|
||||
The possible values and behaviors of the `type` option are platform dependent.
|
||||
Possible values are:
|
||||
|
||||
* On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`,
|
||||
`notification`.
|
||||
* The `desktop` type places the window at the desktop background window level
|
||||
(kCGDesktopWindowLevel - 1). However, note that a desktop window will not
|
||||
receive focus, keyboard, or mouse events. You can still use globalShortcut to
|
||||
receive input sparingly.
|
||||
* The `dock` type creates a dock-like window behavior.
|
||||
* The `toolbar` type creates a window with a toolbar appearance.
|
||||
* The `splash` type behaves in a specific way. It is not
|
||||
draggable, even if the CSS styling of the window's body contains
|
||||
-webkit-app-region: drag. This type is commonly used for splash screens.
|
||||
* The `notification` type creates a window that behaves like a system notification.
|
||||
* On macOS, possible types are `desktop`, `textured`, `panel`.
|
||||
* The `textured` type adds metal gradient appearance
|
||||
(`NSWindowStyleMaskTexturedBackground`).
|
||||
* The `desktop` type places the window at the desktop background window level
|
||||
(`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive
|
||||
focus, keyboard or mouse events, but you can use `globalShortcut` to receive
|
||||
input sparingly.
|
||||
* The `panel` type enables the window to float on top of full-screened apps
|
||||
by adding the `NSWindowStyleMaskNonactivatingPanel` style mask,normally
|
||||
reserved for NSPanel, at runtime. Also, the window will appear on all
|
||||
spaces (desktops).
|
||||
* On Windows, possible type is `toolbar`.
|
||||
@@ -1,11 +1,161 @@
|
||||
# BrowserWindowConstructorOptions Object extends `BaseWindowConstructorOptions`
|
||||
# BrowserWindowConstructorOptions Object
|
||||
|
||||
* `webPreferences` [WebPreferences](web-preferences.md?inline) (optional) - Settings of web page's features.
|
||||
* `width` Integer (optional) - Window's width in pixels. Default is `800`.
|
||||
* `height` Integer (optional) - Window's height in pixels. Default is `600`.
|
||||
* `x` Integer (optional) - (**required** if y is used) Window's left offset from screen.
|
||||
Default is to center the window.
|
||||
* `y` Integer (optional) - (**required** if x is used) Window's top offset from screen.
|
||||
Default is to center the window.
|
||||
* `useContentSize` boolean (optional) - The `width` and `height` would be used as web
|
||||
page's size, which means the actual window's size will include window
|
||||
frame's size and be slightly larger. Default is `false`.
|
||||
* `center` boolean (optional) - Show window in the center of the screen. Default is `false`.
|
||||
* `minWidth` Integer (optional) - Window's minimum width. Default is `0`.
|
||||
* `minHeight` Integer (optional) - Window's minimum height. Default is `0`.
|
||||
* `maxWidth` Integer (optional) - Window's maximum width. Default is no limit.
|
||||
* `maxHeight` Integer (optional) - Window's maximum height. Default is no limit.
|
||||
* `resizable` boolean (optional) - Whether window is resizable. Default is `true`.
|
||||
* `movable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
movable. This is not implemented on Linux. Default is `true`.
|
||||
* `minimizable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
minimizable. This is not implemented on Linux. Default is `true`.
|
||||
* `maximizable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
maximizable. This is not implemented on Linux. Default is `true`.
|
||||
* `closable` boolean (optional) _macOS_ _Windows_ - Whether window is
|
||||
closable. This is not implemented on Linux. Default is `true`.
|
||||
* `focusable` boolean (optional) - Whether the window can be focused. Default is
|
||||
`true`. On Windows setting `focusable: false` also implies setting
|
||||
`skipTaskbar: true`. On Linux setting `focusable: false` makes the window
|
||||
stop interacting with wm, so the window will always stay on top in all
|
||||
workspaces.
|
||||
* `alwaysOnTop` boolean (optional) - Whether the window should always stay on top of
|
||||
other windows. Default is `false`.
|
||||
* `fullscreen` boolean (optional) - Whether the window should show in fullscreen. When
|
||||
explicitly set to `false` the fullscreen button will be hidden or disabled
|
||||
on macOS. Default is `false`.
|
||||
* `fullscreenable` boolean (optional) - Whether the window can be put into fullscreen
|
||||
mode. On macOS, also whether the maximize/zoom button should toggle full
|
||||
screen mode or maximize window. Default is `true`.
|
||||
* `simpleFullscreen` boolean (optional) _macOS_ - Use pre-Lion fullscreen on
|
||||
macOS. Default is `false`.
|
||||
* `skipTaskbar` boolean (optional) _macOS_ _Windows_ - Whether to show the window in taskbar.
|
||||
Default is `false`.
|
||||
* `hiddenInMissionControl` boolean (optional) _macOS_ - Whether window should be hidden when the user toggles into mission control.
|
||||
* `kiosk` boolean (optional) - Whether the window is in kiosk mode. Default is `false`.
|
||||
* `title` string (optional) - Default window title. Default is `"Electron"`. If the HTML tag `<title>` is defined in the HTML file loaded by `loadURL()`, this property will be ignored.
|
||||
* `icon` ([NativeImage](../native-image.md) | string) (optional) - The window icon. On Windows it is
|
||||
recommended to use `ICO` icons to get best visual effects, you can also
|
||||
leave it undefined so the executable's icon will be used.
|
||||
* `show` boolean (optional) - Whether window should be shown when created. Default is
|
||||
`true`.
|
||||
* `paintWhenInitiallyHidden` boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`.
|
||||
* `frame` boolean (optional) - Specify `false` to create a
|
||||
[frameless window](../../tutorial/window-customization.md#create-frameless-windows). Default is `true`.
|
||||
* `parent` BrowserWindow (optional) - Specify parent window. Default is `null`.
|
||||
* `modal` boolean (optional) - Whether this is a modal window. This only works when the
|
||||
window is a child window. Default is `false`.
|
||||
* `acceptFirstMouse` boolean (optional) _macOS_ - Whether clicking an
|
||||
inactive window will also click through to the web contents. Default is
|
||||
`false` on macOS. This option is not configurable on other platforms.
|
||||
* `disableAutoHideCursor` boolean (optional) - Whether to hide cursor when typing.
|
||||
Default is `false`.
|
||||
* `autoHideMenuBar` boolean (optional) - Auto hide the menu bar unless the `Alt`
|
||||
key is pressed. Default is `false`.
|
||||
* `enableLargerThanScreen` boolean (optional) _macOS_ - Enable the window to
|
||||
be resized larger than screen. Only relevant for macOS, as other OSes
|
||||
allow larger-than-screen windows by default. Default is `false`.
|
||||
* `backgroundColor` string (optional) - The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if `transparent` is set to `true`. Default is `#FFF` (white). See [win.setBackgroundColor](../browser-window.md#winsetbackgroundcolorbackgroundcolor) for more information.
|
||||
* `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`.
|
||||
* `opacity` number (optional) _macOS_ _Windows_ - Set the initial opacity of
|
||||
the window, between 0.0 (fully transparent) and 1.0 (fully opaque). This
|
||||
is only implemented on Windows and macOS.
|
||||
* `darkTheme` boolean (optional) - Forces using dark theme for the window, only works on
|
||||
some GTK+3 desktop environments. Default is `false`.
|
||||
* `transparent` boolean (optional) - Makes the window [transparent](../../tutorial/window-customization.md#create-transparent-windows).
|
||||
Default is `false`. On Windows, does not work unless the window is frameless.
|
||||
* `type` string (optional) - The type of window, default is normal window. See more about
|
||||
this below.
|
||||
* `visualEffectState` string (optional) _macOS_ - Specify how the material
|
||||
appearance should reflect window activity state on macOS. Must be used
|
||||
with the `vibrancy` property. Possible values are:
|
||||
* `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default.
|
||||
* `active` - The backdrop should always appear active.
|
||||
* `inactive` - The backdrop should always appear inactive.
|
||||
* `titleBarStyle` string (optional) _macOS_ _Windows_ - The style of window title bar.
|
||||
Default is `default`. Possible values are:
|
||||
* `default` - Results in the standard title bar for macOS or Windows respectively.
|
||||
* `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (“traffic lights”) in the top left. On Windows, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown.
|
||||
* `hiddenInset` _macOS_ - Only on macOS, results in a hidden title bar
|
||||
with an alternative look where the traffic light buttons are slightly
|
||||
more inset from the window edge.
|
||||
* `customButtonsOnHover` _macOS_ - Only on macOS, results in a hidden
|
||||
title bar and a full size content window, the traffic light buttons will
|
||||
display when being hovered over in the top left of the window.
|
||||
**Note:** This option is currently experimental.
|
||||
* `trafficLightPosition` [Point](point.md) (optional) _macOS_ -
|
||||
Set a custom position for the traffic light buttons in frameless windows.
|
||||
* `roundedCorners` boolean (optional) _macOS_ - Whether frameless window
|
||||
should have rounded corners on macOS. Default is `true`. Setting this property
|
||||
to `false` will prevent the window from being fullscreenable.
|
||||
* `thickFrame` boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on
|
||||
Windows, which adds standard window frame. Setting it to `false` will remove
|
||||
window shadow and window animations. Default is `true`.
|
||||
* `vibrancy` string (optional) _macOS_ - Add a type of vibrancy effect to
|
||||
the window, only on macOS. Can be `appearance-based`, `titlebar`, `selection`,
|
||||
`menu`, `popover`, `sidebar`, `header`, `sheet`, `window`, `hud`, `fullscreen-ui`,
|
||||
`tooltip`, `content`, `under-window`, or `under-page`.
|
||||
* `backgroundMaterial` string (optional) _Windows_ - Set the window's
|
||||
system-drawn background material, including behind the non-client area.
|
||||
Can be `auto`, `none`, `mica`, `acrylic` or `tabbed`. See [win.setBackgroundMaterial](../browser-window.md#winsetbackgroundmaterialmaterial-windows) for more information.
|
||||
* `zoomToPageWidth` boolean (optional) _macOS_ - Controls the behavior on
|
||||
macOS when option-clicking the green stoplight button on the toolbar or by
|
||||
clicking the Window > Zoom menu item. If `true`, the window will grow to
|
||||
the preferred width of the web page when zoomed, `false` will cause it to
|
||||
zoom to the width of the screen. This will also affect the behavior when
|
||||
calling `maximize()` directly. Default is `false`.
|
||||
* `tabbingIdentifier` string (optional) _macOS_ - Tab group name, allows
|
||||
opening the window as a native tab. Windows with the same
|
||||
tabbing identifier will be grouped together. This also adds a native new
|
||||
tab button to your window's tab bar and allows your `app` and window to
|
||||
receive the `new-window-for-tab` event.
|
||||
* `webPreferences` [WebPreferences](web-preferences.md?inline) (optional) - Settings of web page's features.
|
||||
* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjunction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`.
|
||||
* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `height` Integer (optional) _macOS_ _Windows_ - The height of the title bar and Window Controls Overlay in pixels. Default is system height.
|
||||
|
||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||
passing a size that does not follow size constraints to `setBounds`/`setSize` or
|
||||
to the constructor of `BrowserWindow`.
|
||||
|
||||
The possible values and behaviors of the `type` option are platform dependent.
|
||||
Possible values are:
|
||||
|
||||
* On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`,
|
||||
`notification`.
|
||||
* The `desktop` type places the window at the desktop background window level
|
||||
(kCGDesktopWindowLevel - 1). However, note that a desktop window will not
|
||||
receive focus, keyboard, or mouse events. You can still use globalShortcut to
|
||||
receive input sparingly.
|
||||
* The `dock` type creates a dock-like window behavior.
|
||||
* The `toolbar` type creates a window with a toolbar appearance.
|
||||
* The `splash` type behaves in a specific way. It is not
|
||||
draggable, even if the CSS styling of the window's body contains
|
||||
-webkit-app-region: drag. This type is commonly used for splash screens.
|
||||
* The `notification` type creates a window that behaves like a system notification.
|
||||
* On macOS, possible types are `desktop`, `textured`, `panel`.
|
||||
* The `textured` type adds metal gradient appearance
|
||||
(`NSWindowStyleMaskTexturedBackground`).
|
||||
* The `desktop` type places the window at the desktop background window level
|
||||
(`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive
|
||||
focus, keyboard or mouse events, but you can use `globalShortcut` to receive
|
||||
input sparingly.
|
||||
* The `panel` type enables the window to float on top of full-screened apps
|
||||
by adding the `NSWindowStyleMaskNonactivatingPanel` style mask,normally
|
||||
reserved for NSPanel, at runtime. Also, the window will appear on all
|
||||
spaces (desktops).
|
||||
* On Windows, possible type is `toolbar`.
|
||||
|
||||
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
|
||||
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
|
||||
|
||||
@@ -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
|
||||
|
||||
86
docs/api/structures/proxy-config.md
Normal file
86
docs/api/structures/proxy-config.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# ProxyConfig Object
|
||||
|
||||
* `mode` string (optional) - The proxy mode. Should be one of `direct`,
|
||||
`auto_detect`, `pac_script`, `fixed_servers` or `system`.
|
||||
Defaults to `pac_script` proxy mode if `pacScript` option is specified
|
||||
otherwise defaults to `fixed_servers`.
|
||||
* `direct` - In direct mode all connections are created directly, without any proxy involved.
|
||||
* `auto_detect` - In auto_detect mode the proxy configuration is determined by a PAC script that can
|
||||
be downloaded at http://wpad/wpad.dat.
|
||||
* `pac_script` - In pac_script mode the proxy configuration is determined by a PAC script that is
|
||||
retrieved from the URL specified in the `pacScript`. This is the default mode if `pacScript` is specified.
|
||||
* `fixed_servers` - In fixed_servers mode the proxy configuration is specified in `proxyRules`.
|
||||
This is the default mode if `proxyRules` is specified.
|
||||
* `system` - In system mode the proxy configuration is taken from the operating system.
|
||||
Note that the system mode is different from setting no proxy configuration.
|
||||
In the latter case, Electron falls back to the system settings only if no
|
||||
command-line options influence the proxy configuration.
|
||||
* `pacScript` string (optional) - The URL associated with the PAC file.
|
||||
* `proxyRules` string (optional) - Rules indicating which proxies to use.
|
||||
* `proxyBypassRules` string (optional) - Rules indicating which URLs should
|
||||
bypass the proxy settings.
|
||||
|
||||
When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules`
|
||||
option is ignored and `pacScript` configuration is applied.
|
||||
|
||||
The `proxyRules` has to follow the rules below:
|
||||
|
||||
```sh
|
||||
proxyRules = schemeProxies[";"<schemeProxies>]
|
||||
schemeProxies = [<urlScheme>"="]<proxyURIList>
|
||||
urlScheme = "http" | "https" | "ftp" | "socks"
|
||||
proxyURIList = <proxyURL>[","<proxyURIList>]
|
||||
proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and
|
||||
HTTP proxy `foopy2:80` for `ftp://` URLs.
|
||||
* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs.
|
||||
* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing
|
||||
over to `bar` if `foopy:80` is unavailable, and after that using no proxy.
|
||||
* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs.
|
||||
* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail
|
||||
over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable.
|
||||
* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no
|
||||
proxy if `foopy` is unavailable.
|
||||
* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use
|
||||
`socks4://foopy2` for all other URLs.
|
||||
|
||||
The `proxyBypassRules` is a comma separated list of rules described below:
|
||||
|
||||
* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]`
|
||||
|
||||
Match all hostnames that match the pattern HOSTNAME_PATTERN.
|
||||
|
||||
Examples:
|
||||
"foobar.com", "\*foobar.com", "\*.foobar.com", "\*foobar.com:99",
|
||||
"https://x.\*.y.com:99"
|
||||
|
||||
* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]`
|
||||
|
||||
Match a particular domain suffix.
|
||||
|
||||
Examples:
|
||||
".google.com", ".com", "http://.google.com"
|
||||
|
||||
* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]`
|
||||
|
||||
Match URLs which are IP address literals.
|
||||
|
||||
Examples:
|
||||
"127.0.1", "\[0:0::1]", "\[::1]", "http://\[::1]:99"
|
||||
|
||||
* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS`
|
||||
|
||||
Match any URL that is to an IP literal that falls between the
|
||||
given range. IP range is specified using CIDR notation.
|
||||
|
||||
Examples:
|
||||
"192.168.1.1/16", "fefe:13::abc/33".
|
||||
|
||||
* `<local>`
|
||||
|
||||
Match local addresses. The meaning of `<local>` is whether the
|
||||
host matches one of: "127.0.0.1", "::1", "localhost".
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ app.whenReady().then(() => {
|
||||
|
||||
**MacOS**
|
||||
|
||||
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image).
|
||||
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image-macos).
|
||||
* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi.
|
||||
* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image.
|
||||
* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons.
|
||||
|
||||
@@ -21,12 +21,11 @@ Process: [Main](../glossary.md#main-process)<br />
|
||||
of the child process. Default is `inherit`.
|
||||
String value can be one of `pipe`, `ignore`, `inherit`, for more details on these values you can refer to
|
||||
[stdio][] documentation from Node.js. Currently this option only supports configuring `stdout` and
|
||||
`stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` is not supported; `stdin` will
|
||||
always be ignored.
|
||||
`stderr` to either `pipe`, `inherit` or `ignore`. Configuring `stdin` to any property other than `ignore` is not supported and will result in an error.
|
||||
For example, the supported values will be processed as following:
|
||||
* `pipe`: equivalent to \['ignore', 'pipe', 'pipe'] (the default)
|
||||
* `pipe`: equivalent to \['ignore', 'pipe', 'pipe']
|
||||
* `ignore`: equivalent to \['ignore', 'ignore', 'ignore']
|
||||
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit']
|
||||
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit'] (the default)
|
||||
* `serviceName` string (optional) - Name of the process that will appear in `name` property of
|
||||
[`ProcessMetric`](structures/process-metric.md) returned by [`app.getAppMetrics`](app.md#appgetappmetrics)
|
||||
and [`child-process-gone` event of `app`](app.md#event-child-process-gone).
|
||||
|
||||
106
docs/api/view.md
106
docs/api/view.md
@@ -1,106 +0,0 @@
|
||||
# View
|
||||
|
||||
> Create and layout native views.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
This module cannot be used until the `ready` event of the `app`
|
||||
module is emitted.
|
||||
|
||||
```js
|
||||
const { BaseWindow, View } = require('electron')
|
||||
const win = new BaseWindow()
|
||||
const view = new View()
|
||||
|
||||
view.setBackgroundColor('red')
|
||||
view.setBounds({ x: 0, y: 0, width: 100, height: 100 })
|
||||
win.contentView.addChildView(view)
|
||||
```
|
||||
|
||||
## Class: View
|
||||
|
||||
> A basic native view.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
`View` is an [EventEmitter][event-emitter].
|
||||
|
||||
### `new View()`
|
||||
|
||||
Creates a new `View`.
|
||||
|
||||
### Instance Events
|
||||
|
||||
Objects created with `new View` emit the following events:
|
||||
|
||||
#### Event: 'bounds-changed'
|
||||
|
||||
Emitted when the view's bounds have changed in response to being laid out. The
|
||||
new bounds can be retrieved with [`view.getBounds()`](#viewgetbounds).
|
||||
|
||||
### Instance Methods
|
||||
|
||||
Objects created with `new View` have the following instance methods:
|
||||
|
||||
#### `view.addChildView(view[, index])`
|
||||
|
||||
* `view` View - Child view to add.
|
||||
* `index` Integer (optional) - Index at which to insert the child view.
|
||||
Defaults to adding the child at the end of the child list.
|
||||
|
||||
#### `view.removeChildView(view)`
|
||||
|
||||
* `view` View - Child view to remove.
|
||||
|
||||
#### `view.setBounds(bounds)`
|
||||
|
||||
* `bounds` [Rectangle](structures/rectangle.md) - New bounds of the View.
|
||||
|
||||
#### `view.getBounds()`
|
||||
|
||||
Returns [`Rectangle`](structures/rectangle.md) - The bounds of this View, relative to its parent.
|
||||
|
||||
#### `view.setBackgroundColor(color)`
|
||||
|
||||
* `color` string - Color in Hex, RGB, ARGB, HSL, HSLA or named CSS color format. The alpha channel is
|
||||
optional for the hex type.
|
||||
|
||||
Examples of valid `color` values:
|
||||
|
||||
* Hex
|
||||
* `#fff` (RGB)
|
||||
* `#ffff` (ARGB)
|
||||
* `#ffffff` (RRGGBB)
|
||||
* `#ffffffff` (AARRGGBB)
|
||||
* RGB
|
||||
* `rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)`
|
||||
* e.g. `rgb(255, 255, 255)`
|
||||
* RGBA
|
||||
* `rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)`
|
||||
* e.g. `rgba(255, 255, 255, 1.0)`
|
||||
* HSL
|
||||
* `hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)`
|
||||
* e.g. `hsl(200, 20%, 50%)`
|
||||
* HSLA
|
||||
* `hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)`
|
||||
* e.g. `hsla(200, 20%, 50%, 0.5)`
|
||||
* Color name
|
||||
* Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148)
|
||||
* Similar to CSS Color Module Level 3 keywords, but case-sensitive.
|
||||
* e.g. `blueviolet` or `red`
|
||||
|
||||
**Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBAA` or `RGB`.
|
||||
|
||||
#### `view.setVisible(visible)`
|
||||
|
||||
* `visible` boolean - If false, the view will be hidden from display.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
Objects created with `new View` have the following properties:
|
||||
|
||||
#### `view.children` _Readonly_
|
||||
|
||||
A `View[]` property representing the child views of this view.
|
||||
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
@@ -1,58 +0,0 @@
|
||||
# WebContentsView
|
||||
|
||||
> A View that displays a WebContents.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
This module cannot be used until the `ready` event of the `app`
|
||||
module is emitted.
|
||||
|
||||
```js
|
||||
const { BaseWindow, WebContentsView } = require('electron')
|
||||
const win = new BaseWindow({ width: 800, height: 400 })
|
||||
|
||||
const view1 = new WebContentsView()
|
||||
win.contentView.addChildView(view1)
|
||||
view1.webContents.loadURL('https://electronjs.org')
|
||||
view1.setBounds({ x: 0, y: 0, width: 400, height: 400 })
|
||||
|
||||
const view2 = new WebContentsView()
|
||||
win.contentView.addChildView(view2)
|
||||
view2.webContents.loadURL('https://github.com/electron/electron')
|
||||
view2.setBounds({ x: 400, y: 0, width: 400, height: 400 })
|
||||
```
|
||||
|
||||
## Class: WebContentsView extends `View`
|
||||
|
||||
> A View that displays a WebContents.
|
||||
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
`WebContentsView` inherits from [`View`](view.md).
|
||||
|
||||
`WebContentsView` is an [EventEmitter][event-emitter].
|
||||
|
||||
### `new WebContentsView([options])`
|
||||
|
||||
* `options` Object (optional)
|
||||
* `webPreferences` [WebPreferences](structures/web-preferences.md) (optional) - Settings of web page's features.
|
||||
|
||||
Creates an empty WebContentsView.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
Objects created with `new WebContentsView` have the following properties, in
|
||||
addition to those inherited from [View](view.md):
|
||||
|
||||
#### `view.webContents` _Readonly_
|
||||
|
||||
A `WebContents` property containing a reference to the displayed `WebContents`.
|
||||
Use this to interact with the `WebContents`, for instance to load a URL.
|
||||
|
||||
```js
|
||||
const { WebContentsView } = require('electron')
|
||||
const view = new WebContentsView()
|
||||
view.webContents.loadURL('https://electronjs.org/')
|
||||
```
|
||||
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
@@ -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
|
||||
@@ -674,7 +674,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.
|
||||
@@ -894,7 +894,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
|
||||
@@ -1014,7 +1014,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()`.
|
||||
|
||||
@@ -1045,7 +1045,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.
|
||||
@@ -1282,7 +1282,7 @@ Ignore application menu shortcuts while this web contents is focused.
|
||||
|
||||
#### `contents.setWindowOpenHandler(handler)`
|
||||
|
||||
* `handler` Function<{action: 'deny'} | {action: 'allow', outlivesOpener?: boolean, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
|
||||
* `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()`
|
||||
@@ -1560,7 +1560,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.
|
||||
@@ -1614,6 +1614,7 @@ win.webContents.print(options, (success, errorType) => {
|
||||
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
|
||||
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
|
||||
* `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards.
|
||||
* `generateDocumentOutline` boolean (optional) _Experimental_ - Whether or not to generate a PDF document outline from content headers. Defaults to false.
|
||||
|
||||
Returns `Promise<Buffer>` - Resolves with the generated PDF data.
|
||||
|
||||
@@ -1624,24 +1625,26 @@ The `landscape` will be ignored if `@page` CSS at-rule is used in the web page.
|
||||
An example of `webContents.printToPDF`:
|
||||
|
||||
```js
|
||||
const { BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
const os = require('node:os')
|
||||
|
||||
const win = new BrowserWindow()
|
||||
win.loadURL('https://github.com')
|
||||
app.whenReady().then(() => {
|
||||
const win = new BrowserWindow()
|
||||
win.loadURL('https://github.com')
|
||||
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
// Use default printing options
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
win.webContents.printToPDF({}).then(data => {
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
// Use default printing options
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
win.webContents.printToPDF({}).then(data => {
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
})
|
||||
}).catch(error => {
|
||||
console.log(`Failed to write PDF to ${pdfPath}: `, error)
|
||||
})
|
||||
}).catch(error => {
|
||||
console.log(`Failed to write PDF to ${pdfPath}: `, error)
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -2197,6 +2200,10 @@ 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
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
|
||||
Electron's `webview` tag is based on [Chromium's `webview`][chrome-webview], which
|
||||
is undergoing dramatic architectural changes. This impacts the stability of `webviews`,
|
||||
including rendering, navigation, and event routing. We currently recommend to
|
||||
not use the `webview` tag and to consider alternatives, like `iframe`, a
|
||||
[`WebContentsView`](web-contents-view.md), or an architecture that avoids
|
||||
embedded content altogether.
|
||||
including rendering, navigation, and event routing. We currently recommend to not
|
||||
use the `webview` tag and to consider alternatives, like `iframe`, [Electron's `BrowserView`](browser-view.md),
|
||||
or an architecture that avoids embedded content altogether.
|
||||
|
||||
## Enabling
|
||||
|
||||
@@ -221,9 +220,7 @@ windows. Popups are disabled by default.
|
||||
```
|
||||
|
||||
A `string` which is a comma separated list of strings which specifies the web preferences to be set on the webview.
|
||||
The full list of supported preference strings can be found in [BrowserWindow](browser-window.md#new-browserwindowoptions). In addition, webview supports the following preferences:
|
||||
|
||||
* `transparent` boolean (optional) - Whether to enable background transparency for the guest page. Default is `true`. **Note:** The guest page's text and background colors are derived from the [color scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) of its root element. When transparency is enabled, the text color will still change accordingly but the background will remain transparent.
|
||||
The full list of supported preference strings can be found in [BrowserWindow](browser-window.md#new-browserwindowoptions).
|
||||
|
||||
The string follows the same format as the features string in `window.open`.
|
||||
A name by itself is given a `true` boolean value.
|
||||
@@ -287,7 +284,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 +577,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.
|
||||
@@ -611,6 +608,7 @@ Prints `webview`'s web page. Same as `webContents.print([options])`.
|
||||
* `footerTemplate` string (optional) - HTML template for the print footer. Should use the same format as the `headerTemplate`.
|
||||
* `preferCSSPageSize` boolean (optional) - Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.
|
||||
* `generateTaggedPDF` boolean (optional) _Experimental_ - Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards.
|
||||
* `generateDocumentOutline` boolean (optional) _Experimental_ - Whether or not to generate a PDF document outline from content headers. Defaults to false.
|
||||
|
||||
Returns `Promise<Uint8Array>` - Resolves with the generated PDF data.
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ This switch was never formally documented but it's removal is being noted here r
|
||||
|
||||
### Behavior Changed: `ipcRenderer` can no longer be sent over the `contextBridge`
|
||||
|
||||
Attempting to send `ipcRenderer` as an object over the `contextBridge` will now result in
|
||||
Attempting to send the entire `ipcRenderer` module as an object over the `contextBridge` will now result in
|
||||
an empty object on the receiving side of the bridge. This change was made to remove / mitigate
|
||||
a security footgun, you should not directly expose ipcRenderer or it's methods over the bridge.
|
||||
Instead provide a safe wrapper like below:
|
||||
a security footgun. You should not directly expose ipcRenderer or its methods over the bridge.
|
||||
Instead, provide a safe wrapper like below:
|
||||
|
||||
```js
|
||||
contextBridge.exposeInMainWorld('app', {
|
||||
@@ -82,18 +82,6 @@ app.on('gpu-process-crashed', (event, killed) => { /* ... */ })
|
||||
app.on('child-process-gone', (event, details) => { /* ... */ })
|
||||
```
|
||||
|
||||
### Behavior Changed: `BrowserView.setAutoResize` behavior on macOS
|
||||
|
||||
In Electron 29, BrowserView is now a wrapper around the new [WebContentsView](api/web-contents-view.md) API.
|
||||
|
||||
Previously, the `setAutoResize` function of the `BrowserView` API was backed by [autoresizing](https://developer.apple.com/documentation/appkit/nsview/1483281-autoresizingmask?language=objc) on macOS, and by a custom algorithm on Windows and Linux.
|
||||
For simple use cases such as making a BrowserView fill the entire window, the behavior of these two approaches was identical.
|
||||
However, in more advanced cases, BrowserViews would be autoresized differently on macOS than they would be on other platforms, as the custom resizing algorithm for Windows and Linux did not perfectly match the behavior of macOS's autoresizing API.
|
||||
The autoresizing behavior is now standardized across all platforms.
|
||||
|
||||
If your app uses `BrowserView.setAutoResize` to do anything more complex than making a BrowserView fill the entire window, it's likely you already had custom logic in place to handle this difference in behavior on macOS.
|
||||
If so, that logic will no longer be needed in Electron 29 as autoresizing behavior is consistent.
|
||||
|
||||
## Planned Breaking API Changes (28.0)
|
||||
|
||||
### Behavior Changed: `WebContents.backgroundThrottling` set to false affects all `WebContents` in the host `BrowserWindow`
|
||||
@@ -1676,7 +1664,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
|
||||
|
||||
@@ -3,4 +3,54 @@
|
||||
> Goma is a distributed compiler service for open-source projects such as
|
||||
> Chromium and Android.
|
||||
|
||||
Electron's deployment of Goma is deprecated and we are gradually shifting all usage to the [reclient](reclient.md) system. At some point in 2024 the Goma backend will be shutdown.
|
||||
Electron has a deployment of a custom Goma Backend that we make available to
|
||||
all Electron Maintainers. See the [Access](#access) section below for details
|
||||
on authentication. There is also a `cache-only` Goma endpoint that will be
|
||||
used by default if you do not have credentials. Requests to the cache-only
|
||||
Goma will not hit our cluster, but will read from our cache and should result
|
||||
in significantly faster build times.
|
||||
|
||||
## Enabling Goma
|
||||
|
||||
Currently the only supported way to use Goma is to use our [Build Tools](https://github.com/electron/build-tools).
|
||||
Goma configuration is automatically included when you set up `build-tools`.
|
||||
|
||||
If you are a maintainer and have access to our cluster, please ensure that you run
|
||||
`e init` with `--goma=cluster` in order to configure `build-tools` to use
|
||||
the Goma cluster. If you have an existing config, you can just set `"goma": "cluster"`
|
||||
in your config file.
|
||||
|
||||
## Building with Goma
|
||||
|
||||
When you are using Goma you can run `ninja` with a substantially higher `j`
|
||||
value than would normally be supported by your machine.
|
||||
|
||||
Please do not set a value higher than **200**. We monitor Goma system usage, and users
|
||||
found to be abusing it with unreasonable concurrency will be de-activated.
|
||||
|
||||
```bash
|
||||
ninja -C out/Testing electron -j 200
|
||||
```
|
||||
|
||||
If you're using `build-tools`, appropriate `-j` values will automatically be used for you.
|
||||
|
||||
## Monitoring Goma
|
||||
|
||||
If you access [http://localhost:8088](http://localhost:8088) on your local
|
||||
machine you can monitor compile jobs as they flow through the goma system.
|
||||
|
||||
## Access
|
||||
|
||||
For security and cost reasons, access to Electron's Goma cluster is currently restricted
|
||||
to Electron Maintainers. If you want access please head to `#access-requests` in
|
||||
Slack and ping `@goma-squad` to ask for access. Please be aware that being a
|
||||
maintainer does not _automatically_ grant access and access is determined on a
|
||||
case by case basis.
|
||||
|
||||
## Uptime / Support
|
||||
|
||||
We have automated monitoring of our Goma cluster and cache at https://status.notgoma.com
|
||||
|
||||
We do not provide support for usage of Goma and any issues raised asking for help / having
|
||||
issues will _probably_ be closed without much reason, we do not have the capacity to handle
|
||||
that kind of support.
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Reclient
|
||||
|
||||
> Reclient integrates with an existing build system to enable remote execution and caching of build actions.
|
||||
|
||||
Electron has a deployment of a [reclient](https://github.com/bazelbuild/reclient)
|
||||
compatible RBE Backend that is available to all Electron Maintainers.
|
||||
See the [Access](#access) section below for details on authentication. Non-maintainers
|
||||
will not have access to the cluster, but can sign in to receive a `Cache Only` token
|
||||
that gives access to the cache-only CAS backend. Using this should result in
|
||||
significantly faster build times .
|
||||
|
||||
## Enabling Reclient
|
||||
|
||||
Currently the only supported way to use Reclient is to use our [Build Tools](https://github.com/electron/build-tools).
|
||||
Reclient configuration is automatically included when you set up `build-tools`.
|
||||
|
||||
If you have an existing config, you can just set `"reclient": "remote_exec"`
|
||||
in your config file.
|
||||
|
||||
## Building with Reclient
|
||||
|
||||
When you are using Reclient, you can run `autoninja` with a substantially higher `j`
|
||||
value than would normally be supported by your machine.
|
||||
|
||||
Please do not set a value higher than **200**. The RBE system is monitored.
|
||||
Users found to be abusing it with unreasonable concurrency will be deactivated.
|
||||
|
||||
```bash
|
||||
autoninja -C out/Testing electron -j 200
|
||||
```
|
||||
|
||||
If you're using `build-tools`, appropriate `-j` values will automatically be used for you.
|
||||
|
||||
## Access
|
||||
|
||||
For security and cost reasons, access to Electron's RBE backend is currently restricted
|
||||
to Electron Maintainers. If you want access, please head to `#access-requests` in
|
||||
Slack and ping `@infra-wg` to ask for it. Please be aware that being a
|
||||
maintainer does not _automatically_ grant access. Access is determined on a
|
||||
case-by-case basis.
|
||||
|
||||
## Support
|
||||
|
||||
We do not provide support for usage of Reclient. Issues raised asking for help / having
|
||||
issues will _probably_ be closed without much reason. We do not have the capacity to handle
|
||||
that kind of support.
|
||||
@@ -102,7 +102,7 @@ const template = [
|
||||
})(),
|
||||
click: (item, focusedWindow) => {
|
||||
if (focusedWindow) {
|
||||
focusedWindow.webContents.toggleDevTools()
|
||||
focusedWindow.toggleDevTools()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 4.2 MiB |
@@ -196,32 +196,19 @@ support via Electron's support for the [Chrome DevTools Protocol][] (CDP).
|
||||
|
||||
### Install dependencies
|
||||
|
||||
You can install Playwright through your preferred Node.js package manager. The Playwright team
|
||||
recommends using the `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` environment variable to avoid
|
||||
unnecessary browser downloads when testing an Electron app.
|
||||
|
||||
```sh npm2yarn
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --save-dev playwright
|
||||
```
|
||||
|
||||
Playwright also comes with its own test runner, Playwright Test, which is built for end-to-end
|
||||
testing. You can also install it as a dev dependency in your project:
|
||||
You can install Playwright through your preferred Node.js package manager. It comes with its
|
||||
own [test runner][playwright-intro], which is built for end-to-end testing:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev @playwright/test
|
||||
```
|
||||
|
||||
:::caution Dependencies
|
||||
This tutorial was written `playwright@1.16.3` and `@playwright/test@1.16.3`. Check out
|
||||
This tutorial was written with `@playwright/test@1.41.1`. Check out
|
||||
[Playwright's releases][playwright-releases] page to learn about
|
||||
changes that might affect the code below.
|
||||
:::
|
||||
|
||||
:::info Using third-party test runners
|
||||
If you're interested in using an alternative test runner (e.g. Jest or Mocha), check out
|
||||
Playwright's [Third-Party Test Runner][playwright-test-runners] guide.
|
||||
:::
|
||||
|
||||
### Write your tests
|
||||
|
||||
Playwright launches your app in development mode through the `_electron.launch` API.
|
||||
@@ -229,8 +216,7 @@ To point this API to your Electron app, you can pass the path to your main proce
|
||||
entry point (here, it is `main.js`).
|
||||
|
||||
```js {5} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
const { test, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('launch app', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
@@ -242,9 +228,8 @@ test('launch app', async () => {
|
||||
After that, you will access to an instance of Playwright's `ElectronApp` class. This
|
||||
is a powerful class that has access to main process modules for example:
|
||||
|
||||
```js {6-11} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
```js {5-10} @ts-nocheck
|
||||
const { test, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('get isPackaged', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
@@ -263,8 +248,7 @@ It can also create individual [Page][playwright-page] objects from Electron Brow
|
||||
For example, to grab the first BrowserWindow and save a screenshot:
|
||||
|
||||
```js {6-7} @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test } = require('@playwright/test')
|
||||
const { test, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('save screenshot', async () => {
|
||||
const electronApp = await electron.launch({ args: ['main.js'] })
|
||||
@@ -275,12 +259,11 @@ test('save screenshot', async () => {
|
||||
})
|
||||
```
|
||||
|
||||
Putting all this together using the PlayWright Test runner, let's create a `example.spec.js`
|
||||
Putting all this together using the Playwright test-runner, let's create a `example.spec.js`
|
||||
test file with a single test and assertion:
|
||||
|
||||
```js title='example.spec.js' @ts-nocheck
|
||||
const { _electron: electron } = require('playwright')
|
||||
const { test, expect } = require('@playwright/test')
|
||||
const { test, expect, _electron: electron } = require('@playwright/test')
|
||||
|
||||
test('example test', async () => {
|
||||
const electronApp = await electron.launch({ args: ['.'] })
|
||||
@@ -316,6 +299,7 @@ Running 1 test using 1 worker
|
||||
:::info
|
||||
Playwright Test will automatically run any files matching the `.*(test|spec)\.(js|ts|mjs)` regex.
|
||||
You can customize this match in the [Playwright Test configuration options][playwright-test-config].
|
||||
It also works with TypeScript out of the box.
|
||||
:::
|
||||
|
||||
:::tip Further reading
|
||||
@@ -473,10 +457,10 @@ test.after.always('cleanup', async t => {
|
||||
|
||||
[chrome-driver]: https://sites.google.com/chromium.org/driver/
|
||||
[Puppeteer]: https://github.com/puppeteer/puppeteer
|
||||
[playwright-intro]: https://playwright.dev/docs/intro
|
||||
[playwright-electron]: https://playwright.dev/docs/api/class-electron/
|
||||
[playwright-electronapplication]: https://playwright.dev/docs/api/class-electronapplication
|
||||
[playwright-page]: https://playwright.dev/docs/api/class-page
|
||||
[playwright-releases]: https://github.com/microsoft/playwright/releases
|
||||
[playwright-releases]: https://playwright.dev/docs/release-notes
|
||||
[playwright-test-config]: https://playwright.dev/docs/api/class-testconfig#test-config-test-match
|
||||
[playwright-test-runners]: https://playwright.dev/docs/test-runners/
|
||||
[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/
|
||||
|
||||
@@ -5,34 +5,25 @@ slug: code-signing
|
||||
hide_title: false
|
||||
---
|
||||
|
||||
Code signing is a security technology that you use to certify that an app was
|
||||
created by you. You should sign your application so it does not trigger any
|
||||
operating system security checks.
|
||||
Code signing is a security technology to certify that an app was created by you.
|
||||
You should sign your application so it does not trigger any operating system
|
||||
security warnings.
|
||||
|
||||
On macOS, the system can detect any change to the app, whether the change is
|
||||
introduced accidentally or by malicious code.
|
||||

|
||||
|
||||
On Windows, the system assigns a trust level to your code signing certificate
|
||||
which if you don't have, or if your trust level is low, will cause security
|
||||
dialogs to appear when users start using your application. Trust level builds
|
||||
over time so it's better to start code signing as early as possible.
|
||||
|
||||
While it is possible to distribute unsigned apps, it is not recommended. Both
|
||||
Windows and macOS will, by default, prevent either the download or the execution
|
||||
of unsigned applications. Starting with macOS Catalina (version 10.15), users
|
||||
have to go through multiple manual steps to open unsigned applications.
|
||||
|
||||

|
||||
|
||||
As you can see, users get two options: Move the app straight to the trash or
|
||||
cancel running it. You don't want your users to see that dialog.
|
||||
Both Windows and macOS prevent users from running unsigned applications. It is
|
||||
possible to distribute applications without codesigning them - but in order to
|
||||
run them, users need to go through multiple advanced and manual steps to run
|
||||
them.
|
||||
|
||||
If you are building an Electron app that you intend to package and distribute,
|
||||
it should be code signed.
|
||||
it should be code signed. The Electron ecosystem tooling makes codesigning your
|
||||
apps straightforward - this documentation explains how sign your apps on both
|
||||
Windows and macOS.
|
||||
|
||||
## Signing & notarizing macOS builds
|
||||
|
||||
Properly preparing macOS applications for release requires two steps. First, the
|
||||
Preparing macOS applications for release requires two steps: First, the
|
||||
app needs to be code signed. Then, the app needs to be uploaded to Apple for a
|
||||
process called **notarization**, where automated systems will further verify that
|
||||
your app isn't doing anything to endanger its users.
|
||||
@@ -65,7 +56,9 @@ are likely using [`@electron/packager`][], which includes [`@electron/osx-sign`]
|
||||
[`@electron/notarize`][].
|
||||
|
||||
If you're using Packager's API, you can pass [in configuration that both signs
|
||||
and notarizes your application](https://electron.github.io/packager/main/interfaces/electronpackager.options.html).
|
||||
and notarizes your application](https://electron.github.io/packager/main/modules.html).
|
||||
If the example below does not meet your needs, please see [`@electron/osx-sign`][] and
|
||||
[`@electron/notarize`][] for the many possible configuration options.
|
||||
|
||||
```js @ts-nocheck
|
||||
const packager = require('@electron/packager')
|
||||
@@ -86,35 +79,81 @@ See the [Mac App Store Guide][].
|
||||
|
||||
## Signing Windows builds
|
||||
|
||||
Before signing Windows builds, you must do the following:
|
||||
Before you can code sign your application, you need to acquire a code signing
|
||||
certificate. Unlike Apple, Microsoft allows developers to purchase those
|
||||
certificates on the open market. They are usually sold by the same companies
|
||||
also offering HTTPS certificates. Prices vary, so it may be worth your time to
|
||||
shop around. Popular resellers include:
|
||||
|
||||
1. Get a Windows Authenticode code signing certificate (requires an annual fee)
|
||||
2. Install Visual Studio to get the signing utility (the free [Community
|
||||
Edition](https://visualstudio.microsoft.com/vs/community/) is enough)
|
||||
- [Certum EV code signing certificate](https://shop.certum.eu/data-safety/code-signing-certificates/certum-ev-code-sigining.html)
|
||||
- [DigiCert EV code signing certificate](https://www.digicert.com/signing/code-signing-certificates)
|
||||
- [Entrust EV code signing certificate](https://www.entrustdatacard.com/products/digital-signing-certificates/code-signing-certificates)
|
||||
- [GlobalSign EV code signing certificate](https://www.globalsign.com/en/code-signing-certificate/ev-code-signing-certificates)
|
||||
- [IdenTrust EV code signing certificate](https://www.identrust.com/digital-certificates/trustid-ev-code-signing)
|
||||
- [Sectigo (formerly Comodo) EV code signing certificate](https://sectigo.com/ssl-certificates-tls/code-signing)
|
||||
- [SSL.com EV code signing certificate](https://www.ssl.com/certificates/ev-code-signing/)
|
||||
|
||||
You can get a code signing certificate from a lot of resellers. Prices vary, so
|
||||
it may be worth your time to shop around. Popular resellers include:
|
||||
It is important to call out that since June 2023, Microsoft requires software to
|
||||
be signed with an "extended validation" certificate, also called an "EV code signing
|
||||
certificate". In the past, developers could sign software with a simpler and cheaper
|
||||
certificate called "authenticode code signing certificate" or "software-based OV certificate".
|
||||
These simpler certificates no longer provide benefits: Windows will treat your app as
|
||||
completely unsigned and display the equivalent warning dialogs.
|
||||
|
||||
- [digicert](https://www.digicert.com/dc/code-signing/microsoft-authenticode.htm)
|
||||
- [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing)
|
||||
- Amongst others, please shop around to find one that suits your needs! 😄
|
||||
The new EV certificates are required to be stored on a hardware storage module
|
||||
compliant with FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent. In other words,
|
||||
the certificate cannot be simply downloaded onto a CI infrastructure. In practice,
|
||||
those storage modules look like fancy USB thumb drives.
|
||||
|
||||
:::caution Keep your certificate password private
|
||||
Your certificate password should be a **secret**. Do not share it publicly or
|
||||
commit it to your source code.
|
||||
:::
|
||||
Many certificate providers now offer "cloud-based signing" - the entire signing hardware
|
||||
is in their data center and you can use it to remotely sign code. This approach is
|
||||
popular with Electron maintainers since it makes signing your applications in CI (like
|
||||
GitHub Actions, CircleCI, etc) relatively easy.
|
||||
|
||||
At the time of writing, Electron's own apps use [DigiCert KeyLocker](https://docs.digicert.com/en/digicert-keylocker.html), but any provider that provides a command line tool for
|
||||
signing files will be compatible with Electron's tooling.
|
||||
|
||||
All tools in the Electron ecosystem use [`@electron/windows-sign`][] and typically
|
||||
expose configuration options through a `windowsSign` property. You can either use it
|
||||
to sign files directly - or use the same `windowsSign` configuration across Electron
|
||||
Forge, [`@electron/packager`][], [`electron-winstaller`][], and [`electron-wix-msi`][].
|
||||
|
||||
### Using Electron Forge
|
||||
|
||||
Electron Forge is the recommended way to sign your `Squirrel.Windows` and `WiX MSI` installers. Detailed instructions on how to configure your application can be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-macos).
|
||||
Electron Forge is the recommended way to sign your app as well as your `Squirrel.Windows`
|
||||
and `WiX MSI` installers. Detailed instructions on how to configure your application can
|
||||
be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-windows).
|
||||
|
||||
### Using Electron Packager
|
||||
|
||||
If you're not using an integrated build pipeline like Forge, you
|
||||
are likely using [`@electron/packager`][], which includes [`@electron/windows-sign`][].
|
||||
|
||||
If you're using Packager's API, you can pass [in configuration that signs
|
||||
your application](https://electron.github.io/packager/main/modules.html). If the
|
||||
example below does not meet your needs, please see [`@electron/windows-sign`][]
|
||||
for the many possible configuration options.
|
||||
|
||||
```js @ts-nocheck
|
||||
const packager = require('@electron/packager')
|
||||
|
||||
packager({
|
||||
dir: '/path/to/my/app',
|
||||
windowsSign: {
|
||||
signWithParams: '--my=custom --parameters',
|
||||
// If signtool.exe does not work for you, customize!
|
||||
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Using electron-winstaller (Squirrel.Windows)
|
||||
|
||||
[`electron-winstaller`][] is a package that can generate Squirrel.Windows installers for your
|
||||
Electron app. This is the tool used under the hood by Electron Forge's
|
||||
[Squirrel.Windows Maker][maker-squirrel]. If you're not using Electron Forge and want to use
|
||||
`electron-winstaller` directly, use the `certificateFile` and `certificatePassword` configuration
|
||||
options when creating your installer.
|
||||
[Squirrel.Windows Maker][maker-squirrel]. Just like `@electron/packager`, it uses
|
||||
[`@electron/windows-sign`][] under the hood and supports the same `windowsSign`
|
||||
options.
|
||||
|
||||
```js {10-11} @ts-nocheck
|
||||
const electronInstaller = require('electron-winstaller')
|
||||
@@ -126,8 +165,11 @@ try {
|
||||
outputDirectory: '/tmp/build/installer64',
|
||||
authors: 'My App Inc.',
|
||||
exe: 'myapp.exe',
|
||||
certificateFile: './cert.pfx',
|
||||
certificatePassword: 'this-is-a-secret'
|
||||
windowsSign: {
|
||||
signWithParams: '--my=custom --parameters',
|
||||
// If signtool.exe does not work for you, customize!
|
||||
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
|
||||
}
|
||||
})
|
||||
console.log('It worked!')
|
||||
} catch (e) {
|
||||
@@ -141,10 +183,8 @@ For full configuration options, check out the [`electron-winstaller`][] reposito
|
||||
|
||||
[`electron-wix-msi`][] is a package that can generate MSI installers for your
|
||||
Electron app. This is the tool used under the hood by Electron Forge's [MSI Maker][maker-msi].
|
||||
|
||||
If you're not using Electron Forge and want to use `electron-wix-msi` directly, use the
|
||||
`certificateFile` and `certificatePassword` configuration options
|
||||
or pass in parameters directly to [SignTool.exe][] with the `signWithParams` option.
|
||||
Just like `@electron/packager`, it uses [`@electron/windows-sign`][] under the hood
|
||||
and supports the same `windowsSign` options.
|
||||
|
||||
```js {12-13} @ts-nocheck
|
||||
import { MSICreator } from 'electron-wix-msi'
|
||||
@@ -158,8 +198,11 @@ const msiCreator = new MSICreator({
|
||||
manufacturer: 'Kitten Technologies',
|
||||
version: '1.1.2',
|
||||
outputDirectory: '/path/to/output/folder',
|
||||
certificateFile: './cert.pfx',
|
||||
certificatePassword: 'this-is-a-secret'
|
||||
windowsSign: {
|
||||
signWithParams: '--my=custom --parameters',
|
||||
// If signtool.exe does not work for you, customize!
|
||||
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
|
||||
}
|
||||
})
|
||||
|
||||
// Step 2: Create a .wxs template file
|
||||
@@ -192,6 +235,7 @@ See the [Windows Store Guide][].
|
||||
[`@electron/osx-sign`]: https://github.com/electron/osx-sign
|
||||
[`@electron/packager`]: https://github.com/electron/packager
|
||||
[`@electron/notarize`]: https://github.com/electron/notarize
|
||||
[`@electron/windows-sign`]: https://github.com/electron/windows-sign
|
||||
[`electron-winstaller`]: https://github.com/electron/windows-installer
|
||||
[`electron-wix-msi`]: https://github.com/electron-userland/electron-wix-msi
|
||||
[xcode]: https://developer.apple.com/xcode
|
||||
@@ -200,4 +244,3 @@ See the [Windows Store Guide][].
|
||||
[windows store guide]: ./windows-store-guide.md
|
||||
[maker-squirrel]: https://www.electronforge.io/config/makers/squirrel.windows
|
||||
[maker-msi]: https://www.electronforge.io/config/makers/wix-msi
|
||||
[signtool.exe]: https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
|
||||
|
||||
@@ -14,10 +14,10 @@ process:
|
||||
|
||||
Electron will listen for V8 inspector protocol messages on the specified `port`,
|
||||
an external debugger will need to connect on this port. The default `port` is
|
||||
`9229`.
|
||||
`5858`.
|
||||
|
||||
```shell
|
||||
electron --inspect=9229 your/app
|
||||
electron --inspect=5858 your/app
|
||||
```
|
||||
|
||||
### `--inspect-brk=[port]`
|
||||
|
||||
@@ -33,7 +33,7 @@ clicked.
|
||||
## WebHID API
|
||||
|
||||
The [WebHID API](https://web.dev/hid/) can be used to access HID devices such
|
||||
as keyboards and gamepads. Electron provides several APIs for working with
|
||||
as keyboards and gamepads. Electron provides several APIs for working with
|
||||
the WebHID API:
|
||||
|
||||
* The [`select-hid-device` event on the Session](../api/session.md#event-select-hid-device)
|
||||
|
||||
@@ -9,10 +9,10 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
|
||||
|
||||
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
|
||||
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
|
||||
| 29.0.0 | 2023-Dec-07 | 2024-Jan-24 | 2024-Feb-20 | 2024-Aug-20 | M122 | v18.19 | ✅ |
|
||||
| 29.0.0 | 2023-Dec-07 | 2024-Jan-24 | 2024-Feb-20 | 2024-Aug-20 | M122 | v20.9 | ✅ |
|
||||
| 28.0.0 | 2023-Oct-11 | 2023-Nov-06 | 2023-Dec-05 | 2024-Jun-11 | M120 | v18.18 | ✅ |
|
||||
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | 2024-Apr-16 | M118 | v18.17 | ✅ |
|
||||
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-20 | M116 | v18.16 | ✅ |
|
||||
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-20 | M116 | v18.16 | 🚫 |
|
||||
| 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2023-Dec-05 | M114 | v18.15 | 🚫 |
|
||||
| 24.0.0 | 2023-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | 🚫 |
|
||||
| 23.0.0 | 2022-Dec-01 | 2023-Jan-10 | 2023-Feb-07 | 2023-Aug-15 | M110 | v18.12 | 🚫 |
|
||||
|
||||
@@ -15,7 +15,7 @@ Fuses are the solution to this problem, at a high level they are "magic bits" in
|
||||
**Default:** Enabled
|
||||
**@electron/fuses:** `FuseV1Options.RunAsNode`
|
||||
|
||||
The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function.
|
||||
The runAsNode fuse toggles whether the `ELECTRON_RUN_AS_NODE` environment variable is respected or not. Please note that if this fuse is disabled then `process.fork` in the main process will not function as expected as it depends on this environment variable to function. Instead, we recommend that you use [Utility Processes](../api/utility-process.md), which work for many use cases where you need a standalone Node.js process (like a Sqlite server process or similar scenarios).
|
||||
|
||||
### `cookieEncryption`
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ if (!inAppPurchase.canMakePayments()) {
|
||||
inAppPurchase.getProducts(PRODUCT_IDS).then(products => {
|
||||
// Check the parameters.
|
||||
if (!Array.isArray(products) || products.length <= 0) {
|
||||
console.log('Unable to retrieve the product informations.')
|
||||
console.log('Unable to retrieve the product information.')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ careful to understand that the term "performance" means different things for
|
||||
a Node.js backend than it does for an application running on a client.
|
||||
|
||||
This list is provided for your convenience – and is, much like our
|
||||
[security checklist][security] – not meant to exhaustive. It is probably possible
|
||||
[security checklist][security] – not meant to be exhaustive. It is probably possible
|
||||
to build a slow Electron app that follows all the steps outlined below. Electron
|
||||
is a powerful development platform that enables you, the developer, to do more
|
||||
or less whatever you want. All that freedom means that performance is largely
|
||||
@@ -83,7 +83,7 @@ is not in fact the leanest or smallest one available.
|
||||
|
||||
The reasoning behind this recommendation is best illustrated with a real-world
|
||||
example. During the early days of Electron, reliable detection of network
|
||||
connectivity was a problem, resulting many apps to use a module that exposed a
|
||||
connectivity was a problem, resulting in many apps using a module that exposed a
|
||||
simple `isOnline()` method.
|
||||
|
||||
That module detected your network connectivity by attempting to reach out to a
|
||||
|
||||
@@ -83,7 +83,7 @@ terminated as well.
|
||||
|
||||
The main process also controls your application's lifecycle through Electron's
|
||||
[`app`][app] module. This module provides a large set of events and methods
|
||||
that you can use to add custom application behaviour (for instance, programmatically
|
||||
that you can use to add custom application behavior (for instance, programmatically
|
||||
quitting your application, modifying the application dock, or showing an About panel).
|
||||
|
||||
As a practical example, the app shown in the [quick start guide][quick-start-lifecycle]
|
||||
|
||||
@@ -17,7 +17,7 @@ further configuration. If you want to disable the sandbox for a process, see the
|
||||
[Disabling the sandbox for a single process](#disabling-the-sandbox-for-a-single-process)
|
||||
section.
|
||||
|
||||
## Sandbox behaviour in Electron
|
||||
## Sandbox behavior in Electron
|
||||
|
||||
Sandboxed processes in Electron behave _mostly_ in the same way as Chromium's do, but
|
||||
Electron has a few additional concepts to consider because it interfaces with Node.js.
|
||||
|
||||
@@ -79,8 +79,8 @@ will be able to execute native code on the user's machine.
|
||||
Under no circumstances should you load and execute remote code with
|
||||
Node.js integration enabled. Instead, use only local files (packaged together
|
||||
with your application) to execute Node.js code. To display remote content, use
|
||||
the [`<webview>`][webview-tag] tag or a [`WebContentsView`][web-contents-view]
|
||||
and make sure to disable the `nodeIntegration` and enable `contextIsolation`.
|
||||
the [`<webview>`][webview-tag] tag or [`BrowserView`][browser-view], make sure
|
||||
to disable the `nodeIntegration` and enable `contextIsolation`.
|
||||
:::
|
||||
|
||||
:::info Electron security warnings
|
||||
@@ -114,6 +114,8 @@ You should at least follow these steps to improve the security of your applicati
|
||||
15. [Do not use `shell.openExternal` with untrusted content](#15-do-not-use-shellopenexternal-with-untrusted-content)
|
||||
16. [Use a current version of Electron](#16-use-a-current-version-of-electron)
|
||||
17. [Validate the `sender` of all IPC messages](#17-validate-the-sender-of-all-ipc-messages)
|
||||
18. [Avoid usage of the `file://` protocol and prefer usage of custom protocols](#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols)
|
||||
19. [Check which fuses you can change](#19-check-which-fuses-you-can-change)
|
||||
|
||||
To automate the detection of misconfigurations and insecure patterns, it is
|
||||
possible to use
|
||||
@@ -166,7 +168,7 @@ This recommendation is the default behavior in Electron since 5.0.0.
|
||||
:::
|
||||
|
||||
It is paramount that you do not enable Node.js integration in any renderer
|
||||
([`BrowserWindow`][browser-window], [`WebContentsView`][web-contents-view], or
|
||||
([`BrowserWindow`][browser-window], [`BrowserView`][browser-view], or
|
||||
[`<webview>`][webview-tag]) that loads remote content. The goal is to limit the
|
||||
powers you grant to remote content, thus making it dramatically more difficult
|
||||
for an attacker to harm your users should they gain the ability to execute
|
||||
@@ -306,8 +308,8 @@ This recommendation is Electron's default.
|
||||
|
||||
You may have already guessed that disabling the `webSecurity` property on a
|
||||
renderer process ([`BrowserWindow`][browser-window],
|
||||
[`WebContentsView`][web-contents-view], or [`<webview>`][webview-tag]) disables
|
||||
crucial security features.
|
||||
[`BrowserView`][browser-view], or [`<webview>`][webview-tag]) disables crucial
|
||||
security features.
|
||||
|
||||
Do not disable `webSecurity` in production applications.
|
||||
|
||||
@@ -780,12 +782,34 @@ set of files.
|
||||
Follow the [`protocol.handle`](../api/protocol.md#protocolhandlescheme-handler) examples to
|
||||
learn how to serve files / content from a custom protocol.
|
||||
|
||||
### 19. Check which fuses you can change
|
||||
|
||||
Electron ships with a number of options that can be useful but a large portion of
|
||||
applications probably don't need. In order to avoid having to build your own version of
|
||||
Electron, these can be turned off or on using [Fuses](./fuses.md).
|
||||
|
||||
#### Why?
|
||||
|
||||
Some fuses, like `runAsNode` and `nodeCliInspect`, allow the application to behave differently
|
||||
when run from the command line using specific environment variables or CLI arguments. These
|
||||
can be used to execute commands on the device through your application.
|
||||
|
||||
This can let external scripts run commands that they potentially would not be allowed to, but
|
||||
that your application might have the rights for.
|
||||
|
||||
#### How?
|
||||
|
||||
We've made a module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make
|
||||
flipping these fuses easy. Check out the README of that module for more details on usage and
|
||||
potential error cases, and refer to
|
||||
[How do I flip the fuses?](./fuses.md#how-do-i-flip-the-fuses) in our documentation.
|
||||
|
||||
[breaking-changes]: ../breaking-changes.md
|
||||
[browser-window]: ../api/browser-window.md
|
||||
[browser-view]: ../api/browser-view.md
|
||||
[webview-tag]: ../api/webview-tag.md
|
||||
[web-contents-view]: ../api/web-contents-view.md
|
||||
[responsible-disclosure]: https://en.wikipedia.org/wiki/Responsible_disclosure
|
||||
[web-contents]: ../api/web-contents.md
|
||||
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandlerhandler
|
||||
[will-navigate]: ../api/web-contents.md#event-will-navigate
|
||||
[open-external]: ../api/shell.md#shellopenexternalurl-options
|
||||
[responsible-disclosure]: https://en.wikipedia.org/wiki/Responsible_disclosure
|
||||
|
||||
@@ -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 <code>electron/main</code>.
|
||||
main process modules from `electron/main`.
|
||||
|
||||
```js
|
||||
const { app, BrowserWindow } = require('electron/main')
|
||||
|
||||
@@ -152,7 +152,7 @@ command that can handle the version bumping and tagging for you.
|
||||
#### Bonus: Publishing in GitHub Actions
|
||||
|
||||
Publishing locally can be painful, especially because you can only create distributables
|
||||
for your host operating system (i.e. you can't publish a Window `.exe` file from macOS).
|
||||
for your host operating system (i.e. you can't publish a Windows `.exe` file from macOS).
|
||||
|
||||
A solution for this would be to publish your app via automation workflows
|
||||
such as [GitHub Actions][], which can run tasks in the
|
||||
|
||||
@@ -42,15 +42,16 @@ Compared to an `<iframe>`, `<webview>` tends to be slightly slower but offers
|
||||
much greater control in loading and communicating with the third-party content
|
||||
and handling various events.
|
||||
|
||||
### WebContentsView
|
||||
### BrowserViews
|
||||
|
||||
[`WebContentsView`](../api/web-contents-view.md)s are not a part of the
|
||||
DOM—instead, they are created, controlled, positioned, and sized by your
|
||||
Main process. Using `WebContentsView`, you can combine and layer many pages
|
||||
together in the same [`BaseWindow`](../api/base-window.md).
|
||||
[BrowserViews](../api/browser-view.md) are not a part of the DOM - instead,
|
||||
they are created in and controlled by your Main process. They are simply
|
||||
another layer of web content on top of your existing window. This means
|
||||
that they are completely separate from your own `BrowserWindow` content and
|
||||
their position is not controlled by the DOM or CSS. Instead, it is controlled
|
||||
by setting the bounds in the Main process.
|
||||
|
||||
`WebContentsView`s offer the greatest control over their contents, since they
|
||||
implement the `webContents` similarly to how `BrowserWindow` does it. However,
|
||||
as `WebContentsView`s are not elements inside the DOM, positioning them
|
||||
accurately with respect to DOM content requires coordination between the
|
||||
Main and Renderer processes.
|
||||
`BrowserViews` offer the greatest control over their contents, since they
|
||||
implement the `webContents` similarly to how the `BrowserWindow` does it.
|
||||
However, as `BrowserViews` are not a part of your DOM, but are rather overlaid
|
||||
on top of them, you will have to manage their position manually.
|
||||
|
||||
@@ -77,6 +77,7 @@ template("electron_extra_paks") {
|
||||
"//content:content_resources",
|
||||
"//content/browser/resources/gpu:resources",
|
||||
"//content/browser/resources/media:resources",
|
||||
"//content/browser/resources/process:resources",
|
||||
"//content/browser/tracing:resources",
|
||||
"//content/browser/webrtc/resources",
|
||||
"//electron:resources",
|
||||
@@ -96,6 +97,7 @@ template("electron_extra_paks") {
|
||||
# New paks should be added here by default.
|
||||
sources += [
|
||||
"$root_gen_dir/content/browser/devtools/devtools_resources.pak",
|
||||
"$root_gen_dir/content/process_resources.pak",
|
||||
"$root_gen_dir/ui/resources/webui_resources.pak",
|
||||
]
|
||||
deps += [ "//content/browser/devtools:devtools_resources" ]
|
||||
|
||||
@@ -4,7 +4,6 @@ auto_filenames = {
|
||||
"docs/api/accelerator.md",
|
||||
"docs/api/app.md",
|
||||
"docs/api/auto-updater.md",
|
||||
"docs/api/base-window.md",
|
||||
"docs/api/browser-view.md",
|
||||
"docs/api/browser-window.md",
|
||||
"docs/api/client-request.md",
|
||||
@@ -34,6 +33,7 @@ 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",
|
||||
@@ -64,8 +64,6 @@ auto_filenames = {
|
||||
"docs/api/touch-bar.md",
|
||||
"docs/api/tray.md",
|
||||
"docs/api/utility-process.md",
|
||||
"docs/api/view.md",
|
||||
"docs/api/web-contents-view.md",
|
||||
"docs/api/web-contents.md",
|
||||
"docs/api/web-frame-main.md",
|
||||
"docs/api/web-frame.md",
|
||||
@@ -73,7 +71,6 @@ auto_filenames = {
|
||||
"docs/api/web-utils.md",
|
||||
"docs/api/webview-tag.md",
|
||||
"docs/api/window-open.md",
|
||||
"docs/api/structures/base-window-options.md",
|
||||
"docs/api/structures/bluetooth-device.md",
|
||||
"docs/api/structures/browser-window-options.md",
|
||||
"docs/api/structures/certificate-principal.md",
|
||||
@@ -118,6 +115,7 @@ auto_filenames = {
|
||||
"docs/api/structures/protocol-request.md",
|
||||
"docs/api/structures/protocol-response-upload-data.md",
|
||||
"docs/api/structures/protocol-response.md",
|
||||
"docs/api/structures/proxy-config.md",
|
||||
"docs/api/structures/rectangle.md",
|
||||
"docs/api/structures/referrer.md",
|
||||
"docs/api/structures/render-process-gone-details.md",
|
||||
@@ -260,7 +258,6 @@ auto_filenames = {
|
||||
"lib/common/deprecate.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"package.json",
|
||||
@@ -277,7 +274,6 @@ auto_filenames = {
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/clipboard.ts",
|
||||
@@ -316,7 +312,6 @@ auto_filenames = {
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/clipboard.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
@@ -336,10 +331,9 @@ auto_filenames = {
|
||||
"typings/internal-electron.d.ts",
|
||||
]
|
||||
|
||||
asar_bundle_deps = [
|
||||
"lib/asar/fs-wrapper.ts",
|
||||
"lib/asar/init.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
node_bundle_deps = [
|
||||
"lib/node/asar-fs-wrapper.ts",
|
||||
"lib/node/init.ts",
|
||||
"package.json",
|
||||
"tsconfig.electron.json",
|
||||
"tsconfig.json",
|
||||
@@ -353,7 +347,6 @@ auto_filenames = {
|
||||
"lib/common/api/net-client-request.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
"lib/utility/api/exports/electron.ts",
|
||||
"lib/utility/api/module-list.ts",
|
||||
|
||||
@@ -34,7 +34,7 @@ filenames = {
|
||||
"shell/browser/notifications/linux/notification_presenter_linux.h",
|
||||
"shell/browser/relauncher_linux.cc",
|
||||
"shell/browser/ui/electron_desktop_window_tree_host_linux.cc",
|
||||
"shell/browser/ui/file_dialog_gtk.cc",
|
||||
"shell/browser/ui/file_dialog_linux.cc",
|
||||
"shell/browser/ui/gtk/menu_gtk.cc",
|
||||
"shell/browser/ui/gtk/menu_gtk.h",
|
||||
"shell/browser/ui/gtk/menu_util.cc",
|
||||
@@ -118,8 +118,6 @@ filenames = {
|
||||
lib_sources_mac = [
|
||||
"shell/app/electron_main_delegate_mac.h",
|
||||
"shell/app/electron_main_delegate_mac.mm",
|
||||
"shell/browser/animation_util.h",
|
||||
"shell/browser/animation_util_mac.mm",
|
||||
"shell/browser/api/electron_api_app_mac.mm",
|
||||
"shell/browser/api/electron_api_menu_mac.h",
|
||||
"shell/browser/api/electron_api_menu_mac.mm",
|
||||
@@ -143,6 +141,8 @@ filenames = {
|
||||
"shell/browser/mac/in_app_purchase_product.mm",
|
||||
"shell/browser/mac/in_app_purchase.h",
|
||||
"shell/browser/mac/in_app_purchase.mm",
|
||||
"shell/browser/native_browser_view_mac.h",
|
||||
"shell/browser/native_browser_view_mac.mm",
|
||||
"shell/browser/native_window_mac.h",
|
||||
"shell/browser/native_window_mac.mm",
|
||||
"shell/browser/notifications/mac/cocoa_notification.h",
|
||||
@@ -209,6 +209,8 @@ filenames = {
|
||||
lib_sources_views = [
|
||||
"shell/browser/api/electron_api_menu_views.cc",
|
||||
"shell/browser/api/electron_api_menu_views.h",
|
||||
"shell/browser/native_browser_view_views.cc",
|
||||
"shell/browser/native_browser_view_views.h",
|
||||
"shell/browser/native_window_views.cc",
|
||||
"shell/browser/native_window_views.h",
|
||||
"shell/browser/ui/drag_util_views.cc",
|
||||
@@ -253,6 +255,8 @@ filenames = {
|
||||
"shell/browser/api/electron_api_auto_updater.h",
|
||||
"shell/browser/api/electron_api_base_window.cc",
|
||||
"shell/browser/api/electron_api_base_window.h",
|
||||
"shell/browser/api/electron_api_browser_view.cc",
|
||||
"shell/browser/api/electron_api_browser_view.h",
|
||||
"shell/browser/api/electron_api_browser_window.cc",
|
||||
"shell/browser/api/electron_api_browser_window.h",
|
||||
"shell/browser/api/electron_api_content_tracing.cc",
|
||||
@@ -332,8 +336,6 @@ filenames = {
|
||||
"shell/browser/api/save_page_handler.h",
|
||||
"shell/browser/api/ui_event.cc",
|
||||
"shell/browser/api/ui_event.h",
|
||||
"shell/browser/api/views/electron_api_image_view.cc",
|
||||
"shell/browser/api/views/electron_api_image_view.h",
|
||||
"shell/browser/auto_updater.cc",
|
||||
"shell/browser/auto_updater.h",
|
||||
"shell/browser/background_throttling_source.h",
|
||||
@@ -383,6 +385,7 @@ filenames = {
|
||||
"shell/browser/extended_web_contents_observer.h",
|
||||
"shell/browser/feature_list.cc",
|
||||
"shell/browser/feature_list.h",
|
||||
"shell/browser/feature_list_mac.mm",
|
||||
"shell/browser/file_select_helper.cc",
|
||||
"shell/browser/file_select_helper.h",
|
||||
"shell/browser/file_select_helper_mac.mm",
|
||||
@@ -408,6 +411,8 @@ filenames = {
|
||||
"shell/browser/media/media_device_id_salt.h",
|
||||
"shell/browser/microtasks_runner.cc",
|
||||
"shell/browser/microtasks_runner.h",
|
||||
"shell/browser/native_browser_view.cc",
|
||||
"shell/browser/native_browser_view.h",
|
||||
"shell/browser/native_window.cc",
|
||||
"shell/browser/native_window.h",
|
||||
"shell/browser/native_window_features.cc",
|
||||
@@ -656,7 +661,6 @@ filenames = {
|
||||
"shell/common/node_includes.h",
|
||||
"shell/common/node_util.cc",
|
||||
"shell/common/node_util.h",
|
||||
"shell/common/node_util_mac.mm",
|
||||
"shell/common/options_switches.cc",
|
||||
"shell/common/options_switches.h",
|
||||
"shell/common/platform_util.cc",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { wrapFsWithAsar } from './fs-wrapper';
|
||||
|
||||
wrapFsWithAsar(require('fs'));
|
||||
@@ -38,6 +38,8 @@ const spawnUpdate = async function (args: string[], options: { detached: boolean
|
||||
spawnedProcess.stderr.on('data', (data) => { stderr += data; });
|
||||
|
||||
spawnedProcess.on('error', (error) => {
|
||||
spawnedProcess = undefined;
|
||||
spawnedArgs = [];
|
||||
reject(error);
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ const { BaseWindow } = process._linkedBinding('electron_browser_base_window') as
|
||||
|
||||
Object.setPrototypeOf(BaseWindow.prototype, EventEmitter.prototype);
|
||||
|
||||
BaseWindow.prototype._init = function (this: TLWT) {
|
||||
BaseWindow.prototype._init = function () {
|
||||
// Avoid recursive require.
|
||||
const { app } = require('electron');
|
||||
|
||||
@@ -103,7 +103,7 @@ Object.defineProperty(BaseWindow.prototype, 'movable', {
|
||||
});
|
||||
|
||||
BaseWindow.getFocusedWindow = () => {
|
||||
return BaseWindow.getAllWindows().find((win) => win.isFocused()) ?? null;
|
||||
return BaseWindow.getAllWindows().find((win) => win.isFocused());
|
||||
};
|
||||
|
||||
module.exports = BaseWindow;
|
||||
|
||||
@@ -1,120 +1,3 @@
|
||||
import { BrowserWindow, AutoResizeOptions, Rectangle, WebContentsView, WebPreferences, WebContents } from 'electron/main';
|
||||
const { BrowserView } = process._linkedBinding('electron_browser_browser_view');
|
||||
|
||||
const v8Util = process._linkedBinding('electron_common_v8_util');
|
||||
|
||||
export default class BrowserView {
|
||||
#webContentsView: WebContentsView;
|
||||
|
||||
// AutoResize state
|
||||
#resizeListener: ((...args: any[]) => void) | null = null;
|
||||
#lastWindowSize: {width: number, height: number} = { width: 0, height: 0 };
|
||||
#autoResizeFlags: AutoResizeOptions = {};
|
||||
|
||||
constructor (options: {webPreferences: WebPreferences, webContents?: WebContents} = { webPreferences: {} }) {
|
||||
const { webPreferences = {}, webContents } = options;
|
||||
if (webContents) {
|
||||
v8Util.setHiddenValue(webPreferences, 'webContents', webContents);
|
||||
}
|
||||
webPreferences.type = 'browserView';
|
||||
this.#webContentsView = new WebContentsView({ webPreferences });
|
||||
}
|
||||
|
||||
get webContents () {
|
||||
return this.#webContentsView.webContents;
|
||||
}
|
||||
|
||||
setBounds (bounds: Rectangle) {
|
||||
this.#webContentsView.setBounds(bounds);
|
||||
this.#autoHorizontalProportion = null;
|
||||
this.#autoVerticalProportion = null;
|
||||
}
|
||||
|
||||
getBounds () {
|
||||
return this.#webContentsView.getBounds();
|
||||
}
|
||||
|
||||
setAutoResize (options: AutoResizeOptions) {
|
||||
if (options == null || typeof options !== 'object') { throw new Error('Invalid auto resize options'); }
|
||||
this.#autoResizeFlags = {
|
||||
width: !!options.width,
|
||||
height: !!options.height,
|
||||
horizontal: !!options.horizontal,
|
||||
vertical: !!options.vertical
|
||||
};
|
||||
this.#autoHorizontalProportion = null;
|
||||
this.#autoVerticalProportion = null;
|
||||
}
|
||||
|
||||
setBackgroundColor (color: string) {
|
||||
this.#webContentsView.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
// Internal methods
|
||||
get ownerWindow (): BrowserWindow | null {
|
||||
return !this.webContents.isDestroyed() ? this.webContents.getOwnerBrowserWindow() : null;
|
||||
}
|
||||
|
||||
set ownerWindow (w: BrowserWindow | null) {
|
||||
if (this.webContents.isDestroyed()) return;
|
||||
const oldWindow = this.webContents.getOwnerBrowserWindow();
|
||||
if (oldWindow && this.#resizeListener) {
|
||||
oldWindow.off('resize', this.#resizeListener);
|
||||
this.#resizeListener = null;
|
||||
}
|
||||
this.webContents._setOwnerWindow(w);
|
||||
if (w) {
|
||||
this.#lastWindowSize = w.getBounds();
|
||||
w.on('resize', this.#resizeListener = this.#autoResize.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
#autoHorizontalProportion: {width: number, left: number} | null = null;
|
||||
#autoVerticalProportion: {height: number, top: number} | null = null;
|
||||
#autoResize () {
|
||||
if (!this.ownerWindow) throw new Error('Electron bug: #autoResize called without owner window');
|
||||
if (this.#autoResizeFlags.horizontal && this.#autoHorizontalProportion == null) {
|
||||
const viewBounds = this.#webContentsView.getBounds();
|
||||
this.#autoHorizontalProportion = {
|
||||
width: this.#lastWindowSize.width / viewBounds.width,
|
||||
left: this.#lastWindowSize.width / viewBounds.x
|
||||
};
|
||||
}
|
||||
if (this.#autoResizeFlags.vertical && this.#autoVerticalProportion == null) {
|
||||
const viewBounds = this.#webContentsView.getBounds();
|
||||
this.#autoVerticalProportion = {
|
||||
height: this.#lastWindowSize.height / viewBounds.height,
|
||||
top: this.#lastWindowSize.height / viewBounds.y
|
||||
};
|
||||
}
|
||||
const newBounds = this.ownerWindow.getBounds();
|
||||
let widthDelta = newBounds.width - this.#lastWindowSize.width;
|
||||
let heightDelta = newBounds.height - this.#lastWindowSize.height;
|
||||
if (!this.#autoResizeFlags.width) widthDelta = 0;
|
||||
if (!this.#autoResizeFlags.height) heightDelta = 0;
|
||||
|
||||
const newViewBounds = this.#webContentsView.getBounds();
|
||||
if (widthDelta || heightDelta) {
|
||||
this.#webContentsView.setBounds({
|
||||
...newViewBounds,
|
||||
width: newViewBounds.width + widthDelta,
|
||||
height: newViewBounds.height + heightDelta
|
||||
});
|
||||
}
|
||||
|
||||
if (this.#autoHorizontalProportion) {
|
||||
newViewBounds.width = newBounds.width / this.#autoHorizontalProportion.width;
|
||||
newViewBounds.x = newBounds.width / this.#autoHorizontalProportion.left;
|
||||
}
|
||||
if (this.#autoVerticalProportion) {
|
||||
newViewBounds.height = newBounds.height / this.#autoVerticalProportion.height;
|
||||
newViewBounds.y = newBounds.y / this.#autoVerticalProportion.top;
|
||||
}
|
||||
if (this.#autoHorizontalProportion || this.#autoVerticalProportion) {
|
||||
this.#webContentsView.setBounds(newViewBounds);
|
||||
}
|
||||
}
|
||||
|
||||
get webContentsView () {
|
||||
return this.#webContentsView;
|
||||
}
|
||||
}
|
||||
export default BrowserView;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BaseWindow, WebContents, TouchBar, BrowserView } from 'electron/main';
|
||||
import { BaseWindow, WebContents, BrowserView, TouchBar } from 'electron/main';
|
||||
import type { BrowserWindow as BWT } from 'electron/main';
|
||||
const { BrowserWindow } = process._linkedBinding('electron_browser_window') as { BrowserWindow: typeof BWT };
|
||||
|
||||
@@ -6,7 +6,7 @@ Object.setPrototypeOf(BrowserWindow.prototype, BaseWindow.prototype);
|
||||
|
||||
BrowserWindow.prototype._init = function (this: BWT) {
|
||||
// Call parent class's _init.
|
||||
(BaseWindow.prototype as any)._init.call(this);
|
||||
BaseWindow.prototype._init.call(this);
|
||||
|
||||
// Avoid recursive require.
|
||||
const { app } = require('electron');
|
||||
@@ -52,12 +52,6 @@ BrowserWindow.prototype._init = function (this: BWT) {
|
||||
this.on(event as any, visibilityChanged);
|
||||
}
|
||||
|
||||
this._browserViews = [];
|
||||
|
||||
this.on('close', () => {
|
||||
this._browserViews.forEach(b => b.webContents?.close({ waitForBeforeUnload: true }));
|
||||
});
|
||||
|
||||
// Notify the creation of the window.
|
||||
app.emit('browser-window-created', { preventDefault () {} }, this);
|
||||
|
||||
@@ -174,42 +168,4 @@ BrowserWindow.prototype.setBackgroundThrottling = function (allowed: boolean) {
|
||||
return this.webContents.setBackgroundThrottling(allowed);
|
||||
};
|
||||
|
||||
BrowserWindow.prototype.addBrowserView = function (browserView: BrowserView) {
|
||||
if (browserView.ownerWindow) { browserView.ownerWindow.removeBrowserView(browserView); }
|
||||
this.contentView.addChildView(browserView.webContentsView);
|
||||
browserView.ownerWindow = this;
|
||||
browserView.webContents._setOwnerWindow(this);
|
||||
this._browserViews.push(browserView);
|
||||
};
|
||||
|
||||
BrowserWindow.prototype.setBrowserView = function (browserView: BrowserView) {
|
||||
this._browserViews.forEach(bv => {
|
||||
this.removeBrowserView(bv);
|
||||
});
|
||||
if (browserView) { this.addBrowserView(browserView); }
|
||||
};
|
||||
|
||||
BrowserWindow.prototype.removeBrowserView = function (browserView: BrowserView) {
|
||||
const idx = this._browserViews.indexOf(browserView);
|
||||
if (idx >= 0) {
|
||||
this.contentView.removeChildView(browserView.webContentsView);
|
||||
browserView.ownerWindow = null;
|
||||
this._browserViews.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
|
||||
BrowserWindow.prototype.getBrowserView = function () {
|
||||
if (this._browserViews.length > 1) { throw new Error('This BrowserWindow has multiple BrowserViews, use getBrowserViews() instead'); }
|
||||
return this._browserViews[0] ?? null;
|
||||
};
|
||||
|
||||
BrowserWindow.prototype.getBrowserViews = function () {
|
||||
return [...this._browserViews];
|
||||
};
|
||||
|
||||
BrowserWindow.prototype.setTopBrowserView = function (browserView: BrowserView) {
|
||||
if (browserView.ownerWindow !== this) { throw new Error('Given BrowserView is not attached to the window'); }
|
||||
this.addBrowserView(browserView);
|
||||
};
|
||||
|
||||
module.exports = BrowserWindow;
|
||||
|
||||
@@ -14,7 +14,6 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'dialog', loader: () => require('./dialog') },
|
||||
{ name: 'globalShortcut', loader: () => require('./global-shortcut') },
|
||||
{ name: 'ipcMain', loader: () => require('./ipc-main') },
|
||||
{ name: 'ImageView', loader: () => require('./views/image-view') },
|
||||
{ name: 'inAppPurchase', loader: () => require('./in-app-purchase') },
|
||||
{ name: 'Menu', loader: () => require('./menu') },
|
||||
{ name: 'MenuItem', loader: () => require('./menu-item') },
|
||||
@@ -40,3 +39,9 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'WebContentsView', loader: () => require('./web-contents-view') },
|
||||
{ name: 'webFrameMain', loader: () => require('./web-frame-main') }
|
||||
];
|
||||
|
||||
if (BUILDFLAG(ENABLE_VIEWS_API)) {
|
||||
browserModuleList.push(
|
||||
{ name: 'ImageView', loader: () => require('./views/image-view') }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,21 @@ function makeStreamFromPipe (pipe: any): ReadableStream {
|
||||
});
|
||||
}
|
||||
|
||||
function makeStreamFromFileInfo ({
|
||||
filePath,
|
||||
offset = 0,
|
||||
length = -1
|
||||
}: {
|
||||
filePath: string;
|
||||
offset?: number;
|
||||
length?: number;
|
||||
}): ReadableStream {
|
||||
return Readable.toWeb(createReadStream(filePath, {
|
||||
start: offset,
|
||||
end: length >= 0 ? offset + length : undefined
|
||||
}));
|
||||
}
|
||||
|
||||
function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): RequestInit['body'] {
|
||||
if (!uploadData) return null;
|
||||
// Optimization: skip creating a stream if the request is just a single buffer.
|
||||
@@ -37,30 +52,42 @@ function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): Reque
|
||||
const chunks = [...uploadData] as any[]; // TODO: types are wrong
|
||||
let current: ReadableStreamDefaultReader | null = null;
|
||||
return new ReadableStream({
|
||||
pull (controller) {
|
||||
async pull (controller) {
|
||||
if (current) {
|
||||
current.read().then(({ done, value }) => {
|
||||
const { done, value } = await current.read();
|
||||
// (done => value === undefined) as per WHATWG spec
|
||||
if (done) {
|
||||
current = null;
|
||||
return this.pull!(controller);
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
if (done) current = null;
|
||||
}, (err) => {
|
||||
controller.error(err);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!chunks.length) { return controller.close(); }
|
||||
const chunk = chunks.shift()!;
|
||||
if (chunk.type === 'rawData') { controller.enqueue(chunk.bytes); } else if (chunk.type === 'file') {
|
||||
current = Readable.toWeb(createReadStream(chunk.filePath, { start: chunk.offset ?? 0, end: chunk.length >= 0 ? chunk.offset + chunk.length : undefined })).getReader();
|
||||
this.pull!(controller);
|
||||
if (chunk.type === 'rawData') {
|
||||
controller.enqueue(chunk.bytes);
|
||||
} else if (chunk.type === 'file') {
|
||||
current = makeStreamFromFileInfo(chunk).getReader();
|
||||
return this.pull!(controller);
|
||||
} else if (chunk.type === 'stream') {
|
||||
current = makeStreamFromPipe(chunk.body).getReader();
|
||||
this.pull!(controller);
|
||||
return this.pull!(controller);
|
||||
} else if (chunk.type === 'blob') {
|
||||
// Note that even though `getBlobData()` is a `Session` API, it doesn't
|
||||
// actually use the `Session` context. Its implementation solely relies
|
||||
// on global variables which allows us to implement this feature without
|
||||
// knowledge of the `Session` associated with the current request by
|
||||
// always pulling `Blob` data out of the default `Session`.
|
||||
controller.enqueue(await session.defaultSession.getBlobData(chunk.blobUUID));
|
||||
} else {
|
||||
throw new Error(`Unknown upload data chunk type: ${chunk.type}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}) as RequestInit['body'];
|
||||
}
|
||||
|
||||
// TODO(codebytere): Use Object.hasOwn() once we update to ECMAScript 2022.
|
||||
function validateResponse (res: Response) {
|
||||
if (!res || typeof res !== 'object') return false;
|
||||
|
||||
@@ -85,8 +112,12 @@ Protocol.prototype.handle = function (this: Electron.Protocol, scheme: string, h
|
||||
const success = register.call(this, scheme, async (preq: ProtocolRequest, cb: any) => {
|
||||
try {
|
||||
const body = convertToRequestBody(preq.uploadData);
|
||||
const headers = new Headers(preq.headers);
|
||||
if (headers.get('origin') === 'null') {
|
||||
headers.delete('origin');
|
||||
}
|
||||
const req = new Request(preq.url, {
|
||||
headers: preq.headers,
|
||||
headers,
|
||||
method: preq.method,
|
||||
referrer: preq.referrer,
|
||||
body,
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { EventEmitter } from 'events';
|
||||
const { View } = process._linkedBinding('electron_browser_view');
|
||||
|
||||
Object.setPrototypeOf((View as any).prototype, EventEmitter.prototype);
|
||||
|
||||
export default View;
|
||||
|
||||
@@ -220,6 +220,16 @@ function parsePageSize (pageSize: string | ElectronInternal.PageSize) {
|
||||
let pendingPromise: Promise<any> | undefined;
|
||||
WebContents.prototype.printToPDF = async function (options) {
|
||||
const margins = checkType(options.margins ?? {}, 'object', 'margins');
|
||||
const pageSize = parsePageSize(options.pageSize ?? 'letter');
|
||||
|
||||
const { top, bottom, left, right } = margins;
|
||||
const validHeight = [top, bottom].every(u => u === undefined || u <= pageSize.paperHeight);
|
||||
const validWidth = [left, right].every(u => u === undefined || u <= pageSize.paperWidth);
|
||||
|
||||
if (!validHeight || !validWidth) {
|
||||
throw new Error('margins must be less than or equal to pageSize');
|
||||
}
|
||||
|
||||
const printSettings = {
|
||||
requestID: getNextId(),
|
||||
landscape: checkType(options.landscape ?? false, 'boolean', 'landscape'),
|
||||
@@ -235,7 +245,8 @@ WebContents.prototype.printToPDF = async function (options) {
|
||||
pageRanges: checkType(options.pageRanges ?? '', 'string', 'pageRanges'),
|
||||
preferCSSPageSize: checkType(options.preferCSSPageSize ?? false, 'boolean', 'preferCSSPageSize'),
|
||||
generateTaggedPDF: checkType(options.generateTaggedPDF ?? false, 'boolean', 'generateTaggedPDF'),
|
||||
...parsePageSize(options.pageSize ?? 'letter')
|
||||
generateDocumentOutline: checkType(options.generateDocumentOutline ?? false, 'boolean', 'generateDocumentOutline'),
|
||||
...pageSize
|
||||
};
|
||||
|
||||
if (this._printToPDF) {
|
||||
@@ -252,13 +263,11 @@ WebContents.prototype.printToPDF = async function (options) {
|
||||
|
||||
// TODO(codebytere): deduplicate argument sanitization by moving rest of
|
||||
// print param logic into new file shared between printToPDF and print
|
||||
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions, callback) {
|
||||
if (typeof options !== 'object') {
|
||||
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions = {}, callback) {
|
||||
if (typeof options !== 'object' || options == null) {
|
||||
throw new TypeError('webContents.print(): Invalid print settings specified.');
|
||||
}
|
||||
|
||||
const printSettings: Record<string, any> = { ...options };
|
||||
|
||||
const pageSize = options.pageSize ?? 'A4';
|
||||
if (typeof pageSize === 'object') {
|
||||
if (!pageSize.height || !pageSize.width) {
|
||||
@@ -272,7 +281,7 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
|
||||
throw new RangeError('height and width properties must be minimum 352 microns.');
|
||||
}
|
||||
|
||||
printSettings.mediaSize = {
|
||||
options.mediaSize = {
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
@@ -284,7 +293,7 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
|
||||
};
|
||||
} else if (typeof pageSize === 'string' && PDFPageSizes[pageSize]) {
|
||||
const mediaSize = PDFPageSizes[pageSize];
|
||||
printSettings.mediaSize = {
|
||||
options.mediaSize = {
|
||||
...mediaSize,
|
||||
imageable_area_left_microns: 0,
|
||||
imageable_area_bottom_microns: 0,
|
||||
@@ -297,9 +306,9 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
|
||||
|
||||
if (this._print) {
|
||||
if (callback) {
|
||||
this._print(printSettings, callback);
|
||||
this._print(options, callback);
|
||||
} else {
|
||||
this._print(printSettings);
|
||||
this._print(options);
|
||||
}
|
||||
} else {
|
||||
console.error('Error: Printing feature is disabled.');
|
||||
@@ -333,31 +342,24 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||
}));
|
||||
};
|
||||
|
||||
type LoadError = { errorCode: number, errorDescription: string, url: string };
|
||||
|
||||
WebContents.prototype.loadURL = function (url, options) {
|
||||
const p = new Promise<void>((resolve, reject) => {
|
||||
const resolveAndCleanup = () => {
|
||||
removeListeners();
|
||||
resolve();
|
||||
};
|
||||
let error: LoadError | undefined;
|
||||
const rejectAndCleanup = ({ errorCode, errorDescription, url }: LoadError) => {
|
||||
const rejectAndCleanup = (errorCode: number, errorDescription: string, url: string) => {
|
||||
const err = new Error(`${errorDescription} (${errorCode}) loading '${typeof url === 'string' ? url.substr(0, 2048) : url}'`);
|
||||
Object.assign(err, { errno: errorCode, code: errorDescription, url });
|
||||
removeListeners();
|
||||
reject(err);
|
||||
};
|
||||
const finishListener = () => {
|
||||
if (error) {
|
||||
rejectAndCleanup(error);
|
||||
} else {
|
||||
resolveAndCleanup();
|
||||
}
|
||||
resolveAndCleanup();
|
||||
};
|
||||
const failListener = (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
|
||||
if (!error && isMainFrame) {
|
||||
error = { errorCode, errorDescription, url: validatedURL };
|
||||
if (isMainFrame) {
|
||||
rejectAndCleanup(errorCode, errorDescription, validatedURL);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -375,7 +377,7 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
// considered navigation events but are triggered with isSameDocument.
|
||||
// We can ignore these to allow virtual routing on page load as long
|
||||
// as the routing does not leave the document
|
||||
return rejectAndCleanup({ errorCode: -3, errorDescription: 'ERR_ABORTED', url });
|
||||
return rejectAndCleanup(-3, 'ERR_ABORTED', url);
|
||||
}
|
||||
browserInitiatedInPageNavigation = navigationStarted && isSameDocument;
|
||||
navigationStarted = true;
|
||||
@@ -390,10 +392,7 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
// TODO(jeremy): enumerate all the cases in which this can happen. If
|
||||
// the only one is with a bad scheme, perhaps ERR_INVALID_ARGUMENT
|
||||
// would be more appropriate.
|
||||
if (!error) {
|
||||
error = { errorCode: -2, errorDescription: 'ERR_FAILED', url: url };
|
||||
}
|
||||
finishListener();
|
||||
rejectAndCleanup(-2, 'ERR_FAILED', url);
|
||||
};
|
||||
const finishListenerWhenUserInitiatedNavigation = () => {
|
||||
if (!browserInitiatedInPageNavigation) {
|
||||
@@ -519,6 +518,17 @@ 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);
|
||||
@@ -592,16 +602,6 @@ WebContents.prototype._init = function () {
|
||||
}
|
||||
});
|
||||
|
||||
this.on('-before-unload-fired' as any, function (this: Electron.WebContents, event: Electron.Event, proceed: boolean) {
|
||||
const type = this.getType();
|
||||
// These are the "interactive" types, i.e. ones a user might be looking at.
|
||||
// All other types should ignore the "proceed" signal and unload
|
||||
// regardless.
|
||||
if (type === 'window' || type === 'offscreen' || type === 'browserView') {
|
||||
if (!proceed) { return event.preventDefault(); }
|
||||
}
|
||||
});
|
||||
|
||||
// The devtools requests the webContents to reload.
|
||||
this.on('devtools-reload-page', function (this: Electron.WebContents) {
|
||||
this.reload();
|
||||
@@ -786,7 +786,7 @@ WebContents.prototype._init = function () {
|
||||
const promise = parent && !prefs.offscreen ? dialog.showMessageBox(parent, options) : dialog.showMessageBox(options);
|
||||
try {
|
||||
const result = await promise;
|
||||
if (abortController.signal.aborted || this.isDestroyed()) return;
|
||||
if (abortController.signal.aborted) return;
|
||||
if (result.checkboxChecked) originCounts.set(origin, -1);
|
||||
return callback(result.response === 0, '');
|
||||
} finally {
|
||||
|
||||
@@ -3,6 +3,8 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import type * as defaultMenuModule from '@electron/internal/browser/default-menu';
|
||||
import type * as url from 'url';
|
||||
import type * as v8 from 'v8';
|
||||
|
||||
const Module = require('module') as NodeJS.ModuleInternal;
|
||||
|
||||
@@ -10,9 +12,6 @@ const Module = require('module') as NodeJS.ModuleInternal;
|
||||
// we need to restore it here.
|
||||
process.argv.splice(1, 1);
|
||||
|
||||
// Clear search paths.
|
||||
require('../common/reset-search-paths');
|
||||
|
||||
// Import common settings.
|
||||
require('@electron/internal/common/init');
|
||||
|
||||
@@ -135,7 +134,7 @@ if (packageJson.desktopName != null) {
|
||||
// Set v8 flags, deliberately lazy load so that apps that do not use this
|
||||
// feature do not pay the price
|
||||
if (packageJson.v8Flags != null) {
|
||||
require('v8').setFlagsFromString(packageJson.v8Flags);
|
||||
(require('v8') as typeof v8).setFlagsFromString(packageJson.v8Flags);
|
||||
}
|
||||
|
||||
app.setAppPath(packagePath);
|
||||
@@ -152,10 +151,6 @@ require('@electron/internal/browser/api/web-contents');
|
||||
// Load web-frame-main module to ensure it is populated on app ready
|
||||
require('@electron/internal/browser/api/web-frame-main');
|
||||
|
||||
// Required because `new BrowserWindow` calls some WebContentsView stuff, so
|
||||
// the inheritance needs to be set up before that happens.
|
||||
require('@electron/internal/browser/api/web-contents-view');
|
||||
|
||||
// Set main startup script of the app.
|
||||
const mainStartupScript = packageJson.main || 'index.js';
|
||||
|
||||
@@ -202,7 +197,7 @@ if (packagePath) {
|
||||
// Finally load app's main.js and transfer control to C++.
|
||||
if ((packageJson.type === 'module' && !mainStartupScript.endsWith('.cjs')) || mainStartupScript.endsWith('.mjs')) {
|
||||
const { loadESM } = __non_webpack_require__('internal/process/esm_loader');
|
||||
const main = require('url').pathToFileURL(path.join(packagePath, mainStartupScript));
|
||||
const main = (require('url') as typeof url).pathToFileURL(path.join(packagePath, mainStartupScript));
|
||||
loadESM(async (esmLoader: any) => {
|
||||
try {
|
||||
await esmLoader.import(main.toString(), undefined, Object.create(null));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as util from 'util';
|
||||
import type * as stream from 'stream';
|
||||
|
||||
const timers = require('timers');
|
||||
import timers = require('timers');
|
||||
|
||||
type AnyFn = (...args: any[]) => any
|
||||
|
||||
@@ -62,7 +63,7 @@ if (process.type === 'browser' ||
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// Always returns EOF for stdin stream.
|
||||
const { Readable } = require('stream');
|
||||
const { Readable } = require('stream') as typeof stream;
|
||||
const stdin = new Readable();
|
||||
stdin.push(null);
|
||||
Object.defineProperty(process, 'stdin', {
|
||||
@@ -73,3 +74,43 @@ if (process.platform === 'win32') {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const Module = require('module') as NodeJS.ModuleInternal;
|
||||
|
||||
// Make a fake Electron module that we will insert into the module cache
|
||||
const makeElectronModule = (name: string) => {
|
||||
const electronModule = new Module('electron', null);
|
||||
electronModule.id = 'electron';
|
||||
electronModule.loaded = true;
|
||||
electronModule.filename = name;
|
||||
Object.defineProperty(electronModule, 'exports', {
|
||||
get: () => require('electron')
|
||||
});
|
||||
Module._cache[name] = electronModule;
|
||||
};
|
||||
|
||||
makeElectronModule('electron');
|
||||
makeElectronModule('electron/common');
|
||||
if (process.type === 'browser') {
|
||||
makeElectronModule('electron/main');
|
||||
}
|
||||
if (process.type === 'renderer') {
|
||||
makeElectronModule('electron/renderer');
|
||||
}
|
||||
|
||||
const originalResolveFilename = Module._resolveFilename;
|
||||
|
||||
// 'electron/main', 'electron/renderer' and 'electron/common' are module aliases
|
||||
// of the 'electron' module for TypeScript purposes, i.e., the types for
|
||||
// 'electron/main' consist of only main process modules, etc. It is intentional
|
||||
// that these can be `require()`-ed from both the main process as well as the
|
||||
// renderer process regardless of the names, they're superficial for TypeScript
|
||||
// only.
|
||||
const electronModuleNames = new Set(['electron', 'electron/main', 'electron/renderer', 'electron/common']);
|
||||
Module._resolveFilename = function (request, parent, isMain, options) {
|
||||
if (electronModuleNames.has(request)) {
|
||||
return 'electron';
|
||||
} else {
|
||||
return originalResolveFilename(request, parent, isMain, options);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import * as path from 'path';
|
||||
|
||||
const Module = require('module') as NodeJS.ModuleInternal;
|
||||
|
||||
// We do not want to allow use of the VM module in the renderer process as
|
||||
// it conflicts with Blink's V8::Context internal logic.
|
||||
if (process.type === 'renderer') {
|
||||
const _load = Module._load;
|
||||
Module._load = function (request: string) {
|
||||
if (request === 'vm') {
|
||||
console.warn('The vm module of Node.js is deprecated in the renderer process and will be removed.');
|
||||
}
|
||||
return _load.apply(this, arguments as any);
|
||||
};
|
||||
}
|
||||
|
||||
// Prevent Node from adding paths outside this app to search paths.
|
||||
const resourcesPathWithTrailingSlash = process.resourcesPath + path.sep;
|
||||
const originalNodeModulePaths = Module._nodeModulePaths;
|
||||
Module._nodeModulePaths = function (from: string) {
|
||||
const paths: string[] = originalNodeModulePaths(from);
|
||||
const fromPath = path.resolve(from) + path.sep;
|
||||
// If "from" is outside the app then we do nothing.
|
||||
if (fromPath.startsWith(resourcesPathWithTrailingSlash)) {
|
||||
return paths.filter(function (candidate) {
|
||||
return candidate.startsWith(resourcesPathWithTrailingSlash);
|
||||
});
|
||||
} else {
|
||||
return paths;
|
||||
}
|
||||
};
|
||||
|
||||
// Make a fake Electron module that we will insert into the module cache
|
||||
const makeElectronModule = (name: string) => {
|
||||
const electronModule = new Module('electron', null);
|
||||
electronModule.id = 'electron';
|
||||
electronModule.loaded = true;
|
||||
electronModule.filename = name;
|
||||
Object.defineProperty(electronModule, 'exports', {
|
||||
get: () => require('electron')
|
||||
});
|
||||
Module._cache[name] = electronModule;
|
||||
};
|
||||
|
||||
makeElectronModule('electron');
|
||||
makeElectronModule('electron/common');
|
||||
if (process.type === 'browser') {
|
||||
makeElectronModule('electron/main');
|
||||
}
|
||||
if (process.type === 'renderer') {
|
||||
makeElectronModule('electron/renderer');
|
||||
}
|
||||
|
||||
const originalResolveFilename = Module._resolveFilename;
|
||||
|
||||
// 'electron/main', 'electron/renderer' and 'electron/common' are module aliases
|
||||
// of the 'electron' module for TypeScript purposes, i.e., the types for
|
||||
// 'electron/main' consist of only main process modules, etc. It is intentional
|
||||
// that these can be `require()`-ed from both the main process as well as the
|
||||
// renderer process regardless of the names, they're superficial for TypeScript
|
||||
// only.
|
||||
const electronModuleNames = new Set(['electron', 'electron/main', 'electron/renderer', 'electron/common']);
|
||||
Module._resolveFilename = function (request, parent, isMain, options) {
|
||||
if (electronModuleNames.has(request)) {
|
||||
return 'electron';
|
||||
} else {
|
||||
return originalResolveFilename(request, parent, isMain, options);
|
||||
}
|
||||
};
|
||||
@@ -2,7 +2,9 @@ import { Buffer } from 'buffer';
|
||||
import { constants } from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
|
||||
import type * as Crypto from 'crypto';
|
||||
import type * as os from 'os';
|
||||
|
||||
const asar = process._linkedBinding('electron_common_asar');
|
||||
|
||||
@@ -255,7 +257,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
if (!process.env.ELECTRON_LOG_ASAR_READS) return;
|
||||
if (!logFDs.has(asarPath)) {
|
||||
const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`;
|
||||
const logPath = path.join(require('os').tmpdir(), logFilename);
|
||||
const logPath = path.join((require('os') as typeof os).tmpdir(), logFilename);
|
||||
logFDs.set(asarPath, fs.openSync(logPath, 'a'));
|
||||
}
|
||||
fs.writeSync(logFDs.get(asarPath), `${offset}: ${filePath}\n`);
|
||||
49
lib/node/init.ts
Normal file
49
lib/node/init.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
// Initialize ASAR support in fs module.
|
||||
import { wrapFsWithAsar } from './asar-fs-wrapper';
|
||||
wrapFsWithAsar(require('fs'));
|
||||
|
||||
// Hook child_process.fork.
|
||||
import cp = require('child_process'); // eslint-disable-line import/first
|
||||
const originalFork = cp.fork;
|
||||
cp.fork = (modulePath, args?, options?: cp.ForkOptions) => {
|
||||
// Parse optional args.
|
||||
if (args == null) {
|
||||
args = [];
|
||||
} else if (typeof args === 'object' && !Array.isArray(args)) {
|
||||
options = args as cp.ForkOptions;
|
||||
args = [];
|
||||
}
|
||||
// Fallback to original fork to report arg type errors.
|
||||
if (typeof modulePath !== 'string' || !Array.isArray(args) ||
|
||||
(typeof options !== 'object' && typeof options !== 'undefined')) {
|
||||
return originalFork(modulePath, args, options);
|
||||
}
|
||||
// When forking a child script, we setup a special environment to make
|
||||
// the electron binary run like upstream Node.js.
|
||||
options = options ?? {};
|
||||
options.env = Object.create(options.env || process.env);
|
||||
options.env!.ELECTRON_RUN_AS_NODE = '1';
|
||||
// On mac the child script runs in helper executable.
|
||||
if (!options.execPath && process.platform === 'darwin') {
|
||||
options.execPath = process.helperExecPath;
|
||||
}
|
||||
return originalFork(modulePath, args, options);
|
||||
};
|
||||
|
||||
// Prevent Node from adding paths outside this app to search paths.
|
||||
import path = require('path'); // eslint-disable-line import/first
|
||||
const Module = require('module') as NodeJS.ModuleInternal;
|
||||
const resourcesPathWithTrailingSlash = process.resourcesPath + path.sep;
|
||||
const originalNodeModulePaths = Module._nodeModulePaths;
|
||||
Module._nodeModulePaths = function (from) {
|
||||
const paths: string[] = originalNodeModulePaths(from);
|
||||
const fromPath = path.resolve(from) + path.sep;
|
||||
// If "from" is outside the app then we do nothing.
|
||||
if (fromPath.startsWith(resourcesPathWithTrailingSlash)) {
|
||||
return paths.filter(function (candidate) {
|
||||
return candidate.startsWith(resourcesPathWithTrailingSlash);
|
||||
});
|
||||
} else {
|
||||
return paths;
|
||||
}
|
||||
};
|
||||
@@ -7,6 +7,16 @@ import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-re
|
||||
|
||||
const Module = require('module') as NodeJS.ModuleInternal;
|
||||
|
||||
// We do not want to allow use of the VM module in the renderer process as
|
||||
// it conflicts with Blink's V8::Context internal logic.
|
||||
const originalModuleLoad = Module._load;
|
||||
Module._load = function (request: string) {
|
||||
if (request === 'vm') {
|
||||
console.warn('The vm module of Node.js is deprecated in the renderer process and will be removed.');
|
||||
}
|
||||
return originalModuleLoad.apply(this, arguments as any);
|
||||
};
|
||||
|
||||
// Make sure globals like "process" and "global" are always available in preload
|
||||
// scripts even after they are deleted in "loaded" script.
|
||||
//
|
||||
@@ -33,9 +43,6 @@ Module.wrapper = [
|
||||
// init.js, we need to restore it here.
|
||||
process.argv.splice(1, 1);
|
||||
|
||||
// Clear search paths.
|
||||
require('../common/reset-search-paths');
|
||||
|
||||
// Import common settings.
|
||||
require('@electron/internal/common/init');
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as events from 'events';
|
||||
import { setImmediate, clearImmediate } from 'timers';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
@@ -126,7 +127,6 @@ function runPreloadScript (preloadSrc: string) {
|
||||
|
||||
// eval in window scope
|
||||
const preloadFn = binding.createPreloadScript(preloadWrapperSrc);
|
||||
const { setImmediate, clearImmediate } = require('timers');
|
||||
const exports = {};
|
||||
|
||||
preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate, clearImmediate, exports, { exports });
|
||||
|
||||
@@ -10,9 +10,6 @@ const entryScript: string = v8Util.getHiddenValue(process, '_serviceStartupScrip
|
||||
// we need to restore it here.
|
||||
process.argv.splice(1, 1, entryScript);
|
||||
|
||||
// Clear search paths.
|
||||
require('../common/reset-search-paths');
|
||||
|
||||
// Import common settings.
|
||||
require('@electron/internal/common/init');
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@ const Module = require('module') as NodeJS.ModuleInternal;
|
||||
// init.js, we need to restore it here.
|
||||
process.argv.splice(1, 1);
|
||||
|
||||
// Clear search paths.
|
||||
require('../common/reset-search-paths');
|
||||
|
||||
// Import common settings.
|
||||
require('@electron/internal/common/init');
|
||||
|
||||
|
||||
@@ -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.9.0",
|
||||
"@electron/lint-roller": "^1.12.1",
|
||||
"@electron/typescript-definitions": "^8.15.2",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@primer/octicons": "^10.0.0",
|
||||
|
||||
9
patches/DirectXShaderCompiler/.patches
Normal file
9
patches/DirectXShaderCompiler/.patches
Normal file
@@ -0,0 +1,9 @@
|
||||
cherry-pick-a65e511a14b4.patch
|
||||
cherry-pick-bc18aec94c82.patch
|
||||
cherry-pick-bd7aa9779873.patch
|
||||
cherry-pick-2a434fd0af6b.patch
|
||||
cherry-pick-867c1001637e.patch
|
||||
cherry-pick-0b785e88fefa.patch
|
||||
cherry-pick-511cfef8e050.patch
|
||||
cherry-pick-33051b084850.patch
|
||||
cherry-pick-b845fed99111.patch
|
||||
523
patches/DirectXShaderCompiler/cherry-pick-0b785e88fefa.patch
Normal file
523
patches/DirectXShaderCompiler/cherry-pick-0b785e88fefa.patch
Normal file
@@ -0,0 +1,523 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Fri, 24 May 2024 15:51:26 -0400
|
||||
Subject: Fix dxil-remove-dead-blocks removing switch with multiple same
|
||||
successor (#6610)
|
||||
|
||||
Given a switch with a constant condition and all cases the same
|
||||
(branching to the same successor), dxil-remove-dead-blocks would
|
||||
incorrectly remove the switch when replacing it with a branch, by
|
||||
forgetting to remove the N-1 incoming values to the PHIs in the
|
||||
successor block.
|
||||
|
||||
Bug: chromium:338071106
|
||||
Change-Id: Iaa2c42642f3e370afd19d88c96c81056c16349b6
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570270
|
||||
Reviewed-by: Ben Clayton <bclayton@chromium.org>
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
|
||||
index 54308eed2e018903e518be4a5ff809e080be78c0..9a87f4e6740c8da0522c6bf00f2a365f838cb3c0 100644
|
||||
--- a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
|
||||
+++ b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
|
||||
@@ -35,6 +35,7 @@
|
||||
using namespace llvm;
|
||||
using namespace hlsl;
|
||||
|
||||
+// Removes BB from PHI nodes in SuccBB, deleting the PHI nodes if empty.
|
||||
static void RemoveIncomingValueFrom(BasicBlock *SuccBB, BasicBlock *BB) {
|
||||
for (auto inst_it = SuccBB->begin(); inst_it != SuccBB->end();) {
|
||||
Instruction *I = &*(inst_it++);
|
||||
@@ -105,6 +106,8 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
|
||||
} else if (SwitchInst *Switch = dyn_cast<SwitchInst>(BB->getTerminator())) {
|
||||
Value *Cond = Switch->getCondition();
|
||||
BasicBlock *Succ = nullptr;
|
||||
+ // If the condition to Switch is constant, replace Switch with a branch
|
||||
+ // to the current case successor.
|
||||
if (ConstantInt *ConstCond = DVC->GetConstInt(Cond)) {
|
||||
Succ = hlsl::dxilutil::GetSwitchSuccessorForCond(Switch, ConstCond);
|
||||
}
|
||||
@@ -112,16 +115,32 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
|
||||
if (Succ) {
|
||||
Add(Succ);
|
||||
|
||||
+ // Create branch from BB to Succ that will replace Switch.
|
||||
+ // This adds BB to preds of Succ.
|
||||
BranchInst *NewBr = BranchInst::Create(Succ, BB);
|
||||
hlsl::DxilMDHelper::CopyMetadata(*NewBr, *Switch);
|
||||
|
||||
+ // For any successors we're not going to, remove incoming block BB from
|
||||
+ // PHI nodes in those successors.
|
||||
+ unsigned numSucc = 0;
|
||||
for (unsigned i = 0; i < Switch->getNumSuccessors(); i++) {
|
||||
BasicBlock *NotSucc = Switch->getSuccessor(i);
|
||||
- if (NotSucc != Succ) {
|
||||
+ if (NotSucc != Succ)
|
||||
RemoveIncomingValueFrom(NotSucc, BB);
|
||||
- }
|
||||
+ else
|
||||
+ ++numSucc;
|
||||
+ }
|
||||
+
|
||||
+ // We're replacing Switch with a single unconditional branch. If Switch
|
||||
+ // has N cases with the same Succ, we need to remove N-1 incoming values
|
||||
+ // of BB from the PHI nodes in Succ. This ensures that the preds of Succ
|
||||
+ // match the ones in its PHIs.
|
||||
+ for (unsigned i = 1; i < numSucc; i++) {
|
||||
+ RemoveIncomingValueFrom(Succ, BB);
|
||||
}
|
||||
|
||||
+ // Finally, erase Switch, which will remove BB as pred from all
|
||||
+ // successors.
|
||||
Switch->eraseFromParent();
|
||||
Switch = nullptr;
|
||||
Changed = true;
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..43c3510b2ce18b15ff74a0db4697898da807f49f
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
|
||||
@@ -0,0 +1,68 @@
|
||||
+// Test switch with multiple same successors
|
||||
+// RUN: %dxc -T ps_6_6 %s | FileCheck %s
|
||||
+
|
||||
+// This test used to fail with validation errors:
|
||||
+//
|
||||
+// error: validation errors
|
||||
+// error: Module bitcode is invalid.
|
||||
+// error: PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %22 = phi i32 [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ %11, %13 ]
|
||||
+// PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %28 = phi i32 [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ %22, %24 ]
|
||||
+// PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %34 = phi i32 [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ %28, %30 ]
|
||||
+// PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %47 = phi i32 [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ %41, %43 ]
|
||||
+//
|
||||
+// This was fixed in dxil-remove-dead-blocks. See switch-with-multiple-same-successor.ll
|
||||
+// for the pass-specific checks. Here, we just want to make sure dxc compiles this without error.
|
||||
+
|
||||
+// CHECK: @main
|
||||
+
|
||||
+ByteAddressBuffer g_buff : register(t0);
|
||||
+
|
||||
+struct retval {
|
||||
+ float4 value : SV_Target0;
|
||||
+};
|
||||
+
|
||||
+retval main() {
|
||||
+ float4 g = asfloat(g_buff.Load4(0u));
|
||||
+ bool do_discard = false;
|
||||
+
|
||||
+ for (int i = 0; i < 10; ++i) {
|
||||
+ if (g.x != 0.0f)
|
||||
+ continue;
|
||||
+
|
||||
+ // Switch with the same successor in all cases
|
||||
+ switch(i) {
|
||||
+ case 1: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ case 2: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ case 3: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ // Skip 'case 4' to avoid case range combining
|
||||
+ case 5: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (i == 6) {
|
||||
+ break;
|
||||
+ }
|
||||
+ g.x = atan2(1.0f, g.x);
|
||||
+ do_discard = true;
|
||||
+ }
|
||||
+
|
||||
+ if (do_discard) {
|
||||
+ discard;
|
||||
+ }
|
||||
+
|
||||
+ return (retval)0;
|
||||
+}
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d3e7e2f1e40c816c4ed28bfc45a1569e130f472c
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
|
||||
@@ -0,0 +1,369 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -dxil-remove-dead-blocks -S | FileCheck %s
|
||||
+
|
||||
+; Validate that a switch with a constant condition and multiple of the same successor
|
||||
+; is correctly removed, ensuring that PHIs in the successor are properly updated.
|
||||
+; For instance, in:
|
||||
+;
|
||||
+;
|
||||
+; if.end.1: ; preds = %for.inc
|
||||
+; switch i32 1, label %sw.epilog.1 [
|
||||
+; i32 1, label %dx.struct_exit.new_exiting.1
|
||||
+; i32 2, label %dx.struct_exit.new_exiting.1
|
||||
+; i32 3, label %dx.struct_exit.new_exiting.1
|
||||
+; i32 5, label %dx.struct_exit.new_exiting.1
|
||||
+; ], !dbg !31 ; line:23 col:5
|
||||
+;
|
||||
+; sw.epilog.1: ; preds = %if.end.1
|
||||
+; br label %dx.struct_exit.new_exiting.1
|
||||
+;
|
||||
+; dx.struct_exit.new_exiting.1: ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
|
||||
+; %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
|
||||
+; %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
|
||||
+; %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
|
||||
+; br i1 false, label %cleanup, label %for.inc.1
|
||||
+;
|
||||
+;
|
||||
+; After dxil-remove-dead-blocks, the multiple `%if.end.1` in preds and in the two phi instructions should be removed,
|
||||
+; and only one instance should be left.
|
||||
+
|
||||
+; CHECK: if.end.1: ; preds = %for.inc
|
||||
+; CHECK-NEXT: br label %dx.struct_exit.new_exiting.1
|
||||
+
|
||||
+; CHECK: dx.struct_exit.new_exiting.1: ; preds = %if.end.1, %for.inc
|
||||
+; CHECK-NEXT: %do_discard.2.1 = phi i32 [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
|
||||
+; CHECK-NEXT: %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
|
||||
+
|
||||
+;
|
||||
+; Output signature:
|
||||
+;
|
||||
+; Name Index InterpMode DynIdx
|
||||
+; -------------------- ----- ---------------------- ------
|
||||
+; SV_Target 0
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; g_buff texture byte r/o T0 t0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.ByteAddressBuffer = type { i32 }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+%dx.types.ResRet.i32 = type { i32, i32, i32, i32, i32 }
|
||||
+%struct.retval = type { <4 x float> }
|
||||
+
|
||||
+@"\01?g_buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
|
||||
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A" to i8*)], section "llvm.metadata"
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(<4 x float>* noalias nocapture readnone) #0 {
|
||||
+for.body.lr.ph:
|
||||
+ %1 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", align 4, !dbg !23 ; line:15 col:22
|
||||
+ %2 = call %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32 160, %struct.ByteAddressBuffer %1), !dbg !23 ; line:15 col:22 ; CreateHandleForLib(Resource)
|
||||
+ %3 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %2, %dx.types.ResourceProperties { i32 11, i32 0 }), !dbg !23 ; line:15 col:22 ; AnnotateHandle(res,props) resource: ByteAddressBuffer
|
||||
+ %RawBufferLoad = call %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32 139, %dx.types.Handle %3, i32 0, i32 undef, i8 15, i32 4), !dbg !23 ; line:15 col:22 ; RawBufferLoad(srv,index,elementOffset,mask,alignment)
|
||||
+ %4 = extractvalue %dx.types.ResRet.i32 %RawBufferLoad, 0, !dbg !23 ; line:15 col:22
|
||||
+ %.i0 = bitcast i32 %4 to float, !dbg !27 ; line:15 col:14
|
||||
+ br label %for.body, !dbg !28 ; line:18 col:3
|
||||
+
|
||||
+for.body: ; preds = %for.body.lr.ph
|
||||
+ %cmp3 = fcmp fast une float %.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3, label %dx.struct_exit.new_exiting, label %if.end, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end: ; preds = %for.body
|
||||
+ switch i32 0, label %sw.epilog [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting
|
||||
+ i32 2, label %dx.struct_exit.new_exiting
|
||||
+ i32 3, label %dx.struct_exit.new_exiting
|
||||
+ i32 5, label %dx.struct_exit.new_exiting
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog: ; preds = %if.end
|
||||
+ br label %dx.struct_exit.new_exiting
|
||||
+
|
||||
+dx.struct_exit.new_exiting: ; preds = %sw.epilog, %if.end, %if.end, %if.end, %if.end, %for.body
|
||||
+ %do_discard.2 = phi i32 [ 0, %for.body ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %sw.epilog ]
|
||||
+ %g.2.i0 = phi float [ %.i0, %for.body ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %sw.epilog ]
|
||||
+ br i1 false, label %cleanup, label %for.inc
|
||||
+
|
||||
+for.inc: ; preds = %dx.struct_exit.new_exiting
|
||||
+ %cmp3.1 = fcmp fast une float %g.2.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.1, label %dx.struct_exit.new_exiting.1, label %if.end.1, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+cleanup: ; preds = %for.inc.9, %dx.struct_exit.new_exiting.9, %dx.struct_exit.new_exiting.8, %dx.struct_exit.new_exiting.7, %dx.struct_exit.new_exiting.6, %dx.struct_exit.new_exiting.5, %dx.struct_exit.new_exiting.4, %dx.struct_exit.new_exiting.3, %dx.struct_exit.new_exiting.2, %dx.struct_exit.new_exiting.1, %dx.struct_exit.new_exiting
|
||||
+ %do_discard.3 = phi i32 [ 0, %dx.struct_exit.new_exiting ], [ %dx.struct_exit.prop.1, %dx.struct_exit.new_exiting.1 ], [ %dx.struct_exit.prop.2, %dx.struct_exit.new_exiting.2 ], [ %dx.struct_exit.prop.3, %dx.struct_exit.new_exiting.3 ], [ %dx.struct_exit.prop.4, %dx.struct_exit.new_exiting.4 ], [ %dx.struct_exit.prop.5, %dx.struct_exit.new_exiting.5 ], [ %dx.struct_exit.prop.6, %dx.struct_exit.new_exiting.6 ], [ %dx.struct_exit.prop.7, %dx.struct_exit.new_exiting.7 ], [ %dx.struct_exit.prop.8, %dx.struct_exit.new_exiting.8 ], [ %dx.struct_exit.prop.9, %dx.struct_exit.new_exiting.9 ], [ %do_discard.2.9, %for.inc.9 ]
|
||||
+ %tobool15 = icmp eq i32 %do_discard.3, 0, !dbg !32 ; line:49 col:7
|
||||
+ br i1 %tobool15, label %if.end.17, label %if.then.16, !dbg !32 ; line:49 col:7
|
||||
+
|
||||
+if.then.16: ; preds = %cleanup
|
||||
+ call void @dx.op.discard(i32 82, i1 true), !dbg !33 ; line:49 col:19 ; Discard(condition)
|
||||
+ br label %if.end.17, !dbg !34 ; line:51 col:3
|
||||
+
|
||||
+if.end.17: ; preds = %cleanup, %if.then.16
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ ret void, !dbg !36 ; line:54 col:1
|
||||
+
|
||||
+if.end.1: ; preds = %for.inc
|
||||
+ switch i32 1, label %sw.epilog.1 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.1
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.1
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.1
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.1
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.1: ; preds = %if.end.1
|
||||
+ br label %dx.struct_exit.new_exiting.1
|
||||
+
|
||||
+dx.struct_exit.new_exiting.1: ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
|
||||
+ %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
|
||||
+ %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
|
||||
+ %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.1
|
||||
+
|
||||
+for.inc.1: ; preds = %dx.struct_exit.new_exiting.1
|
||||
+ %cmp3.2 = fcmp fast une float %g.2.i0.1, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.2, label %dx.struct_exit.new_exiting.2, label %if.end.2, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.2: ; preds = %for.inc.1
|
||||
+ switch i32 2, label %sw.epilog.2 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.2
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.2
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.2
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.2
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.2: ; preds = %if.end.2
|
||||
+ br label %dx.struct_exit.new_exiting.2
|
||||
+
|
||||
+dx.struct_exit.new_exiting.2: ; preds = %sw.epilog.2, %if.end.2, %if.end.2, %if.end.2, %if.end.2, %for.inc.1
|
||||
+ %dx.struct_exit.prop.2 = phi i32 [ %do_discard.2.1, %sw.epilog.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %for.inc.1 ]
|
||||
+ %do_discard.2.2 = phi i32 [ 1, %sw.epilog.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ %do_discard.2.1, %for.inc.1 ]
|
||||
+ %g.2.i0.2 = phi float [ 0x3FF921FB60000000, %sw.epilog.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ %g.2.i0.1, %for.inc.1 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.2
|
||||
+
|
||||
+for.inc.2: ; preds = %dx.struct_exit.new_exiting.2
|
||||
+ %cmp3.3 = fcmp fast une float %g.2.i0.2, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.3, label %dx.struct_exit.new_exiting.3, label %if.end.3, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.3: ; preds = %for.inc.2
|
||||
+ switch i32 3, label %sw.epilog.3 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.3
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.3
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.3
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.3
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.3: ; preds = %if.end.3
|
||||
+ br label %dx.struct_exit.new_exiting.3
|
||||
+
|
||||
+dx.struct_exit.new_exiting.3: ; preds = %sw.epilog.3, %if.end.3, %if.end.3, %if.end.3, %if.end.3, %for.inc.2
|
||||
+ %dx.struct_exit.prop.3 = phi i32 [ %do_discard.2.2, %sw.epilog.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %for.inc.2 ]
|
||||
+ %do_discard.2.3 = phi i32 [ 1, %sw.epilog.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ %do_discard.2.2, %for.inc.2 ]
|
||||
+ %g.2.i0.3 = phi float [ 0x3FF921FB60000000, %sw.epilog.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ %g.2.i0.2, %for.inc.2 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.3
|
||||
+
|
||||
+for.inc.3: ; preds = %dx.struct_exit.new_exiting.3
|
||||
+ %cmp3.4 = fcmp fast une float %g.2.i0.3, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.4, label %dx.struct_exit.new_exiting.4, label %if.end.4, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.4: ; preds = %for.inc.3
|
||||
+ switch i32 4, label %sw.epilog.4 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.4
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.4
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.4
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.4
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.4: ; preds = %if.end.4
|
||||
+ br label %dx.struct_exit.new_exiting.4
|
||||
+
|
||||
+dx.struct_exit.new_exiting.4: ; preds = %sw.epilog.4, %if.end.4, %if.end.4, %if.end.4, %if.end.4, %for.inc.3
|
||||
+ %dx.struct_exit.prop.4 = phi i32 [ %do_discard.2.3, %sw.epilog.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %for.inc.3 ]
|
||||
+ %do_discard.2.4 = phi i32 [ 1, %sw.epilog.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ %do_discard.2.3, %for.inc.3 ]
|
||||
+ %g.2.i0.4 = phi float [ 0x3FF921FB60000000, %sw.epilog.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ %g.2.i0.3, %for.inc.3 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.4
|
||||
+
|
||||
+for.inc.4: ; preds = %dx.struct_exit.new_exiting.4
|
||||
+ %cmp3.5 = fcmp fast une float %g.2.i0.4, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.5, label %dx.struct_exit.new_exiting.5, label %if.end.5, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.5: ; preds = %for.inc.4
|
||||
+ switch i32 5, label %sw.epilog.5 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.5
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.5
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.5
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.5
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.5: ; preds = %if.end.5
|
||||
+ br label %dx.struct_exit.new_exiting.5
|
||||
+
|
||||
+dx.struct_exit.new_exiting.5: ; preds = %sw.epilog.5, %if.end.5, %if.end.5, %if.end.5, %if.end.5, %for.inc.4
|
||||
+ %dx.struct_exit.prop.5 = phi i32 [ %do_discard.2.4, %sw.epilog.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %for.inc.4 ]
|
||||
+ %do_discard.2.5 = phi i32 [ 1, %sw.epilog.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ %do_discard.2.4, %for.inc.4 ]
|
||||
+ %g.2.i0.5 = phi float [ 0x3FF921FB60000000, %sw.epilog.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ %g.2.i0.4, %for.inc.4 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.5
|
||||
+
|
||||
+for.inc.5: ; preds = %dx.struct_exit.new_exiting.5
|
||||
+ %cmp3.6 = fcmp fast une float %g.2.i0.5, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.6, label %dx.struct_exit.new_exiting.6, label %if.end.6, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.6: ; preds = %for.inc.5
|
||||
+ switch i32 6, label %sw.epilog.6 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.6
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.6
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.6
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.6
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.6: ; preds = %if.end.6
|
||||
+ br label %dx.struct_exit.new_exiting.6
|
||||
+
|
||||
+dx.struct_exit.new_exiting.6: ; preds = %sw.epilog.6, %if.end.6, %if.end.6, %if.end.6, %if.end.6, %for.inc.5
|
||||
+ %dx.struct_exit.prop23.6 = phi i1 [ true, %sw.epilog.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %for.inc.5 ]
|
||||
+ %dx.struct_exit.prop.6 = phi i32 [ %do_discard.2.5, %sw.epilog.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %for.inc.5 ]
|
||||
+ %do_discard.2.6 = phi i32 [ 1, %sw.epilog.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ %do_discard.2.5, %for.inc.5 ]
|
||||
+ %g.2.i0.6 = phi float [ 0x3FF921FB60000000, %sw.epilog.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ %g.2.i0.5, %for.inc.5 ]
|
||||
+ br i1 %dx.struct_exit.prop23.6, label %cleanup, label %for.inc.6
|
||||
+
|
||||
+for.inc.6: ; preds = %dx.struct_exit.new_exiting.6
|
||||
+ %cmp3.7 = fcmp fast une float %g.2.i0.6, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.7, label %dx.struct_exit.new_exiting.7, label %if.end.7, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.7: ; preds = %for.inc.6
|
||||
+ switch i32 7, label %sw.epilog.7 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.7
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.7
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.7
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.7
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.7: ; preds = %if.end.7
|
||||
+ br label %dx.struct_exit.new_exiting.7
|
||||
+
|
||||
+dx.struct_exit.new_exiting.7: ; preds = %sw.epilog.7, %if.end.7, %if.end.7, %if.end.7, %if.end.7, %for.inc.6
|
||||
+ %dx.struct_exit.prop.7 = phi i32 [ %do_discard.2.6, %sw.epilog.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %for.inc.6 ]
|
||||
+ %do_discard.2.7 = phi i32 [ 1, %sw.epilog.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ %do_discard.2.6, %for.inc.6 ]
|
||||
+ %g.2.i0.7 = phi float [ 0x3FF921FB60000000, %sw.epilog.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ %g.2.i0.6, %for.inc.6 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.7
|
||||
+
|
||||
+for.inc.7: ; preds = %dx.struct_exit.new_exiting.7
|
||||
+ %cmp3.8 = fcmp fast une float %g.2.i0.7, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.8, label %dx.struct_exit.new_exiting.8, label %if.end.8, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.8: ; preds = %for.inc.7
|
||||
+ switch i32 8, label %sw.epilog.8 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.8
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.8
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.8
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.8
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.8: ; preds = %if.end.8
|
||||
+ br label %dx.struct_exit.new_exiting.8
|
||||
+
|
||||
+dx.struct_exit.new_exiting.8: ; preds = %sw.epilog.8, %if.end.8, %if.end.8, %if.end.8, %if.end.8, %for.inc.7
|
||||
+ %dx.struct_exit.prop.8 = phi i32 [ %do_discard.2.7, %sw.epilog.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %for.inc.7 ]
|
||||
+ %do_discard.2.8 = phi i32 [ 1, %sw.epilog.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ %do_discard.2.7, %for.inc.7 ]
|
||||
+ %g.2.i0.8 = phi float [ 0x3FF921FB60000000, %sw.epilog.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ %g.2.i0.7, %for.inc.7 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.8
|
||||
+
|
||||
+for.inc.8: ; preds = %dx.struct_exit.new_exiting.8
|
||||
+ %cmp3.9 = fcmp fast une float %g.2.i0.8, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.9, label %dx.struct_exit.new_exiting.9, label %if.end.9, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.9: ; preds = %for.inc.8
|
||||
+ switch i32 9, label %sw.epilog.9 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.9
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.9
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.9
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.9
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.9: ; preds = %if.end.9
|
||||
+ br label %dx.struct_exit.new_exiting.9
|
||||
+
|
||||
+dx.struct_exit.new_exiting.9: ; preds = %sw.epilog.9, %if.end.9, %if.end.9, %if.end.9, %if.end.9, %for.inc.8
|
||||
+ %dx.struct_exit.prop.9 = phi i32 [ %do_discard.2.8, %sw.epilog.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %for.inc.8 ]
|
||||
+ %do_discard.2.9 = phi i32 [ 1, %sw.epilog.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ %do_discard.2.8, %for.inc.8 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.9
|
||||
+
|
||||
+for.inc.9: ; preds = %dx.struct_exit.new_exiting.9
|
||||
+ br label %cleanup
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.discard(i32, i1) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32, %dx.types.Handle, i32, i32, i8, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32, %struct.ByteAddressBuffer) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #2
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readonly }
|
||||
+attributes #2 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.resources = !{!6}
|
||||
+!dx.typeAnnotations = !{!9, !12}
|
||||
+!dx.entryPoints = !{!19}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 6}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 6}
|
||||
+!6 = !{!7, null, null, null}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 0, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", !"g_buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
|
||||
+!9 = !{i32 0, %struct.retval undef, !10}
|
||||
+!10 = !{i32 16, !11}
|
||||
+!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!12 = !{i32 1, void (<4 x float>*)* @main, !13}
|
||||
+!13 = !{!14, !16}
|
||||
+!14 = !{i32 0, !15, !15}
|
||||
+!15 = !{}
|
||||
+!16 = !{i32 1, !17, !18}
|
||||
+!17 = !{i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!18 = !{i32 0}
|
||||
+!19 = !{void (<4 x float>*)* @main, !"main", !20, !6, null}
|
||||
+!20 = !{null, !21, null}
|
||||
+!21 = !{!22}
|
||||
+!22 = !{i32 0, !"SV_Target", i8 9, i8 16, !18, i8 0, i32 1, i8 4, i32 0, i8 0, null}
|
||||
+!23 = !DILocation(line: 15, column: 22, scope: !24)
|
||||
+!24 = !DISubprogram(name: "main", scope: !25, file: !25, line: 14, type: !26, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
|
||||
+!25 = !DIFile(filename: "/home/amaiorano/src/external/DirectXShaderCompiler/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl", directory: "")
|
||||
+!26 = !DISubroutineType(types: !15)
|
||||
+!27 = !DILocation(line: 15, column: 14, scope: !24)
|
||||
+!28 = !DILocation(line: 18, column: 3, scope: !24)
|
||||
+!29 = !DILocation(line: 19, column: 13, scope: !24)
|
||||
+!30 = !DILocation(line: 19, column: 9, scope: !24)
|
||||
+!31 = !DILocation(line: 23, column: 5, scope: !24)
|
||||
+!32 = !DILocation(line: 49, column: 7, scope: !24)
|
||||
+!33 = !DILocation(line: 49, column: 19, scope: !24)
|
||||
+!34 = !DILocation(line: 51, column: 3, scope: !24)
|
||||
+!35 = !DILocation(line: 53, column: 18, scope: !24)
|
||||
+!36 = !DILocation(line: 54, column: 1, scope: !24)
|
||||
419
patches/DirectXShaderCompiler/cherry-pick-2a434fd0af6b.patch
Normal file
419
patches/DirectXShaderCompiler/cherry-pick-2a434fd0af6b.patch
Normal file
@@ -0,0 +1,419 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Wed, 8 May 2024 13:38:38 -0400
|
||||
Subject: Fix invalid IR from scalarrepl-param-hlsl in ReplaceConstantWithInst
|
||||
(#6556)
|
||||
|
||||
ReplaceConstantWithInst(C, V) replaces uses of C in the current function
|
||||
with V. If such a use C is an instruction I, the it replaces uses of C
|
||||
in I with V. However, this function did not make sure to only perform
|
||||
this replacement if V dominates I. As a result, it may end up replacing
|
||||
uses of C in instructions before the definition of V.
|
||||
|
||||
The fix is to lazily compute the dominator tree in
|
||||
ReplaceConstantWithInst so that we can guard the replacement with that
|
||||
dominance check.
|
||||
|
||||
Bug: chromium:333414294
|
||||
Change-Id: I2a8bf64094298b49a1887cc7c1334e91a745c396
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5525429
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
index 3f8ffdbcfa09a96899295fd85291cedb879a248b..9b843ef0e49e554001b827e30eb6256853d90f5b 100644
|
||||
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
@@ -3271,15 +3271,34 @@ bool SROA_Helper::DoScalarReplacement(GlobalVariable *GV,
|
||||
return true;
|
||||
}
|
||||
|
||||
-static void ReplaceConstantWithInst(Constant *C, Value *V,
|
||||
+// Replaces uses of constant C in the current function
|
||||
+// with V, when those uses are dominated by V.
|
||||
+// Returns true if it was completely replaced.
|
||||
+static bool ReplaceConstantWithInst(Constant *C, Value *V,
|
||||
IRBuilder<> &Builder) {
|
||||
+ bool bReplacedAll = true;
|
||||
Function *F = Builder.GetInsertBlock()->getParent();
|
||||
+ Instruction *VInst = dyn_cast<Instruction>(V);
|
||||
+ // Lazily calculate dominance
|
||||
+ DominatorTree DT;
|
||||
+ bool Calculated = false;
|
||||
+ auto Dominates = [&](llvm::Instruction *Def, llvm::Instruction *User) {
|
||||
+ if (!Calculated) {
|
||||
+ DT.recalculate(*F);
|
||||
+ Calculated = true;
|
||||
+ }
|
||||
+ return DT.dominates(Def, User);
|
||||
+ };
|
||||
+
|
||||
for (auto it = C->user_begin(); it != C->user_end();) {
|
||||
User *U = *(it++);
|
||||
if (Instruction *I = dyn_cast<Instruction>(U)) {
|
||||
if (I->getParent()->getParent() != F)
|
||||
continue;
|
||||
- I->replaceUsesOfWith(C, V);
|
||||
+ if (VInst && Dominates(VInst, I))
|
||||
+ I->replaceUsesOfWith(C, V);
|
||||
+ else
|
||||
+ bReplacedAll = false;
|
||||
} else {
|
||||
// Skip unused ConstantExpr.
|
||||
if (U->user_empty())
|
||||
@@ -3288,10 +3307,12 @@ static void ReplaceConstantWithInst(Constant *C, Value *V,
|
||||
Instruction *Inst = CE->getAsInstruction();
|
||||
Builder.Insert(Inst);
|
||||
Inst->replaceUsesOfWith(C, V);
|
||||
- ReplaceConstantWithInst(CE, Inst, Builder);
|
||||
+ if (!ReplaceConstantWithInst(CE, Inst, Builder))
|
||||
+ bReplacedAll = false;
|
||||
}
|
||||
}
|
||||
C->removeDeadConstantUsers();
|
||||
+ return bReplacedAll;
|
||||
}
|
||||
|
||||
static void ReplaceUnboundedArrayUses(Value *V, Value *Src) {
|
||||
@@ -3531,7 +3552,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
|
||||
} else {
|
||||
// Replace Constant with a non-Constant.
|
||||
IRBuilder<> Builder(MC);
|
||||
- ReplaceConstantWithInst(C, Src, Builder);
|
||||
+ if (!ReplaceConstantWithInst(C, Src, Builder))
|
||||
+ return false;
|
||||
}
|
||||
} else {
|
||||
// Try convert special pattern for cbuffer which copy array of float4 to
|
||||
@@ -3539,7 +3561,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
|
||||
if (!tryToReplaceCBVec4ArrayToScalarArray(V, TyV, Src, TySrc, MC, DL)) {
|
||||
IRBuilder<> Builder(MC);
|
||||
Src = Builder.CreateBitCast(Src, V->getType());
|
||||
- ReplaceConstantWithInst(C, Src, Builder);
|
||||
+ if (!ReplaceConstantWithInst(C, Src, Builder))
|
||||
+ return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -5447,9 +5470,9 @@ void SROA_Parameter_HLSL::flattenArgument(
|
||||
if (Ty->isPointerTy())
|
||||
Ty = Ty->getPointerElementType();
|
||||
unsigned size = DL.getTypeAllocSize(Ty);
|
||||
-#if 0 // HLSL Change
|
||||
+#if 0 // HLSL Change
|
||||
DIExpression *DDIExp = DIB.createBitPieceExpression(debugOffset, size);
|
||||
-#else // HLSL Change
|
||||
+#else // HLSL Change
|
||||
Type *argTy = Arg->getType();
|
||||
if (argTy->isPointerTy())
|
||||
argTy = argTy->getPointerElementType();
|
||||
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0f30050e69decaf7da3f2ae645611c1a49a4a719
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
|
||||
@@ -0,0 +1,45 @@
|
||||
+// RUN: not %dxc -T ps_6_2 %s 2>&1 | FileCheck %s
|
||||
+
|
||||
+// Validate that copying from static array to local, then back to static
|
||||
+// array does not crash the compiler. This was resulting in an invalid
|
||||
+// ReplaceConstantWithInst from ScalarReplAggregatesHLSL, which would
|
||||
+// result in referenced deleted instruction in a later pass.
|
||||
+
|
||||
+// CHECK: error: Loop must have break.
|
||||
+
|
||||
+static int arr1[10] = (int[10])0;
|
||||
+static int arr2[10] = (int[10])0;
|
||||
+static float result = 0;
|
||||
+ByteAddressBuffer buff : register(t0);
|
||||
+
|
||||
+void foo() {
|
||||
+ int i = 0;
|
||||
+ if (buff.Load(0u)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ arr2[i] = arr1[i];
|
||||
+ result = float(arr1[0]);
|
||||
+}
|
||||
+
|
||||
+struct tint_symbol {
|
||||
+ float4 value : SV_Target0;
|
||||
+};
|
||||
+
|
||||
+float main_inner() {
|
||||
+ foo();
|
||||
+ bool cond = false;
|
||||
+ while (true) {
|
||||
+ if (cond) { break; }
|
||||
+ }
|
||||
+ int arr1_copy[10] = arr1; // constant to local
|
||||
+ arr1 = arr1_copy; // local to constant
|
||||
+ foo();
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+tint_symbol main() {
|
||||
+ float inner_result = main_inner();
|
||||
+ tint_symbol wrapper_result = (tint_symbol)0;
|
||||
+ wrapper_result.value.x = inner_result;
|
||||
+ return wrapper_result;
|
||||
+}
|
||||
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6ca08ab3a9c500cacb715f63ee407c7add4fc51c
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
|
||||
@@ -0,0 +1,253 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -scalarrepl-param-hlsl -S | FileCheck %s
|
||||
+
|
||||
+; The first memcpy, from arr1 to arr1_copy.i, should be replaced by a series of 10 loads and stores,
|
||||
+; while the second memcpy, from arr1_copy.i back to arr1, should be removed:
|
||||
+; %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !33 ; line:25 col:23
|
||||
+; call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !33 ; line:25 col:23
|
||||
+; %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !34 ; line:26 col:10
|
||||
+; call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !34 ; line:26 col:10
|
||||
+; store i32 0, i32* %i.i.1.i, align 4, !dbg !35, !tbaa !12 ; line:7 col:7
|
||||
+
|
||||
+; CHECK: [[DEST0:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 0
|
||||
+; CHECK-NEXT: [[SRC0:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0)
|
||||
+; CHECK-NEXT: store i32 [[SRC0:%[a-z0-9\.]+]], i32* [[DEST0:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST1:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 1
|
||||
+; CHECK-NEXT: [[SRC1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 1)
|
||||
+; CHECK-NEXT: store i32 [[SRC1:%[a-z0-9\.]+]], i32* [[DEST1:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST2:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 2
|
||||
+; CHECK-NEXT: [[SRC2:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 2)
|
||||
+; CHECK-NEXT: store i32 [[SRC2:%[a-z0-9\.]+]], i32* [[DEST2:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST3:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 3
|
||||
+; CHECK-NEXT: [[SRC3:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 3)
|
||||
+; CHECK-NEXT: store i32 [[SRC3:%[a-z0-9\.]+]], i32* [[DEST3:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST4:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 4
|
||||
+; CHECK-NEXT: [[SRC4:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 4)
|
||||
+; CHECK-NEXT: store i32 [[SRC4:%[a-z0-9\.]+]], i32* [[DEST4:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST5:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 5
|
||||
+; CHECK-NEXT: [[SRC5:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 5)
|
||||
+; CHECK-NEXT: store i32 [[SRC5:%[a-z0-9\.]+]], i32* [[DEST5:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST6:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 6
|
||||
+; CHECK-NEXT: [[SRC6:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 6)
|
||||
+; CHECK-NEXT: store i32 [[SRC6:%[a-z0-9\.]+]], i32* [[DEST6:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST7:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 7
|
||||
+; CHECK-NEXT: [[SRC7:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 7)
|
||||
+; CHECK-NEXT: store i32 [[SRC7:%[a-z0-9\.]+]], i32* [[DEST7:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST8:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 8
|
||||
+; CHECK-NEXT: [[SRC8:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 8)
|
||||
+; CHECK-NEXT: store i32 [[SRC8:%[a-z0-9\.]+]], i32* [[DEST8:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST9:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 9
|
||||
+; CHECK-NEXT: [[SRC9:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 9)
|
||||
+; CHECK-NEXT: store i32 [[SRC9:%[a-z0-9\.]+]], i32* [[DEST9:%[a-z0-9\.]+]]
|
||||
+
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+; cbuffer $Globals
|
||||
+; {
|
||||
+;
|
||||
+; [0 x i8] (type annotation not present)
|
||||
+;
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; $Globals cbuffer NA NA CB0 cb4294967295 1
|
||||
+; buff texture byte r/o T0 t0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.ByteAddressBuffer = type { i32 }
|
||||
+%ConstantBuffer = type opaque
|
||||
+%struct.tint_symbol = type { <4 x float> }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+
|
||||
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
|
||||
+@arr1 = internal global [10 x i32] zeroinitializer, align 4
|
||||
+@arr2 = internal global [10 x i32] zeroinitializer, align 4
|
||||
+@"$Globals" = external constant %ConstantBuffer
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(%struct.tint_symbol* noalias sret %agg.result) #0 {
|
||||
+ %1 = alloca float
|
||||
+ store float 0.000000e+00, float* %1
|
||||
+ %i.i.1.i = alloca i32, align 4
|
||||
+ %i.i.i = alloca i32, align 4
|
||||
+ %cond.i = alloca i32, align 4
|
||||
+ %arr1_copy.i = alloca [10 x i32], align 4
|
||||
+ %inner_result = alloca float, align 4
|
||||
+ %wrapper_result = alloca %struct.tint_symbol, align 4
|
||||
+ store i32 0, i32* %i.i.i, align 4, !dbg !23, !tbaa !31 ; line:7 col:7
|
||||
+ %2 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !35 ; line:8 col:7
|
||||
+ %3 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %2) #0, !dbg !35 ; line:8 col:7
|
||||
+ %4 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %3, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !35 ; line:8 col:7
|
||||
+ %5 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %4, i32 0) #0, !dbg !35 ; line:8 col:7
|
||||
+ %6 = icmp ne i32 %5, 0, !dbg !35 ; line:8 col:7
|
||||
+ br i1 %6, label %"\01?foo@@YAXXZ.exit.i", label %7, !dbg !35 ; line:8 col:7
|
||||
+
|
||||
+; <label>:7 ; preds = %0
|
||||
+ %8 = load i32, i32* %i.i.i, align 4, !dbg !36, !tbaa !31 ; line:11 col:18
|
||||
+ %9 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %8, !dbg !37 ; line:11 col:13
|
||||
+ %10 = load i32, i32* %9, align 4, !dbg !37, !tbaa !31 ; line:11 col:13
|
||||
+ %11 = load i32, i32* %i.i.i, align 4, !dbg !38, !tbaa !31 ; line:11 col:8
|
||||
+ %12 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %11, !dbg !39 ; line:11 col:3
|
||||
+ store i32 %10, i32* %12, align 4, !dbg !40, !tbaa !31 ; line:11 col:11
|
||||
+ %13 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !41, !tbaa !31 ; line:12 col:18
|
||||
+ %14 = sitofp i32 %13 to float, !dbg !41 ; line:12 col:18
|
||||
+ store float %14, float* %1, align 4, !dbg !42, !tbaa !43 ; line:12 col:10
|
||||
+ br label %"\01?foo@@YAXXZ.exit.i", !dbg !45 ; line:13 col:1
|
||||
+
|
||||
+"\01?foo@@YAXXZ.exit.i": ; preds = %7, %0
|
||||
+ store i32 0, i32* %cond.i, align 4, !dbg !46, !tbaa !47 ; line:21 col:8
|
||||
+ br label %15, !dbg !49 ; line:22 col:3
|
||||
+
|
||||
+; <label>:15 ; preds = %15, %"\01?foo@@YAXXZ.exit.i"
|
||||
+ %16 = load i32, i32* %cond.i, align 4, !dbg !50, !tbaa !47, !range !51 ; line:23 col:9
|
||||
+ %17 = icmp ne i32 %16, 0, !dbg !50 ; line:23 col:9
|
||||
+ br i1 %17, label %18, label %15, !dbg !50 ; line:23 col:9
|
||||
+
|
||||
+; <label>:18 ; preds = %15
|
||||
+ %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !52 ; line:25 col:23
|
||||
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !52 ; line:25 col:23
|
||||
+ %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !53 ; line:26 col:10
|
||||
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !53 ; line:26 col:10
|
||||
+ store i32 0, i32* %i.i.1.i, align 4, !dbg !54, !tbaa !31 ; line:7 col:7
|
||||
+ %21 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !56 ; line:8 col:7
|
||||
+ %22 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %21) #0, !dbg !56 ; line:8 col:7
|
||||
+ %23 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %22, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !56 ; line:8 col:7
|
||||
+ %24 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %23, i32 0) #0, !dbg !56 ; line:8 col:7
|
||||
+ %25 = icmp ne i32 %24, 0, !dbg !56 ; line:8 col:7
|
||||
+ br i1 %25, label %"\01?main_inner@@YAMXZ.exit", label %26, !dbg !56 ; line:8 col:7
|
||||
+
|
||||
+; <label>:26 ; preds = %18
|
||||
+ %27 = load i32, i32* %i.i.1.i, align 4, !dbg !57, !tbaa !31 ; line:11 col:18
|
||||
+ %28 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %27, !dbg !58 ; line:11 col:13
|
||||
+ %29 = load i32, i32* %28, align 4, !dbg !58, !tbaa !31 ; line:11 col:13
|
||||
+ %30 = load i32, i32* %i.i.1.i, align 4, !dbg !59, !tbaa !31 ; line:11 col:8
|
||||
+ %31 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %30, !dbg !60 ; line:11 col:3
|
||||
+ store i32 %29, i32* %31, align 4, !dbg !61, !tbaa !31 ; line:11 col:11
|
||||
+ %32 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !62, !tbaa !31 ; line:12 col:18
|
||||
+ %33 = sitofp i32 %32 to float, !dbg !62 ; line:12 col:18
|
||||
+ store float %33, float* %1, align 4, !dbg !63, !tbaa !43 ; line:12 col:10
|
||||
+ br label %"\01?main_inner@@YAMXZ.exit", !dbg !64 ; line:13 col:1
|
||||
+
|
||||
+"\01?main_inner@@YAMXZ.exit": ; preds = %18, %26
|
||||
+ %34 = load float, float* %1, align 4, !dbg !65, !tbaa !43 ; line:28 col:10
|
||||
+ store float %34, float* %inner_result, align 4, !dbg !66, !tbaa !43 ; line:32 col:9
|
||||
+ %35 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !67 ; line:33 col:45
|
||||
+ store <4 x float> zeroinitializer, <4 x float>* %35, !dbg !67 ; line:33 col:45
|
||||
+ %36 = load float, float* %inner_result, align 4, !dbg !68, !tbaa !43 ; line:34 col:28
|
||||
+ %37 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !69 ; line:34 col:18
|
||||
+ %38 = load <4 x float>, <4 x float>* %37, align 4, !dbg !70 ; line:34 col:26
|
||||
+ %39 = getelementptr <4 x float>, <4 x float>* %37, i32 0, i32 0, !dbg !70 ; line:34 col:26
|
||||
+ store float %36, float* %39, !dbg !70 ; line:34 col:26
|
||||
+ %40 = bitcast %struct.tint_symbol* %agg.result to i8*, !dbg !71 ; line:35 col:10
|
||||
+ %41 = bitcast %struct.tint_symbol* %wrapper_result to i8*, !dbg !71 ; line:35 col:10
|
||||
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %40, i8* %41, i64 16, i32 1, i1 false), !dbg !71 ; line:35 col:10
|
||||
+ ret void, !dbg !72 ; line:35 col:3
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readonly }
|
||||
+attributes #2 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.typeAnnotations = !{!6, !9}
|
||||
+!dx.entryPoints = !{!14}
|
||||
+!dx.fnprops = !{!20}
|
||||
+!dx.options = !{!21, !22}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4547 (14ec4b49d)"}
|
||||
+!3 = !{i32 1, i32 2}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 2}
|
||||
+!6 = !{i32 0, %struct.tint_symbol undef, !7}
|
||||
+!7 = !{i32 16, !8}
|
||||
+!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!9 = !{i32 1, void (%struct.tint_symbol*)* @main, !10}
|
||||
+!10 = !{!11, !13}
|
||||
+!11 = !{i32 0, !12, !12}
|
||||
+!12 = !{}
|
||||
+!13 = !{i32 1, !12, !12}
|
||||
+!14 = !{void (%struct.tint_symbol*)* @main, !"main", null, !15, null}
|
||||
+!15 = !{!16, null, !18, null}
|
||||
+!16 = !{!17}
|
||||
+!17 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
|
||||
+!18 = !{!19}
|
||||
+!19 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null}
|
||||
+!20 = !{void (%struct.tint_symbol*)* @main, i32 0, i1 false}
|
||||
+!21 = !{i32 144}
|
||||
+!22 = !{i32 -1}
|
||||
+!23 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !27)
|
||||
+!24 = !DISubprogram(name: "foo", scope: !25, file: !25, line: 6, type: !26, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!25 = !DIFile(filename: "333414294_simplifed.hlsl", directory: "")
|
||||
+!26 = !DISubroutineType(types: !12)
|
||||
+!27 = distinct !DILocation(line: 20, column: 3, scope: !28, inlinedAt: !29)
|
||||
+!28 = !DISubprogram(name: "main_inner", scope: !25, file: !25, line: 19, type: !26, isLocal: false, isDefinition: true, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!29 = distinct !DILocation(line: 32, column: 24, scope: !30)
|
||||
+!30 = !DISubprogram(name: "main", scope: !25, file: !25, line: 31, type: !26, isLocal: false, isDefinition: true, scopeLine: 31, flags: DIFlagPrototyped, isOptimized: false, function: void (%struct.tint_symbol*)* @main)
|
||||
+!31 = !{!32, !32, i64 0}
|
||||
+!32 = !{!"int", !33, i64 0}
|
||||
+!33 = !{!"omnipotent char", !34, i64 0}
|
||||
+!34 = !{!"Simple C/C++ TBAA"}
|
||||
+!35 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !27)
|
||||
+!36 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !27)
|
||||
+!37 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !27)
|
||||
+!38 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !27)
|
||||
+!39 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !27)
|
||||
+!40 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !27)
|
||||
+!41 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !27)
|
||||
+!42 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !27)
|
||||
+!43 = !{!44, !44, i64 0}
|
||||
+!44 = !{!"float", !33, i64 0}
|
||||
+!45 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !27)
|
||||
+!46 = !DILocation(line: 21, column: 8, scope: !28, inlinedAt: !29)
|
||||
+!47 = !{!48, !48, i64 0}
|
||||
+!48 = !{!"bool", !33, i64 0}
|
||||
+!49 = !DILocation(line: 22, column: 3, scope: !28, inlinedAt: !29)
|
||||
+!50 = !DILocation(line: 23, column: 9, scope: !28, inlinedAt: !29)
|
||||
+!51 = !{i32 0, i32 2}
|
||||
+!52 = !DILocation(line: 25, column: 23, scope: !28, inlinedAt: !29)
|
||||
+!53 = !DILocation(line: 26, column: 10, scope: !28, inlinedAt: !29)
|
||||
+!54 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !55)
|
||||
+!55 = distinct !DILocation(line: 27, column: 3, scope: !28, inlinedAt: !29)
|
||||
+!56 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !55)
|
||||
+!57 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !55)
|
||||
+!58 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !55)
|
||||
+!59 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !55)
|
||||
+!60 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !55)
|
||||
+!61 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !55)
|
||||
+!62 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !55)
|
||||
+!63 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !55)
|
||||
+!64 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !55)
|
||||
+!65 = !DILocation(line: 28, column: 10, scope: !28, inlinedAt: !29)
|
||||
+!66 = !DILocation(line: 32, column: 9, scope: !30)
|
||||
+!67 = !DILocation(line: 33, column: 45, scope: !30)
|
||||
+!68 = !DILocation(line: 34, column: 28, scope: !30)
|
||||
+!69 = !DILocation(line: 34, column: 18, scope: !30)
|
||||
+!70 = !DILocation(line: 34, column: 26, scope: !30)
|
||||
+!71 = !DILocation(line: 35, column: 10, scope: !30)
|
||||
+!72 = !DILocation(line: 35, column: 3, scope: !30)
|
||||
332
patches/DirectXShaderCompiler/cherry-pick-33051b084850.patch
Normal file
332
patches/DirectXShaderCompiler/cherry-pick-33051b084850.patch
Normal file
@@ -0,0 +1,332 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Mon, 10 Jun 2024 10:52:30 -0400
|
||||
Subject: Loop exit restructurizer: don't iterate over uses while mutating them
|
||||
(#6644)
|
||||
|
||||
The SkipBlockWithBranch function does the following:
|
||||
- Splits the block into three blocks with an if-then-endif structure.
|
||||
- Moves most instructions from the original block into the "then" block
|
||||
- If any of those values are used outside the original block, they are
|
||||
propagated through newly-constructed phis in the 'endif' block.
|
||||
|
||||
This algorithm had a bug where the uses of a value were being scanned
|
||||
while the uses were also being updated. In some cases a downstream
|
||||
out-of-block use could be skipped. That results in an invalid module
|
||||
because now the original definition is now in the 'then' block, which
|
||||
does not dominate the downstream out-of-block use.
|
||||
|
||||
Add a test that demonstrates the problem.
|
||||
|
||||
Bug: chromium:339171223
|
||||
Change-Id: Ia34fd7a2fe84de635289f7499772d11866a28e24
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5615350
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
index ef6718f0f22ee33e3f16f9801a64c1a6fb6c653a..70e6ccd8ddbaeabdb469710ad8529933f0286abd 100644
|
||||
--- a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
+++ b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
@@ -322,24 +322,26 @@ static void SkipBlockWithBranch(BasicBlock *bb, Value *cond, Loop *L,
|
||||
BranchInst::Create(end, body, cond, bb);
|
||||
|
||||
for (Instruction &inst : *body) {
|
||||
- PHINode *phi = nullptr;
|
||||
|
||||
// For each user that's outside of 'body', replace its use of 'inst' with a
|
||||
// phi created in 'end'
|
||||
- for (auto it = inst.user_begin(); it != inst.user_end();) {
|
||||
- Instruction *user_inst = cast<Instruction>(*(it++));
|
||||
- if (user_inst == phi)
|
||||
- continue;
|
||||
+ SmallPtrSet<Instruction *, 8> users_in_other_blocks;
|
||||
+ for (auto *user : inst.users()) {
|
||||
+ Instruction *user_inst = cast<Instruction>(user);
|
||||
if (user_inst->getParent() != body) {
|
||||
- if (!phi) {
|
||||
- phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
|
||||
- phi->addIncoming(GetDefaultValue(inst.getType()), bb);
|
||||
- phi->addIncoming(&inst, body);
|
||||
- }
|
||||
+ users_in_other_blocks.insert(user_inst);
|
||||
+ }
|
||||
+ }
|
||||
+ if (users_in_other_blocks.size() > 0) {
|
||||
+ auto *phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
|
||||
+ phi->addIncoming(GetDefaultValue(inst.getType()), bb);
|
||||
+ phi->addIncoming(&inst, body);
|
||||
+
|
||||
+ for (auto *user_inst : users_in_other_blocks) {
|
||||
user_inst->replaceUsesOfWith(&inst, phi);
|
||||
}
|
||||
- } // For each user of inst of body
|
||||
- } // For each inst in body
|
||||
+ }
|
||||
+ } // For each inst in body
|
||||
|
||||
L->addBasicBlockToLoop(body, *LI);
|
||||
L->addBasicBlockToLoop(end, *LI);
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ee912c929bdc0424959a29d16c3d5c64f885f809
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
|
||||
@@ -0,0 +1,257 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -loop-unroll,StructurizeLoopExits=1 -S | FileCheck %s
|
||||
+
|
||||
+; The Loop exit structurizer will wrap the definition of %DerivFineX3 in a conditional block.
|
||||
+; Its value will later be propagated into a phi, and that phi replaces all further uses
|
||||
+; of %DerivFineX3.
|
||||
+;
|
||||
+; Tests that a bug is fixed where the code used to iterate through the uses of a value
|
||||
+; while also updating those uses. The old code would fail to update the definition
|
||||
+; of %g.i.2.i3 and the result would be an invalid module: %DerivFineX3 would not dominate
|
||||
+; all its uses.
|
||||
+
|
||||
+
|
||||
+; CHECK: define void @main
|
||||
+; CHECK-NOT: %DerivFineX3
|
||||
+; CHECK: "\01?f@@YAXXZ.exit.i":
|
||||
+; CHECK-NEXT: br i1 true, label %dx.struct_exit.cond_end, label %dx.struct_exit.cond_body
|
||||
+
|
||||
+; CHECK: dx.struct_exit.cond_body:
|
||||
+; CHECK: %DerivFineX3 = call
|
||||
+; CHECK: br label %dx.struct_exit.cond_end
|
||||
+
|
||||
+; CHECK: dx.struct_exit.cond_end:
|
||||
+; CHECK: = phi {{.*}} %DerivFineX3
|
||||
+; CHECK: br
|
||||
+; CHECK-NOT: %DerivFineX3
|
||||
+; CHECK: ret void
|
||||
+
|
||||
+
|
||||
+;
|
||||
+;
|
||||
+; void f() {
|
||||
+; int l_1 = 10;
|
||||
+; for (int l = 0, l_2 = 0; l < 5 && l_2 < 1; l++, l_2++) {
|
||||
+; while (1 < l_1) { }
|
||||
+; }
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; struct tint_symbol {
|
||||
+; float4 value : SV_Target0;
|
||||
+; };
|
||||
+;
|
||||
+; float4 main_inner() {
|
||||
+; float4 g = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
+; bool2 true2 = (true).xx;
|
||||
+; uint2 _e8 = (0u).xx;
|
||||
+; do {
|
||||
+; if (_e8.x != 2u) {
|
||||
+; f();
|
||||
+; float4 _e15 = ddx_fine(g);
|
||||
+; if (_e8[_e8.x] == 2u) {
|
||||
+; g = _e15;
|
||||
+; } else {
|
||||
+; f();
|
||||
+; }
|
||||
+; switch(_e8.x) {
|
||||
+; case 3u: {
|
||||
+; break;
|
||||
+; }
|
||||
+; case 2u: {
|
||||
+; g = _e15;
|
||||
+; break;
|
||||
+; }
|
||||
+; default: {
|
||||
+; g = _e15;
|
||||
+; }
|
||||
+; }
|
||||
+; f();
|
||||
+; }
|
||||
+; } while(!all(true2));
|
||||
+; return g;
|
||||
+;}
|
||||
+;
|
||||
+;tint_symbol main() {
|
||||
+; float4 inner_result = main_inner();
|
||||
+; tint_symbol wrapper_result = (tint_symbol)0;
|
||||
+; wrapper_result.value = inner_result;
|
||||
+; return wrapper_result;
|
||||
+;}
|
||||
+
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.tint_symbol = type { <4 x float> }
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(<4 x float>* noalias) #0 {
|
||||
+entry:
|
||||
+ %1 = alloca [2 x i32], align 4
|
||||
+ %2 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !20 ; line:17 col:9
|
||||
+ store i32 0, i32* %2, align 4, !dbg !20 ; line:17 col:9
|
||||
+ %3 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 1, !dbg !20 ; line:17 col:9
|
||||
+ store i32 0, i32* %3, align 4, !dbg !20 ; line:17 col:9
|
||||
+ br label %do.body.i, !dbg !26 ; line:18 col:3
|
||||
+
|
||||
+do.body.i: ; preds = %do.cond.i, %entry
|
||||
+ %g.i.0.i0 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i0, %do.cond.i ]
|
||||
+ %g.i.0.i1 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i1, %do.cond.i ]
|
||||
+ %g.i.0.i2 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i2, %do.cond.i ]
|
||||
+ %g.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i3, %do.cond.i ]
|
||||
+ %4 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !27 ; line:19 col:9
|
||||
+ %5 = load i32, i32* %4, align 4, !dbg !27 ; line:19 col:9
|
||||
+ %cmp.i = icmp ne i32 %5, 2, !dbg !28 ; line:19 col:15
|
||||
+ br i1 %cmp.i, label %for.cond.i.i, label %do.cond.i, !dbg !27 ; line:19 col:9
|
||||
+
|
||||
+for.cond.i.i: ; preds = %do.body.i
|
||||
+ br i1 true, label %while.cond.i.i.preheader, label %"\01?f@@YAXXZ.exit.i", !dbg !29 ; line:4 col:3
|
||||
+
|
||||
+while.cond.i.i.preheader: ; preds = %for.cond.i.i
|
||||
+ br label %while.cond.i.i, !dbg !32 ; line:5 col:5
|
||||
+
|
||||
+while.cond.i.i: ; preds = %while.cond.i.i.preheader, %while.cond.i.i
|
||||
+ br label %while.cond.i.i, !dbg !32 ; line:5 col:5
|
||||
+
|
||||
+"\01?f@@YAXXZ.exit.i": ; preds = %for.cond.i.i
|
||||
+ %DerivFineX = call float @dx.op.unary.f32(i32 85, float %g.i.0.i0), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %DerivFineX1 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i1), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %DerivFineX2 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i2), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %DerivFineX3 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i3), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %6 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !34 ; line:22 col:15
|
||||
+ %7 = load i32, i32* %6, align 4, !dbg !34 ; line:22 col:15
|
||||
+ %8 = getelementptr [2 x i32], [2 x i32]* %1, i32 0, i32 %7, !dbg !35 ; line:22 col:11
|
||||
+ %9 = load i32, i32* %8, !dbg !35, !tbaa !36 ; line:22 col:11
|
||||
+ %cmp6.i = icmp eq i32 %9, 2, !dbg !40 ; line:22 col:22
|
||||
+ br i1 %cmp6.i, label %if.end.i, label %for.cond.i.19.i, !dbg !35 ; line:22 col:11
|
||||
+
|
||||
+for.cond.i.19.i: ; preds = %"\01?f@@YAXXZ.exit.i"
|
||||
+ br i1 true, label %while.cond.i.24.i.preheader, label %if.end.i, !dbg !41 ; line:4 col:3
|
||||
+
|
||||
+while.cond.i.24.i.preheader: ; preds = %for.cond.i.19.i
|
||||
+ br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
|
||||
+
|
||||
+while.cond.i.24.i: ; preds = %while.cond.i.24.i.preheader, %while.cond.i.24.i
|
||||
+ br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
|
||||
+
|
||||
+if.end.i: ; preds = %for.cond.i.19.i, %"\01?f@@YAXXZ.exit.i"
|
||||
+ %g.i.1.i0 = phi float [ %DerivFineX, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i0, %for.cond.i.19.i ]
|
||||
+ %g.i.1.i1 = phi float [ %DerivFineX1, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i1, %for.cond.i.19.i ]
|
||||
+ %g.i.1.i2 = phi float [ %DerivFineX2, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i2, %for.cond.i.19.i ]
|
||||
+ %g.i.1.i3 = phi float [ %DerivFineX3, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i3, %for.cond.i.19.i ]
|
||||
+ %10 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !44 ; line:27 col:14
|
||||
+ %11 = load i32, i32* %10, align 4, !dbg !44 ; line:27 col:14
|
||||
+ switch i32 %11, label %sw.default.i [
|
||||
+ i32 3, label %for.cond.i.5.i
|
||||
+ i32 2, label %sw.bb.10.i
|
||||
+ ], !dbg !45 ; line:27 col:7
|
||||
+
|
||||
+sw.bb.10.i: ; preds = %if.end.i
|
||||
+ br label %for.cond.i.5.i, !dbg !46 ; line:33 col:11
|
||||
+
|
||||
+sw.default.i: ; preds = %if.end.i
|
||||
+ br label %for.cond.i.5.i, !dbg !47 ; line:38 col:7
|
||||
+
|
||||
+for.cond.i.5.i: ; preds = %if.end.i, %sw.bb.10.i, %sw.default.i
|
||||
+ %g.i.2.i0 = phi float [ %DerivFineX, %sw.default.i ], [ %DerivFineX, %sw.bb.10.i ], [ %g.i.1.i0, %if.end.i ]
|
||||
+ %g.i.2.i1 = phi float [ %DerivFineX1, %sw.default.i ], [ %DerivFineX1, %sw.bb.10.i ], [ %g.i.1.i1, %if.end.i ]
|
||||
+ %g.i.2.i2 = phi float [ %DerivFineX2, %sw.default.i ], [ %DerivFineX2, %sw.bb.10.i ], [ %g.i.1.i2, %if.end.i ]
|
||||
+ %g.i.2.i3 = phi float [ %DerivFineX3, %sw.default.i ], [ %DerivFineX3, %sw.bb.10.i ], [ %g.i.1.i3, %if.end.i ]
|
||||
+ br i1 true, label %while.cond.i.10.i.preheader, label %do.cond.i, !dbg !48 ; line:4 col:3
|
||||
+
|
||||
+while.cond.i.10.i.preheader: ; preds = %for.cond.i.5.i
|
||||
+ br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
|
||||
+
|
||||
+while.cond.i.10.i: ; preds = %while.cond.i.10.i.preheader, %while.cond.i.10.i
|
||||
+ br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
|
||||
+
|
||||
+do.cond.i: ; preds = %for.cond.i.5.i, %do.body.i
|
||||
+ %g.i.3.i0 = phi float [ %g.i.0.i0, %do.body.i ], [ %g.i.2.i0, %for.cond.i.5.i ]
|
||||
+ %g.i.3.i1 = phi float [ %g.i.0.i1, %do.body.i ], [ %g.i.2.i1, %for.cond.i.5.i ]
|
||||
+ %g.i.3.i2 = phi float [ %g.i.0.i2, %do.body.i ], [ %g.i.2.i2, %for.cond.i.5.i ]
|
||||
+ %g.i.3.i3 = phi float [ %g.i.0.i3, %do.body.i ], [ %g.i.2.i3, %for.cond.i.5.i ]
|
||||
+ br i1 false, label %do.body.i, label %"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit", !dbg !51 ; line:41 col:3
|
||||
+
|
||||
+"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit": ; preds = %do.cond.i
|
||||
+ %g.i.3.i3.lcssa = phi float [ %g.i.3.i3, %do.cond.i ]
|
||||
+ %g.i.3.i2.lcssa = phi float [ %g.i.3.i2, %do.cond.i ]
|
||||
+ %g.i.3.i1.lcssa = phi float [ %g.i.3.i1, %do.cond.i ]
|
||||
+ %g.i.3.i0.lcssa = phi float [ %g.i.3.i0, %do.cond.i ]
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %g.i.3.i0.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %g.i.3.i1.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %g.i.3.i2.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %g.i.3.i3.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ ret void, !dbg !53 ; line:49 col:3
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare float @dx.op.unary.f32(i32, float) #1
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.typeAnnotations = !{!6, !9}
|
||||
+!dx.entryPoints = !{!16}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.14549 (main, 0781ded87-dirty)"}
|
||||
+!3 = !{i32 1, i32 0}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 0}
|
||||
+!6 = !{i32 0, %struct.tint_symbol undef, !7}
|
||||
+!7 = !{i32 16, !8}
|
||||
+!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!9 = !{i32 1, void (<4 x float>*)* @main, !10}
|
||||
+!10 = !{!11, !13}
|
||||
+!11 = !{i32 0, !12, !12}
|
||||
+!12 = !{}
|
||||
+!13 = !{i32 1, !14, !15}
|
||||
+!14 = !{i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!15 = !{i32 0}
|
||||
+!16 = !{void (<4 x float>*)* @main, !"main", !17, null, null}
|
||||
+!17 = !{null, !18, null}
|
||||
+!18 = !{!19}
|
||||
+!19 = !{i32 0, !"SV_Target", i8 9, i8 16, !15, i8 0, i32 1, i8 4, i32 0, i8 0, null}
|
||||
+!20 = !DILocation(line: 17, column: 9, scope: !21, inlinedAt: !24)
|
||||
+!21 = !DISubprogram(name: "main_inner", scope: !22, file: !22, line: 14, type: !23, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!22 = !DIFile(filename: "s2.hlsl", directory: "")
|
||||
+!23 = !DISubroutineType(types: !12)
|
||||
+!24 = distinct !DILocation(line: 46, column: 25, scope: !25)
|
||||
+!25 = !DISubprogram(name: "main", scope: !22, file: !22, line: 45, type: !23, isLocal: false, isDefinition: true, scopeLine: 45, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
|
||||
+!26 = !DILocation(line: 18, column: 3, scope: !21, inlinedAt: !24)
|
||||
+!27 = !DILocation(line: 19, column: 9, scope: !21, inlinedAt: !24)
|
||||
+!28 = !DILocation(line: 19, column: 15, scope: !21, inlinedAt: !24)
|
||||
+!29 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !31)
|
||||
+!30 = !DISubprogram(name: "f", scope: !22, file: !22, line: 2, type: !23, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!31 = distinct !DILocation(line: 20, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!32 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !31)
|
||||
+!33 = !DILocation(line: 21, column: 21, scope: !21, inlinedAt: !24)
|
||||
+!34 = !DILocation(line: 22, column: 15, scope: !21, inlinedAt: !24)
|
||||
+!35 = !DILocation(line: 22, column: 11, scope: !21, inlinedAt: !24)
|
||||
+!36 = !{!37, !37, i64 0}
|
||||
+!37 = !{!"int", !38, i64 0}
|
||||
+!38 = !{!"omnipotent char", !39, i64 0}
|
||||
+!39 = !{!"Simple C/C++ TBAA"}
|
||||
+!40 = !DILocation(line: 22, column: 22, scope: !21, inlinedAt: !24)
|
||||
+!41 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !42)
|
||||
+!42 = distinct !DILocation(line: 25, column: 9, scope: !21, inlinedAt: !24)
|
||||
+!43 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !42)
|
||||
+!44 = !DILocation(line: 27, column: 14, scope: !21, inlinedAt: !24)
|
||||
+!45 = !DILocation(line: 27, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!46 = !DILocation(line: 33, column: 11, scope: !21, inlinedAt: !24)
|
||||
+!47 = !DILocation(line: 38, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!48 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !49)
|
||||
+!49 = distinct !DILocation(line: 39, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!50 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !49)
|
||||
+!51 = !DILocation(line: 41, column: 3, scope: !21, inlinedAt: !24)
|
||||
+!52 = !DILocation(line: 49, column: 10, scope: !25)
|
||||
+!53 = !DILocation(line: 49, column: 3, scope: !25)
|
||||
243
patches/DirectXShaderCompiler/cherry-pick-511cfef8e050.patch
Normal file
243
patches/DirectXShaderCompiler/cherry-pick-511cfef8e050.patch
Normal file
@@ -0,0 +1,243 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Mon, 27 May 2024 15:41:40 -0400
|
||||
Subject: Fix use-after-free in SimplifyCFG (#6628)
|
||||
|
||||
When SimplifySwitchOnSelect calls SimplifyTerminatorOnSelect, it holds
|
||||
onto the select's condition value to use for the conditional branch it
|
||||
replaces the switch with. When removing the switch's unused
|
||||
predecessors, it must make sure not to delete PHIs in case one of them
|
||||
is used by the condition value, otherwise the condition value itself may
|
||||
get deleted, resulting in an use-after-free.
|
||||
|
||||
Note that this was fixed in LLVM as well:
|
||||
|
||||
https://github.com/llvm/llvm-project/commit/dc3b67b4cad5c18a687edfabd50779c3c656c620
|
||||
|
||||
Bug: chromium:338103465
|
||||
Change-Id: Iff5d5f2e3ecf38a3fb22bbc65e7c33ad0de659fb
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570018
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: Natalie Chouinard <chouinard@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
index b45caa2929a5cc3aa064fdbd9c06c20ad9e1e155..0d3ba1e00719060c1e71fa238726f0c63bd5b32f 100644
|
||||
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
@@ -2619,7 +2619,10 @@ static bool SimplifyTerminatorOnSelect(TerminatorInst *OldTerm, Value *Cond,
|
||||
else if (Succ == KeepEdge2)
|
||||
KeepEdge2 = nullptr;
|
||||
else
|
||||
- Succ->removePredecessor(OldTerm->getParent());
|
||||
+ Succ->removePredecessor(
|
||||
+ OldTerm->getParent(),
|
||||
+ /*DontDeleteUselessPHIs=*/true // HLSL Change: foward port LLVM fix
|
||||
+ );
|
||||
}
|
||||
|
||||
IRBuilder<> Builder(OldTerm);
|
||||
diff --git a/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..149906c11285ed99a19c0fe1743801a795827792
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
|
||||
@@ -0,0 +1,199 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -simplifycfg -S | FileCheck %s
|
||||
+
|
||||
+; The IR below comes from the following HLSL.
|
||||
+; Compiling this HLSL with dxc was resulting in an ASAN
|
||||
+; use-after-free in SimplifyCFG during
|
||||
+; SimplifyTerminatorOnSelect because it was deleting
|
||||
+; a PHI node with an input value that the pass later
|
||||
+; emits (the select condition value).
|
||||
+
|
||||
+; ByteAddressBuffer buff : register(t0);
|
||||
+;
|
||||
+; [numthreads(1, 1, 1)]
|
||||
+; void main() {
|
||||
+; if (buff.Load(0u)) {
|
||||
+; return;
|
||||
+; }
|
||||
+;
|
||||
+; int i = 0;
|
||||
+; int j = 0;
|
||||
+; while (true) {
|
||||
+; bool a = (i < 2);
|
||||
+; switch(i) {
|
||||
+; case 0: {
|
||||
+; while (true) {
|
||||
+; bool b = (j < 2);
|
||||
+; if (b) {
|
||||
+; } else {
|
||||
+; break;
|
||||
+; }
|
||||
+; while (true) {
|
||||
+; int unused = 0;
|
||||
+; while (true) {
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; while (true) {
|
||||
+; while (true) {
|
||||
+; if (b) {
|
||||
+; if (b) return;
|
||||
+; } else {
|
||||
+; break;
|
||||
+; }
|
||||
+; while (true) {
|
||||
+; i = 0;
|
||||
+; if (b) break;
|
||||
+; }
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; j = (j + 2);
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+
|
||||
+; Make sure the phi node did not get deleted by simplifycfg
|
||||
+; CHECK: cleanup:
|
||||
+; CHECK-NEXT: %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ %.mux, %while.end.37 ]
|
||||
+; CHECK-NEXT: switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
|
||||
+
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; buff texture byte r/o T0 t0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.ByteAddressBuffer = type { i32 }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+
|
||||
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main() #0 {
|
||||
+entry:
|
||||
+ %0 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !17 ; line:5 col:7
|
||||
+ %1 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %0), !dbg !17 ; line:5 col:7
|
||||
+ %2 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %1, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef), !dbg !17 ; line:5 col:7
|
||||
+ %3 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %2, i32 0), !dbg !17 ; line:5 col:7
|
||||
+ %tobool = icmp ne i32 %3, 0, !dbg !17 ; line:5 col:7
|
||||
+ br i1 %tobool, label %return, label %while.body, !dbg !17 ; line:5 col:7
|
||||
+
|
||||
+while.body: ; preds = %while.body.3, %while.body, %cleanup.46, %entry
|
||||
+ %j.0 = phi i32 [ 0, %entry ], [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %j.1, %while.body.3 ]
|
||||
+ %i.0 = phi i32 [ 0, %entry ], [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %while.body.3 ]
|
||||
+ %cmp = icmp slt i32 %i.0, 2, !dbg !21 ; line:12 col:17
|
||||
+ %cond = icmp eq i32 %i.0, 0, !dbg !22 ; line:13 col:5
|
||||
+ br i1 %cond, label %while.body.3, label %while.body, !dbg !22 ; line:13 col:5
|
||||
+
|
||||
+while.body.3: ; preds = %cleanup.46.thread, %while.body, %cleanup.46
|
||||
+ %j.1 = phi i32 [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %add, %cleanup.46.thread ]
|
||||
+ %i.1 = phi i32 [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %cleanup.46.thread ]
|
||||
+ %cmp4 = icmp slt i32 %j.1, 2, !dbg !23 ; line:16 col:23
|
||||
+ br i1 %cmp4, label %while.body.11, label %while.body, !dbg !24 ; line:17 col:15
|
||||
+
|
||||
+while.body.11: ; preds = %while.body.3, %cleanup
|
||||
+ br label %while.body.13, !dbg !25 ; line:23 col:13
|
||||
+
|
||||
+while.body.13: ; preds = %while.body.13, %while.body.11
|
||||
+ br i1 %cmp, label %while.body.20, label %while.body.13, !dbg !26 ; line:24 col:19
|
||||
+
|
||||
+while.body.20: ; preds = %while.body.13, %while.end.37
|
||||
+ br i1 %cmp4, label %cleanup, label %while.end.37, !dbg !27 ; line:28 col:21
|
||||
+
|
||||
+while.end.37: ; preds = %while.body.20
|
||||
+ br i1 %cmp, label %cleanup, label %while.body.20, !dbg !28 ; line:39 col:19
|
||||
+
|
||||
+cleanup: ; preds = %while.end.37, %while.body.20
|
||||
+ %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ 8, %while.end.37 ]
|
||||
+ switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
|
||||
+ i32 0, label %while.body.11
|
||||
+ i32 8, label %cleanup.46.thread
|
||||
+ ]
|
||||
+
|
||||
+cleanup.46.thread: ; preds = %cleanup
|
||||
+ %add = add nsw i32 %j.1, 2, !dbg !29 ; line:43 col:18
|
||||
+ br label %while.body.3
|
||||
+
|
||||
+cleanup.46: ; preds = %cleanup
|
||||
+ switch i32 %cleanup.dest.slot.0, label %return [
|
||||
+ i32 0, label %while.body.3
|
||||
+ i32 6, label %while.body
|
||||
+ ]
|
||||
+
|
||||
+return: ; preds = %cleanup.46, %entry
|
||||
+ ret void, !dbg !30 ; line:48 col:1
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @llvm.lifetime.start(i64, i8* nocapture) #0
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @llvm.lifetime.end(i64, i8* nocapture) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readonly }
|
||||
+attributes #2 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.typeAnnotations = !{!6}
|
||||
+!dx.entryPoints = !{!10}
|
||||
+!dx.fnprops = !{!14}
|
||||
+!dx.options = !{!15, !16}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 6}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"cs", i32 6, i32 6}
|
||||
+!6 = !{i32 1, void ()* @main, !7}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 1, !9, !9}
|
||||
+!9 = !{}
|
||||
+!10 = !{void ()* @main, !"main", null, !11, null}
|
||||
+!11 = !{!12, null, null, null}
|
||||
+!12 = !{!13}
|
||||
+!13 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
|
||||
+!14 = !{void ()* @main, i32 5, i32 1, i32 1, i32 1}
|
||||
+!15 = !{i32 64}
|
||||
+!16 = !{i32 -1}
|
||||
+!17 = !DILocation(line: 5, column: 7, scope: !18)
|
||||
+!18 = !DISubprogram(name: "main", scope: !19, file: !19, line: 4, type: !20, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
|
||||
+!19 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/338103465/standalone_reduced.hlsl", directory: "")
|
||||
+!20 = !DISubroutineType(types: !9)
|
||||
+!21 = !DILocation(line: 12, column: 17, scope: !18)
|
||||
+!22 = !DILocation(line: 13, column: 5, scope: !18)
|
||||
+!23 = !DILocation(line: 16, column: 23, scope: !18)
|
||||
+!24 = !DILocation(line: 17, column: 15, scope: !18)
|
||||
+!25 = !DILocation(line: 23, column: 13, scope: !18)
|
||||
+!26 = !DILocation(line: 24, column: 19, scope: !18)
|
||||
+!27 = !DILocation(line: 28, column: 21, scope: !18)
|
||||
+!28 = !DILocation(line: 39, column: 19, scope: !18)
|
||||
+!29 = !DILocation(line: 43, column: 18, scope: !18)
|
||||
+!30 = !DILocation(line: 48, column: 1, scope: !18)
|
||||
108
patches/DirectXShaderCompiler/cherry-pick-867c1001637e.patch
Normal file
108
patches/DirectXShaderCompiler/cherry-pick-867c1001637e.patch
Normal file
@@ -0,0 +1,108 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Thu, 16 May 2024 14:24:27 -0400
|
||||
Subject: Fix invalid module bitcode when indexing a swizzled bool vector
|
||||
(#6582)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When indexing a swizzled bool vector, some HLSL-specific code in
|
||||
EmitCXXMemberOrOperatorMemberCallExpr kicks in to handle the
|
||||
HLSLVecType. In this case, we’re dealing with an ExtVectorElt because of
|
||||
the swizzle, so this function creates a GEP, Load, and Store on the
|
||||
vector. However, boolean scalars are returned as type i11 while the
|
||||
store is storing to a bool, which is an i32, so we need to insert a cast
|
||||
before the store.
|
||||
|
||||
Bug: chromium:338161969
|
||||
Change-Id: I45f8ec383be49210a10f725d8266b66fd30c34be
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5545820
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@google.com>
|
||||
|
||||
diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp
|
||||
index cc46d067e617f1032bd7bc3ea6f65276984df130..efef0593b334103e511d43e3986fed3c304d28a3 100644
|
||||
--- a/tools/clang/lib/CodeGen/CGExpr.cpp
|
||||
+++ b/tools/clang/lib/CodeGen/CGExpr.cpp
|
||||
@@ -1137,6 +1137,12 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
|
||||
return MDHelper.createRange(Min, End);
|
||||
}
|
||||
|
||||
+static bool ShouldEmitRangeMD(llvm::Value *Value, QualType Ty) {
|
||||
+ if (hasBooleanRepresentation(Ty))
|
||||
+ return cast<llvm::IntegerType>(Value->getType())->getBitWidth() != 1;
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
|
||||
unsigned Alignment, QualType Ty,
|
||||
SourceLocation Loc,
|
||||
@@ -1236,7 +1242,8 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
|
||||
EmitCheck(std::make_pair(Check, Kind), "load_invalid_value", StaticArgs,
|
||||
EmitCheckValue(Load));
|
||||
}
|
||||
- } else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
|
||||
+ } else if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
|
||||
+ ShouldEmitRangeMD(Load, Ty))
|
||||
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
|
||||
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
|
||||
|
||||
diff --git a/tools/clang/lib/CodeGen/CGExprCXX.cpp b/tools/clang/lib/CodeGen/CGExprCXX.cpp
|
||||
index 2efde7c30f7f25fed5b36fe7de062b31e6cd74a2..924a0f806e7a8acf310005a212bb3c50a3c519b9 100644
|
||||
--- a/tools/clang/lib/CodeGen/CGExprCXX.cpp
|
||||
+++ b/tools/clang/lib/CodeGen/CGExprCXX.cpp
|
||||
@@ -235,12 +235,17 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
|
||||
|
||||
llvm::Constant *zero = Builder.getInt32(0);
|
||||
llvm::Value *TmpThis = CreateTempAlloca(Ty);
|
||||
+ QualType ElTy = hlsl::GetElementTypeOrType(Base->getType());
|
||||
+ bool IsBool = ElTy->isSpecificBuiltinType(BuiltinType::Bool);
|
||||
for (unsigned i = 0; i < Ty->getVectorNumElements(); i++) {
|
||||
llvm::Value *EltIdx = Elts->getAggregateElement(i);
|
||||
llvm::Value *EltGEP = Builder.CreateGEP(This, {zero, EltIdx});
|
||||
llvm::Value *TmpEltGEP =
|
||||
Builder.CreateGEP(TmpThis, {zero, Builder.getInt32(i)});
|
||||
llvm::Value *Elt = Builder.CreateLoad(EltGEP);
|
||||
+ if (IsBool)
|
||||
+ Elt = Builder.CreateTrunc(
|
||||
+ Elt, llvm::Type::getInt1Ty(getLLVMContext()));
|
||||
Builder.CreateStore(Elt, TmpEltGEP);
|
||||
}
|
||||
This = TmpThis;
|
||||
diff --git a/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl b/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a47482d204547d01b8f237bdde0765e61e6b7ab0
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl
|
||||
@@ -0,0 +1,30 @@
|
||||
+// Test indexing a swizzled bool vector
|
||||
+// RUN: %dxc -fcgl -T cs_6_0 %s | FileCheck %s
|
||||
+
|
||||
+// This was asserting in Instructions.cpp with:
|
||||
+// void llvm::StoreInst::AssertOK(): Assertion `getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"' failed.
|
||||
+
|
||||
+// Make sure load of i32 gets truncated to i1 when indexing bool vectors
|
||||
+// CHECK: [[TMP:%[a-z0-9\.]+]] = alloca <2 x i1>
|
||||
+// CHECK: [[VA0:%[a-z0-9\.]+]] = getelementptr <2 x i1>, <2 x i1>* [[TMP]], i32 0, i32 0,
|
||||
+// CHECK-NEXT: [[VA1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds (<4 x i32>, <4 x i32>* @"\01?v_bool4@?1??main@@YAXXZ@3V?$vector@_N$03@@B", i32 0, i32 2),
|
||||
+// CHECK-NEXT: [[VA2:%[a-z0-9\.]+]] = trunc i32 [[VA1]] to i1,
|
||||
+// CHECK-NEXT: store i1 [[VA2]], i1* [[VA0]],
|
||||
+// CHECK-NEXT: [[VB0:%[a-z0-9\.]+]] = getelementptr <2 x i1>, <2 x i1>* [[TMP]], i32 0, i32 1,
|
||||
+// CHECK-NEXT: [[VB1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds (<4 x i32>, <4 x i32>* @"\01?v_bool4@?1??main@@YAXXZ@3V?$vector@_N$03@@B", i32 0, i32 3),
|
||||
+// CHECK-NEXT: [[VB2:%[a-z0-9\.]+]] = trunc i32 [[VB1]] to i1,
|
||||
+// CHECK-NEXT: store i1 [[VB2]], i1* [[VB0]],
|
||||
+
|
||||
+
|
||||
+cbuffer cbuffer_tint_symbol_3 : register(b0) {
|
||||
+ uint4 global_uint4[1];
|
||||
+};
|
||||
+
|
||||
+[numthreads(1, 1, 1)]
|
||||
+void main() {
|
||||
+ const bool4 v_bool4 = bool4(true, true, true, true);
|
||||
+ const uint gx = global_uint4[0].x;
|
||||
+ if (v_bool4.zw[gx] == 0) {
|
||||
+ GroupMemoryBarrierWithGroupSync();
|
||||
+ }
|
||||
+}
|
||||
66
patches/DirectXShaderCompiler/cherry-pick-a65e511a14b4.patch
Normal file
66
patches/DirectXShaderCompiler/cherry-pick-a65e511a14b4.patch
Normal file
@@ -0,0 +1,66 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Wed, 3 Apr 2024 15:58:51 -0400
|
||||
Subject: Fix ASAN use-after-free on unreferenced self-assignment of struct
|
||||
instance (#6466)
|
||||
|
||||
When deleting an unused memcpy, ScalarReplAggregatesHLSL was attempting
|
||||
to delete both the target and the source of the memcpy without first
|
||||
checking if they were both same, resulting in a double-delete.
|
||||
|
||||
Bug: chromium:331123811
|
||||
Change-Id: Idaef95a06b10a7fb6f0ca2e662972a44ec662fbc
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5419225
|
||||
Reviewed-by: David Neto <dneto@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@chromium.org>
|
||||
Reviewed-by: Ben Clayton <bclayton@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
index 59f32a953ac5991e38c44d685f0f8fc589377b4d..3f8ffdbcfa09a96899295fd85291cedb879a248b 100644
|
||||
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
@@ -1003,9 +1003,11 @@ void DeleteMemcpy(MemCpyInst *MI) {
|
||||
if (op0->user_empty())
|
||||
op0->eraseFromParent();
|
||||
}
|
||||
- if (Instruction *op1 = dyn_cast<Instruction>(Op1)) {
|
||||
- if (op1->user_empty())
|
||||
- op1->eraseFromParent();
|
||||
+ if (Op0 != Op1) {
|
||||
+ if (Instruction *op1 = dyn_cast<Instruction>(Op1)) {
|
||||
+ if (op1->user_empty())
|
||||
+ op1->eraseFromParent();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl b/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..81adf71867c9868992372e12dc1ba81aebb48344
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl
|
||||
@@ -0,0 +1,24 @@
|
||||
+// RUN: %dxc -T cs_6_0 %s | FileCheck %s
|
||||
+
|
||||
+// Validate that self-assignment of a static struct instance that is not
|
||||
+// referenced does not crash the compiler. This was resulting in an ASAN
|
||||
+// use-after-free in ScalarReplAggregatesHLSL because DeleteMemcpy would
|
||||
+// attempt to delete both source and target, even if both were the same.
|
||||
+// CHECK: define void @main() {
|
||||
+// CHECK-NEXT: ret void
|
||||
+// CHECK-NEXT: }
|
||||
+
|
||||
+struct MyStruct {
|
||||
+ int m0;
|
||||
+};
|
||||
+
|
||||
+static MyStruct s;
|
||||
+
|
||||
+void foo() {
|
||||
+ s = s;
|
||||
+}
|
||||
+
|
||||
+[numthreads(1, 1, 1)]
|
||||
+void main() {
|
||||
+ foo();
|
||||
+}
|
||||
294
patches/DirectXShaderCompiler/cherry-pick-b845fed99111.patch
Normal file
294
patches/DirectXShaderCompiler/cherry-pick-b845fed99111.patch
Normal file
@@ -0,0 +1,294 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Natalie Chouinard <chouinard@google.com>
|
||||
Date: Mon, 10 Jun 2024 18:21:40 +0000
|
||||
Subject: Fix LoopDeletion incorrectly updating PHI with multiple duplicate
|
||||
inputs (#6643)
|
||||
|
||||
LoopDeletion was incorrectly updating PHI nodes in the target block when
|
||||
it had duplicate input edges. This happens, for example, when deleting a
|
||||
loop that uses a switch with multiple cases that exit the same way.
|
||||
|
||||
After determining that this was the bug, I found this fix in LLVM:
|
||||
https://reviews.llvm.org/D34516 and applied it here.
|
||||
|
||||
Bug: 340196361
|
||||
Change-Id: I98b150bb9a164466eb84dd3d46f720d5d92ef909
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5616791
|
||||
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/LoopDeletion.cpp b/lib/Transforms/Scalar/LoopDeletion.cpp
|
||||
index 6c2c1d60548f5a8a7939fee70728e8a34572b648..6cd1fba7c085b6d61dcb23b073358fc4c798e099 100644
|
||||
--- a/lib/Transforms/Scalar/LoopDeletion.cpp
|
||||
+++ b/lib/Transforms/Scalar/LoopDeletion.cpp
|
||||
@@ -195,15 +195,29 @@ bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||
|
||||
// Rewrite phis in the exit block to get their inputs from
|
||||
// the preheader instead of the exiting block.
|
||||
- BasicBlock *exitingBlock = exitingBlocks[0];
|
||||
BasicBlock::iterator BI = exitBlock->begin();
|
||||
while (PHINode *P = dyn_cast<PHINode>(BI)) {
|
||||
- int j = P->getBasicBlockIndex(exitingBlock);
|
||||
- assert(j >= 0 && "Can't find exiting block in exit block's phi node!");
|
||||
- P->setIncomingBlock(j, preheader);
|
||||
- for (unsigned i = 1; i < exitingBlocks.size(); ++i)
|
||||
- P->removeIncomingValue(exitingBlocks[i]);
|
||||
+ // HLSL Change begin - apply https://reviews.llvm.org/D34516
|
||||
+ // Set the zero'th element of Phi to be from the preheader and remove all
|
||||
+ // other incoming values. Given the loop has dedicated exits, all other
|
||||
+ // incoming values must be from the exiting blocks.
|
||||
+ int PredIndex = 0;
|
||||
+ P->setIncomingBlock(PredIndex, preheader);
|
||||
+ // Removes all incoming values from all other exiting blocks (including
|
||||
+ // duplicate values from an exiting block).
|
||||
+ // Nuke all entries except the zero'th entry which is the preheader entry.
|
||||
+ // NOTE! We need to remove Incoming Values in the reverse order as done
|
||||
+ // below, to keep the indices valid for deletion (removeIncomingValues
|
||||
+ // updates getNumIncomingValues and shifts all values down into the operand
|
||||
+ // being deleted).
|
||||
+ for (unsigned i = 0, e = P->getNumIncomingValues() - 1; i != e; ++i)
|
||||
+ P->removeIncomingValue(e - i, false);
|
||||
+
|
||||
+ assert((P->getNumIncomingValues() == 1 &&
|
||||
+ P->getIncomingBlock(PredIndex) == preheader) &&
|
||||
+ "Should have exactly one value and that's from the preheader!");
|
||||
++BI;
|
||||
+ // HLSL Change end
|
||||
}
|
||||
|
||||
// Update the dominator tree and remove the instructions and blocks that will
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..62736bf2934a5db67ee75386431498f49e101f49
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
|
||||
@@ -0,0 +1,229 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -dxil-loop-deletion,NoSink=0 -S | FileCheck %s
|
||||
+
|
||||
+; This test was generated from the following HLSL:
|
||||
+;
|
||||
+; cbuffer cbuffer_g : register(b0) {
|
||||
+; uint4 gu4[1];
|
||||
+; };
|
||||
+;
|
||||
+; float4 f() {
|
||||
+; float4 r = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
+; int i = 0;
|
||||
+; int j = 0;
|
||||
+; while (true) {
|
||||
+; float a = asfloat(gu4[0].y);
|
||||
+; int ai = int(a);
|
||||
+; bool b = (j < ai);
|
||||
+; if (j >= ai) {
|
||||
+; break;
|
||||
+; }
|
||||
+; bool c = (i > 0);
|
||||
+; if (c) {
|
||||
+; break;
|
||||
+; } else {
|
||||
+; bool3 b3 = bool3(b.xxx);
|
||||
+; if (b3[i]) {
|
||||
+; switch(i) {
|
||||
+; case 0: return r;
|
||||
+; case -1: return r;
|
||||
+; }
|
||||
+; if (c) {
|
||||
+; break;
|
||||
+; }
|
||||
+; } else {
|
||||
+; r = float4(0.0f, 0.0f, 0.0f, a);
|
||||
+; }
|
||||
+; }
|
||||
+; i = j;
|
||||
+; j = (j + 1);
|
||||
+; }
|
||||
+; r = (0.0f).xxxx;
|
||||
+; return r;
|
||||
+; }
|
||||
+;
|
||||
+; struct return_val {
|
||||
+; float4 value : SV_Target0;
|
||||
+; };
|
||||
+;
|
||||
+; return_val main() {
|
||||
+; float4 inner_result = f();
|
||||
+; return_val wrapper_result = (return_val)0;
|
||||
+; wrapper_result.value = inner_result;
|
||||
+; return wrapper_result;
|
||||
+; }
|
||||
+;
|
||||
+; When compiling the above with dxc, ASAN reported a use-after-free in simplifycfg,
|
||||
+; which originated from a delete during the dxil-loop-deletion pass. This was due
|
||||
+; to a bug in LoopDeletion::runOnLoop that did not properly handle updated PHIs
|
||||
+; with duplicate input preds. After this test runs, the loop should be deleted,
|
||||
+; and the program optimized to simply write out 0s to the cbuffer.
|
||||
+
|
||||
+; CHECK: define void @main
|
||||
+; CHECK-NEXT: entry:
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00)
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00)
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00)
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00)
|
||||
+; CHECK-NEXT: ret void
|
||||
+
|
||||
+;
|
||||
+; Output signature:
|
||||
+;
|
||||
+; Name Index InterpMode DynIdx
|
||||
+; -------------------- ----- ---------------------- ------
|
||||
+; SV_Target 0
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+; cbuffer cbuffer_g
|
||||
+; {
|
||||
+;
|
||||
+; struct cbuffer_g
|
||||
+; {
|
||||
+;
|
||||
+; uint4 gu4[1]; ; Offset: 0
|
||||
+;
|
||||
+; } cbuffer_g; ; Offset: 0 Size: 16
|
||||
+;
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; cbuffer_g cbuffer NA NA CB0 cb0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%cbuffer_g = type { [1 x <4 x i32>] }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
|
||||
+%struct.return_val = type { <4 x float> }
|
||||
+
|
||||
+@cbuffer_g = external constant %cbuffer_g
|
||||
+@.hca = internal unnamed_addr constant [3 x i32] [i32 1, i32 1, i32 1]
|
||||
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%cbuffer_g* @cbuffer_g to i8*)], section "llvm.metadata"
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_g*, i32)"(i32, %cbuffer_g*, i32) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g) #0
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(<4 x float>* noalias nocapture readnone) #1 {
|
||||
+entry:
|
||||
+ %1 = load %cbuffer_g, %cbuffer_g* @cbuffer_g, align 4, !dbg !25 ; line:45 col:25
|
||||
+ %cbuffer_g = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32 160, %cbuffer_g %1), !dbg !25 ; line:45 col:25 ; CreateHandleForLib(Resource)
|
||||
+ %2 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_g, %dx.types.ResourceProperties { i32 13, i32 16 }), !dbg !25 ; line:45 col:25 ; AnnotateHandle(res,props) resource: CBuffer
|
||||
+ %3 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23 ; CBufferLoadLegacy(handle,regIndex)
|
||||
+ %4 = extractvalue %dx.types.CBufRet.i32 %3, 1, !dbg !29 ; line:10 col:23
|
||||
+ %5 = bitcast i32 %4 to float, !dbg !32 ; line:10 col:15
|
||||
+ %conv.i.6 = fptosi float %5 to i32, !dbg !33 ; line:11 col:18
|
||||
+ %cmp1.i.8 = icmp sgt i32 %conv.i.6, 0, !dbg !34 ; line:13 col:11
|
||||
+ br i1 %cmp1.i.8, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
|
||||
+
|
||||
+if.end.i: ; preds = %entry, %if.end.19.i
|
||||
+ %6 = phi float [ %9, %if.end.19.i ], [ %5, %entry ]
|
||||
+ %j.i.011 = phi i32 [ %add.i, %if.end.19.i ], [ 0, %entry ]
|
||||
+ %r.i.0.i310 = phi float [ %r.i.0.i310, %if.end.19.i ], [ 0.000000e+00, %entry ]
|
||||
+ %i.i.09 = phi i32 [ %j.i.011, %if.end.19.i ], [ 0, %entry ]
|
||||
+ %cmp4.i = icmp sgt i32 %i.i.09, 0, !dbg !36 ; line:16 col:17
|
||||
+ br i1 %cmp4.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", label %if.then.12.i, !dbg !37 ; line:17 col:9
|
||||
+
|
||||
+if.then.12.i: ; preds = %if.end.i
|
||||
+ switch i32 %i.i.09, label %if.end.19.i [
|
||||
+ i32 0, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
|
||||
+ i32 -1, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
|
||||
+ ], !dbg !38 ; line:22 col:9
|
||||
+
|
||||
+if.end.19.i: ; preds = %if.then.12.i
|
||||
+ %add.i = add nuw nsw i32 %j.i.011, 1, !dbg !39 ; line:34 col:12
|
||||
+ %7 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23 ; CBufferLoadLegacy(handle,regIndex)
|
||||
+ %8 = extractvalue %dx.types.CBufRet.i32 %7, 1, !dbg !29 ; line:10 col:23
|
||||
+ %9 = bitcast i32 %8 to float, !dbg !32 ; line:10 col:15
|
||||
+ %conv.i = fptosi float %9 to i32, !dbg !33 ; line:11 col:18
|
||||
+ %cmp.i = icmp slt i32 %add.i, %conv.i, !dbg !40 ; line:12 col:17
|
||||
+ br i1 %cmp.i, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
|
||||
+
|
||||
+"\01?f@@YA?AV?$vector@M$03@@XZ.exit": ; preds = %if.then.12.i, %if.then.12.i, %if.end.i, %if.end.19.i, %entry
|
||||
+ %retval.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %r.i.0.i310, %if.then.12.i ], [ %r.i.0.i310, %if.then.12.i ], [ 0.000000e+00, %if.end.i ], [ 0.000000e+00, %if.end.19.i ]
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %retval.i.0.i3), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ ret void, !dbg !42 ; line:48 col:3
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32, %dx.types.Handle, i32) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32, %cbuffer_g) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #0
|
||||
+
|
||||
+attributes #0 = { nounwind readnone }
|
||||
+attributes #1 = { nounwind }
|
||||
+attributes #2 = { nounwind readonly }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.resources = !{!6}
|
||||
+!dx.typeAnnotations = !{!9, !14}
|
||||
+!dx.entryPoints = !{!21}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 5}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 5}
|
||||
+!6 = !{null, null, !7, null}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 0, %cbuffer_g* @cbuffer_g, !"cbuffer_g", i32 0, i32 0, i32 1, i32 16, null}
|
||||
+!9 = !{i32 0, %struct.return_val undef, !10, %cbuffer_g undef, !12}
|
||||
+!10 = !{i32 16, !11}
|
||||
+!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!12 = !{i32 16, !13}
|
||||
+!13 = !{i32 6, !"gu4", i32 3, i32 0, i32 7, i32 5}
|
||||
+!14 = !{i32 1, void (<4 x float>*)* @main, !15}
|
||||
+!15 = !{!16, !18}
|
||||
+!16 = !{i32 0, !17, !17}
|
||||
+!17 = !{}
|
||||
+!18 = !{i32 1, !19, !20}
|
||||
+!19 = !{i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!20 = !{i32 0}
|
||||
+!21 = !{void (<4 x float>*)* @main, !"main", !22, !6, null}
|
||||
+!22 = !{null, !23, null}
|
||||
+!23 = !{!24}
|
||||
+!24 = !{i32 0, !"SV_Target", i8 9, i8 16, !20, i8 0, i32 1, i8 4, i32 0, i8 0, null}
|
||||
+!25 = !DILocation(line: 45, column: 25, scope: !26)
|
||||
+!26 = !DISubprogram(name: "main", scope: !27, file: !27, line: 44, type: !28, isLocal: false, isDefinition: true, scopeLine: 44, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
|
||||
+!27 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/340196361/standalone_reduced.hlsl", directory: "")
|
||||
+!28 = !DISubroutineType(types: !17)
|
||||
+!29 = !DILocation(line: 10, column: 23, scope: !30, inlinedAt: !31)
|
||||
+!30 = !DISubprogram(name: "f", scope: !27, file: !27, line: 5, type: !28, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!31 = distinct !DILocation(line: 45, column: 25, scope: !26)
|
||||
+!32 = !DILocation(line: 10, column: 15, scope: !30, inlinedAt: !31)
|
||||
+!33 = !DILocation(line: 11, column: 18, scope: !30, inlinedAt: !31)
|
||||
+!34 = !DILocation(line: 13, column: 11, scope: !30, inlinedAt: !31)
|
||||
+!35 = !DILocation(line: 13, column: 9, scope: !30, inlinedAt: !31)
|
||||
+!36 = !DILocation(line: 16, column: 17, scope: !30, inlinedAt: !31)
|
||||
+!37 = !DILocation(line: 17, column: 9, scope: !30, inlinedAt: !31)
|
||||
+!38 = !DILocation(line: 22, column: 9, scope: !30, inlinedAt: !31)
|
||||
+!39 = !DILocation(line: 34, column: 12, scope: !30, inlinedAt: !31)
|
||||
+!40 = !DILocation(line: 12, column: 17, scope: !30, inlinedAt: !31)
|
||||
+!41 = !DILocation(line: 48, column: 10, scope: !26)
|
||||
+!42 = !DILocation(line: 48, column: 3, scope: !26)
|
||||
57
patches/DirectXShaderCompiler/cherry-pick-bc18aec94c82.patch
Normal file
57
patches/DirectXShaderCompiler/cherry-pick-bc18aec94c82.patch
Normal file
@@ -0,0 +1,57 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Thu, 18 Apr 2024 13:07:04 -0400
|
||||
Subject: Replace dynamic_cast with virtual call (#6515)
|
||||
|
||||
Make TextDiagnosticPrinter::setPrefix a virtual function in base class
|
||||
DiagnosticConsumer. This allows us to avoid using dynamic_cast in
|
||||
BackendConsumer::DxilDiagHandler, required for codebases that do not
|
||||
enable RTTI. This is also the only place in the codebase that uses RTTI
|
||||
(AFAICT).
|
||||
|
||||
Bug: chromium:333420620
|
||||
Change-Id: Ida73077f24fdb4b705b5d868b04ac6cfecb30327
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5464347
|
||||
Reviewed-by: dan sinclair <dsinclair@chromium.org>
|
||||
Reviewed-by: David Neto <dneto@google.com>
|
||||
|
||||
diff --git a/tools/clang/include/clang/Basic/Diagnostic.h b/tools/clang/include/clang/Basic/Diagnostic.h
|
||||
index dc9f781c093c0bc8f6da773d514ac6d1503f842d..0b98dffb94185e242320409d43b74dae2c2a908d 100644
|
||||
--- a/tools/clang/include/clang/Basic/Diagnostic.h
|
||||
+++ b/tools/clang/include/clang/Basic/Diagnostic.h
|
||||
@@ -1395,6 +1395,8 @@ public:
|
||||
/// warnings and errors.
|
||||
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
|
||||
const Diagnostic &Info);
|
||||
+
|
||||
+ virtual void setPrefix(std::string Value) {} // HLSL Change
|
||||
};
|
||||
|
||||
/// \brief A diagnostic client that ignores all diagnostics.
|
||||
diff --git a/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
|
||||
index 04a570559fe06a0670ef8a7e6e94c40aa37e55a9..936031e09673a09c6e1164c515efce02ac51b910 100644
|
||||
--- a/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
|
||||
+++ b/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
|
||||
@@ -45,7 +45,8 @@ public:
|
||||
/// setPrefix - Set the diagnostic printer prefix string, which will be
|
||||
/// printed at the start of any diagnostics. If empty, no prefix string is
|
||||
/// used.
|
||||
- void setPrefix(std::string Value) { Prefix = Value; }
|
||||
+ // HLSL Change: add override
|
||||
+ void setPrefix(std::string Value) override { Prefix = Value; }
|
||||
|
||||
void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override;
|
||||
void EndSourceFile() override;
|
||||
diff --git a/tools/clang/lib/CodeGen/CodeGenAction.cpp b/tools/clang/lib/CodeGen/CodeGenAction.cpp
|
||||
index 4fa721e812296356e31fc1bf6ea35ce295c2592c..68ebaadf5a8960c8def189248412136fe9543422 100644
|
||||
--- a/tools/clang/lib/CodeGen/CodeGenAction.cpp
|
||||
+++ b/tools/clang/lib/CodeGen/CodeGenAction.cpp
|
||||
@@ -557,7 +557,7 @@ BackendConsumer::DxilDiagHandler(const llvm::DiagnosticInfoDxil &D) {
|
||||
|
||||
// If no location information is available, add function name
|
||||
if (Loc.isInvalid()) {
|
||||
- auto *DiagClient = dynamic_cast<TextDiagnosticPrinter*>(Diags.getClient());
|
||||
+ auto *DiagClient = Diags.getClient();
|
||||
auto *func = D.getFunction();
|
||||
if (DiagClient && func)
|
||||
DiagClient->setPrefix("Function: " + func->getName().str());
|
||||
161
patches/DirectXShaderCompiler/cherry-pick-bd7aa9779873.patch
Normal file
161
patches/DirectXShaderCompiler/cherry-pick-bd7aa9779873.patch
Normal file
@@ -0,0 +1,161 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Thu, 25 Apr 2024 16:49:11 -0400
|
||||
Subject: Fixed crash in loop unroll caused by bug in structurize loop exits
|
||||
(#6548)
|
||||
|
||||
Fixed a bug in `hlsl::RemoveUnstructuredLoopExits` where when a new
|
||||
exiting block is created from splitting, it was added to the current
|
||||
loop being processed, when it could also part of an inner loop. Not
|
||||
adding the new block to inner loops that it's part of makes the inner
|
||||
loops malformed, and causes crash.
|
||||
|
||||
This fix adds the new block to the inner most loop that it should be
|
||||
part of. Also adds the `StructurizeLoopExits` option to `loop-unroll`
|
||||
pass, which was missing before.
|
||||
|
||||
Bug: chromium:333508731
|
||||
Change-Id: I7efc21bc61aeb81b4906a600c35272af232710ea
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5490380
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: Ben Clayton <bclayton@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
index b6a07d6b27a23ee3831e84cee82299d6d405a288..ef6718f0f22ee33e3f16f9801a64c1a6fb6c653a 100644
|
||||
--- a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
+++ b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
@@ -447,7 +447,12 @@ static bool RemoveUnstructuredLoopExitsIteration(BasicBlock *exiting_block,
|
||||
new_exiting_block->splitBasicBlock(new_exiting_block->getFirstNonPHI());
|
||||
new_exiting_block->setName("dx.struct_exit.new_exiting");
|
||||
new_not_exiting_block->setName(old_name);
|
||||
- L->addBasicBlockToLoop(new_not_exiting_block, *LI);
|
||||
+ // Query for new_exiting_block's own loop to add new_not_exiting_block to.
|
||||
+ // It's possible that new_exiting_block is part of another inner loop
|
||||
+ // separate from L. If added directly to L, the inner loop(s) will not
|
||||
+ // contain new_not_exiting_block, making them malformed.
|
||||
+ Loop *inner_loop_of_exiting_block = LI->getLoopFor(new_exiting_block);
|
||||
+ inner_loop_of_exiting_block->addBasicBlockToLoop(new_not_exiting_block, *LI);
|
||||
|
||||
// Branch to latch_exit
|
||||
new_exiting_block->getTerminator()->eraseFromParent();
|
||||
diff --git a/lib/Transforms/Scalar/LoopUnrollPass.cpp b/lib/Transforms/Scalar/LoopUnrollPass.cpp
|
||||
index dd520f7e57d25311be7f3773849a00efaabe6717..b17a5a4a0bc368f16020c4153370ea2c92e5c26c 100644
|
||||
--- a/lib/Transforms/Scalar/LoopUnrollPass.cpp
|
||||
+++ b/lib/Transforms/Scalar/LoopUnrollPass.cpp
|
||||
@@ -155,6 +155,18 @@ namespace {
|
||||
bool UserAllowPartial;
|
||||
bool UserRuntime;
|
||||
|
||||
+ // HLSL Change - begin
|
||||
+ // Function overrides that resolve options when used for DxOpt
|
||||
+ void applyOptions(PassOptions O) override {
|
||||
+ GetPassOptionBool(O, "StructurizeLoopExits", &StructurizeLoopExits,
|
||||
+ false);
|
||||
+ }
|
||||
+ void dumpConfig(raw_ostream &OS) override {
|
||||
+ LoopPass::dumpConfig(OS);
|
||||
+ OS << ",StructurizeLoopExits=" << StructurizeLoopExits;
|
||||
+ }
|
||||
+ // HLSL Change - end
|
||||
+
|
||||
bool runOnLoop(Loop *L, LPPassManager &LPM) override;
|
||||
|
||||
/// This transformation requires natural loop information & requires that
|
||||
diff --git a/tools/clang/test/DXC/loop_structurize_exit_inner_latch_regression.ll b/tools/clang/test/DXC/loop_structurize_exit_inner_latch_regression.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..743135541cd8faec287164ba3b321a59432832b6
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/loop_structurize_exit_inner_latch_regression.ll
|
||||
@@ -0,0 +1,75 @@
|
||||
+; RUN: %dxopt %s -S -loop-unroll,StructurizeLoopExits=1 | FileCheck %s
|
||||
+; RUN: %dxopt %s -S -dxil-loop-unroll,StructurizeLoopExits=1 | FileCheck %s
|
||||
+
|
||||
+; CHECK: mul nsw i32
|
||||
+; CHECK: mul nsw i32
|
||||
+; CHECK-NOT: mul nsw i32
|
||||
+
|
||||
+; This is a regression test for a crash in loop unroll. When there are multiple
|
||||
+; exits, the compiler will run hlsl::RemoveUnstructuredLoopExits to try to
|
||||
+; avoid unstructured code.
|
||||
+;
|
||||
+; In this test, the compiler will try to unroll the middle loop. The exit edge
|
||||
+; from %land.lhs.true to %if.then will be removed, and %if.end will be split at
|
||||
+; the beginning, and branch to %if.end instead.
|
||||
+;
|
||||
+; Since the new split block at %if.end becomes the new latch of the inner-most
|
||||
+; loop, it needs to be added to the Loop analysis structure of the inner loop.
|
||||
+; However, it was only added to the current middle loop that is being unrolled.
|
||||
+
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(i32 *%arg0, i32 *%arg1, i32 *%arg2) #0 {
|
||||
+entry:
|
||||
+ br label %while.body.3.preheader.lr.ph
|
||||
+
|
||||
+while.body.3.preheader.lr.ph.loopexit: ; preds = %for.inc
|
||||
+ br label %while.body.3.preheader.lr.ph
|
||||
+
|
||||
+while.body.3.preheader.lr.ph: ; preds = %while.body.3.preheader.lr.ph.loopexit, %entry
|
||||
+ br label %while.body.3.preheader
|
||||
+
|
||||
+while.body.3.preheader: ; preds = %while.body.3.preheader.lr.ph, %for.inc
|
||||
+ %i.0 = phi i32 [ 0, %while.body.3.preheader.lr.ph ], [ %inc, %for.inc ]
|
||||
+ br label %while.body.3
|
||||
+
|
||||
+while.body.3: ; preds = %while.body.3.preheader, %if.end
|
||||
+ %load_arg0 = load i32, i32* %arg0
|
||||
+ %cmp4 = icmp sgt i32 %load_arg0, 0
|
||||
+ br i1 %cmp4, label %land.lhs.true, label %if.end
|
||||
+
|
||||
+land.lhs.true: ; preds = %while.body.3
|
||||
+ %load_arg1 = load i32, i32* %arg1
|
||||
+ %load_arg2 = load i32, i32* %arg2
|
||||
+ %mul = mul nsw i32 %load_arg2, %load_arg1
|
||||
+ %cmp7 = icmp eq i32 %mul, 10
|
||||
+ br i1 %cmp7, label %if.then, label %if.end
|
||||
+
|
||||
+if.then: ; preds = %land.lhs.true
|
||||
+ ret void
|
||||
+
|
||||
+if.end: ; preds = %land.lhs.true, %while.body.3
|
||||
+ %cmp10 = icmp sle i32 %i.0, 4
|
||||
+ br i1 %cmp10, label %for.inc, label %while.body.3
|
||||
+
|
||||
+for.inc: ; preds = %if.end
|
||||
+ %inc = add nsw i32 %i.0, 1
|
||||
+ %cmp = icmp slt i32 %inc, 2
|
||||
+ br i1 %cmp, label %while.body.3.preheader, label %while.body.3.preheader.lr.ph.loopexit, !llvm.loop !3
|
||||
+}
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readnone }
|
||||
+attributes #2 = { nounwind readonly }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.14563 (main, 07ce88034-dirty)"}
|
||||
+!3 = distinct !{!3, !4}
|
||||
+!4 = !{!"llvm.loop.unroll.full"}
|
||||
diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py
|
||||
index 77f5671016eb66a4ddf8a943ec8cb05e8d87c9cd..ca8d16bd2562e26e8572413499d32dc2232de5c0 100644
|
||||
--- a/utils/hct/hctdb.py
|
||||
+++ b/utils/hct/hctdb.py
|
||||
@@ -6680,6 +6680,12 @@ class db_dxil(object):
|
||||
"t": "unsigned",
|
||||
"d": "Unrolled size limit for loops with an unroll(full) or unroll_count pragma.",
|
||||
},
|
||||
+ {
|
||||
+ "n": "StructurizeLoopExits",
|
||||
+ "t": "bool",
|
||||
+ "c": 1,
|
||||
+ "d": "Whether the unroller should try to structurize loop exits first.",
|
||||
+ },
|
||||
],
|
||||
)
|
||||
add_pass("mldst-motion", "MergedLoadStoreMotion", "MergedLoadStoreMotion", [])
|
||||
5
patches/angle/.patches
Normal file
5
patches/angle/.patches
Normal file
@@ -0,0 +1,5 @@
|
||||
m123_vulkan_fix_access_to_inactive_attributes.patch
|
||||
cherry-pick-f6672dbbe223.patch
|
||||
cherry-pick-ba3b4e239620.patch
|
||||
cherry-pick-c67f290ef0f0.patch
|
||||
cherry-pick-bda89e1f7c71.patch
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user