Compare commits

...

15 Commits

Author SHA1 Message Date
Shelley Vohr
7e3d9430d6 chore: cherry-pick d8b01057f740 from chromium 2026-04-01 15:41:45 +02:00
trop[bot]
e1e3ecee75 fix: remove menu update debug log (#50614)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: clavin <clavin@electronjs.org>
2026-04-01 14:25:04 +02:00
trop[bot]
d1b34d76a8 fix: invoke print callback directly when no print job exists (#50603)
ShowInvalidPrinterSettingsError() called TerminatePrintJob(true),
but when no print_job_ had been created yet (e.g. settings validation
failed before a job could start), TerminatePrintJob bails out
immediately without reaching ReleasePrintJob() where the callback
is invoked. This left the CompletionCallback stuck in callback_
until WebContents destruction, causing webContents.print() to only
fire its callback when the application closed.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-03-31 21:09:39 +02:00
electron-roller[bot]
d456259da4 chore: bump node to v24.14.1 (42-x-y) (#50479)
* chore: bump node in DEPS to v24.14.1

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2026-03-31 15:27:29 +02:00
trop[bot]
e21a1b8cd1 ci: update nick-fields/retry to v4.0.0 (#50542)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <kleinschmidtorama@gmail.com>
2026-03-31 14:32:03 +02:00
trop[bot]
7f8e35c8c8 fix: add missing HandleScope in contentTracing.getTraceBufferUsage() (#50592)
The `OnTraceBufferUsageAvailable` callback creates V8 handles via
`Dictionary::CreateEmpty()` before `promise.Resolve()` enters its
`SettleScope` (which provides a `HandleScope`). When the callback
fires asynchronously from a Mojo response (i.e. when a trace session
is active), there is no `HandleScope` on the stack, causing a fatal
V8 error: "Cannot create a handle without a HandleScope".

Add an explicit `v8::HandleScope` at the top of the callback, matching
the pattern used by the other contentTracing APIs which resolve their
promises through `SettleScope` or the static `ResolvePromise` helper.

Made-with: Cursor

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Alexey Kozy <alexey@anysphere.co>
2026-03-31 12:15:18 +02:00
trop[bot]
2da7d8dadb refactor: improve input handling in FilePath gin converter (#50546)
refactor: improve input handling in file_path_converter

Properly handle paths containing ASCII control characters in the FilePath gin converter

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2026-03-30 08:34:21 -07:00
trop[bot]
d2e0d19985 perf: enable V8 builtins PGO (#50573)
* build: enable V8 builtins PGO

Removes the gn arg that disabled V8 builtins profile-guided optimization
and adds a V8 patch to warn instead of abort when the builtin PGO profile
data does not match. Also strips the PGO-related flags from the generated
mksnapshot_args so they are not passed through to downstream mksnapshot
invocations.

Co-authored-by: Sam Attard <sattard@anthropic.com>

* docs: clarify Node.js async_hooks as reason for promise_hooks flag

Addresses review feedback: the v8_enable_javascript_promise_hooks flag
is set to support Node.js async_hooks, not used directly by Electron.

Co-authored-by: Sam Attard <sattard@anthropic.com>

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Sam Attard <sattard@anthropic.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2026-03-30 08:33:25 -07:00
trop[bot]
d074963b30 fix: hex-encode Windows notification icon temp filenames (#50482)
* fix: hex-encode Windows notification icon temp filenames

NotificationPresenterWin was using SHA1HashString(origin.spec()) directly
as the basename for the temporary PNG written for toast icons.

SHA1HashString returns raw digest bytes, so the generated filename could
contain invalid path characters on Windows. That caused WriteFile to fail
when saving notification icons, which left toast XML without the expected
icon path.

Hex-encode the digest before appending .png so the temporary filename is
filesystem-safe while keeping deterministic naming for a given origin.

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* Update shell/browser/notifications/win/notification_presenter_win.cc

Co-authored-by: Robo <hop2deep@gmail.com>

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-03-27 17:07:31 -04:00
trop[bot]
ef7f35e15c fix: correct linux zygote process titles (#50533)
* fix: correct linux zygote process titles

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

* pass argv on mac as well

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

* lint

Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>
2026-03-27 12:24:01 -04:00
trop[bot]
5559ffa184 docs: clarify allowed characters in protocol names (#50537)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2026-03-27 09:58:18 -04:00
trop[bot]
4ede07538d test: add interactive macOS dialog tests (#50527)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-03-27 08:21:08 -04:00
trop[bot]
b310e26059 docs: update Notification support info (#50526)
This is a follow-up to
74fd10450f
(https://github.com/electron/electron/pull/48132).
The support for these has been added for Windows,
but not all documentation has been updated accordingly

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: WofWca <wofwca@protonmail.com>
2026-03-26 17:20:50 -04:00
electron-roller[bot]
ad4dc5045f chore: bump chromium to 148.0.7751.0 (42-x-y) (#50429)
* chore: bump chromium in DEPS to 148.0.7749.1

* chore: bump chromium in DEPS to 148.0.7751.1

* chore: bump chromium in DEPS to 148.0.7753.1

* chore: bump chromium in DEPS to 148.0.7755.1

* chore: bump chromium to 148.0.7751.0 (main) (#50427)

* chore: bump chromium in DEPS to 148.0.7749.0

* chore: bump chromium in DEPS to 148.0.7751.0

* chore: update patches

* 7681299: Introduce OccludedWidgetInputProtector to track always-on-top widgets

Refs https://chromium-review.googlesource.com/c/chromium/src/+/7681299

* 7685453: chrome://accessibility: Don't AllowJavascript() in async calls

Refs https://chromium-review.googlesource.com/c/chromium/src/+/7685453

* 7665878: Prefer browser runtime over Node.js in HostRuntime detection

Refs https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7665878

* 7674037: Rename the bookmark-related interfaces of the Clipboard class to URL.

Refs https://chromium-review.googlesource.com/c/chromium/src/+/7674037

* 7621713: Migrate ServiceWorker framework to ChildProcessId

Refs https://chromium-review.googlesource.com/c/chromium/src/+/7621713

* 7680500: Migrate ServiceWorkerHost to ChildProcessId

Refs https://chromium-review.googlesource.com/c/chromium/src/+/7680500

* chore: update roller commit message lint script to handle devtools CLs

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
(cherry picked from commit c44d60cfe4)

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-03-26 17:02:22 -04:00
trop[bot]
a45f5dbcba fix: outdated execution path for COM activation (#50517)
* fix: outdated execution path

Co-authored-by: Jan Hannemann <jan.hannemann@outlook.com>

* fix: use stub exe when detected

Co-authored-by: Jan Hannemann <jan.hannemann@outlook.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Jan Hannemann <jan.hannemann@outlook.com>
2026-03-26 17:00:56 -04:00
83 changed files with 1922 additions and 274 deletions

View File

@@ -128,6 +128,9 @@ runs:
fi
sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
sed $SEDOPTION '/--reorder-builtins/d' out/Default/mksnapshot_args
sed $SEDOPTION '/--warn-about-builtin-profile-data/d' out/Default/mksnapshot_args
sed $SEDOPTION '/--abort-on-bad-builtin-profile-data/d' out/Default/mksnapshot_args
if [ "${{ inputs.target-platform }}" = "win" ]; then
cd out/Default

View File

@@ -24,7 +24,7 @@ runs:
# The cache will always exist here as a result of the checkout job
# Either it was uploaded to Azure in the checkout job for this commit
# or it was uploaded in the checkout job for a previous commit.
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 30
max_attempts: 3
@@ -101,7 +101,7 @@ runs:
- name: Move Src Cache (Windows)
if: ${{ inputs.target-platform == 'win' }}
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
with:
timeout_minutes: 30
max_attempts: 3

1
.gitignore vendored
View File

@@ -42,6 +42,7 @@ spec/.hash
# Generated native addon files
/spec/fixtures/native-addon/echo/build/
/spec/fixtures/native-addon/dialog-helper/build/
# If someone runs tsc this is where stuff will end up
ts-gen

4
DEPS
View File

@@ -2,9 +2,9 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'148.0.7741.0',
'148.0.7751.0',
'node_version':
'v24.14.0',
'v24.14.1',
'nan_version':
'675cefebca42410733da8a454c8d9391fcebfbc2',
'squirrel.mac_version':

View File

@@ -51,9 +51,6 @@ is_cfi = false
use_qt5 = false
use_qt6 = false
# Disables the builtins PGO for V8
v8_builtins_profiling_log_file = ""
# https://chromium.googlesource.com/chromium/src/+/main/docs/dangling_ptr.md
# TODO(vertedinde): hunt down dangling pointers on Linux
enable_dangling_raw_ptr_checks = false

View File

@@ -86,12 +86,12 @@ app.whenReady().then(() => {
* `body` string (optional) - The body text of the notification, which will be displayed below the title or subtitle.
* `silent` boolean (optional) - Whether or not to suppress the OS notification noise when showing the notification.
* `icon` (string | [NativeImage](native-image.md)) (optional) - An icon to use in the notification. If a string is passed, it must be a valid path to a local icon file.
* `hasReply` boolean (optional) _macOS_ - Whether or not to add an inline reply option to the notification.
* `hasReply` boolean (optional) _macOS_ _Windows_ - Whether or not to add an inline reply option to the notification.
* `timeoutType` string (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'.
* `replyPlaceholder` string (optional) _macOS_ - The placeholder to write in the inline reply input field.
* `replyPlaceholder` string (optional) _macOS_ _Windows_ - The placeholder to write in the inline reply input field.
* `sound` string (optional) _macOS_ - The name of the sound file to play when the notification is shown.
* `urgency` string (optional) _Linux_ _Windows_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
* `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation.
* `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ _Windows_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation.
* `closeButtonText` string (optional) _macOS_ - A custom title for the close button of an alert. An empty string will cause the default localized text to be used.
* `toastXml` string (optional) _Windows_ - A custom description of the Notification on Windows superseding all properties above. Provides full customization of design and behavior of the notification.

View File

@@ -56,6 +56,15 @@ app.whenReady().then(() => {
})
```
## Protocol names
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) defines what a valid
protocol name is:
> Scheme names consist of a sequence of characters beginning with a letter and followed
> by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-").
> Although schemes are case-insensitive, the canonical form is lowercase […].
## Methods
The `protocol` module has the following methods:

View File

@@ -147,3 +147,4 @@ fix_pass_trigger_for_global_shortcuts_on_wayland.patch
feat_plumb_node_integration_in_worker_through_workersettings.patch
fix_restore_sdk_inputs_cross-toolchain_deps_for_macos.patch
fix_fire_menu_popup_start_for_dynamically_created_aria_menus.patch
cherry-pick-d8b01057f740.patch

View File

@@ -23,10 +23,10 @@ index 8077ed85e45e56d6cccb691223216c1f6a94b5ee..dd4cee346f16df703d414bf206bbe6c9
int32_t world_id) {}
virtual void DidClearWindowObject() {}
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 42a0a7e5be01fe346cc2ad83d3395425a41e1699..40d1f104794795dba6cd59518819e98a4cdbfc44 100644
index 280091edd7aa92c3cbc9e4b442cba91cb5bd2aa4..92272d5177cc47839169066b860577194cbc5d47 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4769,6 +4769,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
@@ -4744,6 +4744,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
observer.DidCreateScriptContext(context, world_id);
}
@@ -40,7 +40,7 @@ index 42a0a7e5be01fe346cc2ad83d3395425a41e1699..40d1f104794795dba6cd59518819e98a
int world_id) {
for (auto& observer : observers_)
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index c803bf1d93bb9aabf0f9098c4d58aa7528d18d79..ced097d57cec93b3d3062a6d7d9f7d037a355e6c 100644
index 8bdb45a481f16096fa0509570872745531495eb3..0062c466fbe4c625669d3a334fc9b9d8c49837f2 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -606,6 +606,8 @@ class CONTENT_EXPORT RenderFrameImpl

View File

@@ -8,10 +8,10 @@ was removed as part of the Raw Clipboard API scrubbing.
https://bugs.chromium.org/p/chromium/issues/detail?id=1217643
diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc
index 503225a84c1fe3835e97d8cc521f661339de105e..9949bd699ccca7fef8750816663fd66701b08d69 100644
index 12695bb8f3d2cc3f498e5c6e37e4729d9586962f..6bd7b6f2908d3c8316191e3106e50b2137068a0f 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.cc
+++ b/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -240,6 +240,16 @@ void ScopedClipboardWriter::WriteData(std::u16string_view format,
@@ -239,6 +239,16 @@ void ScopedClipboardWriter::WriteData(std::u16string_view format,
}
}
@@ -29,7 +29,7 @@ index 503225a84c1fe3835e97d8cc521f661339de105e..9949bd699ccca7fef8750816663fd667
objects_.clear();
raw_objects_.clear();
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h
index 8c2be540757856a3e704764fe56003205b24812f..e31fbc01f68c0e92284a72298cac878d7247e7fb 100644
index 7d7d015f9725ef39b7d5e82b83ac5195e2cfe309..83565b6d73cbe30e3c24913468862173cfd3a83e 100644
--- a/ui/base/clipboard/scoped_clipboard_writer.h
+++ b/ui/base/clipboard/scoped_clipboard_writer.h
@@ -91,6 +91,10 @@ class COMPONENT_EXPORT(UI_BASE_CLIPBOARD) ScopedClipboardWriter {

View File

@@ -10,7 +10,7 @@ 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 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761dcb30f131 100644
index 1322a7c5f9b3baca837488de2e5323ee5c49800c..cb1895f2be25d210f7508433a352bc1e93369f4a 100644
--- a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
+++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
@@ -48,6 +48,7 @@
@@ -64,7 +64,7 @@ index 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761d
data.Set(kBrowsersField, std::move(browser_list));
#if BUILDFLAG(IS_WIN)
@@ -847,7 +848,8 @@ void AccessibilityUIMessageHandler::SetGlobalString(
@@ -870,7 +871,8 @@ void AccessibilityUIMessageHandler::HandleSetGlobalString(
const std::string value = CheckJSValue(data.FindString(kValueField));
if (string_name == kApiTypeField) {
@@ -74,7 +74,7 @@ index 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761d
pref->SetString(prefs::kShownAccessibilityApiType, value);
}
}
@@ -901,7 +903,8 @@ void AccessibilityUIMessageHandler::RequestWebContentsTree(
@@ -924,7 +926,8 @@ void AccessibilityUIMessageHandler::HandleRequestWebContentsTree(
AXPropertyFilter::ALLOW_EMPTY);
AddPropertyFilters(property_filters, deny, AXPropertyFilter::DENY);
@@ -84,7 +84,7 @@ index 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761d
ui::AXApiType::Type api_type =
ui::AXApiType::From(pref->GetString(prefs::kShownAccessibilityApiType));
std::string accessibility_contents =
@@ -921,7 +924,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
@@ -944,7 +947,7 @@ void AccessibilityUIMessageHandler::HandleRequestNativeUITree(
AllowJavascript();
@@ -93,7 +93,7 @@ index 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761d
std::vector<AXPropertyFilter> property_filters;
AddPropertyFilters(property_filters, allow, AXPropertyFilter::ALLOW);
AddPropertyFilters(property_filters, allow_empty,
@@ -948,7 +951,7 @@ void AccessibilityUIMessageHandler::RequestNativeUITree(
@@ -971,7 +974,7 @@ void AccessibilityUIMessageHandler::HandleRequestNativeUITree(
if (found) {
return;
}
@@ -102,7 +102,7 @@ index 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761d
// No browser with the specified |session_id| was found.
base::DictValue result;
result.Set(kSessionIdField, session_id);
@@ -991,11 +994,13 @@ void AccessibilityUIMessageHandler::StopRecording(
@@ -1014,11 +1017,13 @@ void AccessibilityUIMessageHandler::StopRecording(
}
ui::AXApiType::Type AccessibilityUIMessageHandler::GetRecordingApiType() {
@@ -119,7 +119,7 @@ index 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761d
// 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()) {
@@ -1065,10 +1070,13 @@ void AccessibilityUIMessageHandler::RequestAccessibilityEvents(
@@ -1088,10 +1093,13 @@ void AccessibilityUIMessageHandler::HandleRequestAccessibilityEvents(
// static
void AccessibilityUIMessageHandler::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
@@ -134,7 +134,7 @@ index 9b22efa07e43b60a8bd8bb6288792846709fae87..cf60a541720ffbcdaa5163d727a7761d
void AccessibilityUIMessageHandler::OnVisibilityChanged(
diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.h b/chrome/browser/ui/webui/accessibility/accessibility_ui.h
index 67f7e34271994ff66da2a3c3b90c2f02797c2d14..8f786bc00dc4a7cc775ca3ff3fca4da680272682 100644
index 184a10239d7072572a043f2b4e29bcdb5344f3ec..77d3ca336eaa28b7c476861c8d4a43e45804ac7a 100644
--- a/chrome/browser/ui/webui/accessibility/accessibility_ui.h
+++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.h
@@ -28,6 +28,8 @@ namespace content {
@@ -146,12 +146,12 @@ index 67f7e34271994ff66da2a3c3b90c2f02797c2d14..8f786bc00dc4a7cc775ca3ff3fca4da6
namespace user_prefs {
class PrefRegistrySyncable;
} // namespace user_prefs
@@ -79,6 +81,8 @@ class AccessibilityUIMessageHandler : public content::WebUIMessageHandler,
@@ -81,6 +83,8 @@ class AccessibilityUIMessageHandler : public content::WebUIMessageHandler,
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
private:
+ friend class ElectronAccessibilityUIMessageHandler;
+
void ToggleAccessibilityForWebContents(const base::ListValue& args);
void SetGlobalFlag(const base::ListValue& args);
void SetGlobalString(const base::ListValue& args);
void HandleInitialize(const base::ListValue& args);
void HandleToggleAccessibilityForWebContents(const base::ListValue& args);
void HandleSetGlobalFlag(const base::ListValue& args);

View File

@@ -6,7 +6,7 @@ Subject: allow disabling blink scheduler throttling per RenderView
This allows us to disable throttling for hidden windows.
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index c33775220e161d38e41efe8fea897815737341f8..e9636b69a8eb748aaa493466c3190ec602e16449 100644
index 29d5b174e122cbd140554687548106ead8f8e8d9..da74da96c3fe35a0f3838f04bca08846f7b41abe 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -168,6 +168,12 @@ class MockPageBroadcast : public blink::mojom::PageBroadcast {

View File

@@ -49,7 +49,7 @@ index 901b727ed898cdd840df5ff7e2380fbee5d7fde2..1caacaeed9ddf1162cfa393fe4a7c86a
// its owning reference back to our owning LocalFrame.
client_->Detached(type);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 8d1aa4435bb815b2e8d4b2e14f60e7e11a29ae7d..34603bffa39cf2aaedfd7c3152464c524995f6f0 100644
index b31df93f2210e7030be73b4ee87463bd6318eb7c..daf04130625fda5b6779126e9a63d9f4854a8555 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -758,10 +758,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {

View File

@@ -11,7 +11,7 @@ if we ever align our .pak file generation with Chrome we can remove this
patch.
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 74aadd24a27d31291bb42d452ff247bbf6dad14a..a0d74156745c0d22a332b2547c59b98d1ae8a7c5 100644
index e30ea563d0d74d6dfb198b19edf9ef1c086d10f8..ee0cfd7476700622f445f287dd23f42d48553797 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -201,11 +201,16 @@ if (!is_android && !is_mac) {
@@ -33,10 +33,10 @@ index 74aadd24a27d31291bb42d452ff247bbf6dad14a..a0d74156745c0d22a332b2547c59b98d
"//base",
"//build:branding_buildflags",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f195e70c33b1a88e44f8ad51be6573d609d91b7f..a9195e0149385e7ffc95eb809bc30256683861d7 100644
index 26181ca1d4df95d67e625c8043c148579b5acc7c..ac1d5d4f3618057335fff5fe11418f7b84786775 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4532,7 +4532,7 @@ static_library("browser") {
@@ -4507,7 +4507,7 @@ static_library("browser") {
]
}
@@ -46,10 +46,10 @@ index f195e70c33b1a88e44f8ad51be6573d609d91b7f..a9195e0149385e7ffc95eb809bc30256
# than here in :chrome_dll.
deps += [ "//chrome:packed_resources_integrity_header" ]
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cf7e31b7b1b8eab0e82a669902dc37020f74195a..dfeb9048a85ab2076259c01687d30c2c7f36d8b0 100644
index e627fc93f01fcf5598aa594f18cf6efa03c96268..2723bbe8b197d611f5224505e13adf375c19392f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -7770,9 +7770,12 @@ test("unit_tests") {
@@ -7733,9 +7733,12 @@ test("unit_tests") {
"//chrome/notification_helper",
]
@@ -63,7 +63,7 @@ index cf7e31b7b1b8eab0e82a669902dc37020f74195a..dfeb9048a85ab2076259c01687d30c2c
"//chrome//services/util_win:unit_tests",
"//chrome/app:chrome_dll_resources",
"//chrome/app:win_unit_tests",
@@ -8771,6 +8774,10 @@ test("unit_tests") {
@@ -8734,6 +8737,10 @@ test("unit_tests") {
"../browser/performance_manager/policies/background_tab_loading_policy_unittest.cc",
]
@@ -74,7 +74,7 @@ index cf7e31b7b1b8eab0e82a669902dc37020f74195a..dfeb9048a85ab2076259c01687d30c2c
sources += [
# The importer code is not used on Android.
"../common/importer/firefox_importer_utils_unittest.cc",
@@ -8828,7 +8835,6 @@ test("unit_tests") {
@@ -8791,7 +8798,6 @@ test("unit_tests") {
# TODO(crbug.com/417513088): Maybe merge with the non-android `deps` declaration above?
deps += [
"../browser/screen_ai:screen_ai_install_state",

View File

@@ -9,10 +9,10 @@ potentially prevent a window from being created.
TODO(loc): this patch is currently broken.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 4e7b516f145312e353f112499b2792b27207d84b..222cf1b2bbc98aa5e271426478a774f8a48e693d 100644
index 44493867e40e08f2136c5d3fe116a1e8d313e091..4530ef9ccef717342bc71e37f7a6005b8184b645 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -10125,6 +10125,7 @@ void RenderFrameHostImpl::CreateNewWindow(
@@ -10126,6 +10126,7 @@ void RenderFrameHostImpl::CreateNewWindow(
last_committed_origin_, params->window_container_type,
params->target_url, params->referrer.To<Referrer>(),
params->frame_name, params->disposition, *params->features,
@@ -21,10 +21,10 @@ index 4e7b516f145312e353f112499b2792b27207d84b..222cf1b2bbc98aa5e271426478a774f8
&no_javascript_access);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index b0f3579f18f3b6dd5a9b328324348770319ccf67..1567ac2a65d222080430a47dce97b6d387ebe49d 100644
index 96d5fbb522045a9d1c1d22ab2b625801206dd9a6..daab93ed099913477d94c7790325a0aea2f3c75f 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5385,6 +5385,10 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5487,6 +5487,10 @@ FrameTree* WebContentsImpl::CreateNewWindow(
create_params.initially_hidden = renderer_started_hidden;
create_params.initial_popup_url = params.target_url;
@@ -35,7 +35,7 @@ index b0f3579f18f3b6dd5a9b328324348770319ccf67..1567ac2a65d222080430a47dce97b6d3
// Even though all codepaths leading here are in response to a renderer
// trying to open a new window, if the new window ends up in a different
// browsing instance, then the RenderViewHost, RenderWidgetHost,
@@ -5439,6 +5443,12 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5541,6 +5545,12 @@ FrameTree* WebContentsImpl::CreateNewWindow(
// Sets the newly created WebContents WindowOpenDisposition.
new_contents_impl->original_window_open_disposition_ = params.disposition;
@@ -48,7 +48,7 @@ index b0f3579f18f3b6dd5a9b328324348770319ccf67..1567ac2a65d222080430a47dce97b6d3
// If the new frame has a name, make sure any SiteInstances that can find
// this named frame have proxies for it. Must be called after
// SetSessionStorageNamespace, since this calls CreateRenderView, which uses
@@ -5480,12 +5490,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5582,12 +5592,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
AddWebContentsDestructionObserver(new_contents_impl);
}
@@ -62,10 +62,10 @@ index b0f3579f18f3b6dd5a9b328324348770319ccf67..1567ac2a65d222080430a47dce97b6d3
new_contents_impl, opener, params.target_url,
params.referrer.To<Referrer>(), params.disposition,
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 19dbb921c9644522588ff74d0a1925f826736957..4e7b36729741a79cfdf04f89a8ec615d3148b294 100644
index 444fa7009d0db33470cac9ab9cfdc23ceacec942..ab9aeb852e5ea89583284386d9a78a3e3e17a310 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -658,6 +658,10 @@ struct CreateNewWindowParams {
@@ -617,6 +617,10 @@ struct CreateNewWindowParams {
pending_associated_remote<blink.mojom.Widget> widget;
pending_associated_receiver<blink.mojom.FrameWidgetHost> frame_widget_host;
pending_associated_remote<blink.mojom.FrameWidget> frame_widget;
@@ -77,10 +77,10 @@ index 19dbb921c9644522588ff74d0a1925f826736957..4e7b36729741a79cfdf04f89a8ec615d
// Operation result when the renderer asks the browser to create a new window.
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index d2dccc29b0e13ab5c87b4c6803e79dc781e52ea2..be6639ef1a7eebb147afee483a35898d1ea5d95f 100644
index 0ecf7b395a1f270397c25a116d28a4d9cb05fa84..bc437d5f7d14d2d5df13595f78e0fc145285bdbc 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -877,6 +877,8 @@ bool ContentBrowserClient::CanCreateWindow(
@@ -882,6 +882,8 @@ bool ContentBrowserClient::CanCreateWindow(
const std::string& frame_name,
WindowOpenDisposition disposition,
const blink::mojom::WindowFeatures& features,
@@ -90,7 +90,7 @@ index d2dccc29b0e13ab5c87b4c6803e79dc781e52ea2..be6639ef1a7eebb147afee483a35898d
bool opener_suppressed,
bool* no_javascript_access) {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 3b6c42b2c4cd5d9e5753af25b27925ff0d933568..e6f51d39b4f2f6b162814996921958ca1252e1d7 100644
index 486b5f0e6c0969df5373666c257c36dcdc19f96b..11eece7441d775490c4149e607b1812e917a1b00 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -205,6 +205,7 @@ class NetworkService;
@@ -101,7 +101,7 @@ index 3b6c42b2c4cd5d9e5753af25b27925ff0d933568..e6f51d39b4f2f6b162814996921958ca
} // namespace network
namespace sandbox {
@@ -1468,6 +1469,8 @@ class CONTENT_EXPORT ContentBrowserClient {
@@ -1471,6 +1472,8 @@ class CONTENT_EXPORT ContentBrowserClient {
const std::string& frame_name,
WindowOpenDisposition disposition,
const blink::mojom::WindowFeatures& features,
@@ -170,10 +170,10 @@ index 0650197909d484b8a0f48ab61b22471c71bce0e8..29c380d7845aab1a7b3417e0d3940ea0
// typically happens when popups are created.
virtual void WebContentsCreated(WebContents* source_contents,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 6ee766c52202804adc532b1585224b4e35239f9a..42a0a7e5be01fe346cc2ad83d3395425a41e1699 100644
index aaa66a747228097e971587f14b453f4ea4f49f7c..280091edd7aa92c3cbc9e4b442cba91cb5bd2aa4 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6879,6 +6879,10 @@ WebView* RenderFrameImpl::CreateNewWindow(
@@ -6854,6 +6854,10 @@ WebView* RenderFrameImpl::CreateNewWindow(
params->started_by_ad =
GetWebFrame()->IsAdFrame() || GetWebFrame()->IsAdScriptInStack();
@@ -224,10 +224,10 @@ index d92bab531c12c62a5321a23f4a0cb89691668127..2060e04795ba8e7a923fd0fe3485b8c5
} // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 715ca6e188c7e821478fcbaa4496efd25a673c61..e58465eb936b2a8b3479201ec24580501f7fc2f3 100644
index 87856b74d5e0a323b8527d783316d1aab1cf9b1e..9f0d95954ed3d7c7e3ac4825f31ee55255e0c46f 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -2341,6 +2341,8 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
@@ -2366,6 +2366,8 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
WebWindowFeatures window_features =
GetWindowFeaturesFromString(features, entered_window);

View File

@@ -0,0 +1,73 @@
From d8b01057f740d3bb0ec880b34372da63147c2521 Mon Sep 17 00:00:00 2001
From: Steinar H. Gunderson <sesse@chromium.org>
Date: Fri, 20 Mar 2026 07:22:02 -0700
Subject: [PATCH] Fix another use-after-free with lazy style attributes.
This is a similar problem as regular attribute checks, just for
the special case of input type="" (which is a similar but separate
path).
Style perftest and Speedometer3 are neutral.
Fixed: 493952652
Change-Id: I264503545c345325e6d21afa0726f524bb9394b8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7686835
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Steinar H Gunderson <sesse@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1602570}
---
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index 901a258..64198a33 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -957,11 +957,14 @@
if (const AtomicString& input_type =
element.getAttribute(html_names::kTypeAttr);
!input_type.IsNull()) {
+ // Do not use input_type in the loop; the reference
+ // may be dangling if CollectMatchingRulesForList()
+ // adds lazy attributes.
+ AtomicString input_type_lower = input_type.ToAsciiLower();
for (const auto bundle : match_request.RuleSetsWithInputRules()) {
if (CollectMatchingRulesForList<stop_at_first_match>(
- bundle.rule_set->InputRules(input_type.ToAsciiLower()),
- match_request, bundle.rule_set, bundle.style_sheet_index,
- checker, context) &&
+ bundle.rule_set->InputRules(input_type_lower), match_request,
+ bundle.rule_set, bundle.style_sheet_index, checker, context) &&
stop_at_first_match) {
return true;
}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/crashtests/chrome-bug-493952652.html b/third_party/blink/web_tests/external/wpt/css/css-values/crashtests/chrome-bug-493952652.html
new file mode 100644
index 0000000..a9c96ec5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/crashtests/chrome-bug-493952652.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<head>
+ <link rel="help" href="https://crbug.com/493952652">
+ <style>
+ /*
+ Evaluation of [style] will add a new attribute to the element,
+ as lazy style gets synchronized. However, the bucketing will be
+ on input type, so we do not synchronize the attributes _before_
+ iteration.
+ */
+ input[style][type="text"] {}
+ </style>
+ <style>
+ /*
+ For the second stylesheet, when checking the type="" value string,
+ we must not use a reference into the old attributes.
+ */
+ input[style][type="text"] {}
+ </style>
+</head>
+<body>
+ <input id="target" type="text"></input>
+ <script>
+ document.getElementById('target').style.color = 'red';
+ </script>
+</body>

View File

@@ -34,10 +34,10 @@ index dd4cee346f16df703d414bf206bbe6c9f4b1f796..5565f5a9259bd7da0722080bf01b3415
virtual void DidClearWindowObject() {}
virtual void DidChangeScrollOffset() {}
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 40d1f104794795dba6cd59518819e98a4cdbfc44..8352f70c6c11af2890a03a2fae1729d27fc8da1f 100644
index 92272d5177cc47839169066b860577194cbc5d47..776e097dda38e920430ea49b15069dd908c6268e 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4775,10 +4775,11 @@ void RenderFrameImpl::DidInstallConditionalFeatures(
@@ -4750,10 +4750,11 @@ void RenderFrameImpl::DidInstallConditionalFeatures(
observer.DidInstallConditionalFeatures(context, world_id);
}
@@ -52,7 +52,7 @@ index 40d1f104794795dba6cd59518819e98a4cdbfc44..8352f70c6c11af2890a03a2fae1729d2
void RenderFrameImpl::DidChangeScrollOffset() {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index ced097d57cec93b3d3062a6d7d9f7d037a355e6c..c08b9323175e5ec62203fa74d93a307aa35f3616 100644
index 0062c466fbe4c625669d3a334fc9b9d8c49837f2..e4939464a5bc4908fe83799c1920b8f294b4de84 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -608,7 +608,8 @@ class CONTENT_EXPORT RenderFrameImpl

View File

@@ -14,10 +14,10 @@ track down the source of this problem & figure out if we can fix it
by changing something in Electron.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index b3215ec81f8d750cfaa9b66a4880c6a90a6e183d..2d993b4265f6be26da1f0bc98520eec3fe393645 100644
index 6838e858c78b1c12d352860186ee2a75bbed2ad8..e770df76c913bfb126d8e9ecd2eb8548b9bfb2f9 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5356,7 +5356,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5458,7 +5458,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
: IsGuest();
// While some guest types do not have a guest SiteInstance, the ones that
// don't all override WebContents creation above.

View File

@@ -80,10 +80,10 @@ index 39fa45f0a0f9076bd7ac0be6f455dd540a276512..3d0381d463eed73470b28085830f2a23
content::WebContents* source,
const content::OpenURLParams& params,
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 8899a3216052582e35c5c046e1e0baee48052452..461cb574dc1083fae0bc96e53ed94ba117f7691d 100644
index e7fe85a1eae545b1bdcfd81d23ec607a42f3941a..d33125fb7e76b15d68d3c88be319f5ca93f82163 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2288,7 +2288,8 @@ bool Browser::IsWebContentsCreationOverridden(
@@ -2292,7 +2292,8 @@ bool Browser::IsWebContentsCreationOverridden(
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
@@ -93,7 +93,7 @@ index 8899a3216052582e35c5c046e1e0baee48052452..461cb574dc1083fae0bc96e53ed94ba1
if (HasActorTaskPreventingNewWebContents(profile(), opener)) {
// If an ExecutionEngine is acting on the opener, prevent it from creating a
// new WebContents. We'll instead force the navigation to happen in the same
@@ -2301,7 +2302,7 @@ bool Browser::IsWebContentsCreationOverridden(
@@ -2305,7 +2306,7 @@ bool Browser::IsWebContentsCreationOverridden(
return (window_container_type ==
content::mojom::WindowContainerType::BACKGROUND &&
ShouldCreateBackgroundContents(source_site_instance, opener_url,
@@ -103,10 +103,10 @@ index 8899a3216052582e35c5c046e1e0baee48052452..461cb574dc1083fae0bc96e53ed94ba1
WebContents* Browser::CreateCustomWebContents(
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index e92caadbec713996d7eb0af9e59ed4a3f14ea148..fe904aaa2ee0f94d3ff34174bac82464dfded91a 100644
index b78f6ff36aaf1f541fedb8e2cb652f69227c506e..a8c426b0c1099822e9f2396981bf347d9318c451 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -916,8 +916,7 @@ class Browser : public TabStripModelObserver,
@@ -917,8 +917,7 @@ class Browser : public TabStripModelObserver,
content::SiteInstance* source_site_instance,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
@@ -223,10 +223,10 @@ index b969f1d97b7e3396119b579cfbe61e19ff7d2dd4..b8d6169652da28266a514938b45b39c5
content::WebContents* AddNewContents(
content::WebContents* source,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index f605f46115cda0f8f06e5274a26e3b997ca4c62e..16c4c2f73643314a9b8287e13a6472dff2671652 100644
index 2dfacb13990561632441ccc9d0ae3006693b67e2..bef008a5233d7e941d88d5353ce8940df5a17b84 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5320,8 +5320,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
@@ -5422,8 +5422,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
if (delegate_ &&
delegate_->IsWebContentsCreationOverridden(
opener, source_site_instance, params.window_container_type,

View File

@@ -8,10 +8,10 @@ Allow registering custom protocols to handle service worker main script fetching
Refs https://bugs.chromium.org/p/chromium/issues/detail?id=996511
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index fdfa916eac0b6dd3f0fd09f284245f0ceb1b176e..26400bf6d5e0f48d649a31a27e33c8bc812990a6 100644
index 701ce5df52e77f9277b5d548b82eef3120435bf2..0974935ea7a72ade31270c10abfee1be92a3dcb9 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -1958,6 +1958,25 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
@@ -1954,6 +1954,25 @@ ServiceWorkerContextWrapper::GetLoaderFactoryForBrowserInitiatedRequest(
loader_factory_bundle_info =
context()->loader_factory_bundle_for_update_check()->Clone();

View File

@@ -33,10 +33,10 @@ index 0ab8187b0db8ae6db46d81738f653a2bc4c566f6..de3d55e85c22317f7f9375eb94d0d5d4
} // namespace net
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 1fcf11cf90206270c6b0131b687ae668a8a12f83..af072c92721215d3306c165fb571710c91933829 100644
index 9b7b17abed8d2220065e7b6130c77196f88dc825..b9aa61748c31d0e25a5d4ebc2f319a65ca1b30c0 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1923,6 +1923,13 @@ void NetworkContext::SetNetworkConditions(
@@ -1931,6 +1931,13 @@ void NetworkContext::SetNetworkConditions(
std::move(network_conditions));
}
@@ -51,7 +51,7 @@ index 1fcf11cf90206270c6b0131b687ae668a8a12f83..af072c92721215d3306c165fb571710c
// This may only be called on NetworkContexts created with the constructor
// that calls MakeURLRequestContext().
diff --git a/services/network/network_context.h b/services/network/network_context.h
index bb00a6ba93c522b484dc525ba204f1bd537e6285..26e6a215dd4be92f939e18b0b4a8339eb30cde33 100644
index d76159ac97c9c51fc73692e8f76f868259152d00..e6b8c8c5102cfab32126b49483be11866a44a68b 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -322,6 +322,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
@@ -63,10 +63,10 @@ index bb00a6ba93c522b484dc525ba204f1bd537e6285..26e6a215dd4be92f939e18b0b4a8339e
void SetEnableReferrers(bool enable_referrers) override;
#if BUILDFLAG(IS_CT_SUPPORTED)
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 099e103c8e17ff640270744903585d4c76cdd6a7..c8b56dcc8cd2d202c895f4aadcae4f6767a248d5 100644
index 63d410dd356594a5928ed2f84b05b403bf3367f0..ca47c9cb58d5d69faade9f85d1e63683d79cb5e3 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -1294,6 +1294,9 @@ interface NetworkContext {
@@ -1291,6 +1291,9 @@ interface NetworkContext {
SetNetworkConditions(mojo_base.mojom.UnguessableToken throttling_profile_id,
array<MatchedNetworkConditions> conditions);
@@ -77,7 +77,7 @@ index 099e103c8e17ff640270744903585d4c76cdd6a7..c8b56dcc8cd2d202c895f4aadcae4f67
SetAcceptLanguage(string new_accept_language);
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index 9d9e1f63fa138e3393c0395334049d10e8d1329f..1a8ac7dfefe1dde40b8a1dd63f7b2a7a3abe00ec 100644
index bc26f449109b3be84490fbb3569e36aa4aca8c4b..d273faec6c235cb7d29f0f7fb90affdca7240e51 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -156,6 +156,7 @@ class TestNetworkContext : public mojom::NetworkContext {

View File

@@ -315,7 +315,7 @@ index 38aa41a82acdf42fb05d3315c4df408796437873..0c6cbbc920c65a6e671839eb8022fbc9
// Although ScreenCaptureKit is available in 12.3 there were some bugs that
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
index 9887b022744234f11322806982962390d79031ac..631022789ffb51b45b120520977bea7239f28636 100644
index be22921bec3f112eb3d92c6a696aee2c3ed3a097..6d71bac3ac7b1318cd741efa50a5f40bd92b17fa 100644
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
@@ -321,8 +321,16 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(

View File

@@ -91,7 +91,7 @@ index 2afe18e9e4a5404ed184aeedc1c02a313853f463..7c3b0c2da6ded539764ce59bc43f49e9
return a.EmptyCells() == b.EmptyCells();
case CSSPropertyID::kFill:
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 6bcd20f64680f2f78984d686a7e2b7027f8fb111..8184630b3238f739aad68568b099d7d9416bc107 100644
index 7407d5592f54dfbdb6c8099c9fd96d4f8921aaf8..71fe4155378b22e1bad523794882fa47a7b504ac 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -13263,5 +13263,36 @@ const CSSValue* InternalEmptyLineHeight::ParseSingleValue(
@@ -132,10 +132,10 @@ index 6bcd20f64680f2f78984d686a7e2b7027f8fb111..8184630b3238f739aad68568b099d7d9
} // namespace css_longhand
} // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index 7e435bbd4a8ac83eee4be981dcff5c504261ce73..f560c4070d19396d0e9219bcd5682395c8495a8c 100644
index c7b826dd29b9a4c5a06a3bd352e3c481219f8d40..3ca28dd12cc1a20c7acba53f7e7180f8f28ed0ba 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -4192,6 +4192,15 @@ PositionTryFallback StyleBuilderConverter::ConvertSinglePositionTryFallback(
@@ -4196,6 +4196,15 @@ PositionTryFallback StyleBuilderConverter::ConvertSinglePositionTryFallback(
return PositionTryFallback(scoped_name, tactic_list);
}
@@ -203,10 +203,10 @@ index 19cda703154dab9397827ab6ea66c2ca446c644d..dd5943c511886f4e39b2e7f10e67e60f
return result;
}
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 784ce295c0bca0a7bd096585c0f6ff603f688abc..aeb07b03395d0ea4fd2ca229aed1da4ec80dd969 100644
index 33c91f31f548d54bcf3937e87ac391098bfd1905..4afbee0c16769a2ddbb115efa60951d7d062a62f 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1673,6 +1673,8 @@ component("platform") {
@@ -1676,6 +1676,8 @@ component("platform") {
"widget/widget_base.h",
"widget/widget_base_client.h",
"windows_keyboard_codes.h",
@@ -314,7 +314,7 @@ index 18f283e625101318ee14b50e6e765dfd1c9a1a44..44a3a55974c9e4b9e715574075f25661
auto DrawAsSinglePath = [&]() {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index b95006c3b2c040a21f65f93c5fc95dbde92b8e55..571ebaf1390970aa0759506e0731e74c20782efb 100644
index a4c41a7d2356e0e7be404380f3e7c59847b46230..e4b395b5ce2b2e5d161b75f9b51b810e3f362983 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -214,6 +214,10 @@

View File

@@ -112,10 +112,10 @@ index 0d3aa45778e02c4a5bcdea6e8b0f5ab722e86aa3..fbe4f3d2931cdd9893a3c96667015d40
string mime_type;
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index ed2de2a74f757f8dbb03d24934468933bc6923ed..a985ad9c86b4cf55abd52d62275e56788dd46a3d 100644
index 4f74407b7bdfdcba2cf4b76d9cb9ef317e243285..3010f32a6189251c448f31be8bab7ce8e6d058e5 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -373,6 +373,9 @@ URLLoader::URLLoader(
@@ -372,6 +372,9 @@ URLLoader::URLLoader(
mojo::SimpleWatcher::ArmingPolicy::MANUAL,
TaskRunner(request.priority)),
per_factory_orb_state_(context.GetMutableOrbState()),
@@ -125,7 +125,7 @@ index ed2de2a74f757f8dbb03d24934468933bc6923ed..a985ad9c86b4cf55abd52d62275e5678
devtools_request_id_(request.devtools_request_id),
options_(PopulateOptions(options,
factory_params_->is_orb_enabled,
@@ -570,7 +573,7 @@ void URLLoader::SetUpUrlRequestCallbacks(
@@ -569,7 +572,7 @@ void URLLoader::SetUpUrlRequestCallbacks(
&URLLoader::IsSharedDictionaryReadAllowed, base::Unretained(this)));
}
@@ -134,7 +134,7 @@ index ed2de2a74f757f8dbb03d24934468933bc6923ed..a985ad9c86b4cf55abd52d62275e5678
url_request_->SetResponseHeadersCallback(base::BindRepeating(
&URLLoader::SetRawResponseHeaders, base::Unretained(this)));
}
@@ -1176,6 +1179,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
@@ -1175,6 +1178,19 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
}
response_ = BuildResponseHead();

View File

@@ -139,10 +139,10 @@ index 96678f5de2a0b67cd338012fb84b9ea7ff904084..afc4c3030d15eeb7a270ca6d3cc29e64
// Register the CGWindowID (used to identify this window for video capture)
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index e62f180fd782f29c25cf47a4e6be0cce46c99b17..b65d050fee7a607658efa6914c35186d9452f26f 100644
index e02d00c5928f02791f71f348048bda50a7800eac..e73037b52ef2f81738ed7eeb5cb6f3b199b23249 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -223,6 +223,18 @@ ui::ZOrderLevel Widget::InitParams::EffectiveZOrderLevel() const {
@@ -224,6 +224,18 @@ ui::ZOrderLevel Widget::InitParams::EffectiveZOrderLevel() const {
}
}
@@ -161,7 +161,7 @@ index e62f180fd782f29c25cf47a4e6be0cce46c99b17..b65d050fee7a607658efa6914c35186d
void Widget::InitParams::SetParent(Widget* parent_widget) {
SetParent(parent_widget->GetNativeView());
}
@@ -470,6 +482,7 @@ void Widget::Init(InitParams params) {
@@ -471,6 +483,7 @@ void Widget::Init(InitParams params) {
params.child |= (params.type == InitParams::TYPE_CONTROL);
is_top_level_ = !params.child;

View File

@@ -28,10 +28,10 @@ The patch should be removed in favor of either:
Upstream bug https://bugs.chromium.org/p/chromium/issues/detail?id=1081397.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index f1c701adc36a69ccd0940a5dc7f2033cfd30ef6c..48236f4a9defef53625ad4b8ebaaaabffd535c75 100644
index 09a1c29bbae86da44b3433eaf78551e72b485245..b9501ec28078c3a95004fdfd9c7ac410e36f7d57 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -11785,6 +11785,11 @@ url::Origin NavigationRequest::GetOriginForURLLoaderFactoryUnchecked() {
@@ -11817,6 +11817,11 @@ url::Origin NavigationRequest::GetOriginForURLLoaderFactoryUnchecked() {
target_rph_id);
}

View File

@@ -87,10 +87,10 @@ index a4768b51dae6817c9e9a467e9b16e827e0bfebda..83c42b5062aa8193fe2f56e407abe67d
// The view with active text input state, i.e., a focused <input> element.
// It will be nullptr if no such view exists. Note that the active view
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 76def190aabe280bb8e0971dc5c72643bbce8f53..b3215ec81f8d750cfaa9b66a4880c6a90a6e183d 100644
index 4fb9fcdc24376c81fe6092a484eb72a55e1ea45a..6838e858c78b1c12d352860186ee2a75bbed2ad8 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -10284,7 +10284,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame(
@@ -10415,7 +10415,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame(
"WebContentsImpl::OnFocusedElementChangedInFrame",
"render_frame_host", frame);
RenderWidgetHostViewBase* root_view =

View File

@@ -59,7 +59,7 @@ index cba373664bec3a32abad6fe0396bd67b53b7e67f..a54f1b3351efd2d8f324436f7f35cd43
#endif // THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_SCRIPT_EXECUTION_CALLBACK_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 34603bffa39cf2aaedfd7c3152464c524995f6f0..df2bf77d922cd5fed2d29b99bc35f28988d6d14f 100644
index daf04130625fda5b6779126e9a63d9f4854a8555..c5bd0e7930e17541f9fbae5994933c80fbe91f54 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -3197,6 +3197,7 @@ void LocalFrame::RequestExecuteScript(
@@ -92,10 +92,10 @@ index 0f119c1170f3379754b03ff38358ed6f191fb578..64024aaa3630bacbaf13b7491ff4ed54
mojom::blink::WantResultOption,
mojom::blink::PromiseResultOption);
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
index 56d681d3eea661fb0a5b1a135b4d4ea09e9e4577..7bcae985c6c918782f2795746f3ea01fcdcb1bff 100644
index aa2666a03b9f0b4585f6025b45e1a1a914508843..3d88ea81f4d524979e42bbc6f5a2b1c0a4d15e26 100644
--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
@@ -987,6 +987,7 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld(
@@ -988,6 +988,7 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld(
std::move(callback).Run(value ? std::move(*value) : base::Value());
},
std::move(callback)),
@@ -223,7 +223,7 @@ index 6e87cd9a855bd3f1145f864367f34d966088ce6c..6b0448254eec33896686544ebc2a9bf6
mojom::blink::WantResultOption::kWantResult, wait_for_promise);
}
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 6ce6c0af328f722d02228feae910b129e0f41a74..d4a11cc2cd9be3a97058ec800ff23bc2ce33b12b 100644
index d2b005438958f685e2187d8853926a94211427ad..e3446c84a068a954dfaa809580e8945f359f9e3c 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -1128,14 +1128,15 @@ void WebLocalFrameImpl::RequestExecuteScript(

View File

@@ -6,10 +6,10 @@ Subject: frame_host_manager.patch
Allows embedder to intercept site instances created by chromium.
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index a5165a08f161844898281c18d3963f8abffd58a8..c4d995aec772a6818c747adceb9fc63fe8d272e2 100644
index c6a3a45f875c010a9f9cda637fb91d74427aeec6..15ec1a4c8796378effd9e1530851eb6d7fa4dfa1 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -4925,6 +4925,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
@@ -4864,6 +4864,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
request->ResetStateForSiteInstanceChange();
}
@@ -20,7 +20,7 @@ index a5165a08f161844898281c18d3963f8abffd58a8..c4d995aec772a6818c747adceb9fc63f
}
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index e6f51d39b4f2f6b162814996921958ca1252e1d7..1f496db16389734a30f1c07903ff6225aeb1f1b4 100644
index 11eece7441d775490c4149e607b1812e917a1b00..978a5688a5be1ee05888264250c3356ba1ad707b 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -350,6 +350,11 @@ class CONTENT_EXPORT ContentBrowserClient {

View File

@@ -6,10 +6,10 @@ Subject: gritsettings_resource_ids.patch
Add electron resources file to the list of resource ids generation.
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index bc4d99704dcdb1f2d688fb6d847304ac7a45d3a8..5087a431bb9bd1fba7779f01c738c9d19cbfb63c 100644
index a71d0f633287f6832a933447b9edb71aafece4ba..0d92a115b539f5449205fddaa34ef27e5d364592 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -1661,6 +1661,11 @@
@@ -1665,6 +1665,11 @@
"includes": [12000],
},

View File

@@ -50,7 +50,7 @@ system font by checking if it's kCTFontPriorityAttribute is set to
system priority.
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 17b0a948c762996026885cbb63d66cbd0ab94981..a1a18ffa59d45518cb171efb08cf24d1648de425 100644
index aacecd4fbfa237ed17e8264abd37cce969dfa331..17af90379af2b07c7f7645adc2955df22afb32dc 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1085,6 +1085,7 @@ component("base") {
@@ -974,7 +974,7 @@ index 664e12c07204feeb5be16581fe51e8adc4b898dd..38159d146cdf71f84611d58e2983418a
return kAttributes;
}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 29104a461b7a3e04dc86baab0521288f974750a8..ea54cab0a72e931299871968afab7701e21547e4 100644
index 6fb162e7f477fabde5a83de7bf68b87f1708f274..c276641783fc8a88f09fe7e0e6c48a937b69fead 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -363,6 +363,7 @@ source_set("browser") {
@@ -1189,7 +1189,7 @@ index a1068589ad844518038ee7bc15a3de9bc5cba525..1ff781c49f086ec8015c7d3c44567dbe
} // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 3235936853681da70e93a31d51a7f6a91be698b0..a3c78319d97fe84621c29d778e354a6384f8583f 100644
index 457752f9e929414b6d5afd1fa58b3916939157af..3227168bb01fa03c24f2496fd3848699ed3f8c8e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -701,6 +701,7 @@ static_library("test_support") {
@@ -1378,7 +1378,7 @@ index 3a079b0fc34031d062045510fe0e2444792ff942..1be75833d46aaa124e5467904f68e46c
} // namespace
#endif
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index 012632a440f5078a71cbb327b04990654f282141..8e47b039b63fe74d3de441b8d21e7a9c4ec974f5 100644
index 5be47a39edb9c5f3b05a13d10732b772d30cc2d7..a455b220b1e16770888bb02daeb88bfc4fa86fbd 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -223,6 +223,8 @@ source_set("dns") {
@@ -1789,7 +1789,7 @@ index eb81a70e4d5d5cd3e6ae9b45f8cd1c795ea76c51..9921ccb10d3455600eddd85f77f10228
} // namespace sandbox
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 9b399ad326a19af7fd5e717bf8940ec562338f6d..96cc912489ab4423e0592d9c90c3d38f57131087 100644
index 7b4ad32dfe88c07b8b82fbd58e7eb2da98cc86d7..b769dd1db63d6cf2f52d7b241237aa9601042b93 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -444,6 +444,7 @@ component("core") {
@@ -2359,10 +2359,10 @@ index bbe355cf69f160866188216cc274d75bd35603db..06ee100d7ea2e892dbf3c0b1adc96c50
// enough.
return PlatformFontMac::SystemFontType::kGeneral;
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 5c0cad2640d84193e396ac1faff7d61230ab388c..edaf2a169d67cfa7903c56989801b1563ecf7af3 100644
index 82c365a68444028440a3147193c49047ea1737d3..d338b652ebbe84891c5a5678ed5295fc907d0974 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -732,6 +732,8 @@ component("views") {
@@ -734,6 +734,8 @@ component("views") {
"IOSurface.framework",
"QuartzCore.framework",
]
@@ -2371,7 +2371,7 @@ index 5c0cad2640d84193e396ac1faff7d61230ab388c..edaf2a169d67cfa7903c56989801b156
}
if (is_win) {
@@ -1161,6 +1163,8 @@ source_set("test_support") {
@@ -1163,6 +1165,8 @@ source_set("test_support") {
"//ui/base/mojom:ui_base_types",
]

View File

@@ -7,7 +7,7 @@ This adds a callback from the network service that's used to implement
session.setCertificateVerifyCallback.
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 55832bf73e134f21948821fbe13dd0642661e8d3..1fcf11cf90206270c6b0131b687ae668a8a12f83 100644
index 504a8d0cd8bbc7b5e597e784d26d9fd905ba43da..9b7b17abed8d2220065e7b6130c77196f88dc825 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -171,6 +171,11 @@
@@ -134,7 +134,7 @@ index 55832bf73e134f21948821fbe13dd0642661e8d3..1fcf11cf90206270c6b0131b687ae668
constexpr uint32_t NetworkContext::kMaxOutstandingRequestsPerProcess;
NetworkContext::NetworkContextHttpAuthPreferences::
@@ -1036,6 +1146,13 @@ void NetworkContext::SetClient(
@@ -1044,6 +1154,13 @@ void NetworkContext::SetClient(
client_.Bind(std::move(client));
}
@@ -148,7 +148,7 @@ index 55832bf73e134f21948821fbe13dd0642661e8d3..1fcf11cf90206270c6b0131b687ae668
void NetworkContext::CreateURLLoaderFactory(
mojo::PendingReceiver<mojom::URLLoaderFactory> receiver,
mojom::URLLoaderFactoryParamsPtr params) {
@@ -2723,6 +2840,10 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
@@ -2733,6 +2850,10 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
cert_verifier = std::make_unique<net::CachingCertVerifier>(
std::make_unique<net::CoalescingCertVerifier>(
std::move(cert_verifier)));
@@ -160,7 +160,7 @@ index 55832bf73e134f21948821fbe13dd0642661e8d3..1fcf11cf90206270c6b0131b687ae668
builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
diff --git a/services/network/network_context.h b/services/network/network_context.h
index f4bc2b75bc833dc7a47e1fa178f5542824843b36..bb00a6ba93c522b484dc525ba204f1bd537e6285 100644
index 3e95a8a8c8c8e4d43cc461ce1c13589cc881b09e..d76159ac97c9c51fc73692e8f76f868259152d00 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -119,6 +119,7 @@ class SimpleUrlPatternMatcher;
@@ -180,7 +180,7 @@ index f4bc2b75bc833dc7a47e1fa178f5542824843b36..bb00a6ba93c522b484dc525ba204f1bd
void ResetURLLoaderFactories() override;
void GetViaObliviousHttp(
mojom::ObliviousHttpRequestPtr request,
@@ -970,6 +973,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
@@ -971,6 +974,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
std::vector<base::OnceClosure> dismount_closures_;
#endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
@@ -190,10 +190,10 @@ index f4bc2b75bc833dc7a47e1fa178f5542824843b36..bb00a6ba93c522b484dc525ba204f1bd
std::unique_ptr<HostResolver> internal_host_resolver_;
std::set<std::unique_ptr<HostResolver>, base::UniquePtrComparator>
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 116ecc87549d02fa20ef9fd8068b3410590a2879..099e103c8e17ff640270744903585d4c76cdd6a7 100644
index 47134ad9365ce50035d5a305418e36a41fc917c9..63d410dd356594a5928ed2f84b05b403bf3367f0 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -324,6 +324,17 @@ struct SocketBrokerRemotes {
@@ -325,6 +325,17 @@ struct SocketBrokerRemotes {
pending_remote<SocketBroker> server;
};
@@ -211,7 +211,7 @@ index 116ecc87549d02fa20ef9fd8068b3410590a2879..099e103c8e17ff640270744903585d4c
// Parameters for constructing a network context.
struct NetworkContextParams {
// The user agent string.
@@ -980,6 +991,9 @@ interface NetworkContext {
@@ -977,6 +988,9 @@ interface NetworkContext {
// Sets a client for this network context.
SetClient(pending_remote<NetworkContextClient> client);
@@ -222,7 +222,7 @@ index 116ecc87549d02fa20ef9fd8068b3410590a2879..099e103c8e17ff640270744903585d4c
CreateURLLoaderFactory(
pending_receiver<URLLoaderFactory> url_loader_factory,
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index 817b69f7b36f996a5f3f068649a997fdf67afd1b..9d9e1f63fa138e3393c0395334049d10e8d1329f 100644
index beb1c3dba14fcc504886f100b1568768231a4f2d..bc26f449109b3be84490fbb3569e36aa4aca8c4b 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -63,6 +63,8 @@ class TestNetworkContext : public mojom::NetworkContext {

View File

@@ -133,7 +133,7 @@ index 9bf238e64af483294ae3c3f18a4e9aed49a8658d..b9b2a4c8c387b8e8b4eb1f02fc0f891c
const GURL& document_url,
const WeakDocumentPtr& weak_document_ptr,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c160b8ad92ad648dd7657fc3b94d2cc6c72c3824..23ddb2009a6118aad1f9629c7cd7a6d566b3bcc6 100644
index 50bf9100cd0dacd5c1a1c7293683101efcf7f1b2..40c41c074c75ec04badee292310d13d393e42fdd 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2375,7 +2375,7 @@ void RenderProcessHostImpl::CreateNotificationService(

View File

@@ -36,10 +36,10 @@ index 6f31a20329a7bc7cafb6384c3b8ec9ed7a11e64e..3bf92efa5c0ad0212096e61383b53095
Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture;
diff --git a/media/video/renderable_mappable_shared_image_video_frame_pool.cc b/media/video/renderable_mappable_shared_image_video_frame_pool.cc
index 36ed797edc58a6cf094a0b720bf949b3f6379890..36a4a080da38cddad645d42e5c53c840e211105e 100644
index 6b1abdebe1fb0043f535e731d0bd14a6d3e3c083..cde2239a516133fedb46dc4bd06b791a1a4d12aa 100644
--- a/media/video/renderable_mappable_shared_image_video_frame_pool.cc
+++ b/media/video/renderable_mappable_shared_image_video_frame_pool.cc
@@ -211,6 +211,24 @@ bool FrameResources::Initialize(VideoPixelFormat format,
@@ -212,6 +212,24 @@ bool FrameResources::Initialize(VideoPixelFormat format,
const gfx::Size coded_size =
GetCodedSizeForVideoPixelFormat(format, visible_size_);

View File

@@ -68,7 +68,7 @@ index f91857eb0b6ad385721b8224100de26dfdd7dd8d..45e8766fcb8d46d8edc3bf8d21d3f826
: PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3;
}
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a705b5d994 100644
index aa79c324af2cec50019bca3bccff5d420fb30ffd..455095a2cd63eabe4f267747070b443f0c49c1e8 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -80,6 +80,20 @@ namespace printing {
@@ -326,14 +326,23 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
ReleasePrinterQuery();
}
@@ -851,15 +886,24 @@ void PrintViewManagerBase::RemoveTestObserver(TestObserver& observer) {
@@ -851,15 +886,33 @@ void PrintViewManagerBase::RemoveTestObserver(TestObserver& observer) {
test_observers_.RemoveObserver(&observer);
}
+void PrintViewManagerBase::ShowInvalidPrinterSettingsError() {
+ if (!callback_.is_null()) {
+ printing_status_ = PrintStatus::kInvalid;
+ TerminatePrintJob(true);
+ if (print_job_) {
+ TerminatePrintJob(true);
+ } else {
+ // No print job was created, so TerminatePrintJob would bail out
+ // without ever calling ReleasePrintJob (where the callback is
+ // invoked). Fire the callback directly to avoid leaking it until
+ // WebContents destruction.
+ std::move(callback_).Run(false,
+ PrintReasonFromPrintStatus(printing_status_));
+ }
+ }
+}
+
@@ -351,7 +360,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
}
void PrintViewManagerBase::RenderFrameDeleted(
@@ -901,13 +945,14 @@ void PrintViewManagerBase::SystemDialogCancelled() {
@@ -901,13 +954,14 @@ void PrintViewManagerBase::SystemDialogCancelled() {
// System dialog was cancelled. Clean up the print job and notify the
// BackgroundPrintingManager.
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -367,7 +376,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
}
void PrintViewManagerBase::OnDocDone(int job_id, PrintedDocument* document) {
@@ -921,18 +966,26 @@ void PrintViewManagerBase::OnJobDone() {
@@ -921,18 +975,26 @@ void PrintViewManagerBase::OnJobDone() {
// Printing is done, we don't need it anymore.
// print_job_->is_job_pending() may still be true, depending on the order
// of object registration.
@@ -396,7 +405,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
TerminatePrintJob(true);
}
@@ -942,7 +995,7 @@ bool PrintViewManagerBase::RenderAllMissingPagesNow() {
@@ -942,7 +1004,7 @@ bool PrintViewManagerBase::RenderAllMissingPagesNow() {
// Is the document already complete?
if (print_job_->document() && print_job_->document()->IsComplete()) {
@@ -405,7 +414,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
return true;
}
@@ -995,7 +1048,10 @@ bool PrintViewManagerBase::SetupNewPrintJob(
@@ -995,7 +1057,10 @@ bool PrintViewManagerBase::SetupNewPrintJob(
// Disconnect the current `print_job_`.
auto weak_this = weak_ptr_factory_.GetWeakPtr();
@@ -417,7 +426,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
if (!weak_this)
return false;
@@ -1015,7 +1071,7 @@ bool PrintViewManagerBase::SetupNewPrintJob(
@@ -1015,7 +1080,7 @@ bool PrintViewManagerBase::SetupNewPrintJob(
#endif
print_job_->AddObserver(*this);
@@ -426,7 +435,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
return true;
}
@@ -1073,7 +1129,7 @@ void PrintViewManagerBase::ReleasePrintJob() {
@@ -1073,7 +1138,7 @@ void PrintViewManagerBase::ReleasePrintJob() {
// Ensure that any residual registration of printing client is released.
// This might be necessary in some abnormal cases, such as the associated
// render process having terminated.
@@ -435,7 +444,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
if (!analyzing_content_) {
UnregisterSystemPrintClient();
}
@@ -1083,6 +1139,11 @@ void PrintViewManagerBase::ReleasePrintJob() {
@@ -1083,6 +1148,11 @@ void PrintViewManagerBase::ReleasePrintJob() {
}
#endif
@@ -447,7 +456,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
if (!print_job_)
return;
@@ -1090,7 +1151,7 @@ void PrintViewManagerBase::ReleasePrintJob() {
@@ -1090,7 +1160,7 @@ void PrintViewManagerBase::ReleasePrintJob() {
// printing_rfh_ should only ever point to a RenderFrameHost with a live
// RenderFrame.
DCHECK(rfh->IsRenderFrameLive());
@@ -456,7 +465,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
}
print_job_->RemoveObserver(*this);
@@ -1132,7 +1193,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
@@ -1132,7 +1202,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() {
}
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
@@ -465,7 +474,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
return true;
if (!cookie) {
@@ -1155,7 +1216,7 @@ bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
@@ -1155,7 +1225,7 @@ bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
return false;
}
@@ -474,7 +483,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
// Don't start printing if enterprise checks are being performed to check if
// printing is allowed, or if content analysis is going to take place right
// before starting `print_job_`.
@@ -1286,6 +1347,8 @@ void PrintViewManagerBase::CompleteScriptedPrint(
@@ -1286,6 +1356,8 @@ void PrintViewManagerBase::CompleteScriptedPrint(
auto callback_wrapper = base::BindOnce(
&PrintViewManagerBase::ScriptedPrintReply, weak_ptr_factory_.GetWeakPtr(),
std::move(callback), render_process_host->GetDeprecatedID());
@@ -483,7 +492,7 @@ index aa79c324af2cec50019bca3bccff5d420fb30ffd..eb76ee91743236d05c3a70a54d5345a7
std::unique_ptr<PrinterQuery> printer_query =
queue()->PopPrinterQuery(params->cookie);
if (!printer_query)
@@ -1296,10 +1359,10 @@ void PrintViewManagerBase::CompleteScriptedPrint(
@@ -1296,10 +1368,10 @@ void PrintViewManagerBase::CompleteScriptedPrint(
params->expected_pages_count, params->has_selection, params->margin_type,
params->is_scripted, !render_process_host->IsPdf(),
base::BindOnce(&OnDidScriptedPrint, queue_, std::move(printer_query),

View File

@@ -44,10 +44,10 @@ index 5e7d992ba2144d32f8eb1c6fa5233c68954318e1..4ff55ddc2286fff096a7e2bcdfb87d87
void RenderWidgetHostImpl::ShowContextMenuAtPoint(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 1567ac2a65d222080430a47dce97b6d387ebe49d..f605f46115cda0f8f06e5274a26e3b997ca4c62e 100644
index daab93ed099913477d94c7790325a0aea2f3c75f..2dfacb13990561632441ccc9d0ae3006693b67e2 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -6212,6 +6212,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
@@ -6320,6 +6320,11 @@ TextInputManager* WebContentsImpl::GetTextInputManager() {
return text_input_manager_.get();
}
@@ -60,7 +60,7 @@ index 1567ac2a65d222080430a47dce97b6d387ebe49d..f605f46115cda0f8f06e5274a26e3b99
RenderWidgetHostImpl* render_widget_host) {
return render_widget_host == GetPrimaryMainFrame()->GetRenderWidgetHost();
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index c1fdb7e3d899dbdd4413361040158395a6d4eb98..ce46eaa39b053850e2692c906a9e991052cd7195 100644
index c353ef73e003f50f4a047dd4dcce5b6673ca4942..56690cd6d4603f91e1a5ce06d93a66b5381560cd 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1204,6 +1204,7 @@ class CONTENT_EXPORT WebContentsImpl

View File

@@ -8,7 +8,7 @@ it in Electron and prevent drift from Chrome's blocklist. We should look for a w
to upstream this change to Chrome.
diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
index e45b723af85446b5c7537d49e70f34b2a67bab97..ac44b6723085c7a94a5d8736e24ea4ea22ac206a 100644
index 4e769e8be28ffd18788d8786fe7341e5d5b0697c..2f447d1a3e7ab50458159bcb717220bb60f6f6ea 100644
--- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
+++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
@@ -83,11 +83,13 @@
@@ -25,7 +25,7 @@ index e45b723af85446b5c7537d49e70f34b2a67bab97..ac44b6723085c7a94a5d8736e24ea4ea
#include "components/tabs/public/tab_interface.h"
#if BUILDFLAG(ENABLE_PLATFORM_APPS)
#include "extensions/browser/extension_registry.h" // nogncheck
@@ -287,190 +289,10 @@ bool MaybeIsLocalUNCPath(const base::FilePath& path) {
@@ -286,190 +288,10 @@ bool MaybeIsLocalUNCPath(const base::FilePath& path) {
}
#endif
@@ -220,7 +220,7 @@ index e45b723af85446b5c7537d49e70f34b2a67bab97..ac44b6723085c7a94a5d8736e24ea4ea
// Checks if `path` should be blocked by the `rules`.
// The BlockType of the nearest ancestor of a path to check is what
@@ -1405,16 +1227,6 @@ struct ChromeFileSystemAccessPermissionContext::OriginState {
@@ -1404,16 +1226,6 @@ struct ChromeFileSystemAccessPermissionContext::OriginState {
std::unique_ptr<base::RetainingOneShotTimer> cleanup_timer;
};
@@ -237,7 +237,7 @@ index e45b723af85446b5c7537d49e70f34b2a67bab97..ac44b6723085c7a94a5d8736e24ea4ea
ChromeFileSystemAccessPermissionContext::
ChromeFileSystemAccessPermissionContext(content::BrowserContext* context,
const base::Clock* clock)
@@ -1433,7 +1245,7 @@ ChromeFileSystemAccessPermissionContext::
@@ -1432,7 +1244,7 @@ ChromeFileSystemAccessPermissionContext::
#if BUILDFLAG(IS_ANDROID)
one_time_permissions_tracker_.Observe(
OneTimePermissionsTrackerFactory::GetForBrowserContext(context));
@@ -246,7 +246,7 @@ index e45b723af85446b5c7537d49e70f34b2a67bab97..ac44b6723085c7a94a5d8736e24ea4ea
auto* provider = web_app::WebAppProvider::GetForWebApps(
Profile::FromBrowserContext(profile_));
if (provider) {
@@ -2813,7 +2625,7 @@ void ChromeFileSystemAccessPermissionContext::OnShutdown() {
@@ -2812,7 +2624,7 @@ void ChromeFileSystemAccessPermissionContext::OnShutdown() {
one_time_permissions_tracker_.Reset();
}
@@ -255,7 +255,7 @@ index e45b723af85446b5c7537d49e70f34b2a67bab97..ac44b6723085c7a94a5d8736e24ea4ea
void ChromeFileSystemAccessPermissionContext::OnWebAppInstalled(
const webapps::AppId& app_id) {
if (!base::FeatureList::IsEnabled(
@@ -3171,11 +2983,7 @@ bool ChromeFileSystemAccessPermissionContext::
@@ -3170,11 +2982,7 @@ bool ChromeFileSystemAccessPermissionContext::
HandleType handle_type,
UserAction user_action,
GrantType grant_type) {
@@ -268,7 +268,7 @@ index e45b723af85446b5c7537d49e70f34b2a67bab97..ac44b6723085c7a94a5d8736e24ea4ea
if (!base::FeatureList::IsEnabled(
features::kFileSystemAccessPersistentPermissions)) {
return false;
@@ -3226,6 +3034,7 @@ bool ChromeFileSystemAccessPermissionContext::
@@ -3225,6 +3033,7 @@ bool ChromeFileSystemAccessPermissionContext::
return false;
#endif // BUILDFLAG(IS_ANDROID)

View File

@@ -15,10 +15,10 @@ This CL removes these filters so the unresponsive event can still be
accessed from our JS event. The filtering is moved into Electron's code.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 2d993b4265f6be26da1f0bc98520eec3fe393645..a526b1071029a33983060e3f379e3030ac723403 100644
index e770df76c913bfb126d8e9ecd2eb8548b9bfb2f9..e8578f1c2c63fa83c7b8ba413a55121c4479aa3e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -10446,25 +10446,13 @@ void WebContentsImpl::RendererUnresponsive(
@@ -10567,25 +10567,13 @@ void WebContentsImpl::RendererUnresponsive(
base::RepeatingClosure hang_monitor_restarter) {
OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RendererUnresponsive",
"render_widget_host", render_widget_host);

View File

@@ -52,7 +52,7 @@ Some alternatives to this patch:
None of these options seems like a substantial maintainability win over this patch to me (@nornagon).
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index d8f51269f5edb6fa698bc40abb3900a551f2ab0d..74aadd24a27d31291bb42d452ff247bbf6dad14a 100644
index f74c98ab47e2917781a689856b4d05d9ea175de2..e30ea563d0d74d6dfb198b19edf9ef1c086d10f8 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1550,7 +1550,7 @@ if (is_chrome_branded && !is_android) {

View File

@@ -245,10 +245,10 @@ index 1ef2c9052262eccdbc40030746a858b7f30ac469..c7101b0d71826b05f61bfe0e74429d92
}
diff --git a/content/common/features.cc b/content/common/features.cc
index a66e20e2f49f02c314a863b6877608b81c1f6ec4..0ddfd42a86aa09ef01c7d0a5ab1c075cf40527dc 100644
index 60450dda6cdc81dae8d288df7c03a13c86beed0e..efce8544ae5b7d5b904d99b242af4a04144bb548 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -370,6 +370,14 @@ BASE_FEATURE(kInterestGroupUpdateIfOlderThan, base::FEATURE_ENABLED_BY_DEFAULT);
@@ -393,6 +393,14 @@ BASE_FEATURE(kInterestGroupUpdateIfOlderThan, base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kIOSurfaceCapturer, base::FEATURE_ENABLED_BY_DEFAULT);
#endif
@@ -264,10 +264,10 @@ index a66e20e2f49f02c314a863b6877608b81c1f6ec4..0ddfd42a86aa09ef01c7d0a5ab1c075c
BASE_FEATURE(kKeepChildProcessAfterIPCReset, base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/content/common/features.h b/content/common/features.h
index 85097d0c88411409c91a2a64cbc19133b703de57..4dd265220050c3bd723e0ef62cc8cc9ab8dcd442 100644
index f26e5c9f95dd3cfd81bee53507d181c08df3a044..b6efabd4fd0ebfdbea904bc19918aec9a6ba0ff0 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -143,6 +143,9 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kInterestGroupUpdateIfOlderThan);
@@ -149,6 +149,9 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kInterestGroupUpdateIfOlderThan);
#if BUILDFLAG(IS_MAC)
CONTENT_EXPORT BASE_DECLARE_FEATURE(kIOSurfaceCapturer);
#endif

View File

@@ -54,10 +54,10 @@ index e3fa1bdc048a59dd64dae19b2372119335686643..b5ceb81ecc4d0274a411267e975ea413
if (mouse_event_callback.Run(mouse_event)) {
return;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index a526b1071029a33983060e3f379e3030ac723403..28a98260183ad24529ef5848ffcb117e9e1a6e3b 100644
index e8578f1c2c63fa83c7b8ba413a55121c4479aa3e..cc1294bc66b38bae4960fecb0380ad6cacd39df3 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4486,6 +4486,12 @@ void WebContentsImpl::RenderWidgetWasResized(
@@ -4582,6 +4582,12 @@ void WebContentsImpl::RenderWidgetWasResized(
width_changed);
}
@@ -71,10 +71,10 @@ index a526b1071029a33983060e3f379e3030ac723403..28a98260183ad24529ef5848ffcb117e
const gfx::PointF& client_pt) {
if (delegate_) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ce46eaa39b053850e2692c906a9e991052cd7195..953deca8142154ffd0a27c11e9beb42270107a8c 100644
index 56690cd6d4603f91e1a5ce06d93a66b5381560cd..ef40925c6aa3875f34af3027937d1f856b4cbff5 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1134,6 +1134,7 @@ class CONTENT_EXPORT WebContentsImpl
@@ -1132,6 +1132,7 @@ class CONTENT_EXPORT WebContentsImpl
double GetPendingZoomLevel(RenderWidgetHostImpl* rwh) override;

View File

@@ -10,10 +10,10 @@ on Windows. We should refactor our code so that this patch isn't
necessary.
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 8dcd23b01d299057ce13c1a4d9016c1f3a4331b6..804b4e3a3c63c6302f92f9ba6738966957eb42c8 100644
index f11731797c7063b837e3d9396b84d02881754894..9f90a2b1c9849aa37f711cab9fb0006ba3e3dd12 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -21965,6 +21965,21 @@
@@ -22324,6 +22324,21 @@
]
}
],
@@ -36,10 +36,10 @@ index 8dcd23b01d299057ce13c1a4d9016c1f3a4331b6..804b4e3a3c63c6302f92f9ba67389669
{
"platforms": [
diff --git a/ui/views/views_features.cc b/ui/views/views_features.cc
index d033e4924e4646665840db11e988d430523cd65a..2c89de182d1bff0904762b88f6e16eec5839469d 100644
index c74cf661f64e60ad6740e011f372e53426ce0c4d..77ce34e4f47a54f7ecabbd6e6d4d19555af248ff 100644
--- a/ui/views/views_features.cc
+++ b/ui/views/views_features.cc
@@ -34,6 +34,14 @@ BASE_FEATURE(kEnableClickjackingProtection, base::FEATURE_DISABLED_BY_DEFAULT);
@@ -34,6 +34,14 @@ BASE_FEATURE(kEnableInputProtection, base::FEATURE_DISABLED_BY_DEFAULT);
// crbug.com/370856871.
BASE_FEATURE(kEnableTouchDragCursorSync, base::FEATURE_ENABLED_BY_DEFAULT);
@@ -55,12 +55,12 @@ index d033e4924e4646665840db11e988d430523cd65a..2c89de182d1bff0904762b88f6e16eec
// to kKeyboardAccessibleTooltip in //ui/base/ui_base_features.cc.
BASE_FEATURE(kKeyboardAccessibleTooltipInViews,
diff --git a/ui/views/views_features.h b/ui/views/views_features.h
index 78d8585e83bb12acb9e95867dfb586299c511277..838b40eb0aa31e12d6527f39a673f71af7ffa851 100644
index 092e51509d4adccb8adbe2481909068e3e6836aa..5093a4c08bf6675ed1e5cb944c1bcb8251bdb033 100644
--- a/ui/views/views_features.h
+++ b/ui/views/views_features.h
@@ -16,6 +16,7 @@ VIEWS_EXPORT BASE_DECLARE_FEATURE(kAnnounceTextAdditionalAttributes);
VIEWS_EXPORT BASE_DECLARE_FEATURE(kApplyInitialUrlToWebContents);
VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableClickjackingProtection);
VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableInputProtection);
VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableTouchDragCursorSync);
+VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableTransparentHwndEnlargement);
VIEWS_EXPORT BASE_DECLARE_FEATURE(kKeyboardAccessibleTooltipInViews);

View File

@@ -6,7 +6,7 @@ Subject: scroll_bounce_flag.patch
Patch to make scrollBounce option work.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 6dfee417bf6fbf94fd47aa4e9e9717378eabdfc9..623f2de73b5ae1c2129b8deb74faecb5a03423d2 100644
index 98ffa5d66e413682f01b3a86a90d7889d73b999e..bbcef0b179405d44200aadcf01a6595f7f2bafa2 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1127,11 +1127,11 @@ bool RenderThreadImpl::IsLcdTextEnabled() {

View File

@@ -22,7 +22,7 @@ However, the patch would need to be reviewed by the security team, as it
does touch a security-sensitive class.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 23ddb2009a6118aad1f9629c7cd7a6d566b3bcc6..27c80d6dfca4c422be531bf5376bb23844e731a6 100644
index 40c41c074c75ec04badee292310d13d393e42fdd..b45fb6cd8881315e2696eb1de4697c6077efb024 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1955,6 +1955,10 @@ bool RenderProcessHostImpl::Init() {

View File

@@ -9,10 +9,10 @@ is needed for OSR.
Originally landed in https://github.com/electron/libchromiumcontent/pull/226.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 16c4c2f73643314a9b8287e13a6472dff2671652..859643e7796440bf1966007c598effffba7e47c9 100644
index bef008a5233d7e941d88d5353ce8940df5a17b84..1cc1fa8f02bd84a8c30de178fcb0a91da772bbcb 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4203,6 +4203,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
@@ -4299,6 +4299,13 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
params.main_frame_name, GetOpener(), primary_main_frame_policy,
base::UnguessableToken::Create());
@@ -26,7 +26,7 @@ index 16c4c2f73643314a9b8287e13a6472dff2671652..859643e7796440bf1966007c598effff
std::unique_ptr<WebContentsViewDelegate> delegate =
GetContentClient()->browser()->GetWebContentsViewDelegate(this);
@@ -4213,6 +4220,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
@@ -4309,6 +4316,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
view_ = CreateWebContentsView(this, std::move(delegate),
&render_view_host_delegate_view_);
}
@@ -35,7 +35,7 @@ index 16c4c2f73643314a9b8287e13a6472dff2671652..859643e7796440bf1966007c598effff
CHECK(view_.get());
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index a02a9134feae75d4fe95f2d8163983bdec447b2b..055302c00a625f4570c57243be3bd0ae02a73347 100644
index 89902fe3d1fec3e0af044ab1737353f07ca6362d..b5982fd7f17a48c92ed2beb4e31a28f73714a66e 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -130,11 +130,14 @@ class PrerenderHandle;

View File

@@ -15,10 +15,10 @@ Note that we also need to manually update embedder's
`api::WebContents::IsFullscreenForTabOrPending` value.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 222cf1b2bbc98aa5e271426478a774f8a48e693d..865df1914009165ef0b0ea0e812e9e53535551bb 100644
index 4530ef9ccef717342bc71e37f7a6005b8184b645..2a44f82dabfbb9d56846d44d52153056942c3925 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -9190,6 +9190,17 @@ void RenderFrameHostImpl::EnterFullscreen(
@@ -9191,6 +9191,17 @@ void RenderFrameHostImpl::EnterFullscreen(
}
}
@@ -37,10 +37,10 @@ index 222cf1b2bbc98aa5e271426478a774f8a48e693d..865df1914009165ef0b0ea0e812e9e53
if (had_fullscreen_token && !GetView()->HasFocus()) {
GetView()->Focus();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 859643e7796440bf1966007c598effffba7e47c9..76def190aabe280bb8e0971dc5c72643bbce8f53 100644
index 1cc1fa8f02bd84a8c30de178fcb0a91da772bbcb..4fb9fcdc24376c81fe6092a484eb72a55e1ea45a 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4503,21 +4503,25 @@ KeyboardEventProcessingResult WebContentsImpl::PreHandleKeyboardEvent(
@@ -4599,21 +4599,25 @@ KeyboardEventProcessingResult WebContentsImpl::PreHandleKeyboardEvent(
const input::NativeWebKeyboardEvent& event) {
OPTIONAL_TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("content.verbose"),
"WebContentsImpl::PreHandleKeyboardEvent");
@@ -80,7 +80,7 @@ index 859643e7796440bf1966007c598effffba7e47c9..76def190aabe280bb8e0971dc5c72643
}
bool WebContentsImpl::HandleMouseEvent(const blink::WebMouseEvent& event) {
@@ -4690,7 +4694,7 @@ void WebContentsImpl::EnterFullscreenMode(
@@ -4792,7 +4796,7 @@ void WebContentsImpl::EnterFullscreenMode(
OPTIONAL_TRACE_EVENT0("content", "WebContentsImpl::EnterFullscreenMode");
DCHECK(CanEnterFullscreenMode(requesting_frame));
DCHECK(requesting_frame->IsActive());

View File

@@ -26,10 +26,10 @@ index 1f6c015c361b3146db760643e3670a110634d75b..d4d9c10d3420a5ff998aeb593ea6a255
// An empty URL is returned if the URL is not overriden.
virtual GURL OverrideFlashEmbedWithHTML(const GURL& url);
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 78f0ab75486f90ad9bda568cd28c20ec0c48f298..5e2fff57b0a4e08d4263546a8914575501fc9082 100644
index b21e367edf3e7bba172f3d63f5e3a18e53342ab4..d6cfc578d52fab79635fea73138262431abc3a63 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -922,6 +922,12 @@ void RendererBlinkPlatformImpl::WillStopWorkerThread() {
@@ -928,6 +928,12 @@ void RendererBlinkPlatformImpl::WillStopWorkerThread() {
WorkerThreadRegistry::Instance()->WillStopCurrentWorkerThread();
}
@@ -43,10 +43,10 @@ index 78f0ab75486f90ad9bda568cd28c20ec0c48f298..5e2fff57b0a4e08d4263546a89145755
const v8::Local<v8::Context>& worker) {
GetContentClient()->renderer()->DidInitializeWorkerContextOnWorkerThread(
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 4535d0bf0328301f6ed1a602f6ff97a0243f7685..e191b4ef4185a6cb745c50e949ce6281719e0265 100644
index 9664dd32d8945ca5303825377c8e345573d83a26..96898a41c3efe31e9043b092d37d7c4b42709bcc 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -209,6 +209,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
@@ -212,6 +212,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
void DidStartWorkerThread() override;
void WillStopWorkerThread() override;
void WorkerContextCreated(const v8::Local<v8::Context>& worker) override;
@@ -55,10 +55,10 @@ index 4535d0bf0328301f6ed1a602f6ff97a0243f7685..e191b4ef4185a6cb745c50e949ce6281
const blink::WebSecurityOrigin& script_origin) override;
blink::ProtocolHandlerSecurityLevel GetProtocolHandlerSecurityLevel(
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index a26e45d64229f692efb4a218c653afc212788d1f..4c797975567026268ea107f42e47f6411c5b7311 100644
index bb80991d521edbb22bb08e50805dd8c131cf75a4..495f557bd1a727c95749b05ac7945292b372f371 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -685,6 +685,7 @@ class BLINK_PLATFORM_EXPORT Platform {
@@ -695,6 +695,7 @@ class BLINK_PLATFORM_EXPORT Platform {
virtual void DidStartWorkerThread() {}
virtual void WillStopWorkerThread() {}
virtual void WorkerContextCreated(const v8::Local<v8::Context>& worker) {}

View File

@@ -35,10 +35,10 @@ index d4d9c10d3420a5ff998aeb593ea6a25556d1215e..d64fef6bfc37264dcdc1bbea22eb5c4e
// from the worker thread.
virtual void WillDestroyWorkerContextOnWorkerThread(
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 5e2fff57b0a4e08d4263546a8914575501fc9082..bfc88be930331b75be718fe3f7017f7ec477b086 100644
index d6cfc578d52fab79635fea73138262431abc3a63..37b2b2820a817f79e8e43f49d84bbb1675a5dc9f 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -934,6 +934,12 @@ void RendererBlinkPlatformImpl::WorkerContextCreated(
@@ -940,6 +940,12 @@ void RendererBlinkPlatformImpl::WorkerContextCreated(
worker);
}
@@ -52,10 +52,10 @@ index 5e2fff57b0a4e08d4263546a8914575501fc9082..bfc88be930331b75be718fe3f7017f7e
const blink::WebSecurityOrigin& script_origin) {
return GetContentClient()->renderer()->AllowScriptExtensionForServiceWorker(
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index e191b4ef4185a6cb745c50e949ce6281719e0265..826134f19df305cb79598739174bc09808ea472e 100644
index 96898a41c3efe31e9043b092d37d7c4b42709bcc..f6fbc3f4893b1894f4170a4b595ec8e72146b5bc 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -209,6 +209,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
@@ -212,6 +212,8 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
void DidStartWorkerThread() override;
void WillStopWorkerThread() override;
void WorkerContextCreated(const v8::Local<v8::Context>& worker) override;
@@ -65,10 +65,10 @@ index e191b4ef4185a6cb745c50e949ce6281719e0265..826134f19df305cb79598739174bc098
bool AllowScriptExtensionForServiceWorker(
const blink::WebSecurityOrigin& script_origin) override;
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 4c797975567026268ea107f42e47f6411c5b7311..ae463faa3d16ab2697a4c20f3b038755205188f7 100644
index 495f557bd1a727c95749b05ac7945292b372f371..6588d1fabf1c05950f0cd2768fbbef9fe48a036a 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -685,6 +685,8 @@ class BLINK_PLATFORM_EXPORT Platform {
@@ -695,6 +695,8 @@ class BLINK_PLATFORM_EXPORT Platform {
virtual void DidStartWorkerThread() {}
virtual void WillStopWorkerThread() {}
virtual void WorkerContextCreated(const v8::Local<v8::Context>& worker) {}

View File

@@ -1,2 +1 @@
chore_expose_ui_to_allow_electron_to_set_dock_side.patch
fix_prefer_browser_runtime_over_node_in_hostruntime_detection.patch

View File

@@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Thu, 12 Mar 2026 17:03:29 +0100
Subject: fix: prefer browser runtime over node in HostRuntime detection
In Electron, the `process` global is available in renderer processes,
including the DevTools renderer. This causes the IS_NODE check to pass,
leading DevTools to attempt importing the Node.js platform runtime
(which uses `node:worker_threads`). However, DevTools Web Workers
running under the `devtools://` protocol don't have access to Node.js
built-in modules, resulting in a failed dynamic import.
Fix by checking IS_BROWSER first, since DevTools always runs in a
browser-like environment. The Node.js runtime is only needed when
DevTools runs under pure Node.js (e.g., CLI tooling or testing).
diff --git a/front_end/core/platform/HostRuntime.ts b/front_end/core/platform/HostRuntime.ts
index 91adba7c966a9c4c0e5315d2cfee07f8f622b731..16822b8d4ea74a4ffd6870e5e95948d75918f5d2 100644
--- a/front_end/core/platform/HostRuntime.ts
+++ b/front_end/core/platform/HostRuntime.ts
@@ -14,12 +14,12 @@ export const IS_BROWSER =
typeof window !== 'undefined' || (typeof self !== 'undefined' && typeof self.postMessage === 'function');
export const HOST_RUNTIME = await (async(): Promise<Api.HostRuntime.HostRuntime> => {
- if (IS_NODE) {
- return (await import('./node/node.js')).HostRuntime.HOST_RUNTIME;
- }
if (IS_BROWSER) {
return (await import('./browser/browser.js')).HostRuntime.HOST_RUNTIME;
}
+ if (IS_NODE) {
+ return (await import('./node/node.js')).HostRuntime.HOST_RUNTIME;
+ }
throw new Error('Unknown runtime!');
})();

View File

@@ -533,10 +533,10 @@ index 55a0c986c5b6989ee9ce277bb6a9778abb2ad2ee..809d88f21e5572807e38132d40ee7587
READONLY_PROPERTY(target, "exitCodes", exit_codes);
diff --git a/src/node_file.cc b/src/node_file.cc
index ba6ffc2b6565dea500bc8dd4818c8fcb7648694a..e834325a763f7ea8f53210145b5edd134d6b67e6 100644
index 96aac2d86695732bf6805f2ad2168a62241b5045..547455bb5011677719a8de1f98cb447561bce6aa 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -3843,7 +3843,7 @@ void BindingData::Deserialize(Local<Context> context,
@@ -3850,7 +3850,7 @@ void BindingData::Deserialize(Local<Context> context,
int index,
InternalFieldInfoBase* info) {
DCHECK_IS_SNAPSHOT_SLOT(index);
@@ -686,7 +686,7 @@ index d33ee3c26c111e53edf27e6368ca8f64ff30a349..f1c53c44f201b295888e7932c5e3e2b1
Environment* env = Environment::GetCurrent(isolate);
diff --git a/src/node_url.cc b/src/node_url.cc
index 9d1e8ec05161570db11f7b662395509774668d78..9b91f83d879ea02fd3d61913c8dfd35b3bf1ac31 100644
index 9b676a0156ab8ef47f62627be953c23d4fcbf4f4..6294cd03667980e2ad23cae9e7961262369efb62 100644
--- a/src/node_url.cc
+++ b/src/node_url.cc
@@ -70,7 +70,7 @@ void BindingData::Deserialize(Local<Context> context,

View File

@@ -7,7 +7,7 @@ Subject: build: ensure native module compilation fails if not using a new
This should not be upstreamed, it is a quality-of-life patch for downstream module builders.
diff --git a/common.gypi b/common.gypi
index b3b5c23e471ece7584d209b3ae4197c46011d50e..bdcea65ad3e0315c85b1818e695d8b63093aed34 100644
index d9eb9527e3cbb3b101274ab19e6d6ace42f0e022..a1243ad39b8fcf564285ace0b51b1482bd85071b 100644
--- a/common.gypi
+++ b/common.gypi
@@ -89,6 +89,8 @@

View File

@@ -11,7 +11,7 @@ node-gyp will use the result of `process.config` that reflects the environment
in which the binary got built.
diff --git a/common.gypi b/common.gypi
index bdcea65ad3e0315c85b1818e695d8b63093aed34..0653735a0b154e326e5df7049a7beb395f0015c8 100644
index a1243ad39b8fcf564285ace0b51b1482bd85071b..60ac7a50718fd8239fd96b811cdccd1c73b2d606 100644
--- a/common.gypi
+++ b/common.gypi
@@ -128,6 +128,7 @@

View File

@@ -10,7 +10,7 @@ M151, and so we should allow for building until then.
This patch can be removed at the M151 branch point.
diff --git a/common.gypi b/common.gypi
index 0653735a0b154e326e5df7049a7beb395f0015c8..006f52ed18d955da0d9a06e881e86e6e724095ac 100644
index 60ac7a50718fd8239fd96b811cdccd1c73b2d606..709eb83801eeed81f79c4305a86d1a19710298c2 100644
--- a/common.gypi
+++ b/common.gypi
@@ -677,7 +677,7 @@

View File

@@ -7,7 +7,7 @@ common.gypi is a file that's included in the node header bundle, despite
the fact that we do not build node with gyp.
diff --git a/common.gypi b/common.gypi
index c5a7dc9cacf8b983984e7c7de9e63d26e418cc8d..b3b5c23e471ece7584d209b3ae4197c46011d50e 100644
index 283c60eab356a5befc15027cd186ea0416914ee6..d9eb9527e3cbb3b101274ab19e6d6ace42f0e022 100644
--- a/common.gypi
+++ b/common.gypi
@@ -91,6 +91,23 @@

View File

@@ -53,10 +53,10 @@ index 81799fc159cf20344aac64cd7129240deb9a4fe8..12b476ff97603718186dd25b1f435d37
const maybeMain = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ?
packageConfig.main || './' : '';
diff --git a/src/node_file.cc b/src/node_file.cc
index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb7648694a 100644
index c69b4eb461cab79906833152d02f76f81149ad7e..96aac2d86695732bf6805f2ad2168a62241b5045 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -3592,13 +3592,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
@@ -3599,13 +3599,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
}
BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
@@ -83,7 +83,7 @@ index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb
uv_fs_t req;
int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr);
@@ -3656,6 +3668,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -3663,6 +3675,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
std::optional<std::string> initial_file_path;
std::string file_path;
@@ -95,7 +95,7 @@ index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb
if (args.Length() >= 2 && args[1]->IsString()) {
auto package_config_main = Utf8Value(isolate, args[1]).ToString();
@@ -3676,7 +3693,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -3683,7 +3700,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
BufferValue buff_file_path(isolate, local_file_path);
ToNamespacedPath(env, &buff_file_path);
@@ -104,7 +104,7 @@ index 58476306172433db98a3e3a1ab31d13bf42014f1..ba6ffc2b6565dea500bc8dd4818c8fcb
case BindingData::FilePathIsFileReturnType::kIsFile:
return args.GetReturnValue().Set(i);
case BindingData::FilePathIsFileReturnType::kIsNotFile:
@@ -3713,7 +3730,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -3720,7 +3737,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
BufferValue buff_file_path(isolate, local_file_path);
ToNamespacedPath(env, &buff_file_path);

View File

@@ -7,10 +7,10 @@ libc++ added [[nodiscard]] to std::filesystem::copy_options operator|=
which causes build failures with -Werror.
diff --git a/src/node_file.cc b/src/node_file.cc
index e834325a763f7ea8f53210145b5edd134d6b67e6..5197202255bcd9345ac19c7fb6106f49c2800770 100644
index 547455bb5011677719a8de1f98cb447561bce6aa..385db5fd6fe5db6bb7ff17e98309b6cd605a82d3 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -3453,11 +3453,11 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
@@ -3460,11 +3460,11 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
auto file_copy_opts = std::filesystem::copy_options::recursive;
if (force) {

View File

@@ -1 +1,2 @@
chore_allow_customizing_microtask_policy_per_context.patch
build_warn_instead_of_abort_on_builtin_pgo_profile_mismatch.patch

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sam Attard <sattard@anthropic.com>
Date: Sun, 22 Mar 2026 10:51:26 +0000
Subject: build: warn instead of abort on builtin PGO profile mismatch
Electron sets v8_enable_javascript_promise_hooks = true to support
Node.js async_hooks (see node/src/env.cc SetPromiseHooks usage:
https://github.com/nodejs/node/blob/abff716eaccd0c4f4949d1315cb057a45979649d/src/env.cc#L223-L236).
This flag adds conditional branches to builtins-microtask-queue-gen.cc
and promise-misc.tq, changing the control-flow graph hash of several
Promise/async builtins. This invalidates V8's pre-generated PGO profile
for those builtins (built with Chrome defaults where the flag is off).
Rather than disabling builtins PGO entirely, warn and skip mismatched
builtins so all other builtins still benefit from PGO.
diff --git a/BUILD.gn b/BUILD.gn
index 4b7de10c45c1c6530b2105eb10be204128821042..01893af66b8a9c9cc39a25e9287c32c5dc37537e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2803,9 +2803,11 @@ template("run_mksnapshot") {
"--turbo-profiling-input",
rebase_path(v8_builtins_profiling_log_file, root_build_dir),
- # Replace this with --warn-about-builtin-profile-data to see the full
- # list of builtins with incompatible profiles.
- "--abort-on-bad-builtin-profile-data",
+ # Electron: Use warn instead of abort so that builtins whose control
+ # flow is changed by Electron's build flags (e.g. RunMicrotasks via
+ # v8_enable_javascript_promise_hooks) are skipped rather than failing
+ # the build. All other builtins still receive PGO.
+ "--warn-about-builtin-profile-data",
]
if (!v8_enable_builtins_profiling && v8_enable_builtins_reordering) {

View File

@@ -11,7 +11,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
const ELECTRON_DIR = resolve(__dirname, '..');
const DEPS_REGEX = /chromium_version':\n +'(.+?)',/m;
const CL_REGEX = /https:\/\/chromium-review\.googlesource\.com\/c\/(?:chromium\/src|v8\/v8)\/\+\/(\d+)(#\S+)?/g;
const CL_REGEX = /https:\/\/chromium-review\.googlesource\.com\/c\/(chromium\/src|devtools\/devtools-frontend|v8\/v8)\/\+\/(\d+)(#\S+)?/g;
const ROLLER_BRANCH_PATTERN = /^roller\/chromium\/(.+)$/;
function getCurrentBranch () {
@@ -177,8 +177,9 @@ async function main () {
const cls = [...commit.message.matchAll(CL_REGEX)].map((match) => ({
url: match[0],
clNumber: match[1],
fragment: match[2] ?? null
fullRepo: match[1],
clNumber: match[2],
fragment: match[3] ?? null
}));
if (cls.length === 0) {
@@ -207,9 +208,7 @@ async function main () {
continue;
}
// Determine repo from URL
const isV8 = cl.url.startsWith('https://chromium-review.googlesource.com/c/v8/v8/');
const repo = isV8 ? 'v8' : 'chromium';
const repo = cl.fullRepo.split('/')[0];
// Fetch Gerrit details to get commit SHA
const gerritDetails = await getGerritPatchDetails(cl.url);
@@ -243,9 +242,9 @@ async function main () {
continue;
}
// For V8 CLs, we need to find the corresponding Chromium commit
// For non-Chromium CLs, we need to find the corresponding Chromium commit
let chromiumVersion = clEarliestVersion;
if (isV8 && dashDetails.relations) {
if (repo !== 'chromium' && dashDetails.relations) {
const chromiumRelation = dashDetails.relations.find(
(rel) => rel.from_commit === gerritDetails.commitSha
);

View File

@@ -10,6 +10,7 @@
#include "base/apple/scoped_nsautorelease_pool.h"
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/i18n/icu_util.h"
#include "base/notreached.h"
#include "content/public/app/content_main.h"
@@ -33,7 +34,10 @@ int ElectronMain(int argc, char* argv[]) {
delegate.OverrideFrameworkBundlePath();
delegate.SetUpBundleOverrides();
return content::ContentMain(content::ContentMainParams{&delegate});
content::ContentMainParams params{&delegate};
params.argc = argc;
params.argv = UNSAFE_BUFFERS(const_cast<const char**>(argv));
return content::ContentMain(std::move(params));
}
int ElectronInitializeICUandStartNode(int argc, char* argv[]) {

View File

@@ -6,6 +6,7 @@
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/i18n/icu_util.h"
#include "base/strings/cstring_view.h"
#include "content/public/app/content_main.h"
@@ -29,6 +30,9 @@ namespace {
int main(int argc, char* argv[]) {
FixStdioStreams();
// Chromium expects the original argv in its original memory location
// to update /proc/<pid>/cmdline.
const char** original_argv = UNSAFE_BUFFERS(const_cast<const char**>(argv));
argv = uv_setup_args(argc, argv);
base::CommandLine::Init(argc, argv);
electron::ElectronCommandLine::Init(argc, argv);
@@ -40,5 +44,8 @@ int main(int argc, char* argv[]) {
}
electron::ElectronMainDelegate delegate;
return content::ContentMain(content::ContentMainParams{&delegate});
content::ContentMainParams params{&delegate};
params.argc = argc;
params.argv = original_argv;
return content::ContentMain(std::move(params));
}

View File

@@ -151,7 +151,10 @@ void OnTraceBufferUsageAvailable(
gin_helper::Promise<gin_helper::Dictionary> promise,
float percent_full,
size_t approximate_count) {
auto dict = gin_helper::Dictionary::CreateEmpty(promise.isolate());
v8::Isolate* isolate = promise.isolate();
v8::HandleScope handle_scope(isolate);
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
dict.Set("percentage", percent_full);
dict.Set("value", approximate_count);

View File

@@ -69,7 +69,7 @@ v8::Local<v8::Value> ServiceWorkerRunningInfoToDict(
return gin::DataObjectBuilder(isolate)
.Set("scriptUrl", info.script_url.spec())
.Set("scope", info.scope.spec())
.Set("renderProcessId", info.render_process_id)
.Set("renderProcessId", info.render_process_id.GetUnsafeValue())
.Build();
}

View File

@@ -1469,9 +1469,8 @@ void ElectronBrowserClient::RegisterAssociatedInterfaceBindersForServiceWorker(
base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
service_worker_version_info.process_id));
associated_registry.AddInterface<extensions::mojom::ServiceWorkerHost>(
base::BindRepeating(
&extensions::ServiceWorkerHost::BindReceiver,
service_worker_version_info.process_id.GetUnsafeValue()));
base::BindRepeating(&extensions::ServiceWorkerHost::BindReceiver,
service_worker_version_info.process_id));
#endif
}

View File

@@ -72,7 +72,8 @@ std::wstring NotificationPresenterWin::SaveIconToFilesystem(
std::string filename;
if (origin.is_valid()) {
filename = base::SHA1HashString(origin.spec()) + ".png";
const auto hash = base::SHA1HashString(origin.spec());
filename = base::HexEncode(hash) + ".png";
} else {
const int64_t now_usec = base::Time::Now().since_origin().InMicroseconds();
filename = base::NumberToString(now_usec) + ".png";

View File

@@ -133,6 +133,21 @@ std::wstring GetExecutablePath() {
return std::wstring(path, len);
}
// Installers sometimes put the running app in a versioned subfolder and ship a
// stub with the same filename one directory up. Point the Start Menu shortcut
// at the stub when it exists so toast activation and updates keep a stable
// launch path.
std::wstring GetShortcutTargetPath(const std::wstring& exe_path) {
if (exe_path.empty())
return L"";
base::FilePath exe_fp(exe_path);
base::FilePath stub_candidate =
exe_fp.DirName().DirName().Append(exe_fp.BaseName());
if (base::PathExists(stub_candidate))
return stub_candidate.value();
return exe_path;
}
void EnsureCLSIDRegistry() {
std::wstring exe = GetExecutablePath();
if (exe.empty())
@@ -153,7 +168,10 @@ void EnsureCLSIDRegistry() {
server_key.WriteValue(nullptr, exe.c_str());
}
bool ExistingShortcutValid(const base::FilePath& lnk_path, PCWSTR aumid) {
bool ExistingShortcutValid(const base::FilePath& lnk_path,
PCWSTR aumid,
const std::wstring& expected_target_path,
const std::wstring& expected_working_dir) {
if (!base::PathExists(lnk_path))
return false;
Microsoft::WRL::ComPtr<IShellLink> existing;
@@ -165,6 +183,31 @@ bool ExistingShortcutValid(const base::FilePath& lnk_path, PCWSTR aumid) {
FAILED(pf->Load(lnk_path.value().c_str(), STGM_READ))) {
return false;
}
// After an auto-update the .lnk may still have the correct AUMID/CLSID but
// point at an old install path; treat that as invalid so we rewrite it.
wchar_t target_path[MAX_PATH];
if (FAILED(existing->GetPath(target_path, MAX_PATH, nullptr, SLGP_RAWPATH)))
return false;
if (base::FilePath::CompareIgnoreCase(
base::FilePath(expected_target_path).value(),
base::FilePath(target_path).value()) != 0) {
return false;
}
wchar_t work_dir[MAX_PATH];
work_dir[0] = L'\0';
if (FAILED(existing->GetWorkingDirectory(work_dir, MAX_PATH)))
return false;
base::FilePath expected_cwd =
base::FilePath(expected_working_dir).NormalizePathSeparators();
base::FilePath actual_cwd =
base::FilePath(work_dir).NormalizePathSeparators();
if (base::FilePath::CompareIgnoreCase(expected_cwd.value(),
actual_cwd.value()) != 0) {
return false;
}
Microsoft::WRL::ComPtr<IPropertyStore> store;
if (FAILED(existing.As(&store)))
return false;
@@ -194,6 +237,7 @@ void EnsureShortcut() {
std::wstring exe = GetExecutablePath();
if (exe.empty())
return;
std::wstring shortcut_target = GetShortcutTargetPath(exe);
PWSTR programs_path = nullptr;
if (FAILED(
@@ -232,18 +276,20 @@ void EnsureShortcut() {
}
}
if (ExistingShortcutValid(lnk_path, aumid))
const std::wstring expected_working_dir =
base::FilePath(exe).DirName().value();
if (ExistingShortcutValid(lnk_path, aumid, shortcut_target,
expected_working_dir))
return;
Microsoft::WRL::ComPtr<IShellLink> shell_link;
if (FAILED(CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&shell_link))))
return;
shell_link->SetPath(exe.c_str());
shell_link->SetPath(shortcut_target.c_str());
shell_link->SetArguments(L"");
shell_link->SetDescription(product_name.c_str());
shell_link->SetWorkingDirectory(
base::FilePath(exe).DirName().value().c_str());
shell_link->SetWorkingDirectory(expected_working_dir.c_str());
Microsoft::WRL::ComPtr<IPropertyStore> prop_store;
if (SUCCEEDED(shell_link.As(&prop_store))) {

View File

@@ -478,7 +478,6 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
if (![represented
isKindOfClass:[WeakPtrToElectronMenuModelAsNSObject class]]) {
NSLog(@"representedObject is not a WeakPtrToElectronMenuModelAsNSObject");
return;
}

View File

@@ -473,23 +473,27 @@ void ElectronAccessibilityUIMessageHandler::RequestNativeUITree(
void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
web_ui()->RegisterMessageCallback(
"initialize",
base::BindRepeating(&AccessibilityUIMessageHandler::HandleInitialize,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"toggleAccessibility",
base::BindRepeating(
&AccessibilityUIMessageHandler::ToggleAccessibilityForWebContents,
base::Unretained(this)));
base::BindRepeating(&AccessibilityUIMessageHandler::
HandleToggleAccessibilityForWebContents,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setGlobalFlag",
base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalFlag,
base::BindRepeating(&AccessibilityUIMessageHandler::HandleSetGlobalFlag,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setGlobalString",
base::BindRepeating(&AccessibilityUIMessageHandler::SetGlobalString,
base::BindRepeating(&AccessibilityUIMessageHandler::HandleSetGlobalString,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"requestWebContentsTree",
base::BindRepeating(
&AccessibilityUIMessageHandler::RequestWebContentsTree,
&AccessibilityUIMessageHandler::HandleRequestWebContentsTree,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"requestNativeUITree",
@@ -499,13 +503,14 @@ void ElectronAccessibilityUIMessageHandler::RegisterMessages() {
#if defined(USE_AURA)
web_ui()->RegisterMessageCallback(
"requestWidgetsTree",
base::BindRepeating(&AccessibilityUIMessageHandler::RequestWidgetsTree,
base::Unretained(this)));
base::BindRepeating(
&AccessibilityUIMessageHandler::HandleRequestWidgetsTree,
base::Unretained(this)));
#endif
web_ui()->RegisterMessageCallback(
"requestAccessibilityEvents",
base::BindRepeating(
&AccessibilityUIMessageHandler::RequestAccessibilityEvents,
&AccessibilityUIMessageHandler::HandleRequestAccessibilityEvents,
base::Unretained(this)));
auto* web_contents = web_ui()->GetWebContents();

View File

@@ -18,6 +18,7 @@
#include "shell/common/process_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/clipboard_url_info.h"
#include "ui/base/clipboard/file_info.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/gfx/codec/png_codec.h"
@@ -210,7 +211,8 @@ void Clipboard::Write(const gin_helper::Dictionary& data,
writer.WriteText(text);
if (data.Get("bookmark", &bookmark))
writer.WriteBookmark(bookmark, base::UTF16ToUTF8(text));
writer.WriteURL(
ui::ClipboardUrlInfo{.url = GURL(text), .title = bookmark});
}
if (data.Get("rtf", &text)) {
@@ -333,13 +335,13 @@ v8::Local<v8::Value> Clipboard::ReadBookmark(v8::Isolate* const isolate) {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
clipboard->ReadBookmark(
clipboard->ReadURL(
/* data_dst = */ std::nullopt,
base::BindOnce(
[](std::u16string* out_title, GURL* out_url, base::OnceClosure quit,
std::u16string title, GURL url) {
*out_title = std::move(title);
*out_url = std::move(url);
ui::ClipboardUrlInfo url_info) {
*out_title = std::move(url_info.title);
*out_url = std::move(url_info.url);
std::move(quit).Run();
},
&title, &url, run_loop.QuitClosure()));
@@ -354,7 +356,7 @@ void Clipboard::WriteBookmark(const std::u16string& title,
const std::string& url,
gin::Arguments* const args) {
ui::ScopedClipboardWriter writer(GetClipboardBuffer(args));
writer.WriteBookmark(title, url);
writer.WriteURL(ui::ClipboardUrlInfo{.url = GURL(url), .title = title});
}
gfx::Image Clipboard::ReadImage(gin::Arguments* const args) {

View File

@@ -5,6 +5,8 @@
#ifndef ELECTRON_SHELL_COMMON_GIN_CONVERTERS_FILE_PATH_CONVERTER_H_
#define ELECTRON_SHELL_COMMON_GIN_CONVERTERS_FILE_PATH_CONVERTER_H_
#include <algorithm>
#include "base/files/file_path.h"
#include "gin/converter.h"
#include "shell/common/gin_converters/std_converter.h"
@@ -30,6 +32,11 @@ struct Converter<base::FilePath> {
base::FilePath::StringType path;
if (Converter<base::FilePath::StringType>::FromV8(isolate, val, &path)) {
bool has_control_chars = std::any_of(
path.begin(), path.end(),
[](base::FilePath::CharType c) { return c >= 0 && c < 0x20; });
if (has_control_chars)
return false;
*out = base::FilePath(path);
return true;
} else {

View File

@@ -608,6 +608,9 @@ bool Converter<scoped_refptr<network::ResourceRequestBody>>::FromV8(
const std::string* file = dict.FindString("filePath");
if (!file)
return false;
if (std::any_of(file->begin(), file->end(),
[](char c) { return c >= 0 && c < 0x20; }))
return false;
double modification_time =
dict.FindDouble("modificationTime").value_or(0.0);
int offset = dict.FindInt("offset").value_or(0);

View File

@@ -132,6 +132,36 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
});
});
describe('getTraceBufferUsage', function () {
this.timeout(10e3);
it('does not crash and returns valid usage data', async () => {
await app.whenReady();
await contentTracing.startRecording({
categoryFilter: '*',
traceOptions: 'record-until-full'
});
// Yield to the event loop so the JS HandleScope from this tick is gone.
// When the Mojo response arrives it fires OnTraceBufferUsageAvailable
// as a plain Chromium task — if that callback lacks its own HandleScope
// the process will crash with "Cannot create a handle without a HandleScope".
const result = await contentTracing.getTraceBufferUsage();
expect(result).to.have.property('percentage').that.is.a('number');
expect(result).to.have.property('value').that.is.a('number');
await contentTracing.stopRecording();
});
it('returns zero usage when no trace is active', async () => {
await app.whenReady();
const result = await contentTracing.getTraceBufferUsage();
expect(result).to.have.property('percentage').that.is.a('number');
expect(result.percentage).to.equal(0);
});
});
describe('captured events', () => {
it('include V8 samples from the main process', async function () {
this.timeout(60000);

View File

@@ -2,9 +2,10 @@ import { dialog, BaseWindow, BrowserWindow } from 'electron/main';
import { expect } from 'chai';
import * as path from 'node:path';
import { setTimeout } from 'node:timers/promises';
import { ifit } from './lib/spec-helpers';
import { ifdescribe, ifit } from './lib/spec-helpers';
import { closeAllWindows } from './lib/window-helpers';
describe('dialog module', () => {
@@ -243,4 +244,785 @@ describe('dialog module', () => {
}).to.throw(/message must be a string/);
});
});
ifdescribe(process.platform === 'darwin' && !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS)('end-to-end dialog interaction (macOS)', () => {
let dialogHelper: any;
before(() => {
dialogHelper = require('@electron-ci/dialog-helper');
});
afterEach(closeAllWindows);
// Poll for a sheet to appear on the given window.
async function waitForSheet (w: BrowserWindow): Promise<void> {
const handle = w.getNativeWindowHandle();
for (let i = 0; i < 50; i++) {
const info = dialogHelper.getDialogInfo(handle);
if (info.type !== 'none') return;
await setTimeout(100);
}
throw new Error('Timed out waiting for dialog sheet to appear');
}
describe('showMessageBox', () => {
it('shows the correct message and buttons', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Test message',
buttons: ['OK', 'Cancel']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.type).to.equal('message-box');
expect(info.message).to.equal('Test message');
const buttons = JSON.parse(info.buttons);
expect(buttons).to.include('OK');
expect(buttons).to.include('Cancel');
dialogHelper.clickMessageBoxButton(handle, 0);
await p;
});
it('shows detail text', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Main message',
detail: 'Extra detail text',
buttons: ['OK']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.message).to.equal('Main message');
expect(info.detail).to.equal('Extra detail text');
dialogHelper.clickMessageBoxButton(handle, 0);
await p;
});
it('returns the correct response when a specific button is clicked', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Choose a button',
buttons: ['First', 'Second', 'Third']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
dialogHelper.clickMessageBoxButton(handle, 1);
const result = await p;
expect(result.response).to.equal(1);
});
it('returns the correct response when the last button is clicked', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Choose a button',
buttons: ['Yes', 'No', 'Maybe']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
dialogHelper.clickMessageBoxButton(handle, 2);
const result = await p;
expect(result.response).to.equal(2);
});
it('shows a single button when no buttons are specified', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'No buttons specified'
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.type).to.equal('message-box');
// macOS adds a default "OK" button when none are specified.
const buttons = JSON.parse(info.buttons);
expect(buttons).to.have.lengthOf(1);
dialogHelper.clickMessageBoxButton(handle, 0);
const result = await p;
expect(result.response).to.equal(0);
});
it('renders checkbox with the correct label and initial state', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Checkbox test',
buttons: ['OK'],
checkboxLabel: 'Do not show again',
checkboxChecked: false
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.checkboxLabel).to.equal('Do not show again');
expect(info.checkboxChecked).to.be.false();
dialogHelper.clickMessageBoxButton(handle, 0);
const result = await p;
expect(result.checkboxChecked).to.be.false();
});
it('returns checkboxChecked as true when checkbox is initially checked', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Pre-checked checkbox',
buttons: ['OK'],
checkboxLabel: 'Remember my choice',
checkboxChecked: true
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.checkboxLabel).to.equal('Remember my choice');
expect(info.checkboxChecked).to.be.true();
dialogHelper.clickMessageBoxButton(handle, 0);
const result = await p;
expect(result.checkboxChecked).to.be.true();
});
it('can toggle checkbox and returns updated state', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Toggle test',
buttons: ['OK'],
checkboxLabel: 'Toggle me',
checkboxChecked: false
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
// Verify initially unchecked.
let info = dialogHelper.getDialogInfo(handle);
expect(info.checkboxChecked).to.be.false();
// Click the checkbox to check it.
dialogHelper.clickCheckbox(handle);
info = dialogHelper.getDialogInfo(handle);
expect(info.checkboxChecked).to.be.true();
dialogHelper.clickMessageBoxButton(handle, 0);
const result = await p;
expect(result.checkboxChecked).to.be.true();
});
it('strips access keys on macOS with normalizeAccessKeys', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Access key test',
buttons: ['&Save', '&Cancel'],
normalizeAccessKeys: true
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
// On macOS, ampersands are stripped by normalizeAccessKeys.
const buttons = JSON.parse(info.buttons);
expect(buttons).to.include('Save');
expect(buttons).to.include('Cancel');
expect(buttons).not.to.include('&Save');
expect(buttons).not.to.include('&Cancel');
dialogHelper.clickMessageBoxButton(handle, 0);
await p;
});
it('respects defaultId by making it the default button', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Default button test',
buttons: ['One', 'Two', 'Three'],
defaultId: 2
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
const buttons = JSON.parse(info.buttons);
expect(buttons).to.deep.equal(['One', 'Two', 'Three']);
dialogHelper.clickMessageBoxButton(handle, 2);
const result = await p;
expect(result.response).to.equal(2);
});
it('respects cancelId and returns it when cancelled via signal', async () => {
const controller = new AbortController();
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: 'Cancel ID test',
buttons: ['OK', 'Dismiss', 'Abort'],
cancelId: 2,
signal: controller.signal
});
await waitForSheet(w);
controller.abort();
const result = await p;
expect(result.response).to.equal(2);
});
it('works with all message box types', async () => {
const types: Array<'none' | 'info' | 'warning' | 'error' | 'question'> =
['none', 'info', 'warning', 'error', 'question'];
for (const type of types) {
const w = new BrowserWindow({ show: false });
const p = dialog.showMessageBox(w, {
message: `Type: ${type}`,
type,
buttons: ['OK']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.type).to.equal('message-box');
expect(info.message).to.equal(`Type: ${type}`);
dialogHelper.clickMessageBoxButton(handle, 0);
await p;
w.destroy();
// Allow the event loop to settle between iterations to avoid
// Chromium DCHECK failures from rapid window lifecycle churn.
await setTimeout(100);
}
});
});
describe('showOpenDialog', () => {
it('can cancel an open dialog', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
title: 'Test Open',
properties: ['openFile']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.type).to.equal('open-dialog');
dialogHelper.cancelFileDialog(handle);
const result = await p;
expect(result.canceled).to.be.true();
expect(result.filePaths).to.have.lengthOf(0);
});
it('sets a custom button label', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
buttonLabel: 'Select This',
properties: ['openFile']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.prompt).to.equal('Select This');
dialogHelper.cancelFileDialog(handle);
await p;
});
it('sets a message on the dialog', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
message: 'Choose a file to import',
properties: ['openFile']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.panelMessage).to.equal('Choose a file to import');
dialogHelper.cancelFileDialog(handle);
await p;
});
it('defaults to openFile with canChooseFiles enabled', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.canChooseFiles).to.be.true();
expect(info.canChooseDirectories).to.be.false();
expect(info.allowsMultipleSelection).to.be.false();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('enables directory selection with openDirectory', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.canChooseDirectories).to.be.true();
// openFile is not set, so canChooseFiles should be false
expect(info.canChooseFiles).to.be.false();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('enables both file and directory selection together', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile', 'openDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.canChooseFiles).to.be.true();
expect(info.canChooseDirectories).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('enables multiple selection with multiSelections', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile', 'multiSelections']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.allowsMultipleSelection).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('shows hidden files with showHiddenFiles', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile', 'showHiddenFiles']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.showsHiddenFiles).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('does not show hidden files by default', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.showsHiddenFiles).to.be.false();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('disables alias resolution with noResolveAliases', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile', 'noResolveAliases']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.resolvesAliases).to.be.false();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('resolves aliases by default', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.resolvesAliases).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('treats packages as directories with treatPackageAsDirectory', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile', 'treatPackageAsDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.treatsPackagesAsDirectories).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('enables directory creation with createDirectory', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
properties: ['openFile', 'createDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.canCreateDirectories).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('sets the default path directory', async () => {
const defaultDir = path.join(__dirname, 'fixtures');
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
defaultPath: defaultDir,
properties: ['openFile']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.directory).to.equal(defaultDir);
dialogHelper.cancelFileDialog(handle);
await p;
});
it('applies multiple properties simultaneously', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
title: 'Multi-Property Test',
buttonLabel: 'Pick',
message: 'Select items',
properties: [
'openFile',
'openDirectory',
'multiSelections',
'showHiddenFiles',
'createDirectory',
'treatPackageAsDirectory',
'noResolveAliases'
]
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.type).to.equal('open-dialog');
expect(info.prompt).to.equal('Pick');
expect(info.panelMessage).to.equal('Select items');
expect(info.canChooseFiles).to.be.true();
expect(info.canChooseDirectories).to.be.true();
expect(info.allowsMultipleSelection).to.be.true();
expect(info.showsHiddenFiles).to.be.true();
expect(info.canCreateDirectories).to.be.true();
expect(info.treatsPackagesAsDirectories).to.be.true();
expect(info.resolvesAliases).to.be.false();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('can accept an open dialog and return a file path', async () => {
const targetDir = path.join(__dirname, 'fixtures');
const w = new BrowserWindow({ show: false });
const p = dialog.showOpenDialog(w, {
defaultPath: targetDir,
properties: ['openDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
dialogHelper.acceptFileDialog(handle);
const result = await p;
expect(result.canceled).to.be.false();
expect(result.filePaths).to.have.lengthOf(1);
expect(result.filePaths[0]).to.equal(targetDir);
});
});
describe('showSaveDialog', () => {
it('can cancel a save dialog', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
title: 'Test Save'
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.type).to.equal('save-dialog');
dialogHelper.cancelFileDialog(handle);
const result = await p;
expect(result.canceled).to.be.true();
expect(result.filePath).to.equal('');
});
it('can accept a save dialog with a filename', async () => {
const defaultDir = path.join(__dirname, 'fixtures');
const filename = 'test-save-output.txt';
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
title: 'Test Save',
defaultPath: path.join(defaultDir, filename)
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
dialogHelper.acceptFileDialog(handle);
const result = await p;
expect(result.canceled).to.be.false();
expect(result.filePath).to.equal(path.join(defaultDir, filename));
});
it('sets a custom button label', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
buttonLabel: 'Export'
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.prompt).to.equal('Export');
dialogHelper.cancelFileDialog(handle);
await p;
});
it('sets a message on the dialog', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
message: 'Choose where to save'
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.panelMessage).to.equal('Choose where to save');
dialogHelper.cancelFileDialog(handle);
await p;
});
it('sets a custom name field label', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
nameFieldLabel: 'Export As:'
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.nameFieldLabel).to.equal('Export As:');
dialogHelper.cancelFileDialog(handle);
await p;
});
it('sets the default filename from defaultPath', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
defaultPath: path.join(__dirname, 'fixtures', 'my-document.txt')
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.nameFieldValue).to.equal('my-document.txt');
dialogHelper.cancelFileDialog(handle);
await p;
});
it('sets the default directory from defaultPath', async () => {
const defaultDir = path.join(__dirname, 'fixtures');
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
defaultPath: path.join(defaultDir, 'some-file.txt')
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.directory).to.equal(defaultDir);
dialogHelper.cancelFileDialog(handle);
await p;
});
it('hides the tag field when showsTagField is false', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
showsTagField: false
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.showsTagField).to.be.false();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('shows the tag field by default', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.showsTagField).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('enables directory creation with createDirectory', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
properties: ['createDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.canCreateDirectories).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('shows hidden files with showHiddenFiles', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
properties: ['showHiddenFiles']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.showsHiddenFiles).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('does not show hidden files by default', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.showsHiddenFiles).to.be.false();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('treats packages as directories with treatPackageAsDirectory', async () => {
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
properties: ['treatPackageAsDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.treatsPackagesAsDirectories).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
it('applies multiple options simultaneously', async () => {
const defaultDir = path.join(__dirname, 'fixtures');
const w = new BrowserWindow({ show: false });
const p = dialog.showSaveDialog(w, {
buttonLabel: 'Save Now',
message: 'Pick a location',
nameFieldLabel: 'File Name:',
defaultPath: path.join(defaultDir, 'output.txt'),
showsTagField: false,
properties: ['showHiddenFiles', 'createDirectory']
});
await waitForSheet(w);
const handle = w.getNativeWindowHandle();
const info = dialogHelper.getDialogInfo(handle);
expect(info.type).to.equal('save-dialog');
expect(info.prompt).to.equal('Save Now');
expect(info.panelMessage).to.equal('Pick a location');
expect(info.nameFieldLabel).to.equal('File Name:');
expect(info.nameFieldValue).to.equal('output.txt');
expect(info.directory).to.equal(defaultDir);
expect(info.showsTagField).to.be.false();
expect(info.showsHiddenFiles).to.be.true();
expect(info.canCreateDirectories).to.be.true();
dialogHelper.cancelFileDialog(handle);
await p;
});
});
});
});

View File

@@ -0,0 +1,7 @@
/node_modules
/build
*.swp
*.log
*~
.node-version
package-lock.json

View File

@@ -0,0 +1,23 @@
{
'targets': [
{
'target_name': 'dialog_helper',
'conditions': [
['OS=="mac"', {
'sources': [
'src/main.cc',
'src/dialog_helper_mac.mm',
],
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
],
'xcode_settings': {
'OTHER_CFLAGS': ['-fobjc-arc'],
},
}, {
'type': 'none',
}],
],
}
]
}

View File

@@ -0,0 +1,2 @@
const binding = require('../build/Release/dialog_helper.node');
module.exports = binding;

View File

@@ -0,0 +1,10 @@
{
"name": "@electron-ci/dialog-helper",
"version": "0.0.1",
"main": "./lib/index.js",
"private": true,
"licenses": "MIT",
"scripts": {
"install": "node-gyp configure && node-gyp build"
}
}

View File

@@ -0,0 +1,68 @@
#ifndef SRC_DIALOG_HELPER_H_
#define SRC_DIALOG_HELPER_H_
#include <cstddef>
#include <string>
namespace dialog_helper {
struct DialogInfo {
// "message-box", "open-dialog", "save-dialog", or "none"
std::string type;
// Button titles for message boxes
std::string buttons; // JSON array string, e.g. '["OK","Cancel"]'
// Message text (NSAlert messageText or panel title)
std::string message;
// Detail / informative text (NSAlert informativeText)
std::string detail;
// Checkbox (suppression button) label, empty if none
std::string checkbox_label;
// Whether the checkbox is checked
bool checkbox_checked = false;
// File dialog properties (open/save panels)
std::string prompt; // Button label (NSSavePanel prompt)
std::string panel_message; // Panel message text (NSSavePanel message)
std::string directory; // Current directory URL path
// NSSavePanel-specific properties
std::string name_field_label; // Label for the name field
std::string name_field_value; // Current value of the name field
bool shows_tag_field = true;
// NSOpenPanel-specific properties
bool can_choose_files = false;
bool can_choose_directories = false;
bool allows_multiple_selection = false;
// Shared panel properties (open and save)
bool shows_hidden_files = false;
bool resolves_aliases = true;
bool treats_packages_as_directories = false;
bool can_create_directories = false;
};
// Get information about the sheet dialog attached to the window identified
// by the given native handle buffer (NSView* on macOS).
DialogInfo GetDialogInfo(char* handle, size_t size);
// Click a button at the given index on an NSAlert sheet attached to the window.
// Returns true if a message box was found and the button was clicked.
bool ClickMessageBoxButton(char* handle, size_t size, int button_index);
// Toggle the checkbox (suppression button) on an NSAlert sheet.
// Returns true if a checkbox was found and clicked.
bool ClickCheckbox(char* handle, size_t size);
// Cancel the file dialog (NSOpenPanel/NSSavePanel) sheet attached to the window.
// Returns true if a file dialog was found and cancelled.
bool CancelFileDialog(char* handle, size_t size);
// Accept the file dialog sheet attached to the window.
// For save dialogs, |filename| is set in the name field before accepting.
// Returns true if a file dialog was found and accepted.
bool AcceptFileDialog(char* handle, size_t size, const std::string& filename);
} // namespace dialog_helper
#endif // SRC_DIALOG_HELPER_H_

View File

@@ -0,0 +1,320 @@
#include "dialog_helper.h"
#import <Cocoa/Cocoa.h>
namespace {
// Extract the NSWindow* from the native handle buffer.
// The buffer contains an NSView* (the content view of the window).
NSWindow* GetNSWindowFromHandle(char* handle, size_t size) {
if (size != sizeof(void*))
return nil;
// Read the raw pointer from the buffer, then bridge to ARC.
void* raw = *reinterpret_cast<void**>(handle);
NSView* view = (__bridge NSView*)raw;
if (!view || ![view isKindOfClass:[NSView class]])
return nil;
return [view window];
}
} // namespace
namespace dialog_helper {
DialogInfo GetDialogInfo(char* handle, size_t size) {
DialogInfo info;
info.type = "none";
NSWindow* window = GetNSWindowFromHandle(handle, size);
if (!window)
return info;
NSWindow* sheet = [window attachedSheet];
if (!sheet)
return info;
// NSOpenPanel is a subclass of NSSavePanel, so check NSOpenPanel first.
if ([sheet isKindOfClass:[NSOpenPanel class]]) {
info.type = "open-dialog";
NSOpenPanel* panel = (NSOpenPanel*)sheet;
info.message = [[panel title] UTF8String] ?: "";
info.prompt = [[panel prompt] UTF8String] ?: "";
info.panel_message = [[panel message] UTF8String] ?: "";
if ([panel directoryURL])
info.directory = [[[panel directoryURL] path] UTF8String] ?: "";
info.can_choose_files = [panel canChooseFiles];
info.can_choose_directories = [panel canChooseDirectories];
info.allows_multiple_selection = [panel allowsMultipleSelection];
info.shows_hidden_files = [panel showsHiddenFiles];
info.resolves_aliases = [panel resolvesAliases];
info.treats_packages_as_directories = [panel treatsFilePackagesAsDirectories];
info.can_create_directories = [panel canCreateDirectories];
return info;
}
if ([sheet isKindOfClass:[NSSavePanel class]]) {
info.type = "save-dialog";
NSSavePanel* panel = (NSSavePanel*)sheet;
info.message = [[panel title] UTF8String] ?: "";
info.prompt = [[panel prompt] UTF8String] ?: "";
info.panel_message = [[panel message] UTF8String] ?: "";
if ([panel directoryURL])
info.directory = [[[panel directoryURL] path] UTF8String] ?: "";
info.name_field_label = [[panel nameFieldLabel] UTF8String] ?: "";
info.name_field_value = [[panel nameFieldStringValue] UTF8String] ?: "";
info.shows_tag_field = [panel showsTagField];
info.shows_hidden_files = [panel showsHiddenFiles];
info.treats_packages_as_directories =
[panel treatsFilePackagesAsDirectories];
info.can_create_directories = [panel canCreateDirectories];
return info;
}
// For NSAlert, the sheet window is not an NSSavePanel.
// Check if it contains typical NSAlert button structure.
// NSAlert's window contains buttons as subviews in its content view.
NSView* contentView = [sheet contentView];
NSMutableArray<NSButton*>* buttons = [NSMutableArray array];
// Recursively find all NSButton instances in the view hierarchy.
NSMutableArray<NSView*>* stack =
[NSMutableArray arrayWithObject:contentView];
while ([stack count] > 0) {
NSView* current = [stack lastObject];
[stack removeLastObject];
if ([current isKindOfClass:[NSButton class]]) {
NSButton* btn = (NSButton*)current;
// Filter to push-type buttons (not checkboxes, radio buttons, etc.)
if ([btn bezelStyle] == NSBezelStyleRounded ||
[btn bezelStyle] == NSBezelStyleRegularSquare) {
[buttons addObject:btn];
}
}
for (NSView* subview in [current subviews]) {
[stack addObject:subview];
}
}
if ([buttons count] > 0) {
info.type = "message-box";
// Sort buttons by tag to maintain the order they were added.
[buttons sortUsingComparator:^NSComparisonResult(NSButton* a, NSButton* b) {
if ([a tag] < [b tag])
return NSOrderedAscending;
if ([a tag] > [b tag])
return NSOrderedDescending;
return NSOrderedSame;
}];
std::string btn_json = "[";
for (NSUInteger i = 0; i < [buttons count]; i++) {
if (i > 0)
btn_json += ",";
btn_json += "\"";
NSString* title = [[buttons objectAtIndex:i] title];
btn_json += [title UTF8String] ?: "";
btn_json += "\"";
}
btn_json += "]";
info.buttons = btn_json;
// NSAlert's content view contains static NSTextFields for message and
// detail text. The first non-editable text field with content is the
// message; the second is the detail (informative text).
int text_field_index = 0;
// Walk all subviews (non-recursive — NSAlert places labels directly).
for (NSView* subview in [contentView subviews]) {
if ([subview isKindOfClass:[NSTextField class]]) {
NSTextField* field = (NSTextField*)subview;
if (![field isEditable] && [[field stringValue] length] > 0) {
if (text_field_index == 0) {
info.message = [[field stringValue] UTF8String];
} else if (text_field_index == 1) {
info.detail = [[field stringValue] UTF8String];
}
text_field_index++;
}
}
}
// Check for the suppression (checkbox) button.
// NSAlert's suppression button is a non-bordered NSButton, unlike
// push buttons which are bordered. This reliably identifies it
// across macOS versions where the accessibility role may differ.
NSMutableArray<NSView*>* cbStack =
[NSMutableArray arrayWithObject:contentView];
while ([cbStack count] > 0) {
NSView* current = [cbStack lastObject];
[cbStack removeLastObject];
if ([current isKindOfClass:[NSButton class]]) {
NSButton* btn = (NSButton*)current;
if (![btn isBordered]) {
NSString* title = [btn title];
if (title && [title length] > 0) {
info.checkbox_label = [title UTF8String];
info.checkbox_checked =
([btn state] == NSControlStateValueOn);
}
}
}
for (NSView* sub in [current subviews]) {
[cbStack addObject:sub];
}
}
}
return info;
}
bool ClickMessageBoxButton(char* handle, size_t size, int button_index) {
NSWindow* window = GetNSWindowFromHandle(handle, size);
if (!window)
return false;
NSWindow* sheet = [window attachedSheet];
if (!sheet)
return false;
// Find buttons in the sheet, sorted by tag.
NSView* contentView = [sheet contentView];
NSMutableArray<NSButton*>* buttons = [NSMutableArray array];
NSMutableArray<NSView*>* stack =
[NSMutableArray arrayWithObject:contentView];
while ([stack count] > 0) {
NSView* current = [stack lastObject];
[stack removeLastObject];
if ([current isKindOfClass:[NSButton class]]) {
NSButton* btn = (NSButton*)current;
if ([btn bezelStyle] == NSBezelStyleRounded ||
[btn bezelStyle] == NSBezelStyleRegularSquare) {
[buttons addObject:btn];
}
}
for (NSView* subview in [current subviews]) {
[stack addObject:subview];
}
}
[buttons sortUsingComparator:^NSComparisonResult(NSButton* a, NSButton* b) {
if ([a tag] < [b tag])
return NSOrderedAscending;
if ([a tag] > [b tag])
return NSOrderedDescending;
return NSOrderedSame;
}];
if (button_index < 0 || button_index >= (int)[buttons count])
return false;
NSButton* target = [buttons objectAtIndex:button_index];
[target performClick:nil];
return true;
}
bool ClickCheckbox(char* handle, size_t size) {
NSWindow* window = GetNSWindowFromHandle(handle, size);
if (!window)
return false;
NSWindow* sheet = [window attachedSheet];
if (!sheet)
return false;
// Find the suppression/checkbox button — it is a non-bordered NSButton,
// unlike the push buttons which are bordered.
NSView* contentView = [sheet contentView];
NSMutableArray<NSView*>* stack =
[NSMutableArray arrayWithObject:contentView];
while ([stack count] > 0) {
NSView* current = [stack lastObject];
[stack removeLastObject];
if ([current isKindOfClass:[NSButton class]]) {
NSButton* btn = (NSButton*)current;
if (![btn isBordered] && [[btn title] length] > 0) {
[btn performClick:nil];
return true;
}
}
for (NSView* subview in [current subviews]) {
[stack addObject:subview];
}
}
return false;
}
bool CancelFileDialog(char* handle, size_t size) {
NSWindow* window = GetNSWindowFromHandle(handle, size);
if (!window)
return false;
NSWindow* sheet = [window attachedSheet];
if (!sheet)
return false;
// sheet is the NSSavePanel/NSOpenPanel window itself when presented as a
// sheet. We need to find the actual panel object. On macOS, when an
// NSSavePanel is run as a sheet, [window attachedSheet] returns the panel's
// window. The panel can be retrieved because NSSavePanel IS the window.
if ([sheet isKindOfClass:[NSSavePanel class]]) {
NSSavePanel* panel = (NSSavePanel*)sheet;
[panel cancel:nil];
return true;
}
// If it's not a recognized panel type, try ending the sheet directly.
[NSApp endSheet:sheet returnCode:NSModalResponseCancel];
return true;
}
bool AcceptFileDialog(char* handle, size_t size, const std::string& filename) {
NSWindow* window = GetNSWindowFromHandle(handle, size);
if (!window)
return false;
NSWindow* sheet = [window attachedSheet];
if (!sheet)
return false;
if (![sheet isKindOfClass:[NSSavePanel class]])
return false;
NSSavePanel* panel = (NSSavePanel*)sheet;
// Set the filename if provided (for save dialogs).
if (!filename.empty()) {
NSString* name = [NSString stringWithUTF8String:filename.c_str()];
[panel setNameFieldStringValue:name];
// Resign first responder to commit the name field edit. Without this,
// the panel may still use the previous value (e.g. "Untitled") when
// the accept button is clicked immediately after.
[sheet makeFirstResponder:nil];
}
NSView* contentView = [sheet contentView];
// Search for the default button (key equivalent "\r") in the view hierarchy.
NSMutableArray<NSView*>* stack =
[NSMutableArray arrayWithObject:contentView];
while ([stack count] > 0) {
NSView* current = [stack lastObject];
[stack removeLastObject];
if ([current isKindOfClass:[NSButton class]]) {
NSButton* btn = (NSButton*)current;
if ([[btn keyEquivalent] isEqualToString:@"\r"]) {
[btn performClick:nil];
return true;
}
}
for (NSView* subview in [current subviews]) {
[stack addObject:subview];
}
}
[NSApp endSheet:sheet returnCode:NSModalResponseOK];
return true;
}
} // namespace dialog_helper

View File

@@ -0,0 +1,231 @@
#include <js_native_api.h>
#include <node_api.h>
#include <string>
#include "dialog_helper.h"
namespace {
// Helper: extract (char* data, size_t length) from the first Buffer argument.
bool GetHandleArg(napi_env env, napi_callback_info info, size_t expected_argc,
napi_value* args, char** data, size_t* length) {
size_t argc = expected_argc;
napi_status status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
if (status != napi_ok || argc < 1)
return false;
bool is_buffer;
status = napi_is_buffer(env, args[0], &is_buffer);
if (status != napi_ok || !is_buffer) {
napi_throw_error(env, NULL, "First argument must be a Buffer (native window handle)");
return false;
}
status = napi_get_buffer_info(env, args[0], (void**)data, length);
return status == napi_ok;
}
napi_value GetDialogInfo(napi_env env, napi_callback_info info) {
napi_value args[1];
char* data;
size_t length;
if (!GetHandleArg(env, info, 1, args, &data, &length))
return NULL;
dialog_helper::DialogInfo di = dialog_helper::GetDialogInfo(data, length);
napi_value result;
napi_create_object(env, &result);
// Message box properties
napi_value type_val;
napi_create_string_utf8(env, di.type.c_str(), di.type.size(), &type_val);
napi_set_named_property(env, result, "type", type_val);
napi_value buttons_val;
napi_create_string_utf8(env, di.buttons.c_str(), di.buttons.size(), &buttons_val);
napi_set_named_property(env, result, "buttons", buttons_val);
napi_value message_val;
napi_create_string_utf8(env, di.message.c_str(), di.message.size(), &message_val);
napi_set_named_property(env, result, "message", message_val);
napi_value detail_val;
napi_create_string_utf8(env, di.detail.c_str(), di.detail.size(), &detail_val);
napi_set_named_property(env, result, "detail", detail_val);
napi_value checkbox_label_val;
napi_create_string_utf8(env, di.checkbox_label.c_str(),
di.checkbox_label.size(), &checkbox_label_val);
napi_set_named_property(env, result, "checkboxLabel", checkbox_label_val);
napi_value checkbox_checked_val;
napi_get_boolean(env, di.checkbox_checked, &checkbox_checked_val);
napi_set_named_property(env, result, "checkboxChecked", checkbox_checked_val);
// File dialog properties
napi_value prompt_val;
napi_create_string_utf8(env, di.prompt.c_str(), di.prompt.size(), &prompt_val);
napi_set_named_property(env, result, "prompt", prompt_val);
napi_value panel_message_val;
napi_create_string_utf8(env, di.panel_message.c_str(),
di.panel_message.size(), &panel_message_val);
napi_set_named_property(env, result, "panelMessage", panel_message_val);
napi_value directory_val;
napi_create_string_utf8(env, di.directory.c_str(), di.directory.size(),
&directory_val);
napi_set_named_property(env, result, "directory", directory_val);
// NSSavePanel-specific string/boolean properties
napi_value name_field_label_val;
napi_create_string_utf8(env, di.name_field_label.c_str(),
di.name_field_label.size(), &name_field_label_val);
napi_set_named_property(env, result, "nameFieldLabel", name_field_label_val);
napi_value name_field_value_val;
napi_create_string_utf8(env, di.name_field_value.c_str(),
di.name_field_value.size(), &name_field_value_val);
napi_set_named_property(env, result, "nameFieldValue", name_field_value_val);
napi_value shows_tag_field_val;
napi_get_boolean(env, di.shows_tag_field, &shows_tag_field_val);
napi_set_named_property(env, result, "showsTagField", shows_tag_field_val);
// NSOpenPanel-specific properties
napi_value can_choose_files_val;
napi_get_boolean(env, di.can_choose_files, &can_choose_files_val);
napi_set_named_property(env, result, "canChooseFiles", can_choose_files_val);
napi_value can_choose_dirs_val;
napi_get_boolean(env, di.can_choose_directories, &can_choose_dirs_val);
napi_set_named_property(env, result, "canChooseDirectories",
can_choose_dirs_val);
napi_value allows_multi_val;
napi_get_boolean(env, di.allows_multiple_selection, &allows_multi_val);
napi_set_named_property(env, result, "allowsMultipleSelection",
allows_multi_val);
// Shared panel properties (open and save)
napi_value shows_hidden_val;
napi_get_boolean(env, di.shows_hidden_files, &shows_hidden_val);
napi_set_named_property(env, result, "showsHiddenFiles", shows_hidden_val);
napi_value resolves_aliases_val;
napi_get_boolean(env, di.resolves_aliases, &resolves_aliases_val);
napi_set_named_property(env, result, "resolvesAliases", resolves_aliases_val);
napi_value treats_packages_val;
napi_get_boolean(env, di.treats_packages_as_directories, &treats_packages_val);
napi_set_named_property(env, result, "treatsPackagesAsDirectories",
treats_packages_val);
napi_value can_create_dirs_val;
napi_get_boolean(env, di.can_create_directories, &can_create_dirs_val);
napi_set_named_property(env, result, "canCreateDirectories",
can_create_dirs_val);
return result;
}
napi_value ClickMessageBoxButton(napi_env env, napi_callback_info info) {
napi_value args[2];
char* data;
size_t length;
if (!GetHandleArg(env, info, 2, args, &data, &length))
return NULL;
int32_t button_index;
napi_status status = napi_get_value_int32(env, args[1], &button_index);
if (status != napi_ok) {
napi_throw_error(env, NULL, "Second argument must be a number (button index)");
return NULL;
}
bool ok = dialog_helper::ClickMessageBoxButton(data, length, button_index);
napi_value result;
napi_get_boolean(env, ok, &result);
return result;
}
napi_value ClickCheckbox(napi_env env, napi_callback_info info) {
napi_value args[1];
char* data;
size_t length;
if (!GetHandleArg(env, info, 1, args, &data, &length))
return NULL;
bool ok = dialog_helper::ClickCheckbox(data, length);
napi_value result;
napi_get_boolean(env, ok, &result);
return result;
}
napi_value CancelFileDialog(napi_env env, napi_callback_info info) {
napi_value args[1];
char* data;
size_t length;
if (!GetHandleArg(env, info, 1, args, &data, &length))
return NULL;
bool ok = dialog_helper::CancelFileDialog(data, length);
napi_value result;
napi_get_boolean(env, ok, &result);
return result;
}
napi_value AcceptFileDialog(napi_env env, napi_callback_info info) {
napi_value args[2];
char* data;
size_t length;
if (!GetHandleArg(env, info, 2, args, &data, &length))
return NULL;
std::string filename;
// Second argument (filename) is optional.
napi_valuetype vtype;
napi_typeof(env, args[1], &vtype);
if (vtype == napi_string) {
size_t str_len;
napi_get_value_string_utf8(env, args[1], NULL, 0, &str_len);
filename.resize(str_len);
napi_get_value_string_utf8(env, args[1], &filename[0], str_len + 1,
&str_len);
}
bool ok = dialog_helper::AcceptFileDialog(data, length, filename);
napi_value result;
napi_get_boolean(env, ok, &result);
return result;
}
napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor descriptors[] = {
{"getDialogInfo", NULL, GetDialogInfo, NULL, NULL, NULL,
napi_enumerable, NULL},
{"clickMessageBoxButton", NULL, ClickMessageBoxButton, NULL, NULL, NULL,
napi_enumerable, NULL},
{"clickCheckbox", NULL, ClickCheckbox, NULL, NULL, NULL,
napi_enumerable, NULL},
{"cancelFileDialog", NULL, CancelFileDialog, NULL, NULL, NULL,
napi_enumerable, NULL},
{"acceptFileDialog", NULL, AcceptFileDialog, NULL, NULL, NULL,
napi_enumerable, NULL},
};
napi_define_properties(env, exports,
sizeof(descriptors) / sizeof(*descriptors),
descriptors);
return exports;
}
} // namespace
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

View File

@@ -7,6 +7,7 @@
"node-gyp-install": "node-gyp install"
},
"devDependencies": {
"@electron-ci/dialog-helper": "*",
"@electron-ci/echo": "*",
"@electron-ci/external-ab": "*",
"@electron-ci/is-valid-window": "*",

View File

@@ -616,6 +616,12 @@ __metadata:
languageName: unknown
linkType: soft
"@electron-ci/dialog-helper@npm:*, @electron-ci/dialog-helper@workspace:spec/fixtures/native-addon/dialog-helper":
version: 0.0.0-use.local
resolution: "@electron-ci/dialog-helper@workspace:spec/fixtures/native-addon/dialog-helper"
languageName: unknown
linkType: soft
"@electron-ci/echo@npm:*, @electron-ci/echo@workspace:spec/fixtures/native-addon/echo":
version: 0.0.0-use.local
resolution: "@electron-ci/echo@workspace:spec/fixtures/native-addon/echo"
@@ -4741,6 +4747,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "electron-test-main@workspace:spec"
dependencies:
"@electron-ci/dialog-helper": "npm:*"
"@electron-ci/echo": "npm:*"
"@electron-ci/external-ab": "npm:*"
"@electron-ci/is-valid-window": "npm:*"