mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
21 Commits
v34.0.0-be
...
v31.0.0-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12bc4dc6c0 | ||
|
|
cdf508a734 | ||
|
|
1dd99250c3 | ||
|
|
d2cb956a75 | ||
|
|
004ca01049 | ||
|
|
ec4ffa99b6 | ||
|
|
844265303c | ||
|
|
aee588b650 | ||
|
|
8f51e8fb5d | ||
|
|
773777f209 | ||
|
|
9437dd3ea8 | ||
|
|
fb5ffd2876 | ||
|
|
2d36065a15 | ||
|
|
e19963b0ac | ||
|
|
9c631ea744 | ||
|
|
9ab77e77b1 | ||
|
|
eb56416cb5 | ||
|
|
703241e1e7 | ||
|
|
0a8ed258da | ||
|
|
7ef5402599 | ||
|
|
a799513b2e |
@@ -27,7 +27,8 @@
|
||||
]
|
||||
},
|
||||
"vscode": {
|
||||
"extensions": ["joeleinbinder.mojom-language",
|
||||
"extensions": [
|
||||
"joeleinbinder.mojom-language",
|
||||
"rafaelmaiolla.diff",
|
||||
"surajbarkale.ninja",
|
||||
"ms-vscode.cpptools",
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
buildtools:
|
||||
image: ghcr.io/electron/devcontainer:3d8d44d0f15b05bef6149e448f9cc522111847e9
|
||||
image: ghcr.io/electron/devcontainer:9a43c14f5c19be0359843299f79e736521373adc
|
||||
|
||||
volumes:
|
||||
- ..:/workspaces/gclient/src/electron:cached
|
||||
|
||||
@@ -39,7 +39,6 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
write_config() {
|
||||
echo "
|
||||
{
|
||||
\"goma\": \"$1\",
|
||||
\"root\": \"/workspaces/gclient\",
|
||||
\"remotes\": {
|
||||
\"electron\": {
|
||||
@@ -49,7 +48,7 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
\"gen\": {
|
||||
\"args\": [
|
||||
\"import(\\\"//electron/build/args/testing.gn\\\")\",
|
||||
\"import(\\\"/home/builduser/.electron_build_tools/third_party/goma.gn\\\")\"
|
||||
\"use_remoteexec = true\"
|
||||
],
|
||||
\"out\": \"Testing\"
|
||||
},
|
||||
@@ -57,26 +56,18 @@ if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
\"CHROMIUM_BUILDTOOLS_PATH\": \"/workspaces/gclient/src/buildtools\",
|
||||
\"GIT_CACHE_PATH\": \"/workspaces/gclient/.git-cache\"
|
||||
},
|
||||
\"\$schema\": \"file:///home/builduser/.electron_build_tools/evm-config.schema.json\"
|
||||
\"\$schema\": \"file:///home/builduser/.electron_build_tools/evm-config.schema.json\",
|
||||
\"configValidationLevel\": \"strict\",
|
||||
\"reclient\": \"$1\",
|
||||
\"goma\": \"none\",
|
||||
\"preserveXcode\": 5
|
||||
}
|
||||
" >$buildtools/configs/evm.testing.json
|
||||
}
|
||||
|
||||
# Start out as cache only
|
||||
write_config cache-only
|
||||
write_config remote_exec
|
||||
|
||||
e use testing
|
||||
|
||||
# Attempt to auth to the goma service via codespaces tokens
|
||||
# if it works we can use the goma cluster
|
||||
export NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN
|
||||
if e d goma_auth login; then
|
||||
echo "$GITHUB_USER has GOMA access - switching to cluster mode"
|
||||
write_config cluster
|
||||
fi
|
||||
e use testing
|
||||
else
|
||||
echo "build-tools testing config already exists"
|
||||
|
||||
# Re-auth with the goma cluster regardless.
|
||||
NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN e d goma_auth login || true
|
||||
fi
|
||||
|
||||
@@ -50,10 +50,6 @@ is_cfi = false
|
||||
# TODO: fix this once sysroots have been updated.
|
||||
use_qt = false
|
||||
|
||||
# https://chromium-review.googlesource.com/c/chromium/src/+/4365718
|
||||
# TODO(codebytere): fix perfetto incompatibility with Node.js.
|
||||
use_perfetto_client_library = false
|
||||
|
||||
# Disables the builtins PGO for V8
|
||||
v8_builtins_profiling_log_file = ""
|
||||
|
||||
|
||||
@@ -600,7 +600,7 @@ Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls
|
||||
on the right edge and 50 pixels of controls below the player. In order to
|
||||
maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within
|
||||
the player itself we would call this function with arguments of 16/9 and
|
||||
{ width: 40, height: 50 }. The second argument doesn't care where the extra width and height
|
||||
\{ width: 40, height: 50 \}. The second argument doesn't care where the extra width and height
|
||||
are within the content view--only that they exist. Sum any extra width and
|
||||
height areas you have within the overall content view.
|
||||
|
||||
|
||||
@@ -723,7 +723,7 @@ Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls
|
||||
on the right edge and 50 pixels of controls below the player. In order to
|
||||
maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within
|
||||
the player itself we would call this function with arguments of 16/9 and
|
||||
{ width: 40, height: 50 }. The second argument doesn't care where the extra width and height
|
||||
\{ width: 40, height: 50 \}. The second argument doesn't care where the extra width and height
|
||||
are within the content view--only that they exist. Sum any extra width and
|
||||
height areas you have within the overall content view.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -66,7 +66,7 @@ requests according to the specified protocol scheme in the `options` object.
|
||||
### `net.fetch(input[, init])`
|
||||
|
||||
* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & { bypassCustomProtocolHandlers?: boolean } (optional)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & \{ bypassCustomProtocolHandlers?: boolean \} (optional)
|
||||
|
||||
Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
|
||||
|
||||
|
||||
@@ -695,7 +695,7 @@ Returns `Promise<void>` - Resolves when all connections are closed.
|
||||
#### `ses.fetch(input[, init])`
|
||||
|
||||
* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & { bypassCustomProtocolHandlers?: boolean } (optional)
|
||||
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & \{ bypassCustomProtocolHandlers?: boolean \} (optional)
|
||||
|
||||
Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
|
||||
|
||||
|
||||
@@ -110,22 +110,51 @@ $ export CHROMIUM_BUILDTOOLS_PATH=`pwd`/buildtools
|
||||
On Windows:
|
||||
|
||||
```sh
|
||||
# cmd
|
||||
$ cd src
|
||||
$ set CHROMIUM_BUILDTOOLS_PATH=%cd%\buildtools
|
||||
|
||||
# PowerShell
|
||||
$ cd src
|
||||
$ $env:CHROMIUM_BUILDTOOLS_PATH = "$(Get-Location)\buildtools"
|
||||
```
|
||||
|
||||
**To generate Testing build config of Electron:**
|
||||
|
||||
On Linux & MacOS
|
||||
|
||||
```sh
|
||||
$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")"
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```sh
|
||||
# cmd
|
||||
$ gn gen out/Testing --args="import(\"//electron/build/args/testing.gn\")"
|
||||
|
||||
# PowerShell
|
||||
gn gen out/Testing --args="import(\`"//electron/build/args/testing.gn\`")"
|
||||
```
|
||||
|
||||
**To generate Release build config of Electron:**
|
||||
|
||||
On Linux & MacOS
|
||||
|
||||
```sh
|
||||
$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")"
|
||||
```
|
||||
|
||||
On Windows:
|
||||
|
||||
```sh
|
||||
# cmd
|
||||
$ gn gen out/Release --args="import(\"//electron/build/args/release.gn\")"
|
||||
|
||||
# PowerShell
|
||||
$ gn gen out/Release --args="import(\`"//electron/build/args/release.gn\`")"
|
||||
```
|
||||
|
||||
**Note:** This will generate a `out/Testing` or `out/Release` build directory under `src/` with the testing or release build depending upon the configuration passed above. You can replace `Testing|Release` with another names, but it should be a subdirectory of `out`.
|
||||
|
||||
Also you shouldn't have to run `gn gen` again—if you want to change the build arguments, you can run `gn args out/Testing` to bring up an editor. To see the list of available build configuration options, run `gn args out/Testing --list`.
|
||||
|
||||
@@ -15,7 +15,7 @@ calls, and other compiler optimizations. The only workaround is to build an
|
||||
unoptimized local build.
|
||||
|
||||
The official symbol server URL for Electron is
|
||||
<https://symbols.electronjs.org>.
|
||||
[https://symbols.electronjs.org](https://symbols.electronjs.org).
|
||||
You cannot visit this URL directly, you must add it to the symbol path of your
|
||||
debugging tool. In the examples below, a local cache directory is used to avoid
|
||||
repeatedly fetching the PDB from the server. Replace `c:\code\symbols` with an
|
||||
|
||||
@@ -78,7 +78,8 @@ JavaScript transpilers (e.g. Babel, TypeScript) have historically supported ES M
|
||||
syntax before Node.js supported ESM imports by turning these calls to CommonJS
|
||||
`require` calls.
|
||||
|
||||
<details><summary>Example: @babel/plugin-transform-modules-commonjs</summary>
|
||||
<details>
|
||||
<summary>Example: @babel/plugin-transform-modules-commonjs</summary>
|
||||
|
||||
The `@babel/plugin-transform-modules-commonjs` plugin will transform
|
||||
ESM imports down to `require` calls. The exact syntax will depend on the
|
||||
|
||||
@@ -121,7 +121,7 @@ need to install Node.js themselves as a prerequisite to running your app.
|
||||
|
||||
To check which version of Node.js is running in your app, you can access the global
|
||||
[`process.versions`][] variable in the main process or preload script. You can also reference
|
||||
<https://releases.electronjs.org/releases.json>.
|
||||
[https://releases.electronjs.org/releases.json](https://releases.electronjs.org/releases.json).
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@@ -222,7 +222,8 @@ with CommonJS module syntax:
|
||||
- [app][app], which controls your application's event lifecycle.
|
||||
- [BrowserWindow][browser-window], which creates and manages app windows.
|
||||
|
||||
<details><summary>Module capitalization conventions</summary>
|
||||
<details>
|
||||
<summary>Module capitalization conventions</summary>
|
||||
|
||||
You might have noticed the capitalization difference between the **a**pp
|
||||
and **B**rowser**W**indow modules. Electron follows typical JavaScript conventions here,
|
||||
@@ -231,7 +232,8 @@ Notification) whereas camelCase modules are not instantiable (e.g. app, ipcRende
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Typed import aliases</summary>
|
||||
<details>
|
||||
<summary>Typed import aliases</summary>
|
||||
|
||||
For better type checking when writing TypeScript code, you can choose to import
|
||||
main process modules from `electron/main`.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
If you want to embed (third-party) web content in an Electron `BrowserWindow`,
|
||||
there are three options available to you: `<iframe>` tags, `<webview>` tags,
|
||||
and `BrowserViews`. Each one offers slightly different functionality and is
|
||||
and `WebContentsView`. Each one offers slightly different functionality and is
|
||||
useful in different situations. To help you choose between these, this guide
|
||||
explains the differences and capabilities of each option.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ function makeStreamFromPipe (pipe: any): ReadableStream {
|
||||
try {
|
||||
const rv = await pipe.read(buf);
|
||||
if (rv > 0) {
|
||||
controller.enqueue(buf.subarray(0, rv));
|
||||
controller.enqueue(buf.slice(0, rv));
|
||||
} else {
|
||||
controller.close();
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ crash_allow_setting_more_options.patch
|
||||
upload_list_add_loadsync_method.patch
|
||||
allow_setting_secondary_label_via_simplemenumodel.patch
|
||||
feat_add_streaming-protocol_registry_to_multibuffer_data_source.patch
|
||||
fix_patch_out_profile_refs_in_accessibility_ui.patch
|
||||
adjust_accessibility_ui_for_electron.patch
|
||||
skip_atk_toolchain_check.patch
|
||||
worker_feat_add_hook_to_notify_script_ready.patch
|
||||
chore_provide_iswebcontentscreationoverridden_with_full_params.patch
|
||||
@@ -128,3 +128,4 @@ fix_getcursorscreenpoint_wrongly_returns_0_0.patch
|
||||
fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.patch
|
||||
refactor_expose_file_system_access_blocklist.patch
|
||||
revert_power_update_trace_counter_in_power_monitor.patch
|
||||
cherry-pick-b2cc7b7ac538.patch
|
||||
|
||||
@@ -1,47 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 6 Jul 2020 13:46:06 -0700
|
||||
Subject: fix: patch out Profile refs in accessibility_ui
|
||||
Subject: Adjust accessibility_ui for Electron
|
||||
|
||||
This tweaks Chrome's Accessibility support at chrome://accessibility
|
||||
to make it usable from Electron by removing Profile references.
|
||||
to make it usable from Electron by replacing use of the Profile PrefService
|
||||
with Electron's own PrefService in ElectronBrowserContext. It also removes
|
||||
usage of BrowserList and Browser as we subclass related methods and use our
|
||||
WindowList.
|
||||
|
||||
diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
|
||||
index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3086e8794 100644
|
||||
index 45b085ebb5096b2cdd083337371539a249c7a0a8..9a0a6cb8b37c60641c2c51aa489fbf22cdb123cb 100644
|
||||
--- a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
|
||||
+++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
|
||||
@@ -23,7 +23,10 @@
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
+#if 0
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
+#endif
|
||||
+#include "chrome/common/chrome_features.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "chrome/grit/accessibility_resources.h"
|
||||
@@ -33,6 +36,7 @@
|
||||
#include "content/public/browser/ax_event_notification_details.h"
|
||||
#include "content/public/browser/ax_inspect_factory.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
+#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/favicon_status.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
@@ -52,9 +56,11 @@
|
||||
#include "ui/views/accessibility/view_accessibility.h"
|
||||
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
+#if 0
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/browser_list.h"
|
||||
#include "chrome/browser/ui/browser_window.h"
|
||||
+#endif
|
||||
#include "ui/views/accessibility/widget_ax_tree_id_map.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
@@ -169,7 +175,7 @@ base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) {
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_ui_data_source.h"
|
||||
+#include "electron/shell/browser/electron_browser_context.h"
|
||||
#include "ui/accessibility/accessibility_features.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
|
||||
@@ -169,7 +170,7 @@ base::Value::Dict BuildTargetDescriptor(content::RenderViewHost* rvh) {
|
||||
accessibility_mode);
|
||||
}
|
||||
|
||||
@@ -50,27 +30,25 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
base::Value::Dict BuildTargetDescriptor(Browser* browser) {
|
||||
base::Value::Dict target_data;
|
||||
target_data.Set(kSessionIdField, browser->session_id().id());
|
||||
@@ -203,7 +209,9 @@ void HandleAccessibilityRequestCallback(
|
||||
@@ -203,7 +204,7 @@ void HandleAccessibilityRequestCallback(
|
||||
DCHECK(ShouldHandleAccessibilityRequestCallback(path));
|
||||
|
||||
base::Value::Dict data;
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromBrowserContext(current_context)->GetPrefs();
|
||||
+#endif
|
||||
- PrefService* pref = Profile::FromBrowserContext(current_context)->GetPrefs();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(current_context)->prefs();
|
||||
ui::AXMode mode =
|
||||
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
|
||||
bool is_native_enabled = content::BrowserAccessibilityState::GetInstance()
|
||||
@@ -235,8 +243,7 @@ void HandleAccessibilityRequestCallback(
|
||||
// enabled.
|
||||
@@ -236,7 +237,7 @@ void HandleAccessibilityRequestCallback(
|
||||
data.Set(kViewsAccessibility, features::IsAccessibilityTreeForViewsEnabled());
|
||||
|
||||
- std::string pref_api_type =
|
||||
std::string pref_api_type =
|
||||
- pref->GetString(prefs::kShownAccessibilityApiType);
|
||||
+ std::string pref_api_type = "blink";
|
||||
+ std::string(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
bool pref_api_type_supported = false;
|
||||
|
||||
std::vector<ui::AXApiType::Type> supported_api_types =
|
||||
@@ -303,11 +310,11 @@ void HandleAccessibilityRequestCallback(
|
||||
@@ -303,11 +304,11 @@ void HandleAccessibilityRequestCallback(
|
||||
data.Set(kPagesField, std::move(page_list));
|
||||
|
||||
base::Value::List browser_list;
|
||||
@@ -80,36 +58,31 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
browser_list.Append(BuildTargetDescriptor(browser));
|
||||
}
|
||||
-#endif // !BUILDFLAG(IS_ANDROID)
|
||||
+#endif // !BUILDFLAG(IS_ANDROID)
|
||||
+#endif
|
||||
data.Set(kBrowsersField, std::move(browser_list));
|
||||
|
||||
base::Value::List widgets_list;
|
||||
@@ -647,8 +654,10 @@ void AccessibilityUIMessageHandler::SetGlobalString(
|
||||
@@ -647,7 +648,8 @@ void AccessibilityUIMessageHandler::SetGlobalString(
|
||||
const std::string value = CheckJSValue(data.FindString(kValueField));
|
||||
|
||||
if (string_name == kApiTypeField) {
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(
|
||||
+ web_ui()->GetWebContents()->GetBrowserContext())->prefs();
|
||||
pref->SetString(prefs::kShownAccessibilityApiType, value);
|
||||
+#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,9 +709,13 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree(
|
||||
@@ -700,7 +702,8 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree(
|
||||
AXPropertyFilter::ALLOW_EMPTY);
|
||||
AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY);
|
||||
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(
|
||||
+ web_contents->GetBrowserContext())->prefs();
|
||||
ui::AXApiType::Type api_type =
|
||||
ui::AXApiType::From(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
+#else
|
||||
+ ui::AXApiType::Type api_type = ui::AXApiType::kBlink;
|
||||
+#endif
|
||||
std::string accessibility_contents =
|
||||
web_contents->DumpAccessibilityTree(api_type, property_filters);
|
||||
result.Set(kTreeField, accessibility_contents);
|
||||
@@ -727,6 +740,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
@@ -727,6 +730,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
AXPropertyFilter::ALLOW_EMPTY);
|
||||
AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY);
|
||||
|
||||
@@ -117,7 +90,7 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
for (Browser* browser : *BrowserList::GetInstance()) {
|
||||
if (browser->session_id().id() == session_id) {
|
||||
base::Value::Dict result = BuildTargetDescriptor(browser);
|
||||
@@ -739,6 +753,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
@@ -739,6 +743,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -125,25 +98,24 @@ index 45b085ebb5096b2cdd083337371539a249c7a0a8..404a0a8d99eb68a35c0c06fe1b1dbfa3
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
// No browser with the specified |session_id| was found.
|
||||
base::Value::Dict result;
|
||||
@@ -807,11 +822,15 @@ void AccessibilityUIMessageHandler::StopRecording(
|
||||
@@ -807,11 +812,13 @@ void AccessibilityUIMessageHandler::StopRecording(
|
||||
}
|
||||
|
||||
ui::AXApiType::Type AccessibilityUIMessageHandler::GetRecordingApiType() {
|
||||
+#if 0
|
||||
PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- PrefService* pref = Profile::FromWebUI(web_ui())->GetPrefs();
|
||||
- const std::vector<ui::AXApiType::Type> supported_types =
|
||||
- content::AXInspectFactory::SupportedApis();
|
||||
+ PrefService* pref = static_cast<electron::ElectronBrowserContext*>(
|
||||
+ web_ui()->GetWebContents()->GetBrowserContext())->prefs();
|
||||
ui::AXApiType::Type api_type =
|
||||
ui::AXApiType::From(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
+#else
|
||||
+ ui::AXApiType::Type api_type = ui::AXApiType::kBlink;
|
||||
+#endif
|
||||
+
|
||||
+ const std::vector<ui::AXApiType::Type> supported_types =
|
||||
+ content::AXInspectFactory::SupportedApis();
|
||||
// Check to see if it is in the supported types list.
|
||||
if (std::find(supported_types.begin(), supported_types.end(), api_type) ==
|
||||
supported_types.end()) {
|
||||
@@ -881,8 +900,11 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
|
||||
@@ -881,8 +888,11 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
|
||||
// static
|
||||
void AccessibilityUIMessageHandler::RegisterProfilePrefs(
|
||||
user_prefs::PrefRegistrySyncable* registry) {
|
||||
99
patches/chromium/cherry-pick-b2cc7b7ac538.patch
Normal file
99
patches/chromium/cherry-pick-b2cc7b7ac538.patch
Normal file
@@ -0,0 +1,99 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ken Rockot <rockot@google.com>
|
||||
Date: Wed, 8 May 2024 15:32:48 +0000
|
||||
Subject: Viz: Tolerate SinkGroup destruction during submit
|
||||
|
||||
Fixed: 339266700
|
||||
Change-Id: I8c0ea8c540948016346b00db64fe33260d2446f0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5523748
|
||||
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
|
||||
Reviewed-by: Jonathan Ross <jonross@chromium.org>
|
||||
Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#1298119}
|
||||
|
||||
diff --git a/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc b/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
|
||||
index a43e274a920a7cc189652c29eb2fe4a09ab66ded..9fefc2446d9c95964db512e4c98654c3fcc4e8b4 100644
|
||||
--- a/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
|
||||
+++ b/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
|
||||
@@ -4,12 +4,15 @@
|
||||
|
||||
#include "components/viz/service/frame_sinks/frame_sink_bundle_impl.h"
|
||||
|
||||
+#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/functional/bind.h"
|
||||
+#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/raw_ref.h"
|
||||
+#include "base/memory/weak_ptr.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/viz/service/frame_sinks/compositor_frame_sink_impl.h"
|
||||
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
|
||||
@@ -45,6 +48,10 @@ class FrameSinkBundleImpl::SinkGroup : public BeginFrameObserver {
|
||||
|
||||
bool IsEmpty() const { return frame_sinks_.empty(); }
|
||||
|
||||
+ base::WeakPtr<SinkGroup> GetWeakPtr() {
|
||||
+ return weak_ptr_factory_.GetWeakPtr();
|
||||
+ }
|
||||
+
|
||||
void AddFrameSink(uint32_t sink_id) {
|
||||
frame_sinks_.insert(sink_id);
|
||||
|
||||
@@ -206,6 +213,8 @@ class FrameSinkBundleImpl::SinkGroup : public BeginFrameObserver {
|
||||
std::set<uint32_t> unacked_submissions_;
|
||||
|
||||
BeginFrameArgs last_used_begin_frame_args_;
|
||||
+
|
||||
+ base::WeakPtrFactory<SinkGroup> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
FrameSinkBundleImpl::FrameSinkBundleImpl(
|
||||
@@ -282,8 +291,9 @@ void FrameSinkBundleImpl::SetWantsBeginFrameAcks(uint32_t sink_id) {
|
||||
|
||||
void FrameSinkBundleImpl::Submit(
|
||||
std::vector<mojom::BundledFrameSubmissionPtr> submissions) {
|
||||
- std::set<SinkGroup*> groups;
|
||||
- std::set<SinkGroup*> affected_groups;
|
||||
+ std::map<raw_ptr<SinkGroup>, base::WeakPtr<SinkGroup>> groups;
|
||||
+ std::map<raw_ptr<SinkGroup>, base::WeakPtr<SinkGroup>> affected_groups;
|
||||
+
|
||||
// Count the frame submissions before processing anything. This ensures that
|
||||
// any frames submitted here will be acked together in a batch, and not acked
|
||||
// individually in case they happen to ack synchronously within
|
||||
@@ -294,10 +304,10 @@ void FrameSinkBundleImpl::Submit(
|
||||
// through to the client without batching.
|
||||
for (auto& submission : submissions) {
|
||||
if (auto* group = GetSinkGroup(submission->sink_id)) {
|
||||
- groups.insert(group);
|
||||
+ groups.emplace(group, group->GetWeakPtr());
|
||||
if (submission->data->is_frame()) {
|
||||
group->WillSubmitFrame(submission->sink_id);
|
||||
- affected_groups.insert(group);
|
||||
+ affected_groups.emplace(group, group->GetWeakPtr());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,12 +337,16 @@ void FrameSinkBundleImpl::Submit(
|
||||
}
|
||||
}
|
||||
|
||||
- for (auto* group : groups) {
|
||||
- group->DidFinishFrame();
|
||||
+ for (const auto& [unsafe_group, weak_group] : groups) {
|
||||
+ if (weak_group) {
|
||||
+ weak_group->DidFinishFrame();
|
||||
+ }
|
||||
}
|
||||
|
||||
- for (auto* group : affected_groups) {
|
||||
- group->FlushMessages();
|
||||
+ for (const auto& [unsafe_group, weak_group] : affected_groups) {
|
||||
+ if (weak_group) {
|
||||
+ weak_group->FlushMessages();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,3 +45,4 @@ fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
|
||||
src_preload_function_for_environment.patch
|
||||
deprecate_vector_v8_local_in_v8.patch
|
||||
fix_remove_deprecated_errno_constants.patch
|
||||
build_enable_perfetto.patch
|
||||
|
||||
370
patches/node/build_enable_perfetto.patch
Normal file
370
patches/node/build_enable_perfetto.patch
Normal file
@@ -0,0 +1,370 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Wed, 17 Apr 2024 08:17:49 -0400
|
||||
Subject: build: enable perfetto
|
||||
|
||||
Enable perfetto by default in Node.js. Node.js disables perfetto by
|
||||
default but is broken on build - they don't currently add guards for
|
||||
`V8_USE_PERFETTO` and upstream only defines certain functions
|
||||
on `v8::TracingController` if perfetto is disabled. Electron already
|
||||
had minimal to no support for Node.js trace events, so the impact of
|
||||
adding associated guards there should be relatively small.
|
||||
|
||||
We should upstream this as it will eventually impact Node.js as well.
|
||||
|
||||
diff --git a/lib/internal/constants.js b/lib/internal/constants.js
|
||||
index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..a154559a56bf383d3c26af523c9bb07b564ef600 100644
|
||||
--- a/lib/internal/constants.js
|
||||
+++ b/lib/internal/constants.js
|
||||
@@ -5,12 +5,15 @@ const isWindows = process.platform === 'win32';
|
||||
module.exports = {
|
||||
// Alphabet chars.
|
||||
CHAR_UPPERCASE_A: 65, /* A */
|
||||
+ CHAR_UPPERCASE_B: 66, /* B */
|
||||
CHAR_LOWERCASE_A: 97, /* a */
|
||||
CHAR_UPPERCASE_Z: 90, /* Z */
|
||||
CHAR_LOWERCASE_Z: 122, /* z */
|
||||
CHAR_UPPERCASE_C: 67, /* C */
|
||||
CHAR_LOWERCASE_B: 98, /* b */
|
||||
+ CHAR_UPPERCASE_E: 69, /* E */
|
||||
CHAR_LOWERCASE_E: 101, /* e */
|
||||
+
|
||||
CHAR_LOWERCASE_N: 110, /* n */
|
||||
|
||||
// Non-alphabetic chars.
|
||||
diff --git a/lib/internal/http.js b/lib/internal/http.js
|
||||
index b20b3cd229efcd9701791309361b7d106f315900..6b2820c9dcce5e658b694f53e75d93707c4320d7 100644
|
||||
--- a/lib/internal/http.js
|
||||
+++ b/lib/internal/http.js
|
||||
@@ -10,8 +10,8 @@ const {
|
||||
const { setUnrefTimeout } = require('internal/timers');
|
||||
const { trace, isTraceCategoryEnabled } = internalBinding('trace_events');
|
||||
const {
|
||||
- CHAR_LOWERCASE_B,
|
||||
- CHAR_LOWERCASE_E,
|
||||
+ CHAR_UPPERCASE_B,
|
||||
+ CHAR_UPPERCASE_E,
|
||||
} = require('internal/constants');
|
||||
|
||||
let utcCache;
|
||||
@@ -44,11 +44,13 @@ function isTraceHTTPEnabled() {
|
||||
const traceEventCategory = 'node,node.http';
|
||||
|
||||
function traceBegin(...args) {
|
||||
- trace(CHAR_LOWERCASE_B, traceEventCategory, ...args);
|
||||
+ // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
|
||||
+ trace(CHAR_UPPERCASE_B, traceEventCategory, ...args);
|
||||
}
|
||||
|
||||
function traceEnd(...args) {
|
||||
- trace(CHAR_LOWERCASE_E, traceEventCategory, ...args);
|
||||
+ // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
|
||||
+ trace(CHAR_UPPERCASE_E, traceEventCategory, ...args);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc
|
||||
index 7ce59674356f9743438350949be42fa7ead2afbe..c5fedc3be86a77730c57321b9c73cc8e94a001d7 100644
|
||||
--- a/src/tracing/agent.cc
|
||||
+++ b/src/tracing/agent.cc
|
||||
@@ -50,7 +50,9 @@ using v8::platform::tracing::TraceWriter;
|
||||
using std::string;
|
||||
|
||||
Agent::Agent() : tracing_controller_(new TracingController()) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
tracing_controller_->Initialize(nullptr);
|
||||
+#endif
|
||||
|
||||
CHECK_EQ(uv_loop_init(&tracing_loop_), 0);
|
||||
CHECK_EQ(uv_async_init(&tracing_loop_,
|
||||
@@ -86,10 +88,14 @@ Agent::~Agent() {
|
||||
void Agent::Start() {
|
||||
if (started_)
|
||||
return;
|
||||
-
|
||||
+#ifdef V8_USE_PERFETTO
|
||||
+ std::ostringstream perfetto_output;
|
||||
+ tracing_controller_->InitializeForPerfetto(&perfetto_output);
|
||||
+#else
|
||||
NodeTraceBuffer* trace_buffer_ = new NodeTraceBuffer(
|
||||
NodeTraceBuffer::kBufferChunks, this, &tracing_loop_);
|
||||
tracing_controller_->Initialize(trace_buffer_);
|
||||
+#endif
|
||||
|
||||
// This thread should be created *after* async handles are created
|
||||
// (within NodeTraceWriter and NodeTraceBuffer constructors).
|
||||
@@ -143,8 +149,10 @@ void Agent::StopTracing() {
|
||||
return;
|
||||
// Perform final Flush on TraceBuffer. We don't want the tracing controller
|
||||
// to flush the buffer again on destruction of the V8::Platform.
|
||||
- tracing_controller_->StopTracing();
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
tracing_controller_->Initialize(nullptr);
|
||||
+#endif
|
||||
+ tracing_controller_->StopTracing();
|
||||
started_ = false;
|
||||
|
||||
// Thread should finish when the tracing loop is stopped.
|
||||
@@ -202,6 +210,7 @@ std::string Agent::GetEnabledCategories() const {
|
||||
return categories;
|
||||
}
|
||||
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void Agent::AppendTraceEvent(TraceObject* trace_event) {
|
||||
for (const auto& id_writer : writers_)
|
||||
id_writer.second->AppendTraceEvent(trace_event);
|
||||
@@ -211,18 +220,21 @@ void Agent::AddMetadataEvent(std::unique_ptr<TraceObject> event) {
|
||||
Mutex::ScopedLock lock(metadata_events_mutex_);
|
||||
metadata_events_.push_back(std::move(event));
|
||||
}
|
||||
+#endif
|
||||
|
||||
void Agent::Flush(bool blocking) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
{
|
||||
Mutex::ScopedLock lock(metadata_events_mutex_);
|
||||
for (const auto& event : metadata_events_)
|
||||
AppendTraceEvent(event.get());
|
||||
}
|
||||
-
|
||||
+#endif
|
||||
for (const auto& id_writer : writers_)
|
||||
id_writer.second->Flush(blocking);
|
||||
}
|
||||
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void TracingController::AddMetadataEvent(
|
||||
const unsigned char* category_group_enabled,
|
||||
const char* name,
|
||||
@@ -246,6 +258,6 @@ void TracingController::AddMetadataEvent(
|
||||
if (node_agent != nullptr)
|
||||
node_agent->AddMetadataEvent(std::move(trace_event));
|
||||
}
|
||||
-
|
||||
+#endif
|
||||
} // namespace tracing
|
||||
} // namespace node
|
||||
diff --git a/src/tracing/agent.h b/src/tracing/agent.h
|
||||
index b542a849fe8da7e8bbbcca7067b73dc32b18d6d3..059ce6f6ea17199ead09c6c13bcc680f18f8c4d0 100644
|
||||
--- a/src/tracing/agent.h
|
||||
+++ b/src/tracing/agent.h
|
||||
@@ -27,7 +27,9 @@ class Agent;
|
||||
class AsyncTraceWriter {
|
||||
public:
|
||||
virtual ~AsyncTraceWriter() = default;
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
virtual void AppendTraceEvent(TraceObject* trace_event) = 0;
|
||||
+#endif
|
||||
virtual void Flush(bool blocking) = 0;
|
||||
virtual void InitializeOnThread(uv_loop_t* loop) {}
|
||||
};
|
||||
@@ -36,6 +38,7 @@ class TracingController : public v8::platform::tracing::TracingController {
|
||||
public:
|
||||
TracingController() : v8::platform::tracing::TracingController() {}
|
||||
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
int64_t CurrentTimestampMicroseconds() override {
|
||||
return uv_hrtime() / 1000;
|
||||
}
|
||||
@@ -48,6 +51,7 @@ class TracingController : public v8::platform::tracing::TracingController {
|
||||
const uint64_t* arg_values,
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat>* convertable_values,
|
||||
unsigned int flags);
|
||||
+#endif
|
||||
};
|
||||
|
||||
class AgentWriterHandle {
|
||||
@@ -108,11 +112,12 @@ class Agent {
|
||||
|
||||
// Returns a comma-separated list of enabled categories.
|
||||
std::string GetEnabledCategories() const;
|
||||
-
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
// Writes to all writers registered through AddClient().
|
||||
void AppendTraceEvent(TraceObject* trace_event);
|
||||
|
||||
void AddMetadataEvent(std::unique_ptr<TraceObject> event);
|
||||
+#endif
|
||||
// Flushes all writers registered through AddClient().
|
||||
void Flush(bool blocking);
|
||||
|
||||
@@ -152,7 +157,9 @@ class Agent {
|
||||
std::set<AsyncTraceWriter*> to_be_initialized_;
|
||||
|
||||
Mutex metadata_events_mutex_;
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::list<std::unique_ptr<TraceObject>> metadata_events_;
|
||||
+#endif
|
||||
};
|
||||
|
||||
void AgentWriterHandle::reset() {
|
||||
diff --git a/src/tracing/node_trace_buffer.cc b/src/tracing/node_trace_buffer.cc
|
||||
index e187a1d78c81972b69cd4e03f7079cdb727956ad..3256c6326a08c6cafd83f1e49e3350193e813b51 100644
|
||||
--- a/src/tracing/node_trace_buffer.cc
|
||||
+++ b/src/tracing/node_trace_buffer.cc
|
||||
@@ -55,6 +55,7 @@ TraceObject* InternalTraceBuffer::GetEventByHandle(uint64_t handle) {
|
||||
}
|
||||
|
||||
void InternalTraceBuffer::Flush(bool blocking) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
{
|
||||
Mutex::ScopedLock scoped_lock(mutex_);
|
||||
if (total_chunks_ > 0) {
|
||||
@@ -75,6 +76,7 @@ void InternalTraceBuffer::Flush(bool blocking) {
|
||||
flushing_ = false;
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
agent_->Flush(blocking);
|
||||
}
|
||||
|
||||
diff --git a/src/tracing/node_trace_writer.cc b/src/tracing/node_trace_writer.cc
|
||||
index 8f053efe93324b9acbb4e85f7b974b4f7712e200..e331ed5567caa39ade90ce28cea69f1d10533812 100644
|
||||
--- a/src/tracing/node_trace_writer.cc
|
||||
+++ b/src/tracing/node_trace_writer.cc
|
||||
@@ -95,7 +95,7 @@ void NodeTraceWriter::OpenNewFileForStreaming() {
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
-
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
|
||||
Mutex::ScopedLock scoped_lock(stream_mutex_);
|
||||
// If this is the first trace event, open a new file for streaming.
|
||||
@@ -112,7 +112,7 @@ void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
|
||||
++total_traces_;
|
||||
json_trace_writer_->AppendTraceEvent(trace_event);
|
||||
}
|
||||
-
|
||||
+#endif
|
||||
void NodeTraceWriter::FlushPrivate() {
|
||||
std::string str;
|
||||
int highest_request_id;
|
||||
diff --git a/src/tracing/node_trace_writer.h b/src/tracing/node_trace_writer.h
|
||||
index cd965d77b7859ff2edcf781a934594b5a9b6d251..fe1714ba77fddef693d37eeb8c7a196ddfd15c26 100644
|
||||
--- a/src/tracing/node_trace_writer.h
|
||||
+++ b/src/tracing/node_trace_writer.h
|
||||
@@ -20,7 +20,9 @@ class NodeTraceWriter : public AsyncTraceWriter {
|
||||
~NodeTraceWriter() override;
|
||||
|
||||
void InitializeOnThread(uv_loop_t* loop) override;
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
void AppendTraceEvent(TraceObject* trace_event) override;
|
||||
+#endif
|
||||
void Flush(bool blocking) override;
|
||||
|
||||
static const int kTracesPerFile = 1 << 19;
|
||||
diff --git a/src/tracing/trace_event.h b/src/tracing/trace_event.h
|
||||
index be0f55a409a71bf9c1763c36fdc252857228742e..827b5330b2f8c545338a46c548f8abf4aab7f50c 100644
|
||||
--- a/src/tracing/trace_event.h
|
||||
+++ b/src/tracing/trace_event.h
|
||||
@@ -69,8 +69,16 @@ enum CategoryGroupEnabledFlags {
|
||||
// for best performance when tracing is disabled.
|
||||
// const uint8_t*
|
||||
// TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
|
||||
node::tracing::TraceEventHelper::GetCategoryGroupEnabled
|
||||
+#else
|
||||
+#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group) \
|
||||
+ ([](const char*) -> const uint8_t* { \
|
||||
+ static uint8_t no = 0; \
|
||||
+ return &no; \
|
||||
+ })(category_group)
|
||||
+#endif
|
||||
|
||||
// Get the number of times traces have been recorded. This is used to implement
|
||||
// the TRACE_EVENT_IS_NEW_TRACE facility.
|
||||
@@ -114,10 +122,15 @@ enum CategoryGroupEnabledFlags {
|
||||
// const uint8_t* category_group_enabled,
|
||||
// const char* name,
|
||||
// uint64_t id)
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
|
||||
if (auto controller = \
|
||||
node::tracing::TraceEventHelper::GetTracingController()) \
|
||||
controller->UpdateTraceEventDuration
|
||||
+#else
|
||||
+#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled, name, event_handle) \
|
||||
+ (void)(category_group_enabled), (void)(name), (void)(event_handle)
|
||||
+#endif
|
||||
|
||||
// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
|
||||
// on the convertable value will be called at flush time.
|
||||
@@ -319,10 +332,13 @@ class TraceEventHelper {
|
||||
static void SetAgent(Agent* agent);
|
||||
|
||||
static inline const uint8_t* GetCategoryGroupEnabled(const char* group) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
v8::TracingController* controller = GetTracingController();
|
||||
static const uint8_t disabled = 0;
|
||||
if (UNLIKELY(controller == nullptr)) return &disabled;
|
||||
return controller->GetCategoryGroupEnabled(group);
|
||||
+#endif
|
||||
+ return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -460,6 +476,7 @@ static inline uint64_t AddTraceEventImpl(
|
||||
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
|
||||
const char** arg_names, const uint8_t* arg_types,
|
||||
const uint64_t* arg_values, unsigned int flags) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
|
||||
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||||
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
@@ -469,13 +486,14 @@ static inline uint64_t AddTraceEventImpl(
|
||||
arg_convertibles[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
static_cast<intptr_t>(arg_values[1])));
|
||||
}
|
||||
- // DCHECK(num_args, 2);
|
||||
v8::TracingController* controller =
|
||||
node::tracing::TraceEventHelper::GetTracingController();
|
||||
if (controller == nullptr) return 0;
|
||||
return controller->AddTraceEvent(phase, category_group_enabled, name, scope, id,
|
||||
bind_id, num_args, arg_names, arg_types,
|
||||
arg_values, arg_convertibles, flags);
|
||||
+#endif
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
@@ -483,6 +501,7 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
|
||||
const char** arg_names, const uint8_t* arg_types,
|
||||
const uint64_t* arg_values, unsigned int flags, int64_t timestamp) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertables[2];
|
||||
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||||
arg_convertables[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
@@ -492,19 +511,21 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
|
||||
arg_convertables[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
static_cast<intptr_t>(arg_values[1])));
|
||||
}
|
||||
- // DCHECK_LE(num_args, 2);
|
||||
v8::TracingController* controller =
|
||||
node::tracing::TraceEventHelper::GetTracingController();
|
||||
if (controller == nullptr) return 0;
|
||||
return controller->AddTraceEventWithTimestamp(
|
||||
phase, category_group_enabled, name, scope, id, bind_id, num_args,
|
||||
arg_names, arg_types, arg_values, arg_convertables, flags, timestamp);
|
||||
+#endif
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static V8_INLINE void AddMetadataEventImpl(
|
||||
const uint8_t* category_group_enabled, const char* name, int32_t num_args,
|
||||
const char** arg_names, const uint8_t* arg_types,
|
||||
const uint64_t* arg_values, unsigned int flags) {
|
||||
+#ifndef V8_USE_PERFETTO
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
|
||||
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
|
||||
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
|
||||
@@ -520,6 +541,7 @@ static V8_INLINE void AddMetadataEventImpl(
|
||||
return agent->GetTracingController()->AddMetadataEvent(
|
||||
category_group_enabled, name, num_args, arg_names, arg_types, arg_values,
|
||||
arg_convertibles, flags);
|
||||
+#endif
|
||||
}
|
||||
|
||||
// Define SetTraceValue for each allowed type. It stores the type and
|
||||
@@ -75,7 +75,8 @@ function spawnAndCheckExitCode (cmd, args, opts) {
|
||||
|
||||
function cpplint (args) {
|
||||
args.unshift(`--root=${SOURCE_ROOT}`);
|
||||
const result = childProcess.spawnSync(IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py', args, { encoding: 'utf8', shell: true });
|
||||
const cmd = IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py';
|
||||
const result = childProcess.spawnSync(cmd, args, { encoding: 'utf8', shell: true });
|
||||
// cpplint.py writes EVERYTHING to stderr, including status messages
|
||||
if (result.stderr) {
|
||||
for (const line of result.stderr.split(/[\r\n]+/)) {
|
||||
|
||||
@@ -93,7 +93,8 @@ async function main () {
|
||||
const { status: buildStatus } = cp.spawnSync(NPX_CMD, ['node-gyp', 'rebuild', '--verbose', '--directory', 'test', '-j', 'max'], {
|
||||
env,
|
||||
cwd: NAN_DIR,
|
||||
stdio: 'inherit'
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
|
||||
if (buildStatus !== 0) {
|
||||
@@ -104,7 +105,8 @@ async function main () {
|
||||
const { status: installStatus } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], {
|
||||
env,
|
||||
cwd: NAN_DIR,
|
||||
stdio: 'inherit'
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
if (installStatus !== 0) {
|
||||
console.error('Failed to install nan node_modules');
|
||||
|
||||
@@ -10,7 +10,8 @@ if (fs.existsSync(checkPath)) {
|
||||
command.slice(1),
|
||||
{
|
||||
stdio: 'inherit',
|
||||
cwd: checkPath
|
||||
cwd: checkPath,
|
||||
shell: process.platform === 'win32'
|
||||
}
|
||||
);
|
||||
child.on('exit', code => process.exit(code));
|
||||
|
||||
@@ -221,7 +221,8 @@ async function installSpecModules (dir) {
|
||||
const { status } = childProcess.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install', '--frozen-lockfile'], {
|
||||
env,
|
||||
cwd: dir,
|
||||
stdio: 'inherit'
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
if (status !== 0 && !process.env.IGNORE_YARN_INSTALL_ERROR) {
|
||||
console.log(`${fail} Failed to yarn install in '${dir}'`);
|
||||
|
||||
@@ -11,7 +11,8 @@ if (require.main === module) {
|
||||
env: {
|
||||
...process.env,
|
||||
npm_config_yes: 'true'
|
||||
}
|
||||
},
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
|
||||
child.on('exit', code => process.exit(code));
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
#endif // BUILDFLAG(ENABLE_WIDEVINE)
|
||||
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
#include "components/pdf/common/constants.h"
|
||||
#include "pdf/pdf.h" // nogncheck
|
||||
#include "components/pdf/common/constants.h" // nogncheck
|
||||
#include "pdf/pdf.h" // nogncheck
|
||||
#include "shell/common/electron_constants.h"
|
||||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
|
||||
|
||||
@@ -89,6 +89,9 @@ void WebContentsView::OnViewAddedToWidget(views::View* observed_view) {
|
||||
widget->GetNativeWindowProperty(electron::kElectronNativeWindowKey));
|
||||
if (!native_window)
|
||||
return;
|
||||
// We don't need to call SetOwnerWindow(nullptr) in OnViewRemovedFromWidget
|
||||
// because that's handled in the WebContents dtor called prior.
|
||||
api_web_contents_->SetOwnerWindow(native_window);
|
||||
native_window->AddDraggableRegionProvider(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
#include "components/pdf/browser/pdf_document_helper.h" // nogncheck
|
||||
#include "components/pdf/browser/pdf_navigation_throttle.h"
|
||||
#include "components/pdf/browser/pdf_url_loader_request_interceptor.h"
|
||||
#include "components/pdf/common/constants.h"
|
||||
#include "components/pdf/common/constants.h" // nogncheck
|
||||
#include "shell/browser/electron_pdf_document_helper_client.h"
|
||||
#endif
|
||||
|
||||
@@ -456,7 +456,15 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
|
||||
base::CommandLine* command_line,
|
||||
int process_id) {
|
||||
// Make sure we're about to launch a known executable
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
// On Linux, do not perform this check for /proc/self/exe. It will always
|
||||
// point to the currently running executable so this check is not
|
||||
// necessary, and if the executable has been deleted it will return a fake
|
||||
// name that causes this check to fail.
|
||||
if (command_line->GetProgram() != base::FilePath(base::kProcSelfExe)) {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
ScopedAllowBlockingForElectron allow_blocking;
|
||||
base::FilePath child_path;
|
||||
base::FilePath program =
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "shell/browser/protocol_registry.h"
|
||||
#include "shell/browser/special_storage_policy.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||
#include "shell/browser/ui/webui/accessibility_ui.h"
|
||||
#include "shell/browser/web_contents_permission_helper.h"
|
||||
#include "shell/browser/web_view_manager.h"
|
||||
#include "shell/browser/zoom_level_delegate.h"
|
||||
@@ -352,6 +353,7 @@ void ElectronBrowserContext::InitPrefs() {
|
||||
MediaDeviceIDSalt::RegisterPrefs(registry.get());
|
||||
ZoomLevelDelegate::RegisterPrefs(registry.get());
|
||||
PrefProxyConfigTrackerImpl::RegisterPrefs(registry.get());
|
||||
ElectronAccessibilityUIMessageHandler::RegisterPrefs(registry.get());
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
if (!in_memory_)
|
||||
extensions::ExtensionPrefs::RegisterProfilePrefs(registry.get());
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#include "content/public/browser/media_stream_request.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "electron/shell/browser/media/media_device_id_salt.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "services/network/public/mojom/url_loader_factory.mojom.h"
|
||||
#include "shell/browser/media/media_device_id_salt.h"
|
||||
#include "third_party/blink/public/common/permissions/permission_utils.h"
|
||||
|
||||
class PrefService;
|
||||
|
||||
@@ -131,153 +131,6 @@ JavascriptEnvironment::~JavascriptEnvironment() {
|
||||
platform_->UnregisterIsolate(isolate_);
|
||||
}
|
||||
|
||||
class EnabledStateObserverImpl final
|
||||
: public base::trace_event::TraceLog::EnabledStateObserver {
|
||||
public:
|
||||
EnabledStateObserverImpl() {
|
||||
base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
|
||||
}
|
||||
|
||||
~EnabledStateObserverImpl() override {
|
||||
base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(
|
||||
this);
|
||||
}
|
||||
|
||||
// disable copy
|
||||
EnabledStateObserverImpl(const EnabledStateObserverImpl&) = delete;
|
||||
EnabledStateObserverImpl& operator=(const EnabledStateObserverImpl&) = delete;
|
||||
|
||||
void OnTraceLogEnabled() final {
|
||||
base::AutoLock lock(mutex_);
|
||||
for (auto* o : observers_) {
|
||||
o->OnTraceEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
void OnTraceLogDisabled() final {
|
||||
base::AutoLock lock(mutex_);
|
||||
for (auto* o : observers_) {
|
||||
o->OnTraceDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
void AddObserver(v8::TracingController::TraceStateObserver* observer) {
|
||||
{
|
||||
base::AutoLock lock(mutex_);
|
||||
DCHECK(!observers_.count(observer));
|
||||
observers_.insert(observer);
|
||||
}
|
||||
|
||||
// Fire the observer if recording is already in progress.
|
||||
if (base::trace_event::TraceLog::GetInstance()->IsEnabled())
|
||||
observer->OnTraceEnabled();
|
||||
}
|
||||
|
||||
void RemoveObserver(v8::TracingController::TraceStateObserver* observer) {
|
||||
base::AutoLock lock(mutex_);
|
||||
DCHECK_EQ(observers_.count(observer), 1lu);
|
||||
observers_.erase(observer);
|
||||
}
|
||||
|
||||
private:
|
||||
base::Lock mutex_;
|
||||
std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
|
||||
};
|
||||
|
||||
class TracingControllerImpl : public node::tracing::TracingController {
|
||||
public:
|
||||
TracingControllerImpl() = default;
|
||||
~TracingControllerImpl() override = default;
|
||||
|
||||
// disable copy
|
||||
TracingControllerImpl(const TracingControllerImpl&) = delete;
|
||||
TracingControllerImpl& operator=(const TracingControllerImpl&) = delete;
|
||||
|
||||
// TracingController implementation.
|
||||
const uint8_t* GetCategoryGroupEnabled(const char* name) override {
|
||||
return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
|
||||
}
|
||||
uint64_t AddTraceEvent(
|
||||
char phase,
|
||||
const uint8_t* category_enabled_flag,
|
||||
const char* name,
|
||||
const char* scope,
|
||||
uint64_t id,
|
||||
uint64_t bind_id,
|
||||
int32_t num_args,
|
||||
const char** arg_names,
|
||||
const uint8_t* arg_types,
|
||||
const uint64_t* arg_values,
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
|
||||
unsigned int flags) override {
|
||||
base::trace_event::TraceArguments args(
|
||||
num_args, arg_names, arg_types,
|
||||
reinterpret_cast<const unsigned long long*>( // NOLINT(runtime/int)
|
||||
arg_values),
|
||||
arg_convertables);
|
||||
DCHECK_LE(num_args, 2);
|
||||
base::trace_event::TraceEventHandle handle =
|
||||
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID(
|
||||
phase, category_enabled_flag, name, scope, id, bind_id, &args,
|
||||
flags);
|
||||
uint64_t result;
|
||||
memcpy(&result, &handle, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
uint64_t AddTraceEventWithTimestamp(
|
||||
char phase,
|
||||
const uint8_t* category_enabled_flag,
|
||||
const char* name,
|
||||
const char* scope,
|
||||
uint64_t id,
|
||||
uint64_t bind_id,
|
||||
int32_t num_args,
|
||||
const char** arg_names,
|
||||
const uint8_t* arg_types,
|
||||
const uint64_t* arg_values,
|
||||
std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
|
||||
unsigned int flags,
|
||||
int64_t timestampMicroseconds) override {
|
||||
base::trace_event::TraceArguments args(
|
||||
num_args, arg_names, arg_types,
|
||||
reinterpret_cast<const unsigned long long*>( // NOLINT(runtime/int)
|
||||
arg_values),
|
||||
arg_convertables);
|
||||
DCHECK_LE(num_args, 2);
|
||||
base::TimeTicks timestamp =
|
||||
base::TimeTicks() + base::Microseconds(timestampMicroseconds);
|
||||
base::trace_event::TraceEventHandle handle =
|
||||
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
|
||||
phase, category_enabled_flag, name, scope, id, bind_id,
|
||||
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, &args, flags);
|
||||
uint64_t result;
|
||||
memcpy(&result, &handle, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
|
||||
const char* name,
|
||||
uint64_t handle) override {
|
||||
base::trace_event::TraceEventHandle traceEventHandle;
|
||||
memcpy(&traceEventHandle, &handle, sizeof(handle));
|
||||
TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_enabled_flag, name,
|
||||
traceEventHandle);
|
||||
}
|
||||
|
||||
void AddTraceStateObserver(TraceStateObserver* observer) override {
|
||||
GetObserverDelegate().AddObserver(observer);
|
||||
}
|
||||
|
||||
void RemoveTraceStateObserver(TraceStateObserver* observer) override {
|
||||
GetObserverDelegate().RemoveObserver(observer);
|
||||
}
|
||||
|
||||
private:
|
||||
static EnabledStateObserverImpl& GetObserverDelegate() {
|
||||
static base::NoDestructor<EnabledStateObserverImpl> instance;
|
||||
return *instance;
|
||||
}
|
||||
};
|
||||
|
||||
v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
|
||||
bool setup_wasm_streaming) {
|
||||
auto* cmd = base::CommandLine::ForCurrentProcess();
|
||||
@@ -292,7 +145,7 @@ v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
|
||||
// The V8Platform of gin relies on Chromium's task schedule, which has not
|
||||
// been started at this point, so we have to rely on Node's V8Platform.
|
||||
auto* tracing_agent = node::CreateAgent();
|
||||
auto* tracing_controller = new TracingControllerImpl();
|
||||
auto* tracing_controller = tracing_agent->GetTracingController();
|
||||
node::tracing::TraceEventHelper::SetAgent(tracing_agent);
|
||||
platform_ = node::MultiIsolatePlatform::Create(
|
||||
base::RecommendedMaxNumberOfThreadsInThreadGroup(3, 8, 0.1, 0),
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
#include "ui/ozone/public/ozone_platform.h"
|
||||
@@ -80,9 +81,9 @@
|
||||
#include "shell/browser/ui/win/electron_desktop_native_widget_aura.h"
|
||||
#include "skia/ext/skia_utils_win.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/display/win/screen_win.h"
|
||||
#include "ui/gfx/color_utils.h"
|
||||
#include "ui/gfx/win/hwnd_util.h"
|
||||
#include "ui/gfx/win/msg_util.h"
|
||||
#endif
|
||||
|
||||
@@ -1069,8 +1070,23 @@ ui::ZOrderLevel NativeWindowViews::GetZOrderLevel() const {
|
||||
return widget()->GetZOrderLevel();
|
||||
}
|
||||
|
||||
// We previous called widget()->CenterWindow() here, but in
|
||||
// Chromium CL 4916277 behavior was changed to center relative to the
|
||||
// parent window if there is one. We want to keep the old behavior
|
||||
// for now to avoid breaking API contract, but should consider the long
|
||||
// term plan for this aligning with upstream.
|
||||
void NativeWindowViews::Center() {
|
||||
widget()->CenterWindow(GetSize());
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
auto display =
|
||||
display::Screen::GetScreen()->GetDisplayNearestWindow(GetNativeWindow());
|
||||
gfx::Rect window_bounds_in_screen = display.work_area();
|
||||
window_bounds_in_screen.ClampToCenteredSize(GetSize());
|
||||
widget()->SetBounds(window_bounds_in_screen);
|
||||
#else
|
||||
HWND hwnd = GetAcceleratedWidget();
|
||||
gfx::Size size = display::win::ScreenWin::DIPToScreenSize(hwnd, GetSize());
|
||||
gfx::CenterAndSizeWindow(hwnd, hwnd, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindowViews::Invalidate() {
|
||||
|
||||
@@ -230,6 +230,7 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
|
||||
|
||||
ResizeRootLayer(false);
|
||||
render_widget_host_->SetView(this);
|
||||
render_widget_host_->render_frame_metadata_provider()->AddObserver(this);
|
||||
|
||||
if (content::GpuDataManager::GetInstance()->HardwareAccelerationEnabled()) {
|
||||
video_consumer_ = std::make_unique<OffScreenVideoConsumer>(
|
||||
@@ -240,7 +241,21 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
|
||||
}
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnLocalSurfaceIdChanged(
|
||||
const cc::RenderFrameMetadata& metadata) {
|
||||
if (metadata.local_surface_id) {
|
||||
bool changed = delegated_frame_host_allocator_.UpdateFromChild(
|
||||
*metadata.local_surface_id);
|
||||
|
||||
if (changed) {
|
||||
ResizeRootLayer(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() {
|
||||
render_widget_host_->render_frame_metadata_provider()->RemoveObserver(this);
|
||||
|
||||
// Marking the DelegatedFrameHost as removed from the window hierarchy is
|
||||
// necessary to remove all connections to its old ui::Compositor.
|
||||
if (is_showing_)
|
||||
|
||||
@@ -59,9 +59,11 @@ typedef base::RepeatingCallback<void(const gfx::Rect&, const SkBitmap&)>
|
||||
OnPaintCallback;
|
||||
typedef base::RepeatingCallback<void(const gfx::Rect&)> OnPopupPaintCallback;
|
||||
|
||||
class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
public ui::CompositorDelegate,
|
||||
public OffscreenViewProxyObserver {
|
||||
class OffScreenRenderWidgetHostView
|
||||
: public content::RenderWidgetHostViewBase,
|
||||
public content::RenderFrameMetadataProvider::Observer,
|
||||
public ui::CompositorDelegate,
|
||||
public OffscreenViewProxyObserver {
|
||||
public:
|
||||
OffScreenRenderWidgetHostView(bool transparent,
|
||||
bool painting,
|
||||
@@ -175,6 +177,15 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
RenderWidgetHostViewBase* target_view,
|
||||
gfx::PointF* transformed_point) override;
|
||||
|
||||
// RenderFrameMetadataProvider::Observer:
|
||||
void OnRenderFrameMetadataChangedBeforeActivation(
|
||||
const cc::RenderFrameMetadata& metadata) override {}
|
||||
void OnRenderFrameMetadataChangedAfterActivation(
|
||||
base::TimeTicks activation_time) override {}
|
||||
void OnRenderFrameSubmission() override {}
|
||||
void OnLocalSurfaceIdChanged(
|
||||
const cc::RenderFrameMetadata& metadata) override;
|
||||
|
||||
// ui::CompositorDelegate:
|
||||
bool IsOffscreen() const override;
|
||||
std::unique_ptr<viz::HostDisplayClient> CreateHostDisplayClient(
|
||||
|
||||
@@ -26,8 +26,6 @@ class ElectronMenuModel;
|
||||
@protected
|
||||
base::WeakPtr<electron::ElectronMenuModel> model_;
|
||||
NSMenu* __strong menu_;
|
||||
NSMenuItem* __strong recentDocumentsMenuItem_;
|
||||
NSMenu* __strong recentDocumentsMenuSwap_;
|
||||
BOOL isMenuOpen_;
|
||||
BOOL useDefaultAccelerator_;
|
||||
base::OnceClosure closeCallback;
|
||||
|
||||
@@ -31,10 +31,14 @@ using SharingItem = electron::ElectronMenuModel::SharingItem;
|
||||
|
||||
namespace {
|
||||
|
||||
static NSMenuItem* __strong recentDocumentsMenuItem_;
|
||||
static NSMenu* __strong recentDocumentsMenuSwap_;
|
||||
|
||||
struct Role {
|
||||
SEL selector;
|
||||
const char* role;
|
||||
};
|
||||
|
||||
Role kRolesMap[] = {
|
||||
{@selector(orderFrontStandardAboutPanel:), "about"},
|
||||
{@selector(hide:), "hide"},
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/common/chrome_features.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "chrome/common/webui_url_constants.h"
|
||||
#include "chrome/grit/accessibility_resources.h" // nogncheck
|
||||
@@ -40,11 +39,17 @@
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_ui_data_source.h"
|
||||
#include "shell/browser/electron_browser_context.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "ui/accessibility/accessibility_features.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node.h"
|
||||
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
|
||||
#include "ui/base/webui/web_ui_util.h"
|
||||
#include "ui/views/accessibility/view_accessibility.h"
|
||||
#include "ui/views/accessibility/widget_ax_tree_id_map.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -57,26 +62,34 @@ static const char kFaviconUrlField[] = "faviconUrl";
|
||||
static const char kNameField[] = "name";
|
||||
static const char kPagesField[] = "pages";
|
||||
static const char kPidField[] = "pid";
|
||||
static const char kSessionIdField[] = "sessionId";
|
||||
static const char kProcessIdField[] = "processId";
|
||||
static const char kRequestTypeField[] = "requestType";
|
||||
static const char kRoutingIdField[] = "routingId";
|
||||
static const char kSessionIdField[] = "sessionId";
|
||||
static const char kSupportedApiTypesField[] = "supportedApiTypes";
|
||||
static const char kTreeField[] = "tree";
|
||||
static const char kTypeField[] = "type";
|
||||
static const char kUrlField[] = "url";
|
||||
static const char kTreeField[] = "tree";
|
||||
static const char kWidgetsField[] = "widgets";
|
||||
static const char kApiTypeField[] = "apiType";
|
||||
|
||||
#if defined(USE_AURA)
|
||||
static const char kWidgetIdField[] = "widgetId";
|
||||
static const char kWidget[] = "widget";
|
||||
#endif
|
||||
|
||||
// Global flags
|
||||
static const char kBrowser[] = "browser";
|
||||
static const char kCopyTree[] = "copyTree";
|
||||
static const char kHTML[] = "html";
|
||||
static const char kInternal[] = "internal";
|
||||
static const char kLabelImages[] = "labelImages";
|
||||
static const char kLocked[] = "locked";
|
||||
static const char kNative[] = "native";
|
||||
static const char kPage[] = "page";
|
||||
static const char kPDF[] = "pdf";
|
||||
static const char kPDFPrinting[] = "pdfPrinting";
|
||||
static const char kScreenReader[] = "screenreader";
|
||||
static const char kShowOrRefreshTree[] = "showOrRefreshTree";
|
||||
static const char kText[] = "text";
|
||||
static const char kViewsAccessibility[] = "viewsAccessibility";
|
||||
static const char kWeb[] = "web";
|
||||
|
||||
// Possible global flag values
|
||||
@@ -141,75 +154,23 @@ base::Value::Dict BuildTargetDescriptor(electron::NativeWindow* window) {
|
||||
return target_data;
|
||||
}
|
||||
|
||||
#if defined(USE_AURA)
|
||||
base::Value::Dict BuildTargetDescriptor(views::Widget* widget) {
|
||||
base::Value::Dict widget_data;
|
||||
widget_data.Set(kNameField, widget->widget_delegate()->GetWindowTitle());
|
||||
widget_data.Set(kTypeField, kWidget);
|
||||
|
||||
// Use the Widget's root view ViewAccessibility's unique ID for lookup.
|
||||
int id = widget->GetRootView()->GetViewAccessibility().GetUniqueId().Get();
|
||||
widget_data.Set(kWidgetIdField, id);
|
||||
return widget_data;
|
||||
}
|
||||
#endif // defined(USE_AURA)
|
||||
|
||||
bool ShouldHandleAccessibilityRequestCallback(const std::string& path) {
|
||||
return path == kTargetsDataFile;
|
||||
}
|
||||
|
||||
// Add property filters to the property_filters vector for the given property
|
||||
// filter type. The attributes are passed in as a string with each attribute
|
||||
// separated by a space.
|
||||
void AddPropertyFilters(std::vector<ui::AXPropertyFilter>* property_filters,
|
||||
const std::string& attributes,
|
||||
ui::AXPropertyFilter::Type type) {
|
||||
for (const std::string& attribute : base::SplitString(
|
||||
attributes, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
|
||||
property_filters->emplace_back(attribute, type);
|
||||
}
|
||||
}
|
||||
|
||||
bool MatchesPropertyFilters(
|
||||
const std::vector<ui::AXPropertyFilter>& property_filters,
|
||||
const std::string& text) {
|
||||
bool allow = false;
|
||||
for (const auto& filter : property_filters) {
|
||||
if (base::MatchPattern(text, filter.match_str)) {
|
||||
switch (filter.type) {
|
||||
case ui::AXPropertyFilter::ALLOW_EMPTY:
|
||||
case ui::AXPropertyFilter::SCRIPT:
|
||||
allow = true;
|
||||
break;
|
||||
case ui::AXPropertyFilter::ALLOW:
|
||||
allow = (!base::MatchPattern(text, "*=''"));
|
||||
break;
|
||||
case ui::AXPropertyFilter::DENY:
|
||||
allow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return allow;
|
||||
}
|
||||
|
||||
std::string RecursiveDumpAXPlatformNodeAsString(
|
||||
const ui::AXPlatformNode* node,
|
||||
int indent,
|
||||
const std::vector<ui::AXPropertyFilter>& property_filters) {
|
||||
if (!node)
|
||||
return "";
|
||||
std::string str(2 * indent, '+');
|
||||
const std::string line = node->GetDelegate()->GetData().ToString();
|
||||
const std::vector<std::string> attributes = base::SplitString(
|
||||
line, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
for (const std::string& attribute : attributes) {
|
||||
if (MatchesPropertyFilters(property_filters, attribute)) {
|
||||
str += attribute + " ";
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
for (size_t i = 0; i < node->GetDelegate()->GetChildCount(); i++) {
|
||||
gfx::NativeViewAccessible child = node->GetDelegate()->ChildAtIndex(i);
|
||||
const ui::AXPlatformNode* child_node =
|
||||
ui::AXPlatformNode::FromNativeViewAccessible(child);
|
||||
str += RecursiveDumpAXPlatformNodeAsString(child_node, indent + 1,
|
||||
property_filters);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
bool IsValidJSValue(const std::string* str) {
|
||||
return str && str->length() < 5000U;
|
||||
}
|
||||
|
||||
void HandleAccessibilityRequestCallback(
|
||||
content::BrowserContext* current_context,
|
||||
const std::string& path,
|
||||
@@ -217,6 +178,8 @@ void HandleAccessibilityRequestCallback(
|
||||
DCHECK(ShouldHandleAccessibilityRequestCallback(path));
|
||||
|
||||
base::Value::Dict data;
|
||||
PrefService* pref =
|
||||
static_cast<electron::ElectronBrowserContext*>(current_context)->prefs();
|
||||
ui::AXMode mode =
|
||||
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
|
||||
bool is_native_enabled = content::BrowserAccessibilityState::GetInstance()
|
||||
@@ -226,7 +189,7 @@ void HandleAccessibilityRequestCallback(
|
||||
bool text = mode.has_mode(ui::AXMode::kInlineTextBoxes);
|
||||
bool screenreader = mode.has_mode(ui::AXMode::kScreenReader);
|
||||
bool html = mode.has_mode(ui::AXMode::kHTML);
|
||||
bool pdf = mode.has_mode(ui::AXMode::kPDFPrinting);
|
||||
bool pdf_printing = mode.has_mode(ui::AXMode::kPDFPrinting);
|
||||
|
||||
// The "native" and "web" flags are disabled if
|
||||
// --disable-renderer-accessibility is set.
|
||||
@@ -241,73 +204,161 @@ void HandleAccessibilityRequestCallback(
|
||||
is_web_enabled ? (screenreader ? kOn : kOff) : kDisabled);
|
||||
data.Set(kHTML, is_web_enabled ? (html ? kOn : kOff) : kDisabled);
|
||||
|
||||
// TODO(codebytere): enable use of this flag.
|
||||
//
|
||||
// The "labelImages" flag works only if "web" is enabled, the current profile
|
||||
// has the kAccessibilityImageLabelsEnabled preference set and the appropriate
|
||||
// command line switch has been used. Since this is so closely tied into user
|
||||
// prefs and causes bugs, we're disabling it for now.
|
||||
bool are_accessibility_image_labels_enabled = is_web_enabled;
|
||||
data.Set(kLabelImages, kDisabled);
|
||||
// The "pdfPrinting" flag is independent of the others.
|
||||
data.Set(kPDFPrinting, pdf_printing ? kOn : kOff);
|
||||
|
||||
// The "pdf" flag is independent of the others.
|
||||
data.Set(kPDF, pdf ? kOn : kOff);
|
||||
// The "Top Level Widgets" section is only relevant if views accessibility is
|
||||
// enabled.
|
||||
data.Set(kViewsAccessibility, features::IsAccessibilityTreeForViewsEnabled());
|
||||
|
||||
// Always dump the Accessibility tree.
|
||||
data.Set(kInternal, kOn);
|
||||
std::string pref_api_type =
|
||||
std::string(pref->GetString(prefs::kShownAccessibilityApiType));
|
||||
bool pref_api_type_supported = false;
|
||||
|
||||
base::Value::List rvh_list;
|
||||
std::unique_ptr<content::RenderWidgetHostIterator> widgets(
|
||||
std::vector<ui::AXApiType::Type> supported_api_types =
|
||||
content::AXInspectFactory::SupportedApis();
|
||||
base::Value::List supported_api_list;
|
||||
supported_api_list.reserve(supported_api_types.size());
|
||||
for (ui::AXApiType::Type type : supported_api_types) {
|
||||
supported_api_list.Append(std::string_view(type));
|
||||
if (type == ui::AXApiType::From(pref_api_type)) {
|
||||
pref_api_type_supported = true;
|
||||
}
|
||||
}
|
||||
data.Set(kSupportedApiTypesField, std::move(supported_api_list));
|
||||
|
||||
// If the saved API type is not supported, use the default platform formatter
|
||||
// API type.
|
||||
if (!pref_api_type_supported) {
|
||||
pref_api_type = std::string_view(
|
||||
content::AXInspectFactory::DefaultPlatformFormatterType());
|
||||
}
|
||||
data.Set(kApiTypeField, pref_api_type);
|
||||
|
||||
bool is_mode_locked = !content::BrowserAccessibilityState::GetInstance()
|
||||
->IsAXModeChangeAllowed();
|
||||
data.Set(kLocked, is_mode_locked ? kOn : kOff);
|
||||
|
||||
base::Value::List page_list;
|
||||
std::unique_ptr<content::RenderWidgetHostIterator> widget_iter(
|
||||
content::RenderWidgetHost::GetRenderWidgetHosts());
|
||||
|
||||
while (content::RenderWidgetHost* widget = widgets->GetNextHost()) {
|
||||
while (content::RenderWidgetHost* widget = widget_iter->GetNextHost()) {
|
||||
// Ignore processes that don't have a connection, such as crashed tabs.
|
||||
if (!widget->GetProcess()->IsInitializedAndNotDead())
|
||||
if (!widget->GetProcess()->IsInitializedAndNotDead()) {
|
||||
continue;
|
||||
}
|
||||
content::RenderViewHost* rvh = content::RenderViewHost::From(widget);
|
||||
if (!rvh)
|
||||
if (!rvh) {
|
||||
continue;
|
||||
}
|
||||
content::WebContents* web_contents =
|
||||
content::WebContents::FromRenderViewHost(rvh);
|
||||
content::WebContentsDelegate* delegate = web_contents->GetDelegate();
|
||||
if (!delegate)
|
||||
if (!delegate) {
|
||||
continue;
|
||||
}
|
||||
if (web_contents->GetPrimaryMainFrame()->GetRenderViewHost() != rvh) {
|
||||
continue;
|
||||
}
|
||||
// Ignore views that are never user-visible, like background pages.
|
||||
if (delegate->IsNeverComposited(web_contents))
|
||||
if (delegate->IsNeverComposited(web_contents)) {
|
||||
continue;
|
||||
}
|
||||
content::BrowserContext* context = rvh->GetProcess()->GetBrowserContext();
|
||||
if (context != current_context)
|
||||
if (context != current_context) {
|
||||
continue;
|
||||
}
|
||||
|
||||
base::Value::Dict descriptor = BuildTargetDescriptor(rvh);
|
||||
descriptor.Set(kNative, is_native_enabled);
|
||||
descriptor.Set(kScreenReader, is_web_enabled && screenreader);
|
||||
descriptor.Set(kWeb, is_web_enabled);
|
||||
descriptor.Set(kLabelImages, are_accessibility_image_labels_enabled);
|
||||
rvh_list.Append(std::move(descriptor));
|
||||
page_list.Append(std::move(descriptor));
|
||||
}
|
||||
|
||||
data.Set(kPagesField, std::move(rvh_list));
|
||||
data.Set(kPagesField, std::move(page_list));
|
||||
|
||||
base::Value::List window_list;
|
||||
for (auto* window : electron::WindowList::GetWindows()) {
|
||||
window_list.Append(BuildTargetDescriptor(window));
|
||||
}
|
||||
|
||||
data.Set(kBrowsersField, std::move(window_list));
|
||||
|
||||
base::Value::List widgets_list;
|
||||
#if defined(USE_AURA)
|
||||
if (features::IsAccessibilityTreeForViewsEnabled()) {
|
||||
views::WidgetAXTreeIDMap& manager_map =
|
||||
views::WidgetAXTreeIDMap::GetInstance();
|
||||
const std::vector<views::Widget*> widgets = manager_map.GetWidgets();
|
||||
for (views::Widget* widget : widgets) {
|
||||
widgets_list.Append(BuildTargetDescriptor(widget));
|
||||
}
|
||||
}
|
||||
#endif // defined(USE_AURA)
|
||||
data.Set(kWidgetsField, std::move(widgets_list));
|
||||
|
||||
std::move(callback).Run(base::MakeRefCounted<base::RefCountedString>(
|
||||
base::WriteJson(data).value_or("")));
|
||||
}
|
||||
|
||||
std::string RecursiveDumpAXPlatformNodeAsString(
|
||||
ui::AXPlatformNode* node,
|
||||
int indent,
|
||||
const std::vector<ui::AXPropertyFilter>& property_filters) {
|
||||
if (!node) {
|
||||
return "";
|
||||
}
|
||||
std::string str(2 * indent, '+');
|
||||
std::string line = node->GetDelegate()->GetData().ToString();
|
||||
std::vector<std::string> attributes = base::SplitString(
|
||||
line, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
for (std::string attribute : attributes) {
|
||||
if (ui::AXTreeFormatter::MatchesPropertyFilters(property_filters, attribute,
|
||||
false)) {
|
||||
str += attribute + " ";
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
for (size_t i = 0; i < node->GetDelegate()->GetChildCount(); i++) {
|
||||
gfx::NativeViewAccessible child = node->GetDelegate()->ChildAtIndex(i);
|
||||
ui::AXPlatformNode* child_node =
|
||||
ui::AXPlatformNode::FromNativeViewAccessible(child);
|
||||
str += RecursiveDumpAXPlatformNodeAsString(child_node, indent + 1,
|
||||
property_filters);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Add property filters to the property_filters vector for the given property
|
||||
// filter type. The attributes are passed in as a string with each attribute
|
||||
// separated by a space.
|
||||
void AddPropertyFilters(std::vector<ui::AXPropertyFilter>& property_filters,
|
||||
const std::string& attributes,
|
||||
ui::AXPropertyFilter::Type type) {
|
||||
for (const std::string& attribute : base::SplitString(
|
||||
attributes, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
|
||||
property_filters.emplace_back(attribute, type);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidJSValue(const std::string* str) {
|
||||
return str && str->length() < 5000U;
|
||||
}
|
||||
|
||||
const std::string& CheckJSValue(const std::string* str) {
|
||||
CHECK(IsValidJSValue(str));
|
||||
return *str;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ElectronAccessibilityUI::ElectronAccessibilityUI(content::WebUI* web_ui)
|
||||
: content::WebUIController(web_ui) {
|
||||
auto* const browser_context = web_ui->GetWebContents()->GetBrowserContext();
|
||||
// Set up the chrome://accessibility source.
|
||||
content::WebUIDataSource* html_source =
|
||||
content::WebUIDataSource::CreateAndAdd(
|
||||
web_ui->GetWebContents()->GetBrowserContext(),
|
||||
chrome::kChromeUIAccessibilityHost);
|
||||
browser_context, chrome::kChromeUIAccessibilityHost);
|
||||
|
||||
// Add required resources.
|
||||
html_source->UseStringsJs();
|
||||
@@ -317,8 +368,7 @@ ElectronAccessibilityUI::ElectronAccessibilityUI(content::WebUI* web_ui)
|
||||
html_source->SetRequestFilter(
|
||||
base::BindRepeating(&ShouldHandleAccessibilityRequestCallback),
|
||||
base::BindRepeating(&HandleAccessibilityRequestCallback,
|
||||
web_ui->GetWebContents()->GetBrowserContext()));
|
||||
|
||||
browser_context));
|
||||
html_source->OverrideContentSecurityPolicy(
|
||||
network::mojom::CSPDirectiveName::TrustedTypes,
|
||||
"trusted-types parse-html-subset sanitize-inner-html;");
|
||||
@@ -332,33 +382,35 @@ ElectronAccessibilityUI::~ElectronAccessibilityUI() = default;
|
||||
ElectronAccessibilityUIMessageHandler::ElectronAccessibilityUIMessageHandler() =
|
||||
default;
|
||||
|
||||
void ElectronAccessibilityUIMessageHandler::GetRequestTypeAndFilters(
|
||||
const base::Value::Dict& data,
|
||||
std::string& request_type,
|
||||
std::string& allow,
|
||||
std::string& allow_empty,
|
||||
std::string& deny) {
|
||||
request_type = CheckJSValue(data.FindString(kRequestTypeField));
|
||||
CHECK(request_type == kShowOrRefreshTree || request_type == kCopyTree);
|
||||
allow = CheckJSValue(data.FindStringByDottedPath("filters.allow"));
|
||||
allow_empty = CheckJSValue(data.FindStringByDottedPath("filters.allowEmpty"));
|
||||
deny = CheckJSValue(data.FindStringByDottedPath("filters.deny"));
|
||||
}
|
||||
|
||||
void ElectronAccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
const base::Value::List& args) {
|
||||
const base::Value::Dict& data = args.front().GetDict();
|
||||
|
||||
const int window_id = *data.FindInt(kSessionIdField);
|
||||
const std::string* const request_type_p = data.FindString(kRequestTypeField);
|
||||
CHECK(IsValidJSValue(request_type_p));
|
||||
std::string request_type = *request_type_p;
|
||||
CHECK(request_type == kShowOrRefreshTree || request_type == kCopyTree);
|
||||
request_type = "accessibility." + request_type;
|
||||
std::string request_type, allow, allow_empty, deny;
|
||||
GetRequestTypeAndFilters(data, request_type, allow, allow_empty, deny);
|
||||
|
||||
const std::string* const allow_p =
|
||||
data.FindStringByDottedPath("filters.allow");
|
||||
CHECK(IsValidJSValue(allow_p));
|
||||
const std::string* const allow_empty_p =
|
||||
data.FindStringByDottedPath("filters.allowEmpty");
|
||||
CHECK(IsValidJSValue(allow_empty_p));
|
||||
const std::string* const deny_p = data.FindStringByDottedPath("filters.deny");
|
||||
CHECK(IsValidJSValue(deny_p));
|
||||
int window_id = *data.FindInt(kSessionIdField);
|
||||
|
||||
AllowJavascript();
|
||||
|
||||
std::vector<ui::AXPropertyFilter> property_filters;
|
||||
AddPropertyFilters(&property_filters, *allow_p, ui::AXPropertyFilter::ALLOW);
|
||||
AddPropertyFilters(&property_filters, *allow_empty_p,
|
||||
AddPropertyFilters(property_filters, allow, ui::AXPropertyFilter::ALLOW);
|
||||
AddPropertyFilters(property_filters, allow_empty,
|
||||
ui::AXPropertyFilter::ALLOW_EMPTY);
|
||||
AddPropertyFilters(&property_filters, *deny_p, ui::AXPropertyFilter::DENY);
|
||||
AddPropertyFilters(property_filters, deny, ui::AXPropertyFilter::DENY);
|
||||
|
||||
for (auto* window : electron::WindowList::GetWindows()) {
|
||||
if (window->window_id() == window_id) {
|
||||
@@ -366,9 +418,9 @@ void ElectronAccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
gfx::NativeWindow native_window = window->GetNativeWindow();
|
||||
ui::AXPlatformNode* node =
|
||||
ui::AXPlatformNode::FromNativeWindow(native_window);
|
||||
result.Set(kTreeField, base::Value(RecursiveDumpAXPlatformNodeAsString(
|
||||
node, 0, property_filters)));
|
||||
CallJavascriptFunction(request_type, base::Value(std::move(result)));
|
||||
result.Set(kTreeField, RecursiveDumpAXPlatformNodeAsString(
|
||||
node, 0, property_filters));
|
||||
FireWebUIListener(request_type, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -378,7 +430,7 @@ void ElectronAccessibilityUIMessageHandler::RequestNativeUITree(
|
||||
result.Set(kSessionIdField, window_id);
|
||||
result.Set(kTypeField, kBrowser);
|
||||
result.Set(kErrorField, "Window no longer exists.");
|
||||
CallJavascriptFunction(request_type, base::Value(std::move(result)));
|
||||
FireWebUIListener(request_type, result);
|
||||
}
|
||||
|
||||
void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
|
||||
@@ -393,6 +445,10 @@ void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
|
||||
"setGlobalFlag",
|
||||
base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalFlag,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"setGlobalString",
|
||||
base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalString,
|
||||
base::Unretained(this)));
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"requestWebContentsTree",
|
||||
base::BindRepeating(
|
||||
@@ -403,9 +459,24 @@ void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
|
||||
base::BindRepeating(
|
||||
&ElectronAccessibilityUIMessageHandler::RequestNativeUITree,
|
||||
base::Unretained(this)));
|
||||
#if defined(USE_AURA)
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"requestWidgetsTree",
|
||||
base::BindRepeating(&AccessibilityUIMessageHandler::RequestWidgetsTree,
|
||||
base::Unretained(this)));
|
||||
#endif
|
||||
web_ui()->RegisterMessageCallback(
|
||||
"requestAccessibilityEvents",
|
||||
base::BindRepeating(
|
||||
&AccessibilityUIMessageHandler::RequestAccessibilityEvents,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
// static
|
||||
void ElectronAccessibilityUIMessageHandler::RegisterPrefs(
|
||||
user_prefs::PrefRegistrySyncable* registry) {
|
||||
const std::string_view default_api_type =
|
||||
std::string_view(ui::AXApiType::Type(ui::AXApiType::kBlink));
|
||||
registry->RegisterStringPref(prefs::kShownAccessibilityApiType,
|
||||
std::string(default_api_type));
|
||||
}
|
||||
|
||||
@@ -31,7 +31,14 @@ class ElectronAccessibilityUIMessageHandler
|
||||
|
||||
void RegisterMessages() final;
|
||||
|
||||
static void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry);
|
||||
|
||||
private:
|
||||
void GetRequestTypeAndFilters(const base::Value::Dict& data,
|
||||
std::string& request_type,
|
||||
std::string& allow,
|
||||
std::string& allow_empty,
|
||||
std::string& deny);
|
||||
void RequestNativeUITree(const base::Value::List& args);
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "base/apple/foundation_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/task/bind_post_task.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
@@ -38,6 +39,23 @@ double safeShift(double in, double def) {
|
||||
return def;
|
||||
}
|
||||
|
||||
void ReceivedThumbnailResult(CGSize size,
|
||||
gin_helper::Promise<gfx::Image> p,
|
||||
QLThumbnailRepresentation* thumbnail,
|
||||
NSError* error) {
|
||||
if (error || !thumbnail) {
|
||||
std::string err_msg([error.localizedDescription UTF8String]);
|
||||
p.RejectWithErrorMessage("unable to retrieve thumbnail preview "
|
||||
"image for the given path: " +
|
||||
err_msg);
|
||||
} else {
|
||||
NSImage* result = [[NSImage alloc] initWithCGImage:[thumbnail CGImage]
|
||||
size:size];
|
||||
gfx::Image image(result);
|
||||
p.Resolve(image);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath(
|
||||
v8::Isolate* isolate,
|
||||
@@ -70,31 +88,15 @@ v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath(
|
||||
size:cg_size
|
||||
scale:[screen backingScaleFactor]
|
||||
representationTypes:QLThumbnailGenerationRequestRepresentationTypeAll]);
|
||||
__block gin_helper::Promise<gfx::Image> p = std::move(promise);
|
||||
__block auto block_callback = base::BindPostTaskToCurrentDefault(
|
||||
base::BindOnce(&ReceivedThumbnailResult, cg_size, std::move(promise)));
|
||||
auto completionHandler =
|
||||
^(QLThumbnailRepresentation* thumbnail, NSError* error) {
|
||||
std::move(block_callback).Run(thumbnail, error);
|
||||
};
|
||||
[[QLThumbnailGenerator sharedGenerator]
|
||||
generateBestRepresentationForRequest:request
|
||||
completionHandler:^(
|
||||
QLThumbnailRepresentation* thumbnail,
|
||||
NSError* error) {
|
||||
if (error || !thumbnail) {
|
||||
std::string err_msg(
|
||||
[error.localizedDescription UTF8String]);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
p.RejectWithErrorMessage(
|
||||
"unable to retrieve thumbnail preview "
|
||||
"image for the given path: " +
|
||||
err_msg);
|
||||
});
|
||||
} else {
|
||||
NSImage* result = [[NSImage alloc]
|
||||
initWithCGImage:[thumbnail CGImage]
|
||||
size:cg_size];
|
||||
gfx::Image image(result);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
p.Resolve(image);
|
||||
});
|
||||
}
|
||||
}];
|
||||
completionHandler:completionHandler];
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
#include "base/hash/hash.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "shell/common/api/electron_api_key_weak_map.h"
|
||||
@@ -17,18 +16,6 @@
|
||||
#include "url/origin.h"
|
||||
#include "v8/include/v8-profiler.h"
|
||||
|
||||
namespace std {
|
||||
|
||||
// The hash function used by DoubleIDWeakMap.
|
||||
template <typename Type1, typename Type2>
|
||||
struct hash<std::pair<Type1, Type2>> {
|
||||
std::size_t operator()(std::pair<Type1, Type2> value) const {
|
||||
return base::HashInts(base::Hash(value.first), value.second);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <typename Type1, typename Type2>
|
||||
|
||||
@@ -15,11 +15,15 @@
|
||||
#include "base/apple/osstatus_logging.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/scoped_aedesc.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/apple/url_conversions.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "url/gurl.h"
|
||||
@@ -183,15 +187,12 @@ void OpenExternal(const GURL& url,
|
||||
return;
|
||||
}
|
||||
|
||||
bool activate = options.activate;
|
||||
__block OpenCallback c = std::move(callback);
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
||||
^{
|
||||
__block std::string error = OpenURL(ns_url, activate);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
std::move(c).Run(error);
|
||||
});
|
||||
});
|
||||
base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
FROM_HERE,
|
||||
{base::MayBlock(), base::WithBaseSyncPrimitives(),
|
||||
base::TaskPriority::USER_BLOCKING,
|
||||
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
|
||||
base::BindOnce(&OpenURL, ns_url, options.activate), std::move(callback));
|
||||
}
|
||||
|
||||
bool MoveItemToTrashWithError(const base::FilePath& full_path,
|
||||
|
||||
@@ -69,8 +69,8 @@
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
#include "components/pdf/common/constants.h"
|
||||
#include "components/pdf/common/pdf_util.h"
|
||||
#include "components/pdf/common/constants.h" // nogncheck
|
||||
#include "components/pdf/common/pdf_util.h" // nogncheck
|
||||
#include "components/pdf/renderer/pdf_internal_plugin_delegate.h"
|
||||
#include "shell/common/electron_constants.h"
|
||||
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
|
||||
@@ -6596,6 +6596,7 @@ describe('BrowserWindow module', () => {
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
ifit(hasCapturableScreen())('should allow the window to be dragged when enabled', async () => {
|
||||
// FIXME: nut-js has been removed from npm; we need to find a replacement
|
||||
// WOA fails to load libnut so we're using require to defer loading only
|
||||
// on supported platforms.
|
||||
// "@nut-tree\libnut-win32\build\Release\libnut.node is not a valid Win32 application."
|
||||
@@ -6640,6 +6641,7 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
|
||||
ifit(hasCapturableScreen())('should allow the window to be dragged when no WCO and --webkit-app-region: drag enabled', async () => {
|
||||
// FIXME: nut-js has been removed from npm; we need to find a replacement
|
||||
// @ts-ignore: nut-js is an optional dependency so it may not be installed
|
||||
const { mouse, straightTo, centerOf, Region, Button } = require('@nut-tree/nut-js') as typeof import('@nut-tree/nut-js');
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect } from 'chai';
|
||||
import { nativeImage } from 'electron/common';
|
||||
import { ifdescribe, ifit } from './lib/spec-helpers';
|
||||
import { ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers';
|
||||
import * as path from 'node:path';
|
||||
|
||||
describe('nativeImage module', () => {
|
||||
@@ -426,6 +426,8 @@ describe('nativeImage module', () => {
|
||||
});
|
||||
|
||||
ifdescribe(process.platform !== 'linux')('createThumbnailFromPath(path, size)', () => {
|
||||
useRemoteContext({ webPreferences: { contextIsolation: false, nodeIntegration: true } });
|
||||
|
||||
it('throws when invalid size is passed', async () => {
|
||||
const badSize = { width: -1, height: -1 };
|
||||
|
||||
@@ -473,6 +475,13 @@ describe('nativeImage module', () => {
|
||||
const result = await nativeImage.createThumbnailFromPath(imgPath, maxSize);
|
||||
expect(result.getSize()).to.deep.equal(maxSize);
|
||||
});
|
||||
|
||||
itremote('works in the renderer', async (path: string) => {
|
||||
const { nativeImage } = require('electron');
|
||||
const goodSize = { width: 100, height: 100 };
|
||||
const result = await nativeImage.createThumbnailFromPath(path, goodSize);
|
||||
expect(result.isEmpty()).to.equal(false);
|
||||
}, [path.join(fixturesPath, 'assets', 'logo.png')]);
|
||||
});
|
||||
|
||||
describe('addRepresentation()', () => {
|
||||
|
||||
@@ -1381,6 +1381,49 @@ describe('protocol module', () => {
|
||||
expect(body).to.equal(text);
|
||||
});
|
||||
|
||||
it('can receive stream request body asynchronously', async () => {
|
||||
let done: any;
|
||||
const requestReceived: Promise<Buffer[]> = new Promise(resolve => { done = resolve; });
|
||||
protocol.handle('http-like', async (req) => {
|
||||
const chunks = [];
|
||||
for await (const chunk of (req.body as any)) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
done(chunks);
|
||||
return new Response('ok');
|
||||
});
|
||||
defer(() => { protocol.unhandle('http-like'); });
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.loadURL('about:blank');
|
||||
const expectedHashChunks = await w.webContents.executeJavaScript(`
|
||||
const dataStream = () =>
|
||||
new ReadableStream({
|
||||
async start(controller) {
|
||||
for (let i = 0; i < 10; i++) { controller.enqueue(Array(1024 * 128).fill(+i).join("\\n")); }
|
||||
controller.close();
|
||||
},
|
||||
}).pipeThrough(new TextEncoderStream());
|
||||
fetch(
|
||||
new Request("http-like://host", {
|
||||
method: "POST",
|
||||
body: dataStream(),
|
||||
duplex: "half",
|
||||
})
|
||||
);
|
||||
(async () => {
|
||||
const chunks = []
|
||||
for await (const chunk of dataStream()) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
return chunks;
|
||||
})()
|
||||
`);
|
||||
const expectedHash = Buffer.from(await crypto.subtle.digest('SHA-256', Buffer.concat(expectedHashChunks))).toString('hex');
|
||||
const body = Buffer.concat(await requestReceived);
|
||||
const actualHash = Buffer.from(await crypto.subtle.digest('SHA-256', Buffer.from(body))).toString('hex');
|
||||
expect(actualHash).to.equal(expectedHash);
|
||||
});
|
||||
|
||||
it('can receive multi-part postData from loadURL', async () => {
|
||||
protocol.handle('test-scheme', (req) => new Response(req.body));
|
||||
defer(() => { protocol.unhandle('test-scheme'); });
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('shell module', () => {
|
||||
});
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('opens an external link', async () => {
|
||||
async function urlOpened () {
|
||||
let url = 'http://127.0.0.1';
|
||||
let requestReceived: Promise<any>;
|
||||
if (process.platform === 'linux') {
|
||||
@@ -53,12 +53,26 @@ describe('shell module', () => {
|
||||
url = (await listen(server)).url;
|
||||
requestReceived = new Promise<void>(resolve => server.on('connection', () => resolve()));
|
||||
}
|
||||
return { url, requestReceived };
|
||||
}
|
||||
|
||||
it('opens an external link', async () => {
|
||||
const { url, requestReceived } = await urlOpened();
|
||||
await Promise.all<void>([
|
||||
shell.openExternal(url),
|
||||
requestReceived
|
||||
]);
|
||||
});
|
||||
|
||||
it('opens an external link in the renderer', async () => {
|
||||
const { url, requestReceived } = await urlOpened();
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: false, contextIsolation: false, nodeIntegration: true } });
|
||||
await w.loadURL('about:blank');
|
||||
await Promise.all<void>([
|
||||
w.webContents.executeJavaScript(`require("electron").shell.openExternal(${JSON.stringify(url)})`),
|
||||
requestReceived
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shell.trashItem()', () => {
|
||||
|
||||
@@ -60,6 +60,18 @@ describe('WebContentsView', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('can be fullscreened', async () => {
|
||||
const w = new BaseWindow();
|
||||
const v = new WebContentsView();
|
||||
w.setContentView(v);
|
||||
await v.webContents.loadURL('data:text/html,<div id="div">This is a simple div.</div>');
|
||||
|
||||
const enterFullScreen = once(w, 'enter-full-screen');
|
||||
await v.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
|
||||
await enterFullScreen;
|
||||
expect(w.isFullScreen()).to.be.true('isFullScreen');
|
||||
});
|
||||
|
||||
describe('visibilityState', () => {
|
||||
it('is initially hidden', async () => {
|
||||
const v = new WebContentsView();
|
||||
|
||||
@@ -7,5 +7,7 @@
|
||||
"session module ses.cookies should set cookie for standard scheme",
|
||||
"webFrameMain module WebFrame.visibilityState should match window state",
|
||||
"reporting api sends a report for a deprecation",
|
||||
"chromium features SpeechSynthesis should emit lifecycle events"
|
||||
]
|
||||
"chromium features SpeechSynthesis should emit lifecycle events",
|
||||
"BrowserWindow module draggable regions should allow the window to be dragged when enabled",
|
||||
"BrowserWindow module draggable regions should allow the window to be dragged when no WCO and --webkit-app-region: drag enabled"
|
||||
]
|
||||
|
||||
@@ -40,6 +40,7 @@ protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: global.standardScheme, privileges: { standard: true, secure: true, stream: false } },
|
||||
{ scheme: global.zoomScheme, privileges: { standard: true, secure: true } },
|
||||
{ scheme: global.serviceWorkerScheme, privileges: { allowServiceWorkers: true, standard: true, secure: true } },
|
||||
{ scheme: 'http-like', privileges: { standard: true, secure: true, corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'cors-blob', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'cors', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'no-cors', privileges: { supportFetchAPI: true } },
|
||||
|
||||
@@ -38,9 +38,6 @@
|
||||
"ws": "^7.4.6",
|
||||
"yargs": "^16.0.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@nut-tree/nut-js": "^3.1.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"nan": "file:../../third_party/nan",
|
||||
"dbus-native/optimist/minimist": "1.2.7",
|
||||
|
||||
775
spec/yarn.lock
775
spec/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user