mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
18 Commits
v29.0.0-be
...
v29.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c779f19ee5 | ||
|
|
09fbee9998 | ||
|
|
69d371fc41 | ||
|
|
b6db80c1c4 | ||
|
|
b87cf56b09 | ||
|
|
bc40a1aa0c | ||
|
|
d8606efe94 | ||
|
|
523e0d4574 | ||
|
|
3b23911121 | ||
|
|
516cbfa29a | ||
|
|
5c71377f40 | ||
|
|
85db55516b | ||
|
|
e071faa31b | ||
|
|
53e1c63d69 | ||
|
|
b8917a03d6 | ||
|
|
b33bc21159 | ||
|
|
9bb821a818 | ||
|
|
432b89445f |
@@ -353,10 +353,10 @@ step-setup-rbe-for-build: &step-setup-rbe-for-build
|
||||
mkdir third_party
|
||||
# Pull down credential helper and print status
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath")
|
||||
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
|
||||
$HELPER login
|
||||
echo 'export RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $BASH_ENV
|
||||
echo 'export RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath)"` >> $BASH_ENV
|
||||
echo 'export RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $BASH_ENV
|
||||
echo 'export RBE_experimental_credentials_helper_args="print"' >> $BASH_ENV
|
||||
|
||||
step-restore-brew-cache: &step-restore-brew-cache
|
||||
|
||||
2
DEPS
2
DEPS
@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'122.0.6261.18',
|
||||
'122.0.6261.57',
|
||||
'node_version':
|
||||
'v20.9.0',
|
||||
'nan_version':
|
||||
|
||||
@@ -106,7 +106,7 @@ for:
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath({})"
|
||||
- ps: >-
|
||||
& $env:RECLIENT_HELPER login
|
||||
- ps: >-
|
||||
|
||||
@@ -104,7 +104,7 @@ for:
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath"
|
||||
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath({})"
|
||||
- ps: >-
|
||||
& $env:RECLIENT_HELPER login
|
||||
- ps: >-
|
||||
|
||||
@@ -242,6 +242,8 @@ static_library("chrome") {
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.mm",
|
||||
"//chrome/browser/media/webrtc/thumbnail_capturer_mac.h",
|
||||
"//chrome/browser/media/webrtc/thumbnail_capturer_mac.mm",
|
||||
"//chrome/browser/media/webrtc/window_icon_util_mac.mm",
|
||||
"//chrome/browser/platform_util_mac.mm",
|
||||
"//chrome/browser/process_singleton_mac.mm",
|
||||
|
||||
@@ -29,6 +29,21 @@ function makeStreamFromPipe (pipe: any): ReadableStream {
|
||||
});
|
||||
}
|
||||
|
||||
function makeStreamFromFileInfo ({
|
||||
filePath,
|
||||
offset = 0,
|
||||
length = -1
|
||||
}: {
|
||||
filePath: string;
|
||||
offset?: number;
|
||||
length?: number;
|
||||
}): ReadableStream {
|
||||
return Readable.toWeb(createReadStream(filePath, {
|
||||
start: offset,
|
||||
end: length >= 0 ? offset + length : undefined
|
||||
}));
|
||||
}
|
||||
|
||||
function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): RequestInit['body'] {
|
||||
if (!uploadData) return null;
|
||||
// Optimization: skip creating a stream if the request is just a single buffer.
|
||||
@@ -37,30 +52,42 @@ function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): Reque
|
||||
const chunks = [...uploadData] as any[]; // TODO: types are wrong
|
||||
let current: ReadableStreamDefaultReader | null = null;
|
||||
return new ReadableStream({
|
||||
pull (controller) {
|
||||
async pull (controller) {
|
||||
if (current) {
|
||||
current.read().then(({ done, value }) => {
|
||||
const { done, value } = await current.read();
|
||||
// (done => value === undefined) as per WHATWG spec
|
||||
if (done) {
|
||||
current = null;
|
||||
return this.pull!(controller);
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
if (done) current = null;
|
||||
}, (err) => {
|
||||
controller.error(err);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!chunks.length) { return controller.close(); }
|
||||
const chunk = chunks.shift()!;
|
||||
if (chunk.type === 'rawData') { controller.enqueue(chunk.bytes); } else if (chunk.type === 'file') {
|
||||
current = Readable.toWeb(createReadStream(chunk.filePath, { start: chunk.offset ?? 0, end: chunk.length >= 0 ? chunk.offset + chunk.length : undefined })).getReader();
|
||||
this.pull!(controller);
|
||||
if (chunk.type === 'rawData') {
|
||||
controller.enqueue(chunk.bytes);
|
||||
} else if (chunk.type === 'file') {
|
||||
current = makeStreamFromFileInfo(chunk).getReader();
|
||||
return this.pull!(controller);
|
||||
} else if (chunk.type === 'stream') {
|
||||
current = makeStreamFromPipe(chunk.body).getReader();
|
||||
this.pull!(controller);
|
||||
return this.pull!(controller);
|
||||
} else if (chunk.type === 'blob') {
|
||||
// Note that even though `getBlobData()` is a `Session` API, it doesn't
|
||||
// actually use the `Session` context. Its implementation solely relies
|
||||
// on global variables which allows us to implement this feature without
|
||||
// knowledge of the `Session` associated with the current request by
|
||||
// always pulling `Blob` data out of the default `Session`.
|
||||
controller.enqueue(await session.defaultSession.getBlobData(chunk.blobUUID));
|
||||
} else {
|
||||
throw new Error(`Unknown upload data chunk type: ${chunk.type}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}) as RequestInit['body'];
|
||||
}
|
||||
|
||||
// TODO(codebytere): Use Object.hasOwn() once we update to ECMAScript 2022.
|
||||
function validateResponse (res: Response) {
|
||||
if (!res || typeof res !== 'object') return false;
|
||||
|
||||
@@ -85,8 +112,12 @@ Protocol.prototype.handle = function (this: Electron.Protocol, scheme: string, h
|
||||
const success = register.call(this, scheme, async (preq: ProtocolRequest, cb: any) => {
|
||||
try {
|
||||
const body = convertToRequestBody(preq.uploadData);
|
||||
const headers = new Headers(preq.headers);
|
||||
if (headers.get('origin') === 'null') {
|
||||
headers.delete('origin');
|
||||
}
|
||||
const req = new Request(preq.url, {
|
||||
headers: preq.headers,
|
||||
headers,
|
||||
method: preq.method,
|
||||
referrer: preq.referrer,
|
||||
body,
|
||||
|
||||
@@ -129,3 +129,5 @@ feat_allow_code_cache_in_custom_schemes.patch
|
||||
build_run_reclient_cfg_generator_after_chrome.patch
|
||||
fix_suppress_clang_-wimplicit-const-int-float-conversion_in.patch
|
||||
cherry-pick-e7ffe20ebfac.patch
|
||||
fix_getcursorscreenpoint_wrongly_returns_0_0.patch
|
||||
fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.patch
|
||||
|
||||
@@ -92,10 +92,10 @@ index 2709519d0bbf33548704c14a99324b504d27ccbf..aa3c2d3c1ea73da128616fe676ac09e2
|
||||
int32_t world_id) = 0;
|
||||
virtual bool AllowScriptExtensions() = 0;
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
|
||||
index 6139aed9ebbb459d4d7027312c0f15b669fedfb6..db566ba272b1eff5e67547c5d82bf7420def7285 100644
|
||||
index 070f61ef364eec98080f29d089d39f74222e9759..a6d2f3bbe61486187d23d20fecb01749e1d897b7 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
|
||||
@@ -289,6 +289,13 @@ void LocalFrameClientImpl::DidCreateScriptContext(
|
||||
@@ -290,6 +290,13 @@ void LocalFrameClientImpl::DidCreateScriptContext(
|
||||
web_frame_->Client()->DidCreateScriptContext(context, world_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ index 794efdb773422ddc12ccbe013a13aadeb980b487..a60bbd76141f06202343c68e78688a95
|
||||
// In GTK4, there's no way to obtain the frame thickness from CSS values
|
||||
// directly, so we must determine it experimentally based on the drawn
|
||||
diff --git a/ui/gtk/window_frame_provider_gtk.h b/ui/gtk/window_frame_provider_gtk.h
|
||||
index 91236ec07c01ca14248b997577ae887c0c396cd2..d70639d2ba40e325bbbbf6117741c13354984ed5 100644
|
||||
index bed28192daffe032fde3a74ca70f1298fb12b1b7..268acade8bd1075f3ce756cdf29bf50905ccb433 100644
|
||||
--- a/ui/gtk/window_frame_provider_gtk.h
|
||||
+++ b/ui/gtk/window_frame_provider_gtk.h
|
||||
@@ -18,7 +18,7 @@ namespace gtk {
|
||||
|
||||
@@ -33,10 +33,10 @@ index d09e7aeb788550e7ecefb4b9c177dd26ecc5ad4c..c894dc421f55a94e541d00e05e2f05bf
|
||||
"//base",
|
||||
"//build:branding_buildflags",
|
||||
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
|
||||
index 81dceec0b449c6fa90984f0bede8d3b94a93910a..32e5194b60f7db1d076e2ba3a884cce4e3133b02 100644
|
||||
index 0811d62fd215de0231021c88c6083493b0a6b1ca..502275e7adf9388afeeaeca692784f9e9a060f8c 100644
|
||||
--- a/chrome/browser/BUILD.gn
|
||||
+++ b/chrome/browser/BUILD.gn
|
||||
@@ -4755,7 +4755,7 @@ static_library("browser") {
|
||||
@@ -4763,7 +4763,7 @@ static_library("browser") {
|
||||
|
||||
# On Windows, the hashes are embedded in //chrome:chrome_initial rather
|
||||
# than here in :chrome_dll.
|
||||
@@ -46,10 +46,10 @@ index 81dceec0b449c6fa90984f0bede8d3b94a93910a..32e5194b60f7db1d076e2ba3a884cce4
|
||||
sources += [ "certificate_viewer_stub.cc" ]
|
||||
}
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d0809fc5b 100644
|
||||
index 84ea91c781a2f777461a4e99d1c8c2cdf138dc22..0d8a1ed6cebd86de4efc36a93e20cb6034a16c10 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -7220,7 +7220,6 @@ if (!is_fuchsia) {
|
||||
@@ -7221,7 +7221,6 @@ if (!is_fuchsia) {
|
||||
|
||||
deps += [
|
||||
"//chrome:other_version",
|
||||
@@ -57,7 +57,7 @@ index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d
|
||||
"//chrome//services/util_win:unit_tests",
|
||||
"//chrome/app:chrome_dll_resources",
|
||||
"//chrome/app:win_unit_tests",
|
||||
@@ -7241,6 +7240,10 @@ if (!is_fuchsia) {
|
||||
@@ -7242,6 +7241,10 @@ if (!is_fuchsia) {
|
||||
"//ui/resources",
|
||||
]
|
||||
|
||||
@@ -68,7 +68,7 @@ index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d
|
||||
ldflags = [
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll",
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
|
||||
@@ -8259,7 +8262,6 @@ if (!is_fuchsia) {
|
||||
@@ -8260,7 +8263,6 @@ if (!is_fuchsia) {
|
||||
}
|
||||
|
||||
deps += [
|
||||
@@ -76,7 +76,7 @@ index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d
|
||||
"//chrome/browser/apps:icon_standardizer",
|
||||
"//chrome/browser/apps/app_service",
|
||||
"//chrome/browser/apps/app_service:app_registry_cache_waiter",
|
||||
@@ -8352,6 +8354,10 @@ if (!is_fuchsia) {
|
||||
@@ -8353,6 +8355,10 @@ if (!is_fuchsia) {
|
||||
"//ui/webui/resources/js/browser_command:mojo_bindings",
|
||||
]
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ uses internally for things like menus and devtools.
|
||||
We can remove this patch once it has in some shape been upstreamed.
|
||||
|
||||
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
|
||||
index fbbc35818cfa1709b30520e2336eeab2d96693d0..814230e423a44bfc71b6e028fb870f2a1d15e15f 100644
|
||||
index 17c3b9f659a3b3e7f61463e5900ed53276454a7b..93848cea0c62b5457c9033c477a3fb81120f33cb 100644
|
||||
--- a/ui/native_theme/native_theme.cc
|
||||
+++ b/ui/native_theme/native_theme.cc
|
||||
@@ -198,6 +198,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors,
|
||||
@@ -191,6 +191,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors,
|
||||
NativeTheme::~NativeTheme() = default;
|
||||
|
||||
bool NativeTheme::ShouldUseDarkColors() const {
|
||||
@@ -26,10 +26,10 @@ index fbbc35818cfa1709b30520e2336eeab2d96693d0..814230e423a44bfc71b6e028fb870f2a
|
||||
}
|
||||
|
||||
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
|
||||
index 772c7a34a97588dd20c040be5ca482696990c880..fe1c04d6f9c9e9ca6a3aeacbaf897f1df5783248 100644
|
||||
index 14f3667521de110e6b9cd884ef9311878bb8bc8a..c88da6b43b9caefa50e8606e5a641c7c3dd6287e 100644
|
||||
--- a/ui/native_theme/native_theme.h
|
||||
+++ b/ui/native_theme/native_theme.h
|
||||
@@ -442,6 +442,23 @@ class NATIVE_THEME_EXPORT NativeTheme {
|
||||
@@ -441,6 +441,23 @@ class NATIVE_THEME_EXPORT NativeTheme {
|
||||
scoped_refptr<ColorProviderKey::ThemeInitializerSupplier> custom_theme,
|
||||
bool use_custom_frame = true) const;
|
||||
|
||||
@@ -53,7 +53,7 @@ index 772c7a34a97588dd20c040be5ca482696990c880..fe1c04d6f9c9e9ca6a3aeacbaf897f1d
|
||||
// Returns a shared instance of the native theme that should be used for web
|
||||
// rendering. Do not use it in a normal application context (i.e. browser).
|
||||
// The returned object should not be deleted by the caller. This function is
|
||||
@@ -658,6 +675,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
|
||||
@@ -655,6 +672,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
|
||||
bool inverted_colors_ = false;
|
||||
PreferredColorScheme preferred_color_scheme_ = PreferredColorScheme::kLight;
|
||||
PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference;
|
||||
@@ -62,10 +62,10 @@ index 772c7a34a97588dd20c040be5ca482696990c880..fe1c04d6f9c9e9ca6a3aeacbaf897f1d
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
};
|
||||
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
|
||||
index 6af4df92820d5a9d247a927244522f4c4acd164d..92af8c4a933b8462dce2524b0623a6843abd2600 100644
|
||||
index 50647269ec84f1a543132b3d102152a40e1e65e1..41a7df7e873a7d3300fd48db0ffa5f1fc8e43198 100644
|
||||
--- a/ui/native_theme/native_theme_win.cc
|
||||
+++ b/ui/native_theme/native_theme_win.cc
|
||||
@@ -655,6 +655,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
|
||||
@@ -664,6 +664,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
|
||||
// ...unless --force-dark-mode was specified in which case caveat emptor.
|
||||
if (InForcedColorsMode() && !IsForcedDarkMode())
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <marshallofsound@electronjs.org>
|
||||
Date: Tue, 13 Feb 2024 17:40:15 -0800
|
||||
Subject: fix: add support for skipping first 2 no-op refreshes in thumb cap
|
||||
|
||||
Fixes a bug in the SCK thumbnail capturer, will be reported upstream for a hopefully
|
||||
less hacky fix.
|
||||
|
||||
The first refresh is "no windows yet, no thumbnails".
|
||||
The second refresh is "we have windows, we queued the thumbnail requests"
|
||||
The third refresh (the one we want) is "we have windows, and have thumbnail requests"
|
||||
|
||||
This really isn't ideal at all, we need to refactor desktopCapturer (read completely re-implement it)
|
||||
to use StartUpdating and handle the events instead of using the "get the list once" method.
|
||||
|
||||
diff --git a/chrome/browser/media/webrtc/desktop_media_list.h b/chrome/browser/media/webrtc/desktop_media_list.h
|
||||
index 0c6fccf16a11bbaff10115308e4b489490e5d3e6..e5ec31054a43989e630115605de435399d36559b 100644
|
||||
--- a/chrome/browser/media/webrtc/desktop_media_list.h
|
||||
+++ b/chrome/browser/media/webrtc/desktop_media_list.h
|
||||
@@ -143,6 +143,8 @@ class DesktopMediaList {
|
||||
// important when IsSourceDelegated() returns true, as it helps to notify the
|
||||
// delegated source list when it should be hidden.
|
||||
virtual void HideList() = 0;
|
||||
+
|
||||
+ int skip_next_refresh_ = 0;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_MEDIA_WEBRTC_DESKTOP_MEDIA_LIST_H_
|
||||
diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.cc b/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
index 780927301744ea7312f230cec76a24a33d71f767..d19b1cc9dedf839f12f4113db64293e5c8150f51 100644
|
||||
--- a/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
+++ b/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
@@ -230,7 +230,11 @@ uint32_t DesktopMediaListBase::GetImageHash(const gfx::Image& image) {
|
||||
void DesktopMediaListBase::OnRefreshComplete() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
DCHECK(refresh_callback_);
|
||||
- std::move(refresh_callback_).Run();
|
||||
+ if (skip_next_refresh_ > 0) {
|
||||
+ skip_next_refresh_--;
|
||||
+ } else {
|
||||
+ std::move(refresh_callback_).Run();
|
||||
+ }
|
||||
}
|
||||
|
||||
void DesktopMediaListBase::ScheduleNextRefresh() {
|
||||
@@ -0,0 +1,25 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Charles Kerr <charles@charleskerr.com>
|
||||
Date: Thu, 8 Feb 2024 00:41:40 -0600
|
||||
Subject: fix: GetCursorScreenPoint() wrongly returns 0, 0
|
||||
|
||||
Fixes #41143. Discussion of the issue at
|
||||
https://github.com/electron/electron/issues/41143#issuecomment-1933443163
|
||||
|
||||
This patch should be backported to e29, upstreamed to Chromium, and then
|
||||
removed if it lands upstream.
|
||||
|
||||
diff --git a/ui/events/x/events_x_utils.cc b/ui/events/x/events_x_utils.cc
|
||||
index aa047f2bd39643dc471b25eeb567b0dd3731e0e0..eb312fb1c115751041930539d0d5f15208461e04 100644
|
||||
--- a/ui/events/x/events_x_utils.cc
|
||||
+++ b/ui/events/x/events_x_utils.cc
|
||||
@@ -586,6 +586,9 @@ gfx::Point EventLocationFromXEvent(const x11::Event& xev) {
|
||||
gfx::Point EventSystemLocationFromXEvent(const x11::Event& xev) {
|
||||
if (auto* crossing = xev.As<x11::CrossingEvent>())
|
||||
return gfx::Point(crossing->root_x, crossing->root_y);
|
||||
+ if (auto* crossing = xev.As<x11::Input::CrossingEvent>())
|
||||
+ return gfx::Point(Fp1616ToDouble(crossing->root_x),
|
||||
+ Fp1616ToDouble(crossing->root_y));
|
||||
if (auto* button = xev.As<x11::ButtonEvent>())
|
||||
return gfx::Point(button->root_x, button->root_y);
|
||||
if (auto* motion = xev.As<x11::MotionNotifyEvent>())
|
||||
@@ -13,13 +13,13 @@ messages in the legacy window handle layer.
|
||||
These conditions are regularly hit with WCO-enabled windows on Windows.
|
||||
|
||||
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
|
||||
index 2635d8967c42c85fb6830036e6de694b5736a97b..17bb1932f3a01c5027113061276f7050bb61f80e 100644
|
||||
index 70c19054022dd8ebc28657bb9ec94c0ee3e7ad87..ed9bea21b4ee6d6b9a7b979fc63ccc43d1926184 100644
|
||||
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
|
||||
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
|
||||
@@ -322,12 +322,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnKeyboardRange(UINT message,
|
||||
LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
|
||||
@@ -320,12 +320,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param) {
|
||||
LPARAM l_param,
|
||||
BOOL& handled) {
|
||||
- if (message == WM_MOUSEMOVE) {
|
||||
+ if (message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE) {
|
||||
if (!mouse_tracking_enabled_) {
|
||||
@@ -31,27 +31,27 @@ index 2635d8967c42c85fb6830036e6de694b5736a97b..17bb1932f3a01c5027113061276f7050
|
||||
tme.hwndTrack = hwnd();
|
||||
tme.dwHoverTime = 0;
|
||||
TrackMouseEvent(&tme);
|
||||
@@ -359,7 +359,10 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
|
||||
@@ -356,7 +356,10 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
|
||||
// out of the picture.
|
||||
if (!msg_handled_ &&
|
||||
if (!handled &&
|
||||
(message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) {
|
||||
- ret = ::DefWindowProc(GetParent(), message, w_param, l_param);
|
||||
+ // Send WM_NCMOUSEMOVE messages using the LegacyRenderWidgetHostHWND's
|
||||
+ // handle so mouse tracking on non-client areas doesn't break.
|
||||
+ HWND target = message == WM_NCMOUSEMOVE ? hwnd() : GetParent();
|
||||
+ ret = ::DefWindowProc(target, message, w_param, l_param);
|
||||
msg_handled_ = TRUE;
|
||||
handled = TRUE;
|
||||
}
|
||||
}
|
||||
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h
|
||||
index c478d6351ba160c76871ad657ede69b05b4e09ca..77631423937f7df7c52b4d3d309aa9335ab05bbb 100644
|
||||
index f22af1f3e24033688a4f59666346075831df2243..50c66051efb0bfcb3c13e4ccb37dddfade9abb82 100644
|
||||
--- a/content/browser/renderer_host/legacy_render_widget_host_win.h
|
||||
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.h
|
||||
@@ -91,6 +91,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
|
||||
CR_MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest)
|
||||
CR_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK,
|
||||
OnMouseRange)
|
||||
+ CR_MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave)
|
||||
CR_MESSAGE_HANDLER_EX(WM_NCCALCSIZE, OnNCCalcSize)
|
||||
CR_MESSAGE_HANDLER_EX(WM_SIZE, OnSize)
|
||||
CR_MESSAGE_HANDLER_EX(WM_DESTROY, OnDestroy)
|
||||
@@ -102,6 +102,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
|
||||
MESSAGE_HANDLER_EX(WM_VSCROLL, OnScroll)
|
||||
MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest)
|
||||
MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange)
|
||||
+ MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave)
|
||||
MESSAGE_HANDLER_EX(WM_NCCALCSIZE, OnNCCalcSize)
|
||||
MESSAGE_HANDLER_EX(WM_SIZE, OnSize)
|
||||
MESSAGE_HANDLER_EX(WM_DESTROY, OnDestroy)
|
||||
|
||||
@@ -1,27 +1,15 @@
|
||||
{
|
||||
"src/electron/patches/chromium": "src",
|
||||
|
||||
"src/electron/patches/boringssl": "src/third_party/boringssl/src",
|
||||
|
||||
"src/electron/patches/devtools_frontend": "src/third_party/devtools-frontend/src",
|
||||
|
||||
"src/electron/patches/ffmpeg": "src/third_party/ffmpeg",
|
||||
|
||||
"src/electron/patches/v8": "src/v8",
|
||||
|
||||
"src/electron/patches/node": "src/third_party/electron_node",
|
||||
|
||||
"src/electron/patches/nan": "src/third_party/nan",
|
||||
|
||||
"src/electron/patches/perfetto": "src/third_party/perfetto",
|
||||
|
||||
"src/electron/patches/squirrel.mac": "src/third_party/squirrel.mac",
|
||||
|
||||
"src/electron/patches/Mantle": "src/third_party/squirrel.mac/vendor/Mantle",
|
||||
|
||||
"src/electron/patches/ReactiveObjC": "src/third_party/squirrel.mac/vendor/ReactiveObjC",
|
||||
|
||||
"src/electron/patches/webrtc": "src/third_party/webrtc",
|
||||
|
||||
"src/electron/patches/reclient-configs": "src/third_party/engflow-reclient-configs"
|
||||
}
|
||||
[
|
||||
{ "patch_dir": "src/electron/patches/chromium", "repo": "src" },
|
||||
{ "patch_dir": "src/electron/patches/boringssl", "repo": "src/third_party/boringssl/src" },
|
||||
{ "patch_dir": "src/electron/patches/devtools_frontend", "repo": "src/third_party/devtools-frontend/src" },
|
||||
{ "patch_dir": "src/electron/patches/ffmpeg", "repo": "src/third_party/ffmpeg" },
|
||||
{ "patch_dir": "src/electron/patches/v8", "repo": "src/v8" },
|
||||
{ "patch_dir": "src/electron/patches/node", "repo": "src/third_party/electron_node" },
|
||||
{ "patch_dir": "src/electron/patches/nan", "repo": "src/third_party/nan" },
|
||||
{ "patch_dir": "src/electron/patches/perfetto", "repo": "src/third_party/perfetto" },
|
||||
{ "patch_dir": "src/electron/patches/squirrel.mac", "repo": "src/third_party/squirrel.mac" },
|
||||
{ "patch_dir": "src/electron/patches/Mantle", "repo": "src/third_party/squirrel.mac/vendor/Mantle" },
|
||||
{ "patch_dir": "src/electron/patches/ReactiveObjC", "repo": "src/third_party/squirrel.mac/vendor/ReactiveObjC" },
|
||||
{ "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" },
|
||||
{ "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" }
|
||||
]
|
||||
|
||||
@@ -10,10 +10,10 @@ to handle this without patching, but this is fairly clean for now and no longer
|
||||
patching legacy devtools code.
|
||||
|
||||
diff --git a/front_end/entrypoints/main/MainImpl.ts b/front_end/entrypoints/main/MainImpl.ts
|
||||
index e5beed66e2c81c918b23287a190a628b416b5f6a..1d9b58c2ac3429e704df3b5f6d3dd3af405e8cb4 100644
|
||||
index df915df956604163a9a7dda5dacb628899fe1015..1e449b06d96341ac8d1411b2760a7e2aeb087dca 100644
|
||||
--- a/front_end/entrypoints/main/MainImpl.ts
|
||||
+++ b/front_end/entrypoints/main/MainImpl.ts
|
||||
@@ -729,6 +729,8 @@ export class MainImpl {
|
||||
@@ -734,6 +734,8 @@ export class MainImpl {
|
||||
globalThis.Main = globalThis.Main || {};
|
||||
// @ts-ignore Exported for Tests.js
|
||||
globalThis.Main.Main = MainImpl;
|
||||
|
||||
@@ -51,3 +51,4 @@ fix_capture_embedder_exceptions_before_entering_v8.patch
|
||||
spec_add_iterator_to_global_intrinsics.patch
|
||||
fix_undici_incorrectly_copies_headers_onto_fetches.patch
|
||||
src_preload_function_for_environment.patch
|
||||
fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
|
||||
|
||||
@@ -87,7 +87,7 @@ index a1b0f812391486c5a429398326091a30bbe81692..a316d077f2d2ff38564959345cf8ef29
|
||||
|
||||
MaybeLocal<Value> ModuleWrap::SyntheticModuleEvaluationStepsCallback(
|
||||
diff --git a/src/module_wrap.h b/src/module_wrap.h
|
||||
index 6435bad40936fe235822c0597310b94ab98082f3..c51eb99ce3eb54bc30ae922e0357b637b09d53c6 100644
|
||||
index 6435bad40936fe235822c0597310b94ab98082f3..8f30f546cc47bdb402ef4b1217d7bbb675a85ef7 100644
|
||||
--- a/src/module_wrap.h
|
||||
+++ b/src/module_wrap.h
|
||||
@@ -30,7 +30,14 @@ enum HostDefinedOptions : int {
|
||||
@@ -106,3 +106,20 @@ index 6435bad40936fe235822c0597310b94ab98082f3..c51eb99ce3eb54bc30ae922e0357b637
|
||||
public:
|
||||
enum InternalFields {
|
||||
kModuleSlot = BaseObject::kInternalFieldCount,
|
||||
@@ -65,6 +72,8 @@ class ModuleWrap : public BaseObject {
|
||||
return true;
|
||||
}
|
||||
|
||||
+ static ModuleWrap* GetFromModule(node::Environment*, v8::Local<v8::Module>);
|
||||
+
|
||||
private:
|
||||
ModuleWrap(Environment* env,
|
||||
v8::Local<v8::Object> object,
|
||||
@@ -99,7 +108,6 @@ class ModuleWrap : public BaseObject {
|
||||
v8::Local<v8::String> specifier,
|
||||
v8::Local<v8::FixedArray> import_assertions,
|
||||
v8::Local<v8::Module> referrer);
|
||||
- static ModuleWrap* GetFromModule(node::Environment*, v8::Local<v8::Module>);
|
||||
|
||||
v8::Global<v8::Module> module_;
|
||||
std::unordered_map<std::string, v8::Global<v8::Promise>> resolve_cache_;
|
||||
|
||||
@@ -13,7 +13,7 @@ causing the following error:
|
||||
This should be upstreamed.
|
||||
|
||||
diff --git a/src/module_wrap.h b/src/module_wrap.h
|
||||
index c51eb99ce3eb54bc30ae922e0357b637b09d53c6..55317ced78ee9ceaa13f7e00477c59370eb335fa 100644
|
||||
index 8f30f546cc47bdb402ef4b1217d7bbb675a85ef7..a39f3f36f8e736881c7795cfba1d72e0507ea802 100644
|
||||
--- a/src/module_wrap.h
|
||||
+++ b/src/module_wrap.h
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
@@ -0,0 +1,572 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Keeley Hammond <khammond@slack-corp.com>
|
||||
Date: Mon, 19 Feb 2024 12:05:42 -0800
|
||||
Subject: fix: revert "src,lb: reducing C++ calls of esm legacy main resolve"
|
||||
|
||||
This switch to native legacyMainResolve doesn't take asar into account, and can
|
||||
cause errors when a project using ESM and asar tries to load a dependency which
|
||||
uses commonJS. This will need to be fixed forward, but revert for Electron 29's
|
||||
stable release to avoid potentially breaking apps with a riskier fix.
|
||||
|
||||
This patch can be removed when node's
|
||||
native implementation has been patched
|
||||
to recognize asar files.
|
||||
|
||||
This reverts commit 9cf2e1f55b8446a7cde23699d00a3be73aa0c8f1.
|
||||
|
||||
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
|
||||
index ce8092b96aee8d09ff382110db4be62dcd760cce..fe0b6591e4c86b5fcbda4a1aac9c116e17920f05 100644
|
||||
--- a/lib/internal/modules/esm/resolve.js
|
||||
+++ b/lib/internal/modules/esm/resolve.js
|
||||
@@ -36,10 +36,9 @@ const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
|
||||
const experimentalNetworkImports =
|
||||
getOptionValue('--experimental-network-imports');
|
||||
const typeFlag = getOptionValue('--input-type');
|
||||
-const { URL, pathToFileURL, fileURLToPath, isURL } = require('internal/url');
|
||||
+const { URL, pathToFileURL, fileURLToPath, isURL, toPathIfFileURL } = require('internal/url');
|
||||
const { getCWDURL } = require('internal/util');
|
||||
const { canParse: URLCanParse } = internalBinding('url');
|
||||
-const { legacyMainResolve: FSLegacyMainResolve } = internalBinding('fs');
|
||||
const {
|
||||
ERR_INPUT_TYPE_NOT_ALLOWED,
|
||||
ERR_INVALID_ARG_TYPE,
|
||||
@@ -136,34 +135,13 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
|
||||
|
||||
const realpathCache = new SafeMap();
|
||||
|
||||
-const legacyMainResolveExtensions = [
|
||||
- '',
|
||||
- '.js',
|
||||
- '.json',
|
||||
- '.node',
|
||||
- '/index.js',
|
||||
- '/index.json',
|
||||
- '/index.node',
|
||||
- './index.js',
|
||||
- './index.json',
|
||||
- './index.node',
|
||||
-];
|
||||
-
|
||||
-const legacyMainResolveExtensionsIndexes = {
|
||||
- // 0-6: when packageConfig.main is defined
|
||||
- kResolvedByMain: 0,
|
||||
- kResolvedByMainJs: 1,
|
||||
- kResolvedByMainJson: 2,
|
||||
- kResolvedByMainNode: 3,
|
||||
- kResolvedByMainIndexJs: 4,
|
||||
- kResolvedByMainIndexJson: 5,
|
||||
- kResolvedByMainIndexNode: 6,
|
||||
- // 7-9: when packageConfig.main is NOT defined,
|
||||
- // or when the previous case didn't found the file
|
||||
- kResolvedByPackageAndJs: 7,
|
||||
- kResolvedByPackageAndJson: 8,
|
||||
- kResolvedByPackageAndNode: 9,
|
||||
-};
|
||||
+/**
|
||||
+ * @param {string | URL} url
|
||||
+ * @returns {boolean}
|
||||
+ */
|
||||
+function fileExists(url) {
|
||||
+ return internalModuleStat(toNamespacedPath(toPathIfFileURL(url))) === 0;
|
||||
+}
|
||||
|
||||
/**
|
||||
* Legacy CommonJS main resolution:
|
||||
@@ -178,22 +156,44 @@ const legacyMainResolveExtensionsIndexes = {
|
||||
* @returns {URL}
|
||||
*/
|
||||
function legacyMainResolve(packageJSONUrl, packageConfig, base) {
|
||||
- const packageJsonUrlString = packageJSONUrl.href;
|
||||
-
|
||||
- if (typeof packageJsonUrlString !== 'string') {
|
||||
- throw new ERR_INVALID_ARG_TYPE('packageJSONUrl', ['URL'], packageJSONUrl);
|
||||
+ let guess;
|
||||
+ if (packageConfig.main !== undefined) {
|
||||
+ // Note: fs check redundances will be handled by Descriptor cache here.
|
||||
+ if (fileExists(guess = new URL(`./${packageConfig.main}`,
|
||||
+ packageJSONUrl))) {
|
||||
+ return guess;
|
||||
+ } else if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
|
||||
+ packageJSONUrl)));
|
||||
+ else if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
|
||||
+ packageJSONUrl)));
|
||||
+ else if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
|
||||
+ packageJSONUrl)));
|
||||
+ else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
|
||||
+ packageJSONUrl)));
|
||||
+ else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
|
||||
+ packageJSONUrl)));
|
||||
+ else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
|
||||
+ packageJSONUrl)));
|
||||
+ else guess = undefined;
|
||||
+ if (guess) {
|
||||
+ emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
|
||||
+ packageConfig.main);
|
||||
+ return guess;
|
||||
+ }
|
||||
+ // Fallthrough.
|
||||
}
|
||||
-
|
||||
- const baseStringified = isURL(base) ? base.href : base;
|
||||
-
|
||||
- const resolvedOption = FSLegacyMainResolve(packageJsonUrlString, packageConfig.main, baseStringified);
|
||||
-
|
||||
- const baseUrl = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ? `./${packageConfig.main}` : '';
|
||||
- const resolvedUrl = new URL(baseUrl + legacyMainResolveExtensions[resolvedOption], packageJSONUrl);
|
||||
-
|
||||
- emitLegacyIndexDeprecation(resolvedUrl, packageJSONUrl, base, packageConfig.main);
|
||||
-
|
||||
- return resolvedUrl;
|
||||
+ if (fileExists(guess = new URL('./index.js', packageJSONUrl)));
|
||||
+ // So fs.
|
||||
+ else if (fileExists(guess = new URL('./index.json', packageJSONUrl)));
|
||||
+ else if (fileExists(guess = new URL('./index.node', packageJSONUrl)));
|
||||
+ else guess = undefined;
|
||||
+ if (guess) {
|
||||
+ emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
|
||||
+ return guess;
|
||||
+ }
|
||||
+ // Not found.
|
||||
+ throw new ERR_MODULE_NOT_FOUND(
|
||||
+ fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
|
||||
}
|
||||
|
||||
const encodedSepRegEx = /%2F|%5C/i;
|
||||
diff --git a/src/node_file.cc b/src/node_file.cc
|
||||
index 59780dec1c4b6d157d2b04fea8c57cacce73ec3a..8f8629ed0b8cbc08a544211b63675ea0dcca1828 100644
|
||||
--- a/src/node_file.cc
|
||||
+++ b/src/node_file.cc
|
||||
@@ -19,14 +19,11 @@
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#include "node_file.h" // NOLINT(build/include_inline)
|
||||
-#include "ada.h"
|
||||
#include "aliased_buffer-inl.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "node_buffer.h"
|
||||
-#include "node_errors.h"
|
||||
#include "node_external_reference.h"
|
||||
#include "node_file-inl.h"
|
||||
-#include "node_metadata.h"
|
||||
#include "node_process-inl.h"
|
||||
#include "node_stat_watcher.h"
|
||||
#include "permission/permission.h"
|
||||
@@ -3013,293 +3010,6 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
}
|
||||
|
||||
-static bool FileURLToPath(
|
||||
- Environment* env,
|
||||
- const ada::url_aggregator& file_url,
|
||||
- /* The linter can't detect the assign for result_file_path
|
||||
- So we need to ignore since it suggest to put const */
|
||||
- // NOLINTNEXTLINE(runtime/references)
|
||||
- std::string& result_file_path) {
|
||||
- if (file_url.type != ada::scheme::FILE) {
|
||||
- env->isolate()->ThrowException(ERR_INVALID_URL_SCHEME(env->isolate()));
|
||||
-
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- std::string_view pathname = file_url.get_pathname();
|
||||
-#ifdef _WIN32
|
||||
- size_t first_percent = std::string::npos;
|
||||
- size_t pathname_size = pathname.size();
|
||||
- std::string pathname_escaped_slash;
|
||||
-
|
||||
- for (size_t i = 0; i < pathname_size; i++) {
|
||||
- if (pathname[i] == '/') {
|
||||
- pathname_escaped_slash += '\\';
|
||||
- } else {
|
||||
- pathname_escaped_slash += pathname[i];
|
||||
- }
|
||||
-
|
||||
- if (pathname[i] != '%') continue;
|
||||
-
|
||||
- if (first_percent == std::string::npos) {
|
||||
- first_percent = i;
|
||||
- }
|
||||
-
|
||||
- // just safe-guard against access the pathname
|
||||
- // outside the bounds
|
||||
- if ((i + 2) >= pathname_size) continue;
|
||||
-
|
||||
- char third = pathname[i + 2] | 0x20;
|
||||
-
|
||||
- bool is_slash = pathname[i + 1] == '2' && third == 102;
|
||||
- bool is_forward_slash = pathname[i + 1] == '5' && third == 99;
|
||||
-
|
||||
- if (!is_slash && !is_forward_slash) continue;
|
||||
-
|
||||
- env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
|
||||
- env->isolate(),
|
||||
- "File URL path must not include encoded \\ or / characters"));
|
||||
-
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- std::string_view hostname = file_url.get_hostname();
|
||||
- std::string decoded_pathname = ada::unicode::percent_decode(
|
||||
- std::string_view(pathname_escaped_slash), first_percent);
|
||||
-
|
||||
- if (hostname.size() > 0) {
|
||||
- // If hostname is set, then we have a UNC path
|
||||
- // Pass the hostname through domainToUnicode just in case
|
||||
- // it is an IDN using punycode encoding. We do not need to worry
|
||||
- // about percent encoding because the URL parser will have
|
||||
- // already taken care of that for us. Note that this only
|
||||
- // causes IDNs with an appropriate `xn--` prefix to be decoded.
|
||||
- result_file_path =
|
||||
- "\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;
|
||||
-
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- char letter = decoded_pathname[1] | 0x20;
|
||||
- char sep = decoded_pathname[2];
|
||||
-
|
||||
- // a..z A..Z
|
||||
- if (letter < 'a' || letter > 'z' || sep != ':') {
|
||||
- env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
|
||||
- env->isolate(), "File URL path must be absolute"));
|
||||
-
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- result_file_path = decoded_pathname.substr(1);
|
||||
-
|
||||
- return true;
|
||||
-#else // _WIN32
|
||||
- std::string_view hostname = file_url.get_hostname();
|
||||
-
|
||||
- if (hostname.size() > 0) {
|
||||
- std::string error_message =
|
||||
- std::string("File URL host must be \"localhost\" or empty on ") +
|
||||
- std::string(per_process::metadata.platform);
|
||||
- env->isolate()->ThrowException(
|
||||
- ERR_INVALID_FILE_URL_HOST(env->isolate(), error_message.c_str()));
|
||||
-
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- size_t first_percent = std::string::npos;
|
||||
- for (size_t i = 0; (i + 2) < pathname.size(); i++) {
|
||||
- if (pathname[i] != '%') continue;
|
||||
-
|
||||
- if (first_percent == std::string::npos) {
|
||||
- first_percent = i;
|
||||
- }
|
||||
-
|
||||
- if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
|
||||
- env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
|
||||
- env->isolate(),
|
||||
- "File URL path must not include encoded / characters"));
|
||||
-
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- result_file_path = ada::unicode::percent_decode(pathname, first_percent);
|
||||
-
|
||||
- return true;
|
||||
-#endif // _WIN32
|
||||
-}
|
||||
-
|
||||
-BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
|
||||
- Environment* env, const std::string& file_path) {
|
||||
- THROW_IF_INSUFFICIENT_PERMISSIONS(
|
||||
- env,
|
||||
- permission::PermissionScope::kFileSystemRead,
|
||||
- file_path,
|
||||
- BindingData::FilePathIsFileReturnType::kThrowInsufficientPermissions);
|
||||
-
|
||||
- uv_fs_t req;
|
||||
-
|
||||
- int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr);
|
||||
-
|
||||
- if (rc == 0) {
|
||||
- const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
|
||||
- rc = !!(s->st_mode & S_IFDIR);
|
||||
- }
|
||||
-
|
||||
- uv_fs_req_cleanup(&req);
|
||||
-
|
||||
- // rc is 0 if the path refers to a file
|
||||
- if (rc == 0) return BindingData::FilePathIsFileReturnType::kIsFile;
|
||||
-
|
||||
- return BindingData::FilePathIsFileReturnType::kIsNotFile;
|
||||
-}
|
||||
-
|
||||
-// the possible file extensions that should be tested
|
||||
-// 0-6: when packageConfig.main is defined
|
||||
-// 7-9: when packageConfig.main is NOT defined,
|
||||
-// or when the previous case didn't found the file
|
||||
-const std::array<std::string, 10> BindingData::legacy_main_extensions = {
|
||||
- "",
|
||||
- ".js",
|
||||
- ".json",
|
||||
- ".node",
|
||||
- "/index.js",
|
||||
- "/index.json",
|
||||
- "/index.node",
|
||||
- ".js",
|
||||
- ".json",
|
||||
- ".node"};
|
||||
-
|
||||
-void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
|
||||
- CHECK_GE(args.Length(), 1);
|
||||
- CHECK(args[0]->IsString());
|
||||
-
|
||||
- Environment* env = Environment::GetCurrent(args);
|
||||
-
|
||||
- Utf8Value utf8_package_json_url(env->isolate(), args[0].As<String>());
|
||||
- auto package_json_url =
|
||||
- ada::parse<ada::url_aggregator>(utf8_package_json_url.ToStringView());
|
||||
-
|
||||
- if (!package_json_url) {
|
||||
- env->isolate()->ThrowException(
|
||||
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
|
||||
-
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- ada::result<ada::url_aggregator> file_path_url;
|
||||
- std::string initial_file_path;
|
||||
- std::string file_path;
|
||||
-
|
||||
- if (args.Length() >= 2 && !args[1]->IsNullOrUndefined() &&
|
||||
- args[1]->IsString()) {
|
||||
- std::string package_config_main =
|
||||
- Utf8Value(env->isolate(), args[1].As<String>()).ToString();
|
||||
-
|
||||
- file_path_url = ada::parse<ada::url_aggregator>(
|
||||
- std::string("./") + package_config_main, &package_json_url.value());
|
||||
-
|
||||
- if (!file_path_url) {
|
||||
- env->isolate()->ThrowException(
|
||||
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
|
||||
-
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
|
||||
-
|
||||
- FromNamespacedPath(&initial_file_path);
|
||||
-
|
||||
- for (int i = 0; i < BindingData::legacy_main_extensions_with_main_end;
|
||||
- i++) {
|
||||
- file_path = initial_file_path + BindingData::legacy_main_extensions[i];
|
||||
-
|
||||
- switch (FilePathIsFile(env, file_path)) {
|
||||
- case BindingData::FilePathIsFileReturnType::kIsFile:
|
||||
- return args.GetReturnValue().Set(i);
|
||||
- case BindingData::FilePathIsFileReturnType::kIsNotFile:
|
||||
- continue;
|
||||
- case BindingData::FilePathIsFileReturnType::
|
||||
- kThrowInsufficientPermissions:
|
||||
- // the default behavior when do not have permission is to return
|
||||
- // and exit the execution of the method as soon as possible
|
||||
- // the internal function will throw the exception
|
||||
- return;
|
||||
- default:
|
||||
- UNREACHABLE();
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- file_path_url =
|
||||
- ada::parse<ada::url_aggregator>("./index", &package_json_url.value());
|
||||
-
|
||||
- if (!file_path_url) {
|
||||
- env->isolate()->ThrowException(
|
||||
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
|
||||
-
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
|
||||
-
|
||||
- FromNamespacedPath(&initial_file_path);
|
||||
-
|
||||
- for (int i = BindingData::legacy_main_extensions_with_main_end;
|
||||
- i < BindingData::legacy_main_extensions_package_fallback_end;
|
||||
- i++) {
|
||||
- file_path = initial_file_path + BindingData::legacy_main_extensions[i];
|
||||
-
|
||||
- switch (FilePathIsFile(env, file_path)) {
|
||||
- case BindingData::FilePathIsFileReturnType::kIsFile:
|
||||
- return args.GetReturnValue().Set(i);
|
||||
- case BindingData::FilePathIsFileReturnType::kIsNotFile:
|
||||
- continue;
|
||||
- case BindingData::FilePathIsFileReturnType::kThrowInsufficientPermissions:
|
||||
- // the default behavior when do not have permission is to return
|
||||
- // and exit the execution of the method as soon as possible
|
||||
- // the internal function will throw the exception
|
||||
- return;
|
||||
- default:
|
||||
- UNREACHABLE();
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- std::string module_path;
|
||||
- std::string module_base;
|
||||
-
|
||||
- if (!FileURLToPath(env, package_json_url.value(), module_path)) return;
|
||||
-
|
||||
- if (args.Length() >= 3 && !args[2]->IsNullOrUndefined() &&
|
||||
- args[2]->IsString()) {
|
||||
- Utf8Value utf8_base_path(env->isolate(), args[2].As<String>());
|
||||
- auto base_url =
|
||||
- ada::parse<ada::url_aggregator>(utf8_base_path.ToStringView());
|
||||
-
|
||||
- if (!base_url) {
|
||||
- env->isolate()->ThrowException(
|
||||
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
|
||||
-
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (!FileURLToPath(env, base_url.value(), module_base)) return;
|
||||
- } else {
|
||||
- std::string err_arg_message =
|
||||
- "The \"base\" argument must be of type string or an instance of URL.";
|
||||
- env->isolate()->ThrowException(
|
||||
- ERR_INVALID_ARG_TYPE(env->isolate(), err_arg_message.c_str()));
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- env->isolate()->ThrowException(
|
||||
- ERR_MODULE_NOT_FOUND(env->isolate(),
|
||||
- "Cannot find package '%s' imported from %s",
|
||||
- module_path,
|
||||
- module_base));
|
||||
-}
|
||||
-
|
||||
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
|
||||
tracker->TrackField("stats_field_array", stats_field_array);
|
||||
tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
|
||||
@@ -3399,19 +3109,6 @@ InternalFieldInfoBase* BindingData::Serialize(int index) {
|
||||
return info;
|
||||
}
|
||||
|
||||
-void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
- Local<ObjectTemplate> target) {
|
||||
- Isolate* isolate = isolate_data->isolate();
|
||||
-
|
||||
- SetMethod(
|
||||
- isolate, target, "legacyMainResolve", BindingData::LegacyMainResolve);
|
||||
-}
|
||||
-
|
||||
-void BindingData::RegisterExternalReferences(
|
||||
- ExternalReferenceRegistry* registry) {
|
||||
- registry->Register(BindingData::LegacyMainResolve);
|
||||
-}
|
||||
-
|
||||
static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
Local<ObjectTemplate> target) {
|
||||
Isolate* isolate = isolate_data->isolate();
|
||||
@@ -3468,7 +3165,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
SetMethod(isolate, target, "mkdtemp", Mkdtemp);
|
||||
|
||||
StatWatcher::CreatePerIsolateProperties(isolate_data, target);
|
||||
- BindingData::CreatePerIsolateProperties(isolate_data, target);
|
||||
|
||||
target->Set(
|
||||
FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
|
||||
@@ -3542,7 +3238,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||
registry->Register(Access);
|
||||
registry->Register(AccessSync);
|
||||
StatWatcher::RegisterExternalReferences(registry);
|
||||
- BindingData::RegisterExternalReferences(registry);
|
||||
|
||||
registry->Register(Close);
|
||||
registry->Register(CloseSync);
|
||||
diff --git a/src/node_file.h b/src/node_file.h
|
||||
index 4599546c5245300346557b68070c60292daaed23..7b43d027a2e6524f3ec6b7bccdb6e49a3c8790ea 100644
|
||||
--- a/src/node_file.h
|
||||
+++ b/src/node_file.h
|
||||
@@ -63,13 +63,6 @@ class BindingData : public SnapshotableObject {
|
||||
AliasedBufferIndex statfs_field_array;
|
||||
AliasedBufferIndex statfs_field_bigint_array;
|
||||
};
|
||||
-
|
||||
- enum class FilePathIsFileReturnType {
|
||||
- kIsFile = 0,
|
||||
- kIsNotFile,
|
||||
- kThrowInsufficientPermissions
|
||||
- };
|
||||
-
|
||||
explicit BindingData(Realm* realm,
|
||||
v8::Local<v8::Object> wrap,
|
||||
InternalFieldInfo* info = nullptr);
|
||||
@@ -86,30 +79,12 @@ class BindingData : public SnapshotableObject {
|
||||
SERIALIZABLE_OBJECT_METHODS()
|
||||
SET_BINDING_ID(fs_binding_data)
|
||||
|
||||
- static void LegacyMainResolve(
|
||||
- const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
-
|
||||
- static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
- v8::Local<v8::ObjectTemplate> ctor);
|
||||
- static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
||||
-
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
SET_SELF_SIZE(BindingData)
|
||||
SET_MEMORY_INFO_NAME(BindingData)
|
||||
|
||||
private:
|
||||
InternalFieldInfo* internal_field_info_ = nullptr;
|
||||
-
|
||||
- static FilePathIsFileReturnType FilePathIsFile(Environment* env,
|
||||
- const std::string& file_path);
|
||||
-
|
||||
- static const std::array<std::string, 10> legacy_main_extensions;
|
||||
- // define the final index of the algorithm resolution
|
||||
- // when packageConfig.main is defined.
|
||||
- static const uint8_t legacy_main_extensions_with_main_end = 7;
|
||||
- // define the final index of the algorithm resolution
|
||||
- // when packageConfig.main is NOT defined
|
||||
- static const uint8_t legacy_main_extensions_package_fallback_end = 10;
|
||||
};
|
||||
|
||||
// structure used to store state during a complex operation, e.g., mkdirp.
|
||||
diff --git a/test/es-module/test-cjs-legacyMainResolve.js b/test/es-module/test-cjs-legacyMainResolve.js
|
||||
index 1dc7d8faafe6eb5cea7e43e9783041f2a994be0d..d86d501689b2b72f2b964d6e2a91c5d36b6b62f5 100644
|
||||
--- a/test/es-module/test-cjs-legacyMainResolve.js
|
||||
+++ b/test/es-module/test-cjs-legacyMainResolve.js
|
||||
@@ -82,7 +82,7 @@ describe('legacyMainResolve', () => {
|
||||
{},
|
||||
''
|
||||
),
|
||||
- { message: /instance of URL/, code: 'ERR_INVALID_ARG_TYPE' },
|
||||
+ { message: 'Invalid URL', code: 'ERR_INVALID_URL' },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -129,7 +129,7 @@ describe('legacyMainResolve', () => {
|
||||
);
|
||||
assert.throws(
|
||||
() => legacyMainResolve(packageJsonUrl, { main: null }, packageJsonUrl),
|
||||
- { code: 'ERR_MODULE_NOT_FOUND' },
|
||||
+ { code: 'ERR_INTERNAL_ASSERTION' },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -137,7 +137,7 @@ describe('legacyMainResolve', () => {
|
||||
const packageJsonUrl = pathToFileURL('/c/file%20with%20percents/package.json');
|
||||
assert.throws(
|
||||
() => legacyMainResolve(packageJsonUrl, { main: null }, packageJsonUrl),
|
||||
- { code: 'ERR_MODULE_NOT_FOUND' },
|
||||
+ { code: 'ERR_INTERNAL_ASSERTION' },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -150,7 +150,7 @@ describe('legacyMainResolve', () => {
|
||||
);
|
||||
assert.throws(
|
||||
() => legacyMainResolve(packageJsonUrl, { main: null }, undefined),
|
||||
- { message: /"base" argument must be/, code: 'ERR_INVALID_ARG_TYPE' },
|
||||
+ { message: 'The "path" argument must be of type string or an instance of URL. Received undefined', code: 'ERR_INVALID_ARG_TYPE' },
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -4,5 +4,5 @@ fix_use_kseccschecknestedcode_kseccsstrictvalidate_in_the_sec.patch
|
||||
feat_add_new_squirrel_mac_bundle_installation_method_behind_flag.patch
|
||||
refactor_use_posix_spawn_instead_of_nstask_so_we_can_disclaim_the.patch
|
||||
fix_abort_installation_attempt_at_the_final_mile_if_the_app_is.patch
|
||||
chore_disable_api_deprecation_warnings_in_nskeyedarchiver.patch
|
||||
feat_add_ability_to_prevent_version_downgrades.patch
|
||||
refactor_use_non-deprecated_nskeyedarchiver_apis.patch
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Thu, 22 Jun 2023 12:52:10 +0200
|
||||
Subject: chore: disable API deprecation warnings in NSKeyedArchiver
|
||||
|
||||
This should be updated to use the newer APIs.
|
||||
|
||||
Upstream PR at https://github.com/Squirrel/Squirrel.Mac/pull/273
|
||||
|
||||
diff --git a/Squirrel/SQRLInstaller.m b/Squirrel/SQRLInstaller.m
|
||||
index f502df2f88424ea902a061adfeb30358daf212e4..a18fedc3e47eb9c8bb7afc42aeab7cef3df742a3 100644
|
||||
--- a/Squirrel/SQRLInstaller.m
|
||||
+++ b/Squirrel/SQRLInstaller.m
|
||||
@@ -182,14 +182,20 @@ - (SQRLInstallerOwnedBundle *)ownedBundle {
|
||||
id archiveData = CFBridgingRelease(CFPreferencesCopyValue((__bridge CFStringRef)SQRLInstallerOwnedBundleKey, (__bridge CFStringRef)self.applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost));
|
||||
if (![archiveData isKindOfClass:NSData.class]) return nil;
|
||||
|
||||
+#pragma clang diagnostic push
|
||||
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
SQRLInstallerOwnedBundle *ownedBundle = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
|
||||
if (![ownedBundle isKindOfClass:SQRLInstallerOwnedBundle.class]) return nil;
|
||||
+#pragma clang diagnostic pop
|
||||
|
||||
return ownedBundle;
|
||||
}
|
||||
|
||||
- (void)setOwnedBundle:(SQRLInstallerOwnedBundle *)ownedBundle {
|
||||
+#pragma clang diagnostic push
|
||||
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
NSData *archiveData = (ownedBundle == nil ? nil : [NSKeyedArchiver archivedDataWithRootObject:ownedBundle]);
|
||||
+#pragma clang diagnostic pop
|
||||
CFPreferencesSetValue((__bridge CFStringRef)SQRLInstallerOwnedBundleKey, (__bridge CFPropertyListRef)archiveData, (__bridge CFStringRef)self.applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||
CFPreferencesSynchronize((__bridge CFStringRef)self.applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Thu, 22 Jun 2023 12:26:24 +0200
|
||||
Subject: refactor: use non-deprecated NSKeyedArchiver APIs
|
||||
|
||||
Refs https://chromium-review.googlesource.com/c/chromium/src/+/4628901
|
||||
|
||||
Several NSKeyedArchiver methods have been deprecated and replaced as of macOS 10.13:
|
||||
|
||||
- unarchiveObjectWithData -> unarchivedObjectOfClass:fromData:error:
|
||||
- archivedDataWithRootObject -> archivedDataWithRootObject:requiringSecureCoding:error:
|
||||
|
||||
diff --git a/Squirrel/SQRLInstaller.m b/Squirrel/SQRLInstaller.m
|
||||
index f502df2f88424ea902a061adfeb30358daf212e4..8db6406ec7f0cb51140ea2ee39c04f91626f6e18 100644
|
||||
--- a/Squirrel/SQRLInstaller.m
|
||||
+++ b/Squirrel/SQRLInstaller.m
|
||||
@@ -182,14 +182,30 @@ - (SQRLInstallerOwnedBundle *)ownedBundle {
|
||||
id archiveData = CFBridgingRelease(CFPreferencesCopyValue((__bridge CFStringRef)SQRLInstallerOwnedBundleKey, (__bridge CFStringRef)self.applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost));
|
||||
if (![archiveData isKindOfClass:NSData.class]) return nil;
|
||||
|
||||
- SQRLInstallerOwnedBundle *ownedBundle = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
|
||||
- if (![ownedBundle isKindOfClass:SQRLInstallerOwnedBundle.class]) return nil;
|
||||
+ NSError *error;
|
||||
+ SQRLInstallerOwnedBundle *ownedBundle = [NSKeyedUnarchiver unarchivedObjectOfClass:[SQRLInstallerOwnedBundle class]
|
||||
+ fromData:archiveData
|
||||
+ error:&error];
|
||||
+ if (error) {
|
||||
+ NSLog(@"Couldn't unarchive ownedBundle - %@", error.localizedDescription);
|
||||
+ return nil;
|
||||
+ }
|
||||
|
||||
return ownedBundle;
|
||||
}
|
||||
|
||||
- (void)setOwnedBundle:(SQRLInstallerOwnedBundle *)ownedBundle {
|
||||
- NSData *archiveData = (ownedBundle == nil ? nil : [NSKeyedArchiver archivedDataWithRootObject:ownedBundle]);
|
||||
+ NSData *archiveData = nil;
|
||||
+ if (ownedBundle != nil) {
|
||||
+ NSError *error;
|
||||
+ archiveData = [NSKeyedArchiver archivedDataWithRootObject:ownedBundle
|
||||
+ requiringSecureCoding:NO
|
||||
+ error:&error];
|
||||
+
|
||||
+ if (error)
|
||||
+ NSLog(@"Couldn't archive ownedBundle - %@", error.localizedDescription);
|
||||
+ }
|
||||
+
|
||||
CFPreferencesSetValue((__bridge CFStringRef)SQRLInstallerOwnedBundleKey, (__bridge CFPropertyListRef)archiveData, (__bridge CFStringRef)self.applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||
CFPreferencesSynchronize((__bridge CFStringRef)self.applicationIdentifier, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
||||
}
|
||||
@@ -3,19 +3,30 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from lib import git
|
||||
from lib.patches import patch_from_dir
|
||||
|
||||
THREEWAY = "ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES" in os.environ
|
||||
|
||||
def apply_patches(dirs):
|
||||
threeway = os.environ.get("ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES")
|
||||
for patch_dir, repo in dirs.items():
|
||||
if os.path.exists(repo):
|
||||
git.import_patches(repo=repo, patch_data=patch_from_dir(patch_dir),
|
||||
threeway=threeway is not None,
|
||||
committer_name="Electron Scripts", committer_email="scripts@electron")
|
||||
def apply_patches(target):
|
||||
repo = target.get('repo')
|
||||
if not os.path.exists(repo):
|
||||
warnings.warn('repo not found: %s' % repo)
|
||||
return
|
||||
patch_dir = target.get('patch_dir')
|
||||
git.import_patches(
|
||||
committer_email="scripts@electron",
|
||||
committer_name="Electron Scripts",
|
||||
patch_data=patch_from_dir(patch_dir),
|
||||
repo=repo,
|
||||
threeway=THREEWAY,
|
||||
)
|
||||
|
||||
def apply_config(config):
|
||||
for target in config:
|
||||
apply_patches(target)
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Apply Electron patches')
|
||||
@@ -26,9 +37,8 @@ def parse_args():
|
||||
|
||||
|
||||
def main():
|
||||
configs = parse_args().config
|
||||
for config_json in configs:
|
||||
apply_patches(json.load(config_json))
|
||||
for config_json in parse_args().config:
|
||||
apply_config(json.load(config_json))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -3,14 +3,27 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from lib import git
|
||||
|
||||
|
||||
def export_patches(dirs, dry_run):
|
||||
for patch_dir, repo in dirs.items():
|
||||
if os.path.exists(repo):
|
||||
git.export_patches(repo=repo, out_dir=patch_dir, dry_run=dry_run)
|
||||
def export_patches(target, dry_run):
|
||||
repo = target.get('repo')
|
||||
if not os.path.exists(repo):
|
||||
warnings.warn('repo not found: %s' % repo)
|
||||
return
|
||||
git.export_patches(
|
||||
dry_run=dry_run,
|
||||
grep=target.get('grep'),
|
||||
out_dir=target.get('patch_dir'),
|
||||
repo=repo
|
||||
)
|
||||
|
||||
|
||||
def export_config(config, dry_run):
|
||||
for target in config:
|
||||
export_patches(target, dry_run)
|
||||
|
||||
|
||||
def parse_args():
|
||||
@@ -28,7 +41,7 @@ def main():
|
||||
configs = parse_args().config
|
||||
dry_run = parse_args().dry_run
|
||||
for config_json in configs:
|
||||
export_patches(json.load(config_json), dry_run)
|
||||
export_config(json.load(config_json), dry_run)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -10,13 +10,15 @@ def main(argv):
|
||||
parser.add_argument("-o", "--output",
|
||||
help="directory into which exported patches will be written",
|
||||
required=True)
|
||||
parser.add_argument("--grep",
|
||||
help="only export patches matching a keyword")
|
||||
parser.add_argument("patch_range",
|
||||
nargs='?',
|
||||
help="range of patches to export. Defaults to all commits since the "
|
||||
"most recent tag or remote branch.")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
git.export_patches('.', args.output, patch_range=args.patch_range)
|
||||
git.export_patches('.', args.output, patch_range=args.patch_range, grep=args.grep)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -13,6 +13,9 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from .patches import PATCH_FILENAME_PREFIX, is_patch_location_line
|
||||
|
||||
UPSTREAM_HEAD='refs/patches/upstream-head'
|
||||
|
||||
def is_repo_root(path):
|
||||
path_exists = os.path.exists(path)
|
||||
@@ -75,14 +78,10 @@ def am(repo, patch_data, threeway=False, directory=None, exclude=None,
|
||||
proc.returncode))
|
||||
|
||||
|
||||
def import_patches(repo, **kwargs):
|
||||
def import_patches(repo, ref=UPSTREAM_HEAD, **kwargs):
|
||||
"""same as am(), but we save the upstream HEAD so we can refer to it when we
|
||||
later export patches"""
|
||||
update_ref(
|
||||
repo=repo,
|
||||
ref='refs/patches/upstream-head',
|
||||
newvalue='HEAD'
|
||||
)
|
||||
update_ref(repo=repo, ref=ref, newvalue='HEAD')
|
||||
am(repo=repo, **kwargs)
|
||||
|
||||
|
||||
@@ -92,32 +91,18 @@ def update_ref(repo, ref, newvalue):
|
||||
return subprocess.check_call(args)
|
||||
|
||||
|
||||
def get_upstream_head(repo):
|
||||
args = [
|
||||
'git',
|
||||
'-C',
|
||||
repo,
|
||||
'rev-parse',
|
||||
'--verify',
|
||||
'refs/patches/upstream-head',
|
||||
]
|
||||
def get_commit_for_ref(repo, ref):
|
||||
args = ['git', '-C', repo, 'rev-parse', '--verify', ref]
|
||||
return subprocess.check_output(args).decode('utf-8').strip()
|
||||
|
||||
def get_commit_count(repo, commit_range):
|
||||
args = [
|
||||
'git',
|
||||
'-C',
|
||||
repo,
|
||||
'rev-list',
|
||||
'--count',
|
||||
commit_range
|
||||
]
|
||||
args = ['git', '-C', repo, 'rev-list', '--count', commit_range]
|
||||
return int(subprocess.check_output(args).decode('utf-8').strip())
|
||||
|
||||
def guess_base_commit(repo):
|
||||
def guess_base_commit(repo, ref):
|
||||
"""Guess which commit the patches might be based on"""
|
||||
try:
|
||||
upstream_head = get_upstream_head(repo)
|
||||
upstream_head = get_commit_for_ref(repo, ref)
|
||||
num_commits = get_commit_count(repo, upstream_head + '..')
|
||||
return [upstream_head, num_commits]
|
||||
except subprocess.CalledProcessError:
|
||||
@@ -181,6 +166,16 @@ def split_patches(patch_data):
|
||||
patches[-1].append(line)
|
||||
return patches
|
||||
|
||||
def filter_patches(patches, key):
|
||||
"""Return patches that include the specified key"""
|
||||
if key is None:
|
||||
return patches
|
||||
matches = []
|
||||
for patch in patches:
|
||||
if any(key in line for line in patch):
|
||||
matches.append(patch)
|
||||
continue
|
||||
return matches
|
||||
|
||||
def munge_subject_to_filename(subject):
|
||||
"""Derive a suitable filename from a commit's subject"""
|
||||
@@ -193,8 +188,8 @@ def get_file_name(patch):
|
||||
"""Return the name of the file to which the patch should be written"""
|
||||
file_name = None
|
||||
for line in patch:
|
||||
if line.startswith('Patch-Filename: '):
|
||||
file_name = line[len('Patch-Filename: '):]
|
||||
if line.startswith(PATCH_FILENAME_PREFIX):
|
||||
file_name = line[len(PATCH_FILENAME_PREFIX):]
|
||||
break
|
||||
# If no patch-filename header, munge the subject.
|
||||
if not file_name:
|
||||
@@ -207,19 +202,18 @@ def get_file_name(patch):
|
||||
|
||||
def join_patch(patch):
|
||||
"""Joins and formats patch contents"""
|
||||
return ''.join(remove_patch_filename(patch)).rstrip('\n') + '\n'
|
||||
return ''.join(remove_patch_location(patch)).rstrip('\n') + '\n'
|
||||
|
||||
|
||||
def remove_patch_filename(patch):
|
||||
"""Strip out the Patch-Filename trailer from a patch's message body"""
|
||||
def remove_patch_location(patch):
|
||||
"""Strip out the patch location lines from a patch's message body"""
|
||||
force_keep_next_line = False
|
||||
n = len(patch)
|
||||
for i, l in enumerate(patch):
|
||||
is_patchfilename = l.startswith('Patch-Filename: ')
|
||||
next_is_patchfilename = i < len(patch) - 1 and patch[i + 1].startswith(
|
||||
'Patch-Filename: '
|
||||
)
|
||||
skip_line = is_patch_location_line(l)
|
||||
skip_next = i < n - 1 and is_patch_location_line(patch[i + 1])
|
||||
if not force_keep_next_line and (
|
||||
is_patchfilename or (next_is_patchfilename and len(l.rstrip()) == 0)
|
||||
skip_line or (skip_next and len(l.rstrip()) == 0)
|
||||
):
|
||||
pass # drop this line
|
||||
else:
|
||||
@@ -227,18 +221,24 @@ def remove_patch_filename(patch):
|
||||
force_keep_next_line = l.startswith('Subject: ')
|
||||
|
||||
|
||||
def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
def export_patches(repo, out_dir,
|
||||
patch_range=None, ref=UPSTREAM_HEAD,
|
||||
dry_run=False, grep=None):
|
||||
if not os.path.exists(repo):
|
||||
sys.stderr.write(
|
||||
"Skipping patches in {} because it does not exist.\n".format(repo)
|
||||
)
|
||||
return
|
||||
if patch_range is None:
|
||||
patch_range, num_patches = guess_base_commit(repo)
|
||||
patch_range, num_patches = guess_base_commit(repo, ref)
|
||||
sys.stderr.write("Exporting {} patches in {} since {}\n".format(
|
||||
num_patches, repo, patch_range[0:7]))
|
||||
patch_data = format_patch(repo, patch_range)
|
||||
patches = split_patches(patch_data)
|
||||
if grep:
|
||||
olen = len(patches)
|
||||
patches = filter_patches(patches, grep)
|
||||
sys.stderr.write("Exporting {} of {} patches\n".format(len(patches), olen))
|
||||
|
||||
try:
|
||||
os.mkdir(out_dir)
|
||||
|
||||
@@ -3,19 +3,27 @@
|
||||
import codecs
|
||||
import os
|
||||
|
||||
PATCH_DIR_PREFIX = "Patch-Dir: "
|
||||
PATCH_FILENAME_PREFIX = "Patch-Filename: "
|
||||
PATCH_LINE_PREFIXES = (PATCH_DIR_PREFIX, PATCH_FILENAME_PREFIX)
|
||||
|
||||
|
||||
def is_patch_location_line(line):
|
||||
return line.startswith(PATCH_LINE_PREFIXES)
|
||||
|
||||
def read_patch(patch_dir, patch_filename):
|
||||
"""Read a patch from |patch_dir/filename| and amend the commit message with
|
||||
metadata about the patch file it came from."""
|
||||
ret = []
|
||||
added_filename_line = False
|
||||
added_patch_location = False
|
||||
patch_path = os.path.join(patch_dir, patch_filename)
|
||||
with codecs.open(patch_path, encoding='utf-8') as f:
|
||||
for l in f.readlines():
|
||||
line_has_correct_start = l.startswith('diff -') or l.startswith('---')
|
||||
if not added_filename_line and line_has_correct_start:
|
||||
ret.append('Patch-Filename: {}\n'.format(patch_filename))
|
||||
added_filename_line = True
|
||||
if not added_patch_location and line_has_correct_start:
|
||||
ret.append('{}{}\n'.format(PATCH_DIR_PREFIX, patch_dir))
|
||||
ret.append('{}{}\n'.format(PATCH_FILENAME_PREFIX, patch_filename))
|
||||
added_patch_location = True
|
||||
ret.append(l)
|
||||
return ''.join(ret)
|
||||
|
||||
|
||||
@@ -201,10 +201,9 @@ const LINTERS = [{
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(patchesConfig, 'utf8'));
|
||||
for (const key of Object.keys(config)) {
|
||||
for (const target of JSON.parse(fs.readFileSync(patchesConfig, 'utf8'))) {
|
||||
// The directory the config points to should exist
|
||||
const targetPatchesDir = path.resolve(__dirname, '../../..', key);
|
||||
const targetPatchesDir = path.resolve(__dirname, '../../..', target.patch_dir);
|
||||
if (!fs.existsSync(targetPatchesDir)) {
|
||||
console.error(`target patch directory: "${targetPatchesDir}" does not exist`);
|
||||
process.exit(1);
|
||||
|
||||
@@ -12,7 +12,9 @@ from lib.patches import patch_from_dir
|
||||
|
||||
|
||||
def patched_file_paths(patches_config):
|
||||
for patch_dir, repo in patches_config.items():
|
||||
for target in patches_config:
|
||||
patch_dir = target.get('patch_dir')
|
||||
repo = target.get('repo')
|
||||
for line in patch_from_dir(patch_dir).split("\n"):
|
||||
if line.startswith("+++"):
|
||||
yield posixpath.join(repo, line[6:])
|
||||
|
||||
@@ -1681,7 +1681,7 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
|
||||
.SetMethod("setBadgeCount",
|
||||
base::BindRepeating(&Browser::SetBadgeCount, browser))
|
||||
.SetMethod("getBadgeCount",
|
||||
base::BindRepeating(&Browser::GetBadgeCount, browser))
|
||||
base::BindRepeating(&Browser::badge_count, browser))
|
||||
.SetMethod("getLoginItemSettings", &App::GetLoginItemSettings)
|
||||
.SetMethod("setLoginItemSettings",
|
||||
base::BindRepeating(&Browser::SetLoginItemSettings, browser))
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_capturer_wrapper.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_media_list.h"
|
||||
#include "chrome/browser/media/webrtc/thumbnail_capturer_mac.h"
|
||||
#include "chrome/browser/media/webrtc/window_icon_util.h"
|
||||
#include "content/public/browser/desktop_capture.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
@@ -136,6 +137,38 @@ std::map<int32_t, uint32_t> MonitorAtomIdToDisplayId() {
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
std::unique_ptr<ThumbnailCapturer> MakeWindowCapturer() {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
if (ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kWindow)) {
|
||||
return CreateThumbnailCapturerMac(DesktopMediaList::Type::kWindow);
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer =
|
||||
content::desktop_capture::CreateWindowCapturer();
|
||||
return window_capturer ? std::make_unique<DesktopCapturerWrapper>(
|
||||
std::move(window_capturer))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<ThumbnailCapturer> MakeScreenCapturer() {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
if (ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kScreen)) {
|
||||
return CreateThumbnailCapturerMac(DesktopMediaList::Type::kScreen);
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer =
|
||||
content::desktop_capture::CreateScreenCapturer();
|
||||
return screen_capturer ? std::make_unique<DesktopCapturerWrapper>(
|
||||
std::move(screen_capturer))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <>
|
||||
@@ -265,16 +298,16 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
// Initialize the source list.
|
||||
// Apply the new thumbnail size and restart capture.
|
||||
if (capture_window) {
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer =
|
||||
content::desktop_capture::CreateWindowCapturer();
|
||||
auto capturer = window_capturer
|
||||
? std::make_unique<DesktopCapturerWrapper>(
|
||||
std::move(window_capturer))
|
||||
: nullptr;
|
||||
auto capturer = MakeWindowCapturer();
|
||||
if (capturer) {
|
||||
window_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kWindow, std::move(capturer));
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
window_capturer_->skip_next_refresh_ =
|
||||
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kWindow) ? 2
|
||||
: 0;
|
||||
#endif
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
@@ -295,16 +328,16 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
}
|
||||
|
||||
if (capture_screen) {
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer =
|
||||
content::desktop_capture::CreateScreenCapturer();
|
||||
auto capturer = screen_capturer
|
||||
? std::make_unique<DesktopCapturerWrapper>(
|
||||
std::move(screen_capturer))
|
||||
: nullptr;
|
||||
auto capturer = MakeScreenCapturer();
|
||||
if (capturer) {
|
||||
screen_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kScreen, std::move(capturer));
|
||||
screen_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
screen_capturer_->skip_next_refresh_ =
|
||||
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kScreen) ? 2
|
||||
: 0;
|
||||
#endif
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
|
||||
@@ -31,7 +31,7 @@ bool IsEncryptionAvailable() {
|
||||
return OSCrypt::IsEncryptionAvailable() ||
|
||||
(use_password_v10 &&
|
||||
static_cast<BrowserProcessImpl*>(g_browser_process)
|
||||
->GetLinuxStorageBackend() == "basic_text");
|
||||
->linux_storage_backend() == "basic_text");
|
||||
#else
|
||||
return OSCrypt::IsEncryptionAvailable();
|
||||
#endif
|
||||
@@ -46,7 +46,7 @@ std::string GetSelectedLinuxBackend() {
|
||||
if (!Browser::Get()->is_ready())
|
||||
return "unknown";
|
||||
return static_cast<BrowserProcessImpl*>(g_browser_process)
|
||||
->GetLinuxStorageBackend();
|
||||
->linux_storage_backend();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -859,7 +859,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
|
||||
std::unique_ptr<content::WebContents> web_contents;
|
||||
if (IsGuest()) {
|
||||
if (is_guest()) {
|
||||
scoped_refptr<content::SiteInstance> site_instance =
|
||||
content::SiteInstance::CreateForURL(session->browser_context(),
|
||||
GURL("chrome-guest://fake-host"));
|
||||
@@ -929,7 +929,7 @@ void WebContents::InitWithSessionAndOptions(
|
||||
const gin_helper::Dictionary& options) {
|
||||
Observe(owned_web_contents.get());
|
||||
InitWithWebContents(std::move(owned_web_contents), session->browser_context(),
|
||||
IsGuest());
|
||||
is_guest());
|
||||
|
||||
inspectable_web_contents_->GetView()->SetDelegate(this);
|
||||
|
||||
@@ -989,7 +989,7 @@ void WebContents::InitWithSessionAndOptions(
|
||||
|
||||
SetUserAgent(GetBrowserContext()->GetUserAgent());
|
||||
|
||||
if (IsGuest()) {
|
||||
if (is_guest()) {
|
||||
NativeWindow* owner_window = nullptr;
|
||||
if (embedder_) {
|
||||
// New WebContents's owner_window is the embedder's owner_window.
|
||||
@@ -1024,7 +1024,7 @@ void WebContents::InitWithExtensionView(v8::Isolate* isolate,
|
||||
// Allow toggling DevTools for background pages
|
||||
Observe(web_contents);
|
||||
InitWithWebContents(std::unique_ptr<content::WebContents>(web_contents),
|
||||
GetBrowserContext(), IsGuest());
|
||||
GetBrowserContext(), is_guest());
|
||||
inspectable_web_contents_->GetView()->SetDelegate(this);
|
||||
}
|
||||
#endif
|
||||
@@ -1073,7 +1073,7 @@ WebContents::~WebContents() {
|
||||
|
||||
// For guest view based on OOPIF, the WebContents is released by the embedder
|
||||
// frame, and we need to clear the reference to the memory.
|
||||
bool not_owned_by_this = IsGuest() && attached_;
|
||||
bool not_owned_by_this = is_guest() && attached_;
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
// And background pages are owned by extensions::ExtensionHost.
|
||||
if (type_ == Type::kBackgroundPage)
|
||||
@@ -1103,7 +1103,7 @@ void WebContents::DeleteThisIfAlive() {
|
||||
void WebContents::Destroy() {
|
||||
// The content::WebContents should be destroyed asynchronously when possible
|
||||
// as user may choose to destroy WebContents during an event of it.
|
||||
if (Browser::Get()->is_shutting_down() || IsGuest()) {
|
||||
if (Browser::Get()->is_shutting_down() || is_guest()) {
|
||||
DeleteThisIfAlive();
|
||||
} else {
|
||||
content::GetUIThreadTaskRunner({})->PostTask(
|
||||
@@ -1317,7 +1317,7 @@ void WebContents::CloseContents(content::WebContents* source) {
|
||||
observer.OnCloseContents();
|
||||
|
||||
// This is handled by the embedder frame.
|
||||
if (!IsGuest())
|
||||
if (!is_guest())
|
||||
Destroy();
|
||||
}
|
||||
|
||||
@@ -1631,7 +1631,7 @@ void WebContents::HandleNewRenderFrame(
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents());
|
||||
if (web_preferences) {
|
||||
auto maybe_color = web_preferences->GetBackgroundColor();
|
||||
bool guest = IsGuest() || type_ == Type::kBrowserView;
|
||||
bool guest = is_guest() || type_ == Type::kBrowserView;
|
||||
|
||||
// If webPreferences has no color stored we need to explicitly set guest
|
||||
// webContents background color to transparent.
|
||||
@@ -2134,7 +2134,7 @@ void WebContents::DidFinishNavigation(
|
||||
Emit("did-navigate", url, http_response_code, http_status_text);
|
||||
}
|
||||
}
|
||||
if (IsGuest())
|
||||
if (is_guest())
|
||||
Emit("load-commit", url, is_main_frame);
|
||||
} else {
|
||||
auto url = navigation_handle->GetURL();
|
||||
@@ -2348,10 +2348,6 @@ base::ProcessId WebContents::GetOSProcessID() const {
|
||||
return base::GetProcId(process_handle);
|
||||
}
|
||||
|
||||
WebContents::Type WebContents::GetType() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
bool WebContents::Equal(const WebContents* web_contents) const {
|
||||
return ID() == web_contents->ID();
|
||||
}
|
||||
@@ -3345,7 +3341,7 @@ bool WebContents::IsFocused() const {
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
if (GetType() != Type::kBackgroundPage) {
|
||||
if (type() != Type::kBackgroundPage) {
|
||||
auto* window = web_contents()->GetNativeView()->GetToplevelWindow();
|
||||
if (window && !window->IsVisible())
|
||||
return false;
|
||||
@@ -3541,10 +3537,6 @@ void WebContents::OnCursorChanged(const ui::Cursor& cursor) {
|
||||
}
|
||||
}
|
||||
|
||||
bool WebContents::IsGuest() const {
|
||||
return type_ == Type::kWebView;
|
||||
}
|
||||
|
||||
void WebContents::AttachToIframe(content::WebContents* embedder_web_contents,
|
||||
int embedder_frame_id) {
|
||||
attached_ = true;
|
||||
@@ -4260,7 +4252,7 @@ void WebContents::UpdateHtmlApiFullscreen(bool fullscreen) {
|
||||
}
|
||||
|
||||
// Make sure all child webviews quit html fullscreen.
|
||||
if (!fullscreen && !IsGuest()) {
|
||||
if (!fullscreen && !is_guest()) {
|
||||
auto* manager = WebViewManager::GetWebViewManager(web_contents());
|
||||
manager->ForEachGuest(web_contents(), [&](content::WebContents* guest) {
|
||||
WebContents* api_web_contents = WebContents::From(guest);
|
||||
@@ -4372,7 +4364,7 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
|
||||
.SetMethod("getZoomLevel", &WebContents::GetZoomLevel)
|
||||
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
|
||||
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
|
||||
.SetMethod("getType", &WebContents::GetType)
|
||||
.SetMethod("getType", &WebContents::type)
|
||||
.SetMethod("_getPreloadPaths", &WebContents::GetPreloadPaths)
|
||||
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
|
||||
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
||||
|
||||
@@ -169,7 +169,7 @@ class WebContents : public ExclusiveAccessContext,
|
||||
void SetBackgroundThrottling(bool allowed);
|
||||
int GetProcessID() const;
|
||||
base::ProcessId GetOSProcessID() const;
|
||||
Type GetType() const;
|
||||
[[nodiscard]] Type type() const { return type_; }
|
||||
bool Equal(const WebContents* web_contents) const;
|
||||
void LoadURL(const GURL& url, const gin_helper::Dictionary& options);
|
||||
void Reload();
|
||||
@@ -288,7 +288,7 @@ class WebContents : public ExclusiveAccessContext,
|
||||
v8::Local<v8::Promise> CapturePage(gin::Arguments* args);
|
||||
|
||||
// Methods for creating <webview>.
|
||||
bool IsGuest() const;
|
||||
[[nodiscard]] bool is_guest() const { return type_ == Type::kWebView; }
|
||||
void AttachToIframe(content::WebContents* embedder_web_contents,
|
||||
int embedder_frame_id);
|
||||
void DetachFromOuterFrame();
|
||||
|
||||
@@ -24,7 +24,7 @@ bool WebContents::IsFocused() const {
|
||||
if (!view)
|
||||
return false;
|
||||
|
||||
if (GetType() != Type::kBackgroundPage) {
|
||||
if (type() != Type::kBackgroundPage) {
|
||||
auto window = [web_contents()->GetNativeView().GetNativeNSView() window];
|
||||
// On Mac the render widget host view does not lose focus when the window
|
||||
// loses focus so check if the top level window is the key window.
|
||||
|
||||
@@ -159,10 +159,6 @@ void Browser::SetName(const std::string& name) {
|
||||
OverriddenApplicationName() = name;
|
||||
}
|
||||
|
||||
int Browser::GetBadgeCount() {
|
||||
return badge_count_;
|
||||
}
|
||||
|
||||
bool Browser::OpenFile(const std::string& file_path) {
|
||||
bool prevent_default = false;
|
||||
for (BrowserObserver& observer : observers_)
|
||||
|
||||
@@ -110,7 +110,7 @@ class Browser : public WindowListObserver {
|
||||
|
||||
// Set/Get the badge count.
|
||||
bool SetBadgeCount(std::optional<int> count);
|
||||
int GetBadgeCount();
|
||||
[[nodiscard]] int badge_count() const { return badge_count_; }
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
struct LaunchItem {
|
||||
|
||||
@@ -340,10 +340,6 @@ void BrowserProcessImpl::SetLinuxStorageBackend(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& BrowserProcessImpl::GetLinuxStorageBackend() const {
|
||||
return selected_linux_storage_backend_;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_LINUX)
|
||||
|
||||
void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {
|
||||
|
||||
@@ -59,7 +59,9 @@ class BrowserProcessImpl : public BrowserProcess {
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
void SetLinuxStorageBackend(os_crypt::SelectedLinuxBackend selected_backend);
|
||||
const std::string& GetLinuxStorageBackend() const;
|
||||
[[nodiscard]] const std::string& linux_storage_backend() const {
|
||||
return selected_linux_storage_backend_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void EndSession() override {}
|
||||
|
||||
@@ -518,14 +518,6 @@ bool NativeWindow::IsMenuBarVisible() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
double NativeWindow::GetAspectRatio() const {
|
||||
return aspect_ratio_;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetAspectRatioExtraSize() const {
|
||||
return aspect_ratio_extraSize_;
|
||||
}
|
||||
|
||||
void NativeWindow::SetAspectRatio(double aspect_ratio,
|
||||
const gfx::Size& extra_size) {
|
||||
aspect_ratio_ = aspect_ratio;
|
||||
@@ -763,6 +755,11 @@ int NativeWindow::NonClientHitTest(const gfx::Point& point) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// This is to disable dragging in HTML5 full screen mode.
|
||||
// Details: https://github.com/electron/electron/issues/41002
|
||||
if (GetWidget()->IsFullscreen())
|
||||
return HTNOWHERE;
|
||||
|
||||
for (auto* provider : draggable_region_providers_) {
|
||||
int hit = provider->NonClientHitTest(point);
|
||||
if (hit != HTNOWHERE)
|
||||
|
||||
@@ -265,8 +265,10 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual bool IsMenuBarVisible() const;
|
||||
|
||||
// Set the aspect ratio when resizing window.
|
||||
double GetAspectRatio() const;
|
||||
gfx::Size GetAspectRatioExtraSize() const;
|
||||
[[nodiscard]] double aspect_ratio() const { return aspect_ratio_; }
|
||||
[[nodiscard]] gfx::Size aspect_ratio_extra_size() const {
|
||||
return aspect_ratio_extraSize_;
|
||||
}
|
||||
virtual void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
|
||||
|
||||
// File preview APIs.
|
||||
|
||||
@@ -447,11 +447,14 @@ void NativeWindowMac::Close() {
|
||||
if ([window_ attachedSheet])
|
||||
[window_ endSheet:[window_ attachedSheet]];
|
||||
|
||||
// window_ could be nil after performClose.
|
||||
bool should_notify = is_modal() && parent() && IsVisible();
|
||||
|
||||
[window_ performClose:nil];
|
||||
|
||||
// Closing a sheet doesn't trigger windowShouldClose,
|
||||
// so we need to manually call it ourselves here.
|
||||
if (is_modal() && parent() && IsVisible()) {
|
||||
if (should_notify) {
|
||||
NotifyWindowCloseButtonClicked();
|
||||
}
|
||||
}
|
||||
@@ -646,7 +649,7 @@ bool NativeWindowMac::IsMaximized() const {
|
||||
if (HasStyleMask(NSWindowStyleMaskResizable) != 0)
|
||||
return [window_ isZoomed];
|
||||
|
||||
NSRect rectScreen = GetAspectRatio() > 0.0
|
||||
NSRect rectScreen = aspect_ratio() > 0.0
|
||||
? default_frame_for_zoom()
|
||||
: [[NSScreen mainScreen] visibleFrame];
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ void AutofillPopup::SetItems(const std::vector<std::u16string>& values,
|
||||
void AutofillPopup::AcceptSuggestion(int index) {
|
||||
mojo::AssociatedRemote<mojom::ElectronAutofillAgent> autofill_agent;
|
||||
frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(&autofill_agent);
|
||||
autofill_agent->AcceptDataListSuggestion(GetValueAt(index));
|
||||
autofill_agent->AcceptDataListSuggestion(value_at(index));
|
||||
}
|
||||
|
||||
void AutofillPopup::UpdatePopupBounds() {
|
||||
@@ -272,11 +272,10 @@ int AutofillPopup::GetDesiredPopupWidth() {
|
||||
int popup_width = element_bounds_.width();
|
||||
|
||||
for (size_t i = 0; i < values_.size(); ++i) {
|
||||
int row_size =
|
||||
kEndPadding + 2 * kPopupBorderThickness +
|
||||
gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) +
|
||||
gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i));
|
||||
if (!GetLabelAt(i).empty())
|
||||
int row_size = kEndPadding + 2 * kPopupBorderThickness +
|
||||
gfx::GetStringWidth(value_at(i), GetValueFontListForRow(i)) +
|
||||
gfx::GetStringWidth(label_at(i), GetLabelFontListForRow(i));
|
||||
if (!label_at(i).empty())
|
||||
row_size += kNamePadding + kEndPadding;
|
||||
|
||||
popup_width = std::max(popup_width, row_size);
|
||||
@@ -307,18 +306,6 @@ ui::ColorId AutofillPopup::GetBackgroundColorIDForRow(int index) const {
|
||||
: ui::kColorResultsTableNormalBackground;
|
||||
}
|
||||
|
||||
int AutofillPopup::GetLineCount() {
|
||||
return values_.size();
|
||||
}
|
||||
|
||||
std::u16string AutofillPopup::GetValueAt(int i) {
|
||||
return values_.at(i);
|
||||
}
|
||||
|
||||
std::u16string AutofillPopup::GetLabelAt(int i) {
|
||||
return labels_.at(i);
|
||||
}
|
||||
|
||||
int AutofillPopup::LineFromY(int y) const {
|
||||
int current_height = kPopupBorderThickness;
|
||||
|
||||
|
||||
@@ -57,9 +57,9 @@ class AutofillPopup : public views::ViewObserver {
|
||||
const gfx::FontList& GetLabelFontListForRow(int index) const;
|
||||
ui::ColorId GetBackgroundColorIDForRow(int index) const;
|
||||
|
||||
int GetLineCount();
|
||||
std::u16string GetValueAt(int i);
|
||||
std::u16string GetLabelAt(int i);
|
||||
int line_count() const { return values_.size(); }
|
||||
const std::u16string& value_at(int i) const { return values_.at(i); }
|
||||
const std::u16string& label_at(int i) const { return labels_.at(i); }
|
||||
int LineFromY(int y) const;
|
||||
|
||||
int selected_index_;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
devtools_is_first_responder_ = NO;
|
||||
attached_to_window_ = NO;
|
||||
|
||||
if (inspectableWebContentsView_->inspectable_web_contents()->IsGuest()) {
|
||||
if (inspectableWebContentsView_->inspectable_web_contents()->is_guest()) {
|
||||
fake_view_ = [[NSView alloc] init];
|
||||
[fake_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
[self addSubview:fake_view_];
|
||||
|
||||
@@ -493,8 +493,8 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
|
||||
if (menu_)
|
||||
return menu_;
|
||||
|
||||
if (model_ && model_->GetSharingItem()) {
|
||||
NSMenu* menu = [self createShareMenuForItem:*model_->GetSharingItem()];
|
||||
if (model_ && model_->sharing_item()) {
|
||||
NSMenu* menu = [self createShareMenuForItem:*model_->sharing_item()];
|
||||
menu_ = menu;
|
||||
} else {
|
||||
menu_ = [[NSMenu alloc] initWithTitle:@""];
|
||||
|
||||
@@ -76,7 +76,7 @@ using FullScreenTransitionState =
|
||||
- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
|
||||
defaultFrame:(NSRect)frame {
|
||||
if (!shell_->zoom_to_page_width()) {
|
||||
if (shell_->GetAspectRatio() > 0.0)
|
||||
if (shell_->aspect_ratio() > 0.0)
|
||||
shell_->set_default_frame_for_zoom(frame);
|
||||
return frame;
|
||||
}
|
||||
@@ -104,7 +104,7 @@ using FullScreenTransitionState =
|
||||
// Set the width. Don't touch y or height.
|
||||
frame.size.width = zoomed_width;
|
||||
|
||||
if (shell_->GetAspectRatio() > 0.0)
|
||||
if (shell_->aspect_ratio() > 0.0)
|
||||
shell_->set_default_frame_for_zoom(frame);
|
||||
|
||||
return frame;
|
||||
@@ -139,13 +139,12 @@ using FullScreenTransitionState =
|
||||
|
||||
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
|
||||
NSSize newSize = frameSize;
|
||||
double aspectRatio = shell_->GetAspectRatio();
|
||||
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
|
||||
|
||||
if (aspectRatio > 0.0) {
|
||||
gfx::Size windowSize = shell_->GetSize();
|
||||
gfx::Size contentSize = shell_->GetContentSize();
|
||||
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
|
||||
if (const double aspectRatio = shell_->aspect_ratio(); aspectRatio > 0.0) {
|
||||
const gfx::Size windowSize = shell_->GetSize();
|
||||
const gfx::Size contentSize = shell_->GetContentSize();
|
||||
const gfx::Size extraSize = shell_->aspect_ratio_extra_size();
|
||||
|
||||
double titleBarHeight = windowSize.height() - contentSize.height();
|
||||
double extraWidthPlusFrame =
|
||||
|
||||
@@ -99,11 +99,6 @@ bool ElectronMenuModel::GetSharingItemAt(size_t index,
|
||||
void ElectronMenuModel::SetSharingItem(SharingItem item) {
|
||||
sharing_item_.emplace(std::move(item));
|
||||
}
|
||||
|
||||
const std::optional<ElectronMenuModel::SharingItem>&
|
||||
ElectronMenuModel::GetSharingItem() const {
|
||||
return sharing_item_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ElectronMenuModel::MenuWillClose() {
|
||||
|
||||
@@ -98,7 +98,10 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
|
||||
bool GetSharingItemAt(size_t index, SharingItem* item) const;
|
||||
// Set/Get the SharingItem of this menu.
|
||||
void SetSharingItem(SharingItem item);
|
||||
const std::optional<SharingItem>& GetSharingItem() const;
|
||||
[[nodiscard]] const std::optional<SharingItem>& sharing_item() const {
|
||||
return sharing_item_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ui::SimpleMenuModel:
|
||||
|
||||
@@ -385,10 +385,6 @@ InspectableWebContentsDelegate* InspectableWebContents::GetDelegate() const {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
bool InspectableWebContents::IsGuest() const {
|
||||
return is_guest_;
|
||||
}
|
||||
|
||||
void InspectableWebContents::ReleaseWebContents() {
|
||||
web_contents_.release();
|
||||
WebContentsDestroyed();
|
||||
@@ -455,7 +451,7 @@ void InspectableWebContents::CloseDevTools() {
|
||||
managed_devtools_web_contents_.reset();
|
||||
}
|
||||
embedder_message_dispatcher_.reset();
|
||||
if (!IsGuest())
|
||||
if (!is_guest())
|
||||
web_contents_->Focus();
|
||||
}
|
||||
}
|
||||
@@ -517,10 +513,6 @@ void InspectableWebContents::CallClientFunction(
|
||||
std::move(arguments), std::move(cb));
|
||||
}
|
||||
|
||||
gfx::Rect InspectableWebContents::GetDevToolsBounds() const {
|
||||
return devtools_bounds_;
|
||||
}
|
||||
|
||||
void InspectableWebContents::SaveDevToolsBounds(const gfx::Rect& bounds) {
|
||||
pref_service_->Set(kDevToolsBoundsPref,
|
||||
base::Value{RectToDictionary(bounds)});
|
||||
|
||||
@@ -55,7 +55,7 @@ class InspectableWebContents
|
||||
|
||||
void SetDelegate(InspectableWebContentsDelegate* delegate);
|
||||
InspectableWebContentsDelegate* GetDelegate() const;
|
||||
bool IsGuest() const;
|
||||
[[nodiscard]] bool is_guest() const { return is_guest_; }
|
||||
void ReleaseWebContents();
|
||||
void SetDevToolsWebContents(content::WebContents* devtools);
|
||||
void SetDockState(const std::string& state);
|
||||
@@ -76,7 +76,9 @@ class InspectableWebContents
|
||||
void InspectElement(int x, int y);
|
||||
|
||||
// Return the last position and size of devtools window.
|
||||
gfx::Rect GetDevToolsBounds() const;
|
||||
[[nodiscard]] const gfx::Rect& dev_tools_bounds() const {
|
||||
return devtools_bounds_;
|
||||
}
|
||||
void SaveDevToolsBounds(const gfx::Rect& bounds);
|
||||
|
||||
// Return the last set zoom level of devtools window.
|
||||
|
||||
@@ -124,7 +124,7 @@ void AutofillPopupView::OnSuggestionsChanged() {
|
||||
return;
|
||||
|
||||
CreateChildViews();
|
||||
if (popup_->GetLineCount() == 0) {
|
||||
if (popup_->line_count() == 0) {
|
||||
popup_->Hide();
|
||||
return;
|
||||
}
|
||||
@@ -177,28 +177,28 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas,
|
||||
|
||||
int x_align_left = value_rect.x();
|
||||
const int value_width = gfx::GetStringWidth(
|
||||
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index));
|
||||
popup_->value_at(index), popup_->GetValueFontListForRow(index));
|
||||
int value_x_align_left = x_align_left;
|
||||
value_x_align_left =
|
||||
is_rtl ? value_rect.right() - value_width : value_rect.x();
|
||||
|
||||
canvas->DrawStringRectWithFlags(
|
||||
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index),
|
||||
popup_->value_at(index), popup_->GetValueFontListForRow(index),
|
||||
GetColorProvider()->GetColor(ui::kColorResultsTableNormalText),
|
||||
gfx::Rect(value_x_align_left, value_rect.y(), value_width,
|
||||
value_rect.height()),
|
||||
text_align);
|
||||
|
||||
// Draw the label text, if one exists.
|
||||
if (!popup_->GetLabelAt(index).empty()) {
|
||||
const int label_width = gfx::GetStringWidth(
|
||||
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index));
|
||||
if (auto const& label = popup_->label_at(index); !label.empty()) {
|
||||
const int label_width =
|
||||
gfx::GetStringWidth(label, popup_->GetLabelFontListForRow(index));
|
||||
int label_x_align_left = x_align_left;
|
||||
label_x_align_left =
|
||||
is_rtl ? value_rect.x() : value_rect.right() - label_width;
|
||||
|
||||
canvas->DrawStringRectWithFlags(
|
||||
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index),
|
||||
label, popup_->GetLabelFontListForRow(index),
|
||||
GetColorProvider()->GetColor(ui::kColorResultsTableDimmedText),
|
||||
gfx::Rect(label_x_align_left, entry_rect.y(), label_width,
|
||||
entry_rect.height()),
|
||||
@@ -212,8 +212,8 @@ void AutofillPopupView::CreateChildViews() {
|
||||
|
||||
RemoveAllChildViews();
|
||||
|
||||
for (int i = 0; i < popup_->GetLineCount(); ++i) {
|
||||
auto* child_view = new AutofillPopupChildView(popup_->GetValueAt(i));
|
||||
for (int i = 0; i < popup_->line_count(); ++i) {
|
||||
auto* child_view = new AutofillPopupChildView(popup_->value_at(i));
|
||||
child_view->set_drag_controller(this);
|
||||
AddChildView(child_view);
|
||||
}
|
||||
@@ -234,8 +234,7 @@ void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() {
|
||||
}
|
||||
|
||||
void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
|
||||
if (!popup_ ||
|
||||
static_cast<size_t>(popup_->GetLineCount()) != children().size())
|
||||
if (!popup_ || static_cast<size_t>(popup_->line_count()) != children().size())
|
||||
return;
|
||||
gfx::Canvas* draw_canvas = canvas;
|
||||
SkBitmap bitmap;
|
||||
@@ -252,7 +251,7 @@ void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
|
||||
GetColorProvider()->GetColor(ui::kColorResultsTableNormalBackground));
|
||||
OnPaintBorder(draw_canvas);
|
||||
|
||||
for (int i = 0; i < popup_->GetLineCount(); ++i) {
|
||||
for (int i = 0; i < popup_->line_count(); ++i) {
|
||||
gfx::Rect line_rect = popup_->GetRowBounds(i);
|
||||
|
||||
DrawAutofillEntry(draw_canvas, i, line_rect);
|
||||
@@ -381,7 +380,7 @@ bool AutofillPopupView::HandleKeyPressEvent(
|
||||
SetSelectedLine(0);
|
||||
return true;
|
||||
case ui::VKEY_NEXT: // Page down.
|
||||
SetSelectedLine(popup_->GetLineCount() - 1);
|
||||
SetSelectedLine(popup_->line_count() - 1);
|
||||
return true;
|
||||
case ui::VKEY_ESCAPE:
|
||||
popup_->Hide();
|
||||
@@ -421,7 +420,7 @@ void AutofillPopupView::AcceptSuggestion(int index) {
|
||||
}
|
||||
|
||||
bool AutofillPopupView::AcceptSelectedLine() {
|
||||
if (!selected_line_ || selected_line_.value() >= popup_->GetLineCount())
|
||||
if (!selected_line_ || selected_line_.value() >= popup_->line_count())
|
||||
return false;
|
||||
|
||||
AcceptSuggestion(selected_line_.value());
|
||||
@@ -441,7 +440,7 @@ void AutofillPopupView::SetSelectedLine(std::optional<int> selected_line) {
|
||||
return;
|
||||
if (selected_line_ == selected_line)
|
||||
return;
|
||||
if (selected_line && selected_line.value() >= popup_->GetLineCount())
|
||||
if (selected_line && selected_line.value() >= popup_->line_count())
|
||||
return;
|
||||
|
||||
auto previous_selected_line(selected_line_);
|
||||
@@ -461,7 +460,7 @@ void AutofillPopupView::SelectNextLine() {
|
||||
return;
|
||||
|
||||
int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0;
|
||||
if (new_selected_line >= popup_->GetLineCount())
|
||||
if (new_selected_line >= popup_->line_count())
|
||||
new_selected_line = 0;
|
||||
|
||||
SetSelectedLine(new_selected_line);
|
||||
@@ -473,7 +472,7 @@ void AutofillPopupView::SelectPreviousLine() {
|
||||
|
||||
int new_selected_line = selected_line_.value_or(0) - 1;
|
||||
if (new_selected_line < 0)
|
||||
new_selected_line = popup_->GetLineCount() - 1;
|
||||
new_selected_line = popup_->line_count() - 1;
|
||||
|
||||
SetSelectedLine(new_selected_line);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ InspectableWebContentsViewViews::InspectableWebContentsViewViews(
|
||||
: InspectableWebContentsView(inspectable_web_contents),
|
||||
devtools_web_view_(new views::WebView(nullptr)),
|
||||
title_(u"Developer Tools") {
|
||||
if (!inspectable_web_contents_->IsGuest() &&
|
||||
if (!inspectable_web_contents_->is_guest() &&
|
||||
inspectable_web_contents_->GetWebContents()->GetNativeView()) {
|
||||
auto* contents_web_view = new views::WebView(nullptr);
|
||||
contents_web_view->SetWebContents(
|
||||
@@ -116,8 +116,7 @@ void InspectableWebContentsViewViews::ShowDevTools(bool activate) {
|
||||
if (devtools_window_) {
|
||||
devtools_window_web_view_->SetWebContents(
|
||||
inspectable_web_contents_->GetDevToolsWebContents());
|
||||
devtools_window_->SetBounds(
|
||||
inspectable_web_contents()->GetDevToolsBounds());
|
||||
devtools_window_->SetBounds(inspectable_web_contents()->dev_tools_bounds());
|
||||
if (activate) {
|
||||
devtools_window_->Show();
|
||||
} else {
|
||||
@@ -182,7 +181,7 @@ void InspectableWebContentsViewViews::SetIsDocked(bool docked, bool activate) {
|
||||
views::Widget::InitParams params;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
params.delegate = devtools_window_delegate_;
|
||||
params.bounds = inspectable_web_contents()->GetDevToolsBounds();
|
||||
params.bounds = inspectable_web_contents()->dev_tools_bounds();
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
params.wm_role_name = "devtools";
|
||||
|
||||
@@ -127,6 +127,8 @@ ELECTRON_TESTING_BINDINGS(V)
|
||||
#endif
|
||||
#undef V
|
||||
|
||||
using node::loader::ModuleWrap;
|
||||
|
||||
namespace {
|
||||
|
||||
void stop_and_close_uv_loop(uv_loop_t* loop) {
|
||||
@@ -217,16 +219,24 @@ v8::MaybeLocal<v8::Promise> HostImportModuleDynamically(
|
||||
void HostInitializeImportMetaObject(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Module> module,
|
||||
v8::Local<v8::Object> meta) {
|
||||
if (node::Environment::GetCurrent(context) == nullptr) {
|
||||
node::Environment* env = node::Environment::GetCurrent(context);
|
||||
if (env == nullptr) {
|
||||
if (electron::IsBrowserProcess() || electron::IsUtilityProcess())
|
||||
return;
|
||||
return blink::V8Initializer::HostGetImportMetaProperties(context, module,
|
||||
meta);
|
||||
}
|
||||
|
||||
// If we're running with contextIsolation enabled in the renderer process,
|
||||
// fall back to Blink's logic.
|
||||
if (electron::IsRendererProcess()) {
|
||||
// If the module is created by Node.js, use Node.js' handling.
|
||||
if (env != nullptr) {
|
||||
ModuleWrap* wrap = ModuleWrap::GetFromModule(env, module);
|
||||
if (wrap)
|
||||
return ModuleWrap::HostInitializeImportMetaObjectCallback(context,
|
||||
module, meta);
|
||||
}
|
||||
|
||||
// If contextIsolation is enabled, fall back to Blink's handling.
|
||||
blink::WebLocalFrame* frame =
|
||||
blink::WebLocalFrame::FrameForContext(context);
|
||||
if (!frame || frame->GetScriptContextWorldId(context) !=
|
||||
@@ -236,8 +246,8 @@ void HostInitializeImportMetaObject(v8::Local<v8::Context> context,
|
||||
}
|
||||
}
|
||||
|
||||
return node::loader::ModuleWrap::HostInitializeImportMetaObjectCallback(
|
||||
context, module, meta);
|
||||
return ModuleWrap::HostInitializeImportMetaObjectCallback(context, module,
|
||||
meta);
|
||||
}
|
||||
|
||||
v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
|
||||
|
||||
@@ -57,10 +57,10 @@ ElectronRenderFrameObserver::ElectronRenderFrameObserver(
|
||||
// Initialise resource for directory listing.
|
||||
net::NetModule::SetResourceProvider(NetResourceProvider);
|
||||
|
||||
// App regions are only supported in the main frame.
|
||||
auto* main_frame = frame->GetMainRenderFrame();
|
||||
if (main_frame && main_frame == frame)
|
||||
render_frame_->GetWebView()->SetSupportsAppRegion(true);
|
||||
// In Chrome, app regions are only supported in the main frame.
|
||||
// However, we need to support draggable regions on other
|
||||
// local frames/windows, so extend support beyond the main frame.
|
||||
render_frame_->GetWebView()->SetSupportsAppRegion(true);
|
||||
}
|
||||
|
||||
void ElectronRenderFrameObserver::DidClearWindowObject() {
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "shell/renderer/electron_autofill_agent.h"
|
||||
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
|
||||
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
|
||||
#include "third_party/blink/public/platform/web_runtime_features.h"
|
||||
#include "third_party/blink/public/web/blink.h"
|
||||
#include "third_party/blink/public/web/web_custom_element.h" // NOLINT(build/include_alpha)
|
||||
#include "third_party/blink/public/web/web_frame_widget.h"
|
||||
@@ -225,6 +226,14 @@ bool RendererClientBase::ShouldLoadPreload(
|
||||
void RendererClientBase::RenderThreadStarted() {
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
// Enable MessagePort close event by default.
|
||||
// The feature got reverted from stable to test in
|
||||
// https://chromium-review.googlesource.com/c/chromium/src/+/5276821
|
||||
// We had the event supported through patch before upstream support,
|
||||
// this is an alternative option than restoring our patch.
|
||||
blink::WebRuntimeFeatures::EnableFeatureFromString("MessagePortCloseEvent",
|
||||
true);
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
auto* thread = content::RenderThread::Get();
|
||||
|
||||
|
||||
@@ -61,6 +61,12 @@ class NodeService : public node::mojom::NodeService {
|
||||
void Initialize(node::mojom::NodeServiceParamsPtr params) override;
|
||||
|
||||
private:
|
||||
// This needs to be initialized first so that it can be destroyed last
|
||||
// after the node::Environment is destroyed. This ensures that if
|
||||
// there are crashes in the node::Environment destructor, they
|
||||
// will be propagated to the exit handler.
|
||||
mojo::Receiver<node::mojom::NodeService> receiver_{this};
|
||||
|
||||
bool node_env_stopped_ = false;
|
||||
|
||||
const std::unique_ptr<NodeBindings> node_bindings_;
|
||||
@@ -73,8 +79,6 @@ class NodeService : public node::mojom::NodeService {
|
||||
|
||||
// depends-on: js_env_'s isolate
|
||||
std::shared_ptr<node::Environment> node_env_;
|
||||
|
||||
mojo::Receiver<node::mojom::NodeService> receiver_{this};
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -11,7 +11,7 @@ import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersLi
|
||||
import { emittedUntil, emittedNTimes } from './lib/events-helpers';
|
||||
import { ifit, ifdescribe, defer, listen } from './lib/spec-helpers';
|
||||
import { closeWindow, closeAllWindows } from './lib/window-helpers';
|
||||
import { areColorsSimilar, captureScreen, HexColors, getPixelColor } from './lib/screen-helpers';
|
||||
import { areColorsSimilar, captureScreen, HexColors, getPixelColor, hasCapturableScreen } from './lib/screen-helpers';
|
||||
import { once } from 'node:events';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import { setTimeout as syncSetTimeout } from 'node:timers';
|
||||
@@ -6599,4 +6599,117 @@ describe('BrowserWindow module', () => {
|
||||
expect(areColorsSimilar(centerColor, HexColors.BLUE)).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('draggable regions', () => {
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
ifit(hasCapturableScreen())('should allow the window to be dragged when enabled', async () => {
|
||||
// WOA fails to load libnut so we're using require to defer loading only
|
||||
// on supported platforms.
|
||||
// "@nut-tree\libnut-win32\build\Release\libnut.node is not a valid Win32 application."
|
||||
// @ts-ignore: nut-js is an optional dependency so it may not be installed
|
||||
const { mouse, straightTo, centerOf, Region, Button } = require('@nut-tree/nut-js') as typeof import('@nut-tree/nut-js');
|
||||
|
||||
const display = screen.getPrimaryDisplay();
|
||||
|
||||
const w = new BrowserWindow({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: display.bounds.width / 2,
|
||||
height: display.bounds.height / 2,
|
||||
frame: false,
|
||||
titleBarStyle: 'hidden'
|
||||
});
|
||||
|
||||
const overlayHTML = path.join(__dirname, 'fixtures', 'pages', 'overlay.html');
|
||||
w.loadFile(overlayHTML);
|
||||
await once(w, 'ready-to-show');
|
||||
|
||||
const winBounds = w.getBounds();
|
||||
const titleBarHeight = 30;
|
||||
const titleBarRegion = new Region(winBounds.x, winBounds.y, winBounds.width, titleBarHeight);
|
||||
const screenRegion = new Region(display.bounds.x, display.bounds.y, display.bounds.width, display.bounds.height);
|
||||
|
||||
const startPos = w.getPosition();
|
||||
|
||||
await mouse.setPosition(await centerOf(titleBarRegion));
|
||||
await mouse.pressButton(Button.LEFT);
|
||||
await mouse.drag(straightTo(centerOf(screenRegion)));
|
||||
|
||||
// Wait for move to complete
|
||||
await Promise.race([
|
||||
once(w, 'move'),
|
||||
setTimeout(100) // fallback for possible race condition
|
||||
]);
|
||||
|
||||
const endPos = w.getPosition();
|
||||
|
||||
expect(startPos).to.not.deep.equal(endPos);
|
||||
});
|
||||
|
||||
ifit(hasCapturableScreen())('should allow the window to be dragged when no WCO and --webkit-app-region: drag enabled', async () => {
|
||||
// @ts-ignore: nut-js is an optional dependency so it may not be installed
|
||||
const { mouse, straightTo, centerOf, Region, Button } = require('@nut-tree/nut-js') as typeof import('@nut-tree/nut-js');
|
||||
|
||||
const display = screen.getPrimaryDisplay();
|
||||
const w = new BrowserWindow({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: display.bounds.width / 2,
|
||||
height: display.bounds.height / 2,
|
||||
frame: false
|
||||
});
|
||||
|
||||
const basePageHTML = path.join(__dirname, 'fixtures', 'pages', 'base-page.html');
|
||||
w.loadFile(basePageHTML);
|
||||
await once(w, 'ready-to-show');
|
||||
|
||||
await w.webContents.executeJavaScript(`
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = \`
|
||||
#titlebar {
|
||||
|
||||
background-color: red;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
-webkit-user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1000000000000;
|
||||
}
|
||||
\`;
|
||||
|
||||
const titleBar = document.createElement('title-bar');
|
||||
titleBar.id = 'titlebar';
|
||||
titleBar.textContent = 'test-titlebar';
|
||||
|
||||
document.body.append(style);
|
||||
document.body.append(titleBar);
|
||||
`);
|
||||
// allow time for titlebar to finish loading
|
||||
await setTimeout(2000);
|
||||
|
||||
const winBounds = w.getBounds();
|
||||
const titleBarHeight = 30;
|
||||
const titleBarRegion = new Region(winBounds.x, winBounds.y, winBounds.width, titleBarHeight);
|
||||
const screenRegion = new Region(display.bounds.x, display.bounds.y, display.bounds.width, display.bounds.height);
|
||||
|
||||
const startPos = w.getPosition();
|
||||
await mouse.setPosition(await centerOf(titleBarRegion));
|
||||
await mouse.pressButton(Button.LEFT);
|
||||
await mouse.drag(straightTo(centerOf(screenRegion)));
|
||||
|
||||
// Wait for move to complete
|
||||
await Promise.race([
|
||||
once(w, 'move'),
|
||||
setTimeout(1000) // fallback for possible race condition
|
||||
]);
|
||||
|
||||
const endPos = w.getPosition();
|
||||
|
||||
expect(startPos).to.not.deep.equal(endPos);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,8 @@ import * as http from 'node:http';
|
||||
import * as fs from 'node:fs';
|
||||
import * as qs from 'node:querystring';
|
||||
import * as stream from 'node:stream';
|
||||
import * as streamConsumers from 'node:stream/consumers';
|
||||
import * as webStream from 'node:stream/web';
|
||||
import { EventEmitter, once } from 'node:events';
|
||||
import { closeAllWindows, closeWindow } from './lib/window-helpers';
|
||||
import { WebmGenerator } from './lib/video-helpers';
|
||||
@@ -1548,6 +1550,122 @@ describe('protocol module', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('does not emit undefined chunks into the request body stream when uploading a stream', async () => {
|
||||
protocol.handle('cors', async (request) => {
|
||||
expect(request.body).to.be.an.instanceOf(webStream.ReadableStream);
|
||||
for await (const value of request.body as webStream.ReadableStream<Uint8Array>) {
|
||||
expect(value).to.not.be.undefined();
|
||||
}
|
||||
return new Response(undefined, { status: 200 });
|
||||
});
|
||||
defer(() => { protocol.unhandle('cors'); });
|
||||
|
||||
await contents.loadFile(path.resolve(fixturesPath, 'pages', 'base-page.html'));
|
||||
contents.on('console-message', (e, level, message) => console.log(message));
|
||||
const ok = await contents.executeJavaScript(`(async () => {
|
||||
function wait(milliseconds) {
|
||||
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
}
|
||||
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
await wait(4);
|
||||
controller.enqueue('This ');
|
||||
await wait(4);
|
||||
controller.enqueue('is ');
|
||||
await wait(4);
|
||||
controller.enqueue('a ');
|
||||
await wait(4);
|
||||
controller.enqueue('slow ');
|
||||
await wait(4);
|
||||
controller.enqueue('request.');
|
||||
controller.close();
|
||||
}
|
||||
}).pipeThrough(new TextEncoderStream());
|
||||
return (await fetch('cors://url.invalid', { method: 'POST', body: stream, duplex: 'half' })).ok;
|
||||
})()`);
|
||||
expect(ok).to.be.true();
|
||||
});
|
||||
|
||||
it('does not emit undefined chunks into the request body stream when uploading a file', async () => {
|
||||
protocol.handle('cors', async (request) => {
|
||||
expect(request.body).to.be.an.instanceOf(webStream.ReadableStream);
|
||||
for await (const value of request.body as webStream.ReadableStream<Uint8Array>) {
|
||||
expect(value).to.not.be.undefined();
|
||||
}
|
||||
return new Response(undefined, { status: 200 });
|
||||
});
|
||||
defer(() => { protocol.unhandle('cors'); });
|
||||
|
||||
await contents.loadFile(path.resolve(fixturesPath, 'pages', 'file-input.html'));
|
||||
const { debugger: debug } = contents;
|
||||
debug.attach();
|
||||
try {
|
||||
const { root: { nodeId } } = await debug.sendCommand('DOM.getDocument');
|
||||
const { nodeId: inputNodeId } = await debug.sendCommand('DOM.querySelector', { nodeId, selector: 'input' });
|
||||
await debug.sendCommand('DOM.setFileInputFiles', {
|
||||
files: [path.join(fixturesPath, 'cat-spin.mp4')],
|
||||
nodeId: inputNodeId
|
||||
});
|
||||
const ok = await contents.executeJavaScript(`(async () => {
|
||||
const formData = new FormData();
|
||||
formData.append("data", document.getElementById("file").files[0]);
|
||||
return (await fetch('cors://url.invalid', { method: 'POST', body: formData })).ok;
|
||||
})()`);
|
||||
expect(ok).to.be.true();
|
||||
} finally {
|
||||
debug.detach();
|
||||
}
|
||||
});
|
||||
|
||||
it('filters an illegal "origin: null" header', async () => {
|
||||
protocol.handle('http', (req) => {
|
||||
expect(new Headers(req.headers).get('origin')).to.not.equal('null');
|
||||
return new Response();
|
||||
});
|
||||
defer(() => { protocol.unhandle('http'); });
|
||||
|
||||
const filePath = path.join(fixturesPath, 'pages', 'form-with-data.html');
|
||||
await contents.loadFile(filePath);
|
||||
|
||||
const loadPromise = new Promise((resolve, reject) => {
|
||||
contents.once('did-finish-load', resolve);
|
||||
contents.once('did-fail-load', (_, errorCode, errorDescription) =>
|
||||
reject(new Error(`did-fail-load: ${errorCode} ${errorDescription}. See AssertionError for details.`))
|
||||
);
|
||||
});
|
||||
await contents.executeJavaScript(`
|
||||
const form = document.querySelector('form');
|
||||
form.action = 'http://cors.invalid';
|
||||
form.method = 'POST';
|
||||
form.submit();
|
||||
`);
|
||||
await loadPromise;
|
||||
});
|
||||
|
||||
it('does forward Blob chunks', async () => {
|
||||
// we register the protocol on a separate session to validate the assumption
|
||||
// that `getBlobData()` indeed returns the blob data from a global variable
|
||||
const s = session.fromPartition('protocol-handle-forwards-blob-chunks');
|
||||
|
||||
s.protocol.handle('cors', async (request) => {
|
||||
expect(request.body).to.be.an.instanceOf(webStream.ReadableStream);
|
||||
return new Response(
|
||||
`hello to ${await streamConsumers.text(request.body as webStream.ReadableStream<Uint8Array>)}`,
|
||||
{ status: 200 }
|
||||
);
|
||||
});
|
||||
defer(() => { s.protocol.unhandle('cors'); });
|
||||
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { session: s } });
|
||||
await w.webContents.loadFile(path.resolve(fixturesPath, 'pages', 'base-page.html'));
|
||||
const response = await w.webContents.executeJavaScript(`(async () => {
|
||||
const body = new Blob(["it's-a ", 'me! ', 'Mario!'], { type: 'text/plain' });
|
||||
return await (await fetch('cors://url.invalid', { method: 'POST', body })).text();
|
||||
})()`);
|
||||
expect(response).to.be.string('hello to it\'s-a me! Mario!');
|
||||
});
|
||||
|
||||
// TODO(nornagon): this test doesn't pass on Linux currently, investigate.
|
||||
ifit(process.platform !== 'linux')('is fast', async () => {
|
||||
// 128 MB of spaces.
|
||||
|
||||
@@ -141,7 +141,7 @@ describe('esm', () => {
|
||||
const hostsUrl = pathToFileURL(process.platform === 'win32' ? 'C:\\Windows\\System32\\drivers\\etc\\hosts' : '/etc/hosts');
|
||||
|
||||
describe('without context isolation', () => {
|
||||
it('should use blinks dynamic loader in the main world', async () => {
|
||||
it('should use Blinks dynamic loader in the main world', async () => {
|
||||
const [webContents] = await loadWindowWithPreload('', {
|
||||
nodeIntegration: true,
|
||||
sandbox: false,
|
||||
@@ -156,13 +156,18 @@ describe('esm', () => {
|
||||
}
|
||||
|
||||
expect(error).to.not.equal(null);
|
||||
// This is a blink specific error message
|
||||
// This is a Blink specific error message
|
||||
expect(error?.message).to.include('Failed to fetch dynamically imported module');
|
||||
});
|
||||
|
||||
it('should use import.meta callback handling from Node.js for Node.js modules', async () => {
|
||||
const result = await runFixture(path.resolve(fixturePath, 'import-meta'));
|
||||
expect(result.code).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with context isolation', () => {
|
||||
it('should use nodes esm dynamic loader in the isolated context', async () => {
|
||||
it('should use Node.js ESM dynamic loader in the isolated context', async () => {
|
||||
const [, preloadError] = await loadWindowWithPreload(`await import(${JSON.stringify(hostsUrl)})`, {
|
||||
nodeIntegration: true,
|
||||
sandbox: false,
|
||||
@@ -174,7 +179,7 @@ describe('esm', () => {
|
||||
expect(preloadError!.toString()).to.include('Unknown file extension');
|
||||
});
|
||||
|
||||
it('should use blinks dynamic loader in the main world', async () => {
|
||||
it('should use Blinks dynamic loader in the main world', async () => {
|
||||
const [webContents] = await loadWindowWithPreload('', {
|
||||
nodeIntegration: true,
|
||||
sandbox: false,
|
||||
|
||||
18
spec/fixtures/esm/import-meta/index.html
vendored
Normal file
18
spec/fixtures/esm/import-meta/index.html
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
|
||||
<title>Hello World!</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
We are using Node.js <span id="node-version"></span>,
|
||||
Chromium <span id="chrome-version"></span>,
|
||||
and Electron <span id="electron-version"></span>.
|
||||
</body>
|
||||
|
||||
</html>
|
||||
33
spec/fixtures/esm/import-meta/main.mjs
vendored
Normal file
33
spec/fixtures/esm/import-meta/main.mjs
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
async function createWindow() {
|
||||
const mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
preload: fileURLToPath(new URL('preload.mjs', import.meta.url)),
|
||||
sandbox: false,
|
||||
contextIsolation: false
|
||||
}
|
||||
})
|
||||
|
||||
await mainWindow.loadFile('index.html')
|
||||
|
||||
const importMetaPreload = await mainWindow.webContents.executeJavaScript('window.importMetaPath');
|
||||
const expected = join(dirname(fileURLToPath(import.meta.url)), 'preload.mjs');
|
||||
|
||||
process.exit(importMetaPreload === expected ? 0 : 1);
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
4
spec/fixtures/esm/import-meta/package.json
vendored
Normal file
4
spec/fixtures/esm/import-meta/package.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "main.mjs",
|
||||
"type": "module"
|
||||
}
|
||||
3
spec/fixtures/esm/import-meta/preload.mjs
vendored
Normal file
3
spec/fixtures/esm/import-meta/preload.mjs
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
window.importMetaPath = fileURLToPath(import.meta.url)
|
||||
@@ -91,3 +91,16 @@ export const areColorsSimilar = (
|
||||
const distance = colorDistance(hexColorA, hexColorB);
|
||||
return distance <= distanceThreshold;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the current VM has a valid screen which can be used to capture.
|
||||
*
|
||||
* This is specific to Electron's CI test runners.
|
||||
* - Linux: virtual screen display is 0x0
|
||||
* - Win32 arm64 (WOA): virtual screen display is 0x0
|
||||
* - Win32 ia32: skipped
|
||||
*/
|
||||
export const hasCapturableScreen = () => {
|
||||
return process.platform === 'darwin' ||
|
||||
(process.platform === 'win32' && process.arch === 'x64');
|
||||
};
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
"ws": "^7.4.6",
|
||||
"yargs": "^16.0.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@nut-tree/nut-js": "^3.1.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"nan": "file:../../third_party/nan",
|
||||
"dbus-native/optimist/minimist": "1.2.7",
|
||||
|
||||
778
spec/yarn.lock
778
spec/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user