mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
13 Commits
feat/enabl
...
docs-secur
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7376539603 | ||
|
|
1709b786cd | ||
|
|
4f919c727d | ||
|
|
1029bd1057 | ||
|
|
685412e1be | ||
|
|
edd7b537c1 | ||
|
|
237429bb85 | ||
|
|
50d1c803dd | ||
|
|
0d3e34d0be | ||
|
|
aa06b065c0 | ||
|
|
9f47c9a051 | ||
|
|
dabb95c3f0 | ||
|
|
d05cf9c6bb |
2
.github/actions/checkout/action.yml
vendored
2
.github/actions/checkout/action.yml
vendored
@@ -20,6 +20,8 @@ runs:
|
||||
uses: ./src/electron/.github/actions/install-dependencies
|
||||
- name: Install Build Tools
|
||||
uses: ./src/electron/.github/actions/install-build-tools
|
||||
- name: Set Chromium Git Cookie
|
||||
uses: ./src/electron/.github/actions/set-chromium-cookie
|
||||
- name: Get Depot Tools
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
26
.github/actions/set-chromium-cookie/action.yml
vendored
Normal file
26
.github/actions/set-chromium-cookie/action.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: 'Set Chromium Git Cookie'
|
||||
description: 'Sets an authenticated cookie from Chromium to allow for a higher request limit'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set the git cookie from chromium.googlesource.com (Unix)
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
shell: bash
|
||||
run: |
|
||||
eval 'set +o history' 2>/dev/null || setopt HIST_IGNORE_SPACE 2>/dev/null
|
||||
touch ~/.gitcookies
|
||||
chmod 0600 ~/.gitcookies
|
||||
|
||||
git config --global http.cookiefile ~/.gitcookies
|
||||
|
||||
tr , \\t <<\__END__ >>~/.gitcookies
|
||||
${{ env.CHROMIUM_GIT_COOKIE }}
|
||||
__END__
|
||||
eval 'set -o history' 2>/dev/null || unsetopt HIST_IGNORE_SPACE 2>/dev/null
|
||||
- name: Set the git cookie from chromium.googlesource.com (Windows)
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
shell: cmd
|
||||
run: |
|
||||
git config --global http.cookiefile "%USERPROFILE%\.gitcookies"
|
||||
powershell -noprofile -nologo -command Write-Output "${{ env.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }}" >>"%USERPROFILE%\.gitcookies"
|
||||
|
||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -100,6 +100,7 @@ jobs:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /var/run/sas:/var/run/sas
|
||||
env:
|
||||
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
outputs:
|
||||
build-image-sha: ${{ needs.setup.outputs.build-image-sha }}
|
||||
@@ -126,6 +127,7 @@ jobs:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /var/run/sas:/var/run/sas
|
||||
env:
|
||||
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
PATCH_UP_APP_CREDS: ${{ secrets.PATCH_UP_APP_CREDS }}
|
||||
outputs:
|
||||
@@ -150,6 +152,8 @@ jobs:
|
||||
volumes:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
env:
|
||||
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
|
||||
CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }}
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_win=True'
|
||||
TARGET_OS: 'win'
|
||||
ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN: '1'
|
||||
|
||||
2
.github/workflows/pipeline-electron-lint.yml
vendored
2
.github/workflows/pipeline-electron-lint.yml
vendored
@@ -27,6 +27,8 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install Dependencies
|
||||
uses: ./src/electron/.github/actions/install-dependencies
|
||||
- name: Set Chromium Git Cookie
|
||||
uses: ./src/electron/.github/actions/set-chromium-cookie
|
||||
- name: Setup third_party Depot Tools
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -65,6 +65,8 @@ concurrency:
|
||||
cancel-in-progress: ${{ github.ref_protected != true }}
|
||||
|
||||
env:
|
||||
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
|
||||
CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }}
|
||||
ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
SUDOWOODO_EXCHANGE_URL: ${{ secrets.SUDOWOODO_EXCHANGE_URL }}
|
||||
@@ -125,6 +127,8 @@ jobs:
|
||||
GN_EXTRA_ARGS='is_asan=true'
|
||||
fi
|
||||
echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
|
||||
- name: Set Chromium Git Cookie
|
||||
uses: ./src/electron/.github/actions/set-chromium-cookie
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
|
||||
@@ -36,6 +36,8 @@ permissions:
|
||||
pull-requests: read
|
||||
|
||||
env:
|
||||
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
|
||||
CHROMIUM_GIT_COOKIE_WINDOWS_STRING: ${{ secrets.CHROMIUM_GIT_COOKIE_WINDOWS_STRING }}
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
|
||||
@@ -113,6 +115,9 @@ jobs:
|
||||
configure_sys_tccdb "$values"
|
||||
fi
|
||||
done
|
||||
- name: Turn off the unexpectedly quit dialog on macOS
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
run: defaults write com.apple.CrashReporter DialogType server
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
@@ -121,6 +126,8 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install Dependencies
|
||||
uses: ./src/electron/.github/actions/install-dependencies
|
||||
- name: Set Chromium Git Cookie
|
||||
uses: ./src/electron/.github/actions/set-chromium-cookie
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
|
||||
@@ -57,6 +57,8 @@ jobs:
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }}
|
||||
- name: Install Dependencies
|
||||
uses: ./src/electron/.github/actions/install-dependencies
|
||||
- name: Set Chromium Git Cookie
|
||||
uses: ./src/electron/.github/actions/set-chromium-cookie
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
@@ -118,6 +120,8 @@ jobs:
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }}
|
||||
- name: Install Dependencies
|
||||
uses: ./src/electron/.github/actions/install-dependencies
|
||||
- name: Set Chromium Git Cookie
|
||||
uses: ./src/electron/.github/actions/set-chromium-cookie
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
|
||||
8
DEPS
8
DEPS
@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'134.0.6990.0',
|
||||
'134.0.6998.10',
|
||||
'node_version':
|
||||
'v22.13.1',
|
||||
'nan_version':
|
||||
@@ -62,10 +62,6 @@ vars = {
|
||||
|
||||
'checkout_nacl':
|
||||
False,
|
||||
'checkout_libaom':
|
||||
True,
|
||||
'checkout_oculus_sdk':
|
||||
False,
|
||||
'checkout_openxr':
|
||||
False,
|
||||
'build_with_chromium':
|
||||
@@ -74,8 +70,6 @@ vars = {
|
||||
False,
|
||||
'checkout_android_native_support':
|
||||
False,
|
||||
'checkout_google_benchmark':
|
||||
False,
|
||||
'checkout_clang_tidy':
|
||||
True,
|
||||
}
|
||||
|
||||
@@ -74,3 +74,22 @@ Returns `boolean` - Whether the navigation entry was removed from the webContent
|
||||
#### `navigationHistory.getAllEntries()`
|
||||
|
||||
Returns [`NavigationEntry[]`](structures/navigation-entry.md) - WebContents complete history.
|
||||
|
||||
#### `navigationHistory.restore(options)`
|
||||
|
||||
Restores navigation history and loads the given entry in the in stack. Will make a best effort
|
||||
to restore not just the navigation stack but also the state of the individual pages - for instance
|
||||
including HTML form values or the scroll position. It's recommended to call this API before any
|
||||
navigation entries are created, so ideally before you call `loadURL()` or `loadFile()` on the
|
||||
`webContents` object.
|
||||
|
||||
This API allows you to create common flows that aim to restore, recreate, or clone other webContents.
|
||||
|
||||
* `options` Object
|
||||
* `entries` [NavigationEntry[]](structures/navigation-entry.md) - Result of a prior `getAllEntries()` call
|
||||
* `index` Integer (optional) - Index of the stack that should be loaded. If you set it to `0`, the webContents will load the first (oldest) entry. If you leave it undefined, Electron will automatically load the last (newest) entry.
|
||||
|
||||
Returns `Promise<void>` - the promise will resolve when the page has finished loading the selected navigation entry
|
||||
(see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects
|
||||
if the page fails to load (see
|
||||
[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors.
|
||||
|
||||
@@ -66,7 +66,7 @@ The `session` module has the following properties:
|
||||
|
||||
### `session.defaultSession`
|
||||
|
||||
A `Session` object, the default session object of the app.
|
||||
A `Session` object, the default session object of the app, available after `app.whenReady` is called.
|
||||
|
||||
## Class: Session
|
||||
|
||||
@@ -1541,25 +1541,6 @@ Unloads an extension.
|
||||
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||
is emitted.
|
||||
|
||||
#### `ses.enableExtension(extensionId)`
|
||||
|
||||
* `extensionId` string - ID of extension to enable
|
||||
|
||||
Enables the extension and activates it for use by starting any background
|
||||
workers. If the extension is disabled, marks it as enabled.
|
||||
|
||||
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||
is emitted.
|
||||
|
||||
#### `ses.disableExtension(extensionId)`
|
||||
|
||||
* `extensionId` string - ID of extension to disable
|
||||
|
||||
Disables the extension and deactives it.
|
||||
|
||||
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||
is emitted.
|
||||
|
||||
#### `ses.getExtension(extensionId)`
|
||||
|
||||
* `extensionId` string - ID of extension to query
|
||||
|
||||
@@ -6,4 +6,3 @@
|
||||
* `path` string - The extension's file path.
|
||||
* `version` string
|
||||
* `url` string - The extension's `chrome-extension://` URL.
|
||||
* `enabled` boolean - Whether the extension is enabled.
|
||||
|
||||
@@ -2,3 +2,6 @@
|
||||
|
||||
* `url` string
|
||||
* `title` string
|
||||
* `pageState` string (optional) - A base64 encoded data string containing Chromium page state
|
||||
including information like the current scroll position or form values. It is committed by
|
||||
Chromium before a navigation event and on a regular interval.
|
||||
|
||||
@@ -69,8 +69,25 @@ if (navigationHistory.canGoToOffset(2)) {
|
||||
}
|
||||
```
|
||||
|
||||
## Restoring history
|
||||
|
||||
A common flow is that you want to restore the history of a webContents - for instance to implement an "undo close tab" feature. To do so, you can call `navigationHistory.restore({ index, entries })`. This will restore the webContent's navigation history and the webContents location in said history, meaning that `goBack()` and `goForward()` navigate you through the stack as expected.
|
||||
|
||||
```js @ts-type={navigationHistory:Electron.NavigationHistory}
|
||||
|
||||
const firstWindow = new BrowserWindow()
|
||||
|
||||
// Later, you want a second window to have the same history and navigation position
|
||||
async function restore () {
|
||||
const entries = firstWindow.webContents.navigationHistory.getAllEntries()
|
||||
const index = firstWindow.webContents.navigationHistory.getActiveIndex()
|
||||
|
||||
const secondWindow = new BrowserWindow()
|
||||
await secondWindow.webContents.navigationHistory.restore({ index, entries })
|
||||
}
|
||||
```
|
||||
|
||||
Here's a full example that you can open with Electron Fiddle:
|
||||
|
||||
```fiddle docs/fiddles/features/navigation-history
|
||||
|
||||
```
|
||||
|
||||
@@ -284,7 +284,7 @@ const { session } = require('electron')
|
||||
const { URL } = require('url')
|
||||
|
||||
session
|
||||
.fromPartition('some-partition')
|
||||
.defaultSession
|
||||
.setPermissionRequestHandler((webContents, permission, callback) => {
|
||||
const parsedUrl = new URL(webContents.getURL())
|
||||
|
||||
@@ -301,6 +301,8 @@ session
|
||||
})
|
||||
```
|
||||
|
||||
Note: `session.defaultSession` is only available after `app.whenReady` is called.
|
||||
|
||||
### 6. Do not disable `webSecurity`
|
||||
|
||||
:::info
|
||||
@@ -391,6 +393,8 @@ session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
||||
})
|
||||
```
|
||||
|
||||
Note: `session.defaultSession` is only available after `app.whenReady` is called.
|
||||
|
||||
#### CSP meta tag
|
||||
|
||||
CSP's preferred delivery mechanism is an HTTP header. However, it is not possible
|
||||
|
||||
@@ -763,8 +763,6 @@ filenames = {
|
||||
"shell/browser/extensions/electron_extension_host_delegate.h",
|
||||
"shell/browser/extensions/electron_extension_loader.cc",
|
||||
"shell/browser/extensions/electron_extension_loader.h",
|
||||
"shell/browser/extensions/electron_extension_registrar_delegate.cc",
|
||||
"shell/browser/extensions/electron_extension_registrar_delegate.h",
|
||||
"shell/browser/extensions/electron_extension_system_factory.cc",
|
||||
"shell/browser/extensions/electron_extension_system_factory.h",
|
||||
"shell/browser/extensions/electron_extension_system.cc",
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as deprecate from '@electron/internal/common/deprecate';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
import { app, ipcMain, session, webFrameMain, dialog } from 'electron/main';
|
||||
import type { BrowserWindowConstructorOptions, MessageBoxOptions } from 'electron/main';
|
||||
import type { BrowserWindowConstructorOptions, MessageBoxOptions, NavigationEntry } from 'electron/main';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as url from 'url';
|
||||
@@ -343,8 +343,8 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||
|
||||
type LoadError = { errorCode: number, errorDescription: string, url: string };
|
||||
|
||||
WebContents.prototype.loadURL = function (url, options) {
|
||||
const p = new Promise<void>((resolve, reject) => {
|
||||
function _awaitNextLoad (this: Electron.WebContents, navigationUrl: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const resolveAndCleanup = () => {
|
||||
removeListeners();
|
||||
resolve();
|
||||
@@ -402,7 +402,7 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
// the only one is with a bad scheme, perhaps ERR_INVALID_ARGUMENT
|
||||
// would be more appropriate.
|
||||
if (!error) {
|
||||
error = { errorCode: -2, errorDescription: 'ERR_FAILED', url };
|
||||
error = { errorCode: -2, errorDescription: 'ERR_FAILED', url: navigationUrl };
|
||||
}
|
||||
finishListener();
|
||||
};
|
||||
@@ -426,6 +426,10 @@ WebContents.prototype.loadURL = function (url, options) {
|
||||
this.on('did-stop-loading', stopLoadingListener);
|
||||
this.on('destroyed', stopLoadingListener);
|
||||
});
|
||||
};
|
||||
|
||||
WebContents.prototype.loadURL = function (url, options) {
|
||||
const p = _awaitNextLoad.call(this, url);
|
||||
// Add a no-op rejection handler to silence the unhandled rejection error.
|
||||
p.catch(() => {});
|
||||
this._loadURL(url, options ?? {});
|
||||
@@ -611,7 +615,27 @@ WebContents.prototype._init = function () {
|
||||
length: this._historyLength.bind(this),
|
||||
getEntryAtIndex: this._getNavigationEntryAtIndex.bind(this),
|
||||
removeEntryAtIndex: this._removeNavigationEntryAtIndex.bind(this),
|
||||
getAllEntries: this._getHistory.bind(this)
|
||||
getAllEntries: this._getHistory.bind(this),
|
||||
restore: ({ index, entries }: { index?: number, entries: NavigationEntry[] }) => {
|
||||
if (index === undefined) {
|
||||
index = entries.length - 1;
|
||||
}
|
||||
|
||||
if (index < 0 || !entries[index]) {
|
||||
throw new Error('Invalid index. Index must be a positive integer and within the bounds of the entries length.');
|
||||
}
|
||||
|
||||
const p = _awaitNextLoad.call(this, entries[index].url);
|
||||
p.catch(() => {});
|
||||
|
||||
try {
|
||||
this._restoreHistory(index, entries);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
},
|
||||
writable: false,
|
||||
enumerable: true
|
||||
|
||||
@@ -35,10 +35,10 @@ system font by checking if it's kCTFontPriorityAttribute is set to
|
||||
system priority.
|
||||
|
||||
diff --git a/base/BUILD.gn b/base/BUILD.gn
|
||||
index a4ae9c4c242551f6850cdcbb42551b676db76c95..22281156bcfdd6999d15d511c508415f8f3f9ac7 100644
|
||||
index 05ba2110698b69af677ad1fe898ae6e5953c7af4..7bcbb8f647faea889e295d8919f67745a7f72136 100644
|
||||
--- a/base/BUILD.gn
|
||||
+++ b/base/BUILD.gn
|
||||
@@ -1028,6 +1028,7 @@ component("base") {
|
||||
@@ -1027,6 +1027,7 @@ component("base") {
|
||||
"//build:ios_buildflags",
|
||||
"//build/config/compiler:compiler_buildflags",
|
||||
"//third_party/modp_b64",
|
||||
@@ -192,10 +192,10 @@ index e12c1d078147d956a1d9b1bc498c1b1d6fe7b974..233362259dc4e728ed37435e65041764
|
||||
|
||||
} // namespace base
|
||||
diff --git a/components/os_crypt/sync/BUILD.gn b/components/os_crypt/sync/BUILD.gn
|
||||
index bfb0d2f208170f77df96fb9f14c8525e9dec6e11..e234d95a862198148bae97b4b276d93922f3ca92 100644
|
||||
index ff1e356ff696d3830d02644969c36a71fdf32ff6..b39c716c52524b95f2d3417a98e60c0c41147c93 100644
|
||||
--- a/components/os_crypt/sync/BUILD.gn
|
||||
+++ b/components/os_crypt/sync/BUILD.gn
|
||||
@@ -43,6 +43,8 @@ component("os_crypt") {
|
||||
@@ -38,6 +38,8 @@ component("sync") {
|
||||
"os_crypt_mac.mm",
|
||||
]
|
||||
deps += [ "//crypto:mock_apple_keychain" ]
|
||||
@@ -269,7 +269,7 @@ index e9f4e5131238b9fb5f1b4b3e90a0cb84a7fc15b4..8b5f4cae3123ac5480ad73f0c873fca0
|
||||
|
||||
} // namespace
|
||||
diff --git a/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm b/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm
|
||||
index 19fff43c3daaef5451b6b60b84a610a21311448e..240b954661d34fcc4329d39490be33c485fa8b6e 100644
|
||||
index 3a8b44a2a295119f37ca37d5866dfcfa21121db0..b408e9c73fe97dd8885b5479923481e20955cf8d 100644
|
||||
--- a/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm
|
||||
+++ b/components/remote_cocoa/app_shim/browser_native_widget_window_mac.mm
|
||||
@@ -9,7 +9,9 @@
|
||||
@@ -298,7 +298,7 @@ index 19fff43c3daaef5451b6b60b84a610a21311448e..240b954661d34fcc4329d39490be33c4
|
||||
+ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
|
||||
// - NSThemeFrame and its subclasses will be nil if it's missing at runtime.
|
||||
if ([BrowserWindowFrame class])
|
||||
@@ -165,6 +170,8 @@ - (BOOL)_usesCustomDrawing {
|
||||
@@ -163,6 +168,8 @@ - (BOOL)_usesCustomDrawing {
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ index 19fff43c3daaef5451b6b60b84a610a21311448e..240b954661d34fcc4329d39490be33c4
|
||||
// Handle "Move focus to the window toolbar" configured in System Preferences ->
|
||||
// Keyboard -> Shortcuts -> Keyboard. Usually Ctrl+F5. The argument (|unknown|)
|
||||
// tends to just be nil.
|
||||
@@ -175,8 +182,8 @@ - (void)_handleFocusToolbarHotKey:(id)unknown {
|
||||
@@ -173,8 +180,8 @@ - (void)_handleFocusToolbarHotKey:(id)unknown {
|
||||
}
|
||||
|
||||
- (void)setAlwaysShowTrafficLights:(BOOL)alwaysShow {
|
||||
@@ -354,7 +354,7 @@ index 3a815ebf505bd95fa7f6b61ba433d98fbfe20225..149de0175c2ec0e41e3ba40caad7019c
|
||||
+
|
||||
@end
|
||||
diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h
|
||||
index d55914779bc097cab8afb144f2c47c001bfa7350..e55db3f550b4c082aa087fbcab6760da237f8471 100644
|
||||
index 127a2829fafa04bfbab0b883304dfb815d7e1c22..61d7946e52862f3586b1e098d7d44a125656de81 100644
|
||||
--- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h
|
||||
+++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h
|
||||
@@ -9,6 +9,7 @@
|
||||
@@ -382,7 +382,7 @@ index d55914779bc097cab8afb144f2c47c001bfa7350..e55db3f550b4c082aa087fbcab6760da
|
||||
// The NSWindow used by BridgedNativeWidget. Provides hooks into AppKit that
|
||||
// can only be accomplished by overriding methods.
|
||||
diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
|
||||
index 03ff0478f16f237e6b8082508d5399195bfdca44..9b74f6ca6de6ec057073e175170014b5512040b4 100644
|
||||
index 2b50e3c3750c9ac6dd84a514663062a5d754b43e..49ced9aa87d3bcb00cd3d76ac32d4eec89873549 100644
|
||||
--- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
|
||||
+++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
|
||||
@@ -26,6 +26,7 @@
|
||||
@@ -449,7 +449,7 @@ index 03ff0478f16f237e6b8082508d5399195bfdca44..9b74f6ca6de6ec057073e175170014b5
|
||||
bool shouldShowWindowTitle = YES;
|
||||
if (_bridge)
|
||||
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
|
||||
index 89aca4b47c202f137a5ffe8390986ef6dd62942a..59276806afa7659573eb276149ff8ed47ca72c1f 100644
|
||||
index 36c522793dc37f7c72f7cccde50895927b5560cb..689351b5a6e6e6013b808c1b4924b8848dcc0fa2 100644
|
||||
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
|
||||
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
|
||||
@@ -41,6 +41,7 @@
|
||||
@@ -579,10 +579,10 @@ index a76028eed0249244d0559de102a756e3b2771b63..cb65efb56849d57e2e656f90d5b1d737
|
||||
return kAttributes;
|
||||
}
|
||||
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
|
||||
index 74ca66c0f38b4fc4448d50a9f3674cda6a078f0e..5c49a11dfbe1275f0f8cd21bf970d3b6b98cb71e 100644
|
||||
index e5ca8881f7e05fc3c600cf6f785a2070efff2e5d..ce57b1e635f26ef248fbf8285cf69fe3c6c41105 100644
|
||||
--- a/content/browser/BUILD.gn
|
||||
+++ b/content/browser/BUILD.gn
|
||||
@@ -329,6 +329,7 @@ source_set("browser") {
|
||||
@@ -330,6 +330,7 @@ source_set("browser") {
|
||||
"//ui/touch_selection",
|
||||
"//ui/webui/resources",
|
||||
"//v8:v8_version",
|
||||
@@ -625,7 +625,7 @@ index bea4e26ef8577e8e8bc60287cf1b94c7dfcc9478..eed42b0cbc3422b7fd59ae1b2550c53d
|
||||
// Used to force the NSApplication's focused accessibility element to be the
|
||||
// content::BrowserAccessibilityCocoa accessibility tree when the NSView for
|
||||
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
|
||||
index 9185fd223c9611faee546570c0df36bc94cdb28c..86886e94e9e2c52e297a82175f6071852e792148 100644
|
||||
index 430426a0123508a45bf48dcbfb46d1c4dc9d9347..efa697b7c4d428200d14e436ab062c13273916f4 100644
|
||||
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
|
||||
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
|
||||
@@ -48,6 +48,7 @@
|
||||
@@ -647,7 +647,7 @@ index 9185fd223c9611faee546570c0df36bc94cdb28c..86886e94e9e2c52e297a82175f607185
|
||||
|
||||
// Reset `ns_view_` before resetting `remote_ns_view_` to avoid dangling
|
||||
// pointers. `ns_view_` gets reinitialized later in this method.
|
||||
@@ -1616,8 +1619,10 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback,
|
||||
@@ -1622,8 +1625,10 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback,
|
||||
|
||||
gfx::NativeViewAccessible
|
||||
RenderWidgetHostViewMac::AccessibilityGetNativeViewAccessibleForWindow() {
|
||||
@@ -658,7 +658,7 @@ index 9185fd223c9611faee546570c0df36bc94cdb28c..86886e94e9e2c52e297a82175f607185
|
||||
return [GetInProcessNSView() window];
|
||||
}
|
||||
|
||||
@@ -1666,9 +1671,11 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback,
|
||||
@@ -1672,9 +1677,11 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback,
|
||||
}
|
||||
|
||||
void RenderWidgetHostViewMac::SetAccessibilityWindow(NSWindow* window) {
|
||||
@@ -670,7 +670,7 @@ index 9185fd223c9611faee546570c0df36bc94cdb28c..86886e94e9e2c52e297a82175f607185
|
||||
}
|
||||
|
||||
bool RenderWidgetHostViewMac::SyncIsWidgetForMainFrame(
|
||||
@@ -2195,20 +2202,26 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback,
|
||||
@@ -2201,20 +2208,26 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback,
|
||||
void RenderWidgetHostViewMac::GetRenderWidgetAccessibilityToken(
|
||||
GetRenderWidgetAccessibilityTokenCallback callback) {
|
||||
base::ProcessId pid = getpid();
|
||||
@@ -792,7 +792,7 @@ index a1068589ad844518038ee7bc15a3de9bc5cba525..1ff781c49f086ec8015c7d3c44567dbe
|
||||
|
||||
} // namespace content
|
||||
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
|
||||
index 27adf4138c7ea1cb90460bdd21586163f7614a48..6b422c331bb14489b36a762ad2ced88544d21b60 100644
|
||||
index 190b593519ab8ccfc6309b40947c6e42ff8c6131..ec3dd70e677d7215df1c2cb504faa62ac1e6dff4 100644
|
||||
--- a/content/test/BUILD.gn
|
||||
+++ b/content/test/BUILD.gn
|
||||
@@ -652,6 +652,7 @@ static_library("test_support") {
|
||||
@@ -811,7 +811,7 @@ index 27adf4138c7ea1cb90460bdd21586163f7614a48..6b422c331bb14489b36a762ad2ced885
|
||||
}
|
||||
|
||||
mojom("content_test_mojo_bindings") {
|
||||
@@ -1924,6 +1926,7 @@ test("content_browsertests") {
|
||||
@@ -1935,6 +1937,7 @@ test("content_browsertests") {
|
||||
"//ui/shell_dialogs",
|
||||
"//ui/snapshot",
|
||||
"//ui/webui:test_support",
|
||||
@@ -819,7 +819,7 @@ index 27adf4138c7ea1cb90460bdd21586163f7614a48..6b422c331bb14489b36a762ad2ced885
|
||||
]
|
||||
|
||||
if (!(is_chromeos && target_cpu == "arm64" && current_cpu == "arm")) {
|
||||
@@ -3210,6 +3213,7 @@ test("content_unittests") {
|
||||
@@ -3228,6 +3231,7 @@ test("content_unittests") {
|
||||
"//ui/latency:test_support",
|
||||
"//ui/shell_dialogs:shell_dialogs",
|
||||
"//ui/webui:test_support",
|
||||
@@ -932,10 +932,10 @@ index 36322ddd3047f96569f35807541a37d3c6672b09..0121a780cf3b79fc1120c1b85cd5cd30
|
||||
|
||||
namespace ui {
|
||||
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn
|
||||
index 977aa5b452c882ee69690ba034ec00c9e7ff7e24..3ae3e2ead48ea1af9307dcd12647ca2a24b3a6f4 100644
|
||||
index 87126a36725849cbaf478e2dc24dc3a628a30846..a3a88b07af91b86191d9e5727a1d021ebbbb22ce 100644
|
||||
--- a/media/audio/BUILD.gn
|
||||
+++ b/media/audio/BUILD.gn
|
||||
@@ -198,6 +198,7 @@ source_set("audio") {
|
||||
@@ -196,6 +196,7 @@ source_set("audio") {
|
||||
"CoreMedia.framework",
|
||||
]
|
||||
weak_frameworks = [ "ScreenCaptureKit.framework" ] # macOS 13.0
|
||||
@@ -1023,18 +1023,18 @@ index 70d5665ad7b9ef62370497636af919ede2508ad4..f4dc3e2b8053cdb3e8c439ab1a1d6369
|
||||
}
|
||||
|
||||
diff --git a/sandbox/mac/BUILD.gn b/sandbox/mac/BUILD.gn
|
||||
index 4e53d573ff67615bc7dcee7db6f855c67094f414..8b061d66b1a854b51a5a38b6a71eadab6a7dbbec 100644
|
||||
index 453e2185fc85fcb29fa7af3f94cce5bda8118b0c..1c383675bb9113b5b1df9280b8ee994123794dfc 100644
|
||||
--- a/sandbox/mac/BUILD.gn
|
||||
+++ b/sandbox/mac/BUILD.gn
|
||||
@@ -39,6 +39,7 @@ component("seatbelt") {
|
||||
]
|
||||
public_deps = [ "//third_party/protobuf:protobuf_lite" ]
|
||||
@@ -25,6 +25,7 @@ component("seatbelt") {
|
||||
libs = [ "sandbox" ]
|
||||
deps = [ ":seatbelt_export" ]
|
||||
defines = [ "SEATBELT_IMPLEMENTATION" ]
|
||||
+ deps += ["//electron/build/config:generate_mas_config"]
|
||||
}
|
||||
|
||||
component("seatbelt_extension") {
|
||||
@@ -52,6 +53,7 @@ component("seatbelt_extension") {
|
||||
@@ -38,6 +39,7 @@ component("seatbelt_extension") {
|
||||
libs = [ "sandbox" ]
|
||||
public_deps = [ "//base" ]
|
||||
defines = [ "SEATBELT_IMPLEMENTATION" ]
|
||||
@@ -1042,7 +1042,7 @@ index 4e53d573ff67615bc7dcee7db6f855c67094f414..8b061d66b1a854b51a5a38b6a71eadab
|
||||
}
|
||||
|
||||
component("system_services") {
|
||||
@@ -66,6 +68,7 @@ component("system_services") {
|
||||
@@ -52,6 +54,7 @@ component("system_services") {
|
||||
deps = [ ":seatbelt_export" ]
|
||||
public_deps = [ "//base" ]
|
||||
defines = [ "SEATBELT_IMPLEMENTATION" ]
|
||||
@@ -1050,36 +1050,6 @@ index 4e53d573ff67615bc7dcee7db6f855c67094f414..8b061d66b1a854b51a5a38b6a71eadab
|
||||
}
|
||||
|
||||
source_set("sandbox_unittests") {
|
||||
diff --git a/sandbox/mac/sandbox_compiler.cc b/sandbox/mac/sandbox_compiler.cc
|
||||
index f35d9ef2a2df3db8ecbf1d7b909c7b1cf33f3cd9..5d52330d1bd70cd7b97ee3360721f10c8447c717 100644
|
||||
--- a/sandbox/mac/sandbox_compiler.cc
|
||||
+++ b/sandbox/mac/sandbox_compiler.cc
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
+#include "electron/mas.h"
|
||||
#include "sandbox/mac/seatbelt.h"
|
||||
|
||||
namespace sandbox {
|
||||
@@ -47,6 +48,7 @@ bool SandboxCompiler::SetParameter(const std::string& key,
|
||||
}
|
||||
|
||||
bool SandboxCompiler::CompileAndApplyProfile(std::string& error) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
if (mode_ == Target::kSource) {
|
||||
std::vector<const char*> params;
|
||||
|
||||
@@ -67,6 +69,9 @@ bool SandboxCompiler::CompileAndApplyProfile(std::string& error) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
+#else
|
||||
+ return true;
|
||||
+#endif
|
||||
}
|
||||
|
||||
bool SandboxCompiler::CompilePolicyToProto(mac::SandboxPolicy& policy,
|
||||
diff --git a/sandbox/mac/sandbox_logging.cc b/sandbox/mac/sandbox_logging.cc
|
||||
index 095c639b9893e885d8937e29ed7d47a7c28bc6b6..7e0cf9b9f94b16741358bdb45122f8b2bd68c0f9 100644
|
||||
--- a/sandbox/mac/sandbox_logging.cc
|
||||
@@ -1117,7 +1087,7 @@ index 095c639b9893e885d8937e29ed7d47a7c28bc6b6..7e0cf9b9f94b16741358bdb45122f8b2
|
||||
|
||||
// |error| is strerror(errno) when a P* logging function is called. Pass
|
||||
diff --git a/sandbox/mac/seatbelt.cc b/sandbox/mac/seatbelt.cc
|
||||
index 15c835e118456394c0a00ac98c11241c14ca75bd..a16faabe2bd63a5e0fbe9082a3b4b7c8aa0ea064 100644
|
||||
index 1960e1c8771fad615a098af09ff1f9a191f67764..29b97b352d08cd1fe73b17fd80cb41cc7e58dcaa 100644
|
||||
--- a/sandbox/mac/seatbelt.cc
|
||||
+++ b/sandbox/mac/seatbelt.cc
|
||||
@@ -4,12 +4,14 @@
|
||||
@@ -1220,14 +1190,21 @@ index 15c835e118456394c0a00ac98c11241c14ca75bd..a16faabe2bd63a5e0fbe9082a3b4b7c8
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -129,10 +147,14 @@ bool Seatbelt::InitWithParams(const char* profile,
|
||||
@@ -129,16 +147,21 @@ bool Seatbelt::InitWithParams(const std::string& profile,
|
||||
uint64_t flags,
|
||||
const char* const parameters[],
|
||||
const std::vector<std::string>& parameters,
|
||||
std::string* error) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
std::vector<const char*> weak_params;
|
||||
for (const std::string& param : parameters) {
|
||||
weak_params.push_back(param.c_str());
|
||||
}
|
||||
// The parameters array must be null terminated.
|
||||
weak_params.push_back(nullptr);
|
||||
+
|
||||
char* errorbuf = nullptr;
|
||||
int rv =
|
||||
::sandbox_init_with_parameters(profile, flags, parameters, &errorbuf);
|
||||
int rv = ::sandbox_init_with_parameters(profile.c_str(), flags,
|
||||
weak_params.data(), &errorbuf);
|
||||
return HandleSandboxResult(rv, errorbuf, error);
|
||||
+#else
|
||||
+ return true;
|
||||
@@ -1235,7 +1212,7 @@ index 15c835e118456394c0a00ac98c11241c14ca75bd..a16faabe2bd63a5e0fbe9082a3b4b7c8
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -140,6 +162,7 @@ bool Seatbelt::Compile(const char* profile,
|
||||
@@ -146,6 +169,7 @@ bool Seatbelt::Compile(const char* profile,
|
||||
const Seatbelt::Parameters& params,
|
||||
std::string& compiled_profile,
|
||||
std::string* error) {
|
||||
@@ -1243,7 +1220,7 @@ index 15c835e118456394c0a00ac98c11241c14ca75bd..a16faabe2bd63a5e0fbe9082a3b4b7c8
|
||||
char* errorbuf = nullptr;
|
||||
sandbox_profile_t* sandbox_profile =
|
||||
::sandbox_compile_string(profile, params.params(), &errorbuf);
|
||||
@@ -149,33 +172,44 @@ bool Seatbelt::Compile(const char* profile,
|
||||
@@ -155,33 +179,44 @@ bool Seatbelt::Compile(const char* profile,
|
||||
compiled_profile.assign(reinterpret_cast<const char*>(sandbox_profile->data),
|
||||
sandbox_profile->size);
|
||||
::sandbox_free_profile(sandbox_profile);
|
||||
@@ -1392,7 +1369,7 @@ index eb81a70e4d5d5cd3e6ae9b45f8cd1c795ea76c51..9921ccb10d3455600eddd85f77f10228
|
||||
|
||||
} // namespace sandbox
|
||||
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
|
||||
index 076ae475b3c4f0d2568e5efc9fedf2de7ccc82ad..b961c9c000bbb82c5f6ae63466c6d5d679d92de6 100644
|
||||
index 17b3ddd66513a01a631d77535cfeb1ae94881e0e..bde6c61489fe4f88abba79fd2fb809c292a3f99a 100644
|
||||
--- a/third_party/blink/renderer/core/BUILD.gn
|
||||
+++ b/third_party/blink/renderer/core/BUILD.gn
|
||||
@@ -409,6 +409,7 @@ component("core") {
|
||||
@@ -1634,7 +1611,7 @@ index c8171f0527fe5194f0ea73b57c4444d4c630fbc4..c2ac4da580e3e7f749a0a4de1e859af6
|
||||
// Accessible object
|
||||
if (AXElementWrapper::IsValidElement(value)) {
|
||||
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
|
||||
index 5ca4c8fc961d24985aa4e0459dc2c42003a5346f..2f5880d1d3fbc3aa1461bbe611c33f789a6f4dde 100644
|
||||
index f211074c41fd50597db8b72510149d27ffc8d90a..885511f666318ce1218a09c3ebf5ec1aa00e9ecf 100644
|
||||
--- a/ui/base/BUILD.gn
|
||||
+++ b/ui/base/BUILD.gn
|
||||
@@ -363,6 +363,13 @@ component("base") {
|
||||
@@ -1804,10 +1781,10 @@ index 29ae2da6a8a2c2a612dfb92f7f9c03ca5fa306b1..440c139a32a0c205e77b657d4aab6468
|
||||
// Query the display's refresh rate.
|
||||
if (@available(macos 12.0, *)) {
|
||||
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
|
||||
index 6cf9f1a38ed76edc8f64500476b4b3014dc7677f..54dcf71bd0bf5a1455b31f3d042305f0fc3e345b 100644
|
||||
index 230a9e8266fa494f870ed7fc7dc444d1db5bbb48..99facff7a8e98cbc175354ae4e1d1f592197320a 100644
|
||||
--- a/ui/gfx/BUILD.gn
|
||||
+++ b/ui/gfx/BUILD.gn
|
||||
@@ -331,6 +331,12 @@ component("gfx") {
|
||||
@@ -332,6 +332,12 @@ component("gfx") {
|
||||
"//ui/base:ui_data_pack",
|
||||
]
|
||||
|
||||
@@ -1859,7 +1836,7 @@ index fe3f85073e31de487a08e57d7f9b07aa4eccf8f3..cf5b07203c8bd559a404600cc98cc8ec
|
||||
// enough.
|
||||
return PlatformFontMac::SystemFontType::kGeneral;
|
||||
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
|
||||
index 94afec13361d4ee8d0441da3cbe37d62e287c94b..fd13add3291b113dc57c69700f35ac9943124786 100644
|
||||
index ee47ca61db4c321edce0d6ae49f9f6a21f01918a..c8fcad4a3af57cfb993018f0ad457c271bdefe0e 100644
|
||||
--- a/ui/views/BUILD.gn
|
||||
+++ b/ui/views/BUILD.gn
|
||||
@@ -718,6 +718,8 @@ component("views") {
|
||||
@@ -1871,7 +1848,7 @@ index 94afec13361d4ee8d0441da3cbe37d62e287c94b..fd13add3291b113dc57c69700f35ac99
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
@@ -1135,6 +1137,8 @@ source_set("test_support") {
|
||||
@@ -1138,6 +1140,8 @@ source_set("test_support") {
|
||||
"//ui/base/mojom:ui_base_types",
|
||||
]
|
||||
|
||||
|
||||
@@ -250,11 +250,7 @@ const std::string InclusionStatusToString(net::CookieInclusionStatus status) {
|
||||
{Reason::EXCLUDE_THIRD_PARTY_PHASEOUT,
|
||||
"The cookie is blocked for third-party cookie phaseout."},
|
||||
{Reason::EXCLUDE_NO_COOKIE_CONTENT,
|
||||
"The cookie contains no content or only whitespace."},
|
||||
{Reason::EXCLUDE_ALIASING,
|
||||
"Cookie aliases that of another with a different source_port or "
|
||||
"source scheme. I.e.: Two or more cookies share the same name "
|
||||
"but have different ports/schemes."}});
|
||||
"The cookie contains no content or only whitespace."}});
|
||||
static_assert(
|
||||
Reasons.size() ==
|
||||
net::CookieInclusionStatus::ExclusionReasonBitset::kValueCount,
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "shell/browser/extensions/electron_extension_info.h"
|
||||
#include "shell/browser/extensions/electron_extension_system.h"
|
||||
#include "shell/common/gin_converters/extension_converter.h"
|
||||
#endif
|
||||
@@ -1310,8 +1309,7 @@ v8::Local<v8::Promise> Session::GetSharedDictionaryUsageInfo() {
|
||||
v8::Local<v8::Promise> Session::LoadExtension(
|
||||
const base::FilePath& extension_path,
|
||||
gin::Arguments* args) {
|
||||
gin_helper::Promise<const extensions::ElectronExtensionInfo&> promise(
|
||||
isolate_);
|
||||
gin_helper::Promise<const extensions::Extension*> promise(isolate_);
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
if (!extension_path.IsAbsolute()) {
|
||||
@@ -1340,37 +1338,27 @@ v8::Local<v8::Promise> Session::LoadExtension(
|
||||
extension_system->LoadExtension(
|
||||
extension_path, load_flags,
|
||||
base::BindOnce(
|
||||
[](gin_helper::Promise<const extensions::ElectronExtensionInfo&>
|
||||
promise,
|
||||
base::WeakPtr<ElectronBrowserContext> browser_context,
|
||||
[](gin_helper::Promise<const extensions::Extension*> promise,
|
||||
const extensions::Extension* extension,
|
||||
const std::string& error_msg) {
|
||||
if (extension && browser_context) {
|
||||
if (extension) {
|
||||
if (!error_msg.empty())
|
||||
util::EmitWarning(promise.isolate(), error_msg,
|
||||
"ExtensionLoadWarning");
|
||||
const auto& extension_info = extensions::ElectronExtensionInfo(
|
||||
extension, browser_context.get());
|
||||
promise.Resolve(extension_info);
|
||||
promise.Resolve(extension);
|
||||
} else {
|
||||
promise.RejectWithErrorMessage(error_msg);
|
||||
}
|
||||
},
|
||||
std::move(promise), browser_context()->GetWeakPtr()));
|
||||
std::move(promise)));
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Session::RemoveExtension(const std::string& extension_id) {
|
||||
browser_context()->extension_system()->RemoveExtension(extension_id);
|
||||
}
|
||||
|
||||
void Session::EnableExtension(const std::string& extension_id) {
|
||||
browser_context()->extension_system()->EnableExtension(extension_id);
|
||||
}
|
||||
|
||||
void Session::DisableExtension(const std::string& extension_id) {
|
||||
browser_context()->extension_system()->DisableExtension(extension_id);
|
||||
auto* extension_system = static_cast<extensions::ElectronExtensionSystem*>(
|
||||
extensions::ExtensionSystem::Get(browser_context()));
|
||||
extension_system->RemoveExtension(extension_id);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Session::GetExtension(const std::string& extension_id) {
|
||||
@@ -1378,9 +1366,7 @@ v8::Local<v8::Value> Session::GetExtension(const std::string& extension_id) {
|
||||
const extensions::Extension* extension =
|
||||
registry->GetInstalledExtension(extension_id);
|
||||
if (extension) {
|
||||
const auto& extension_info =
|
||||
extensions::ElectronExtensionInfo(extension, browser_context());
|
||||
return gin::ConvertToV8(isolate_, extension_info);
|
||||
return gin::ConvertToV8(isolate_, extension);
|
||||
} else {
|
||||
return v8::Null(isolate_);
|
||||
}
|
||||
@@ -1390,40 +1376,29 @@ v8::Local<v8::Value> Session::GetAllExtensions() {
|
||||
auto* registry = extensions::ExtensionRegistry::Get(browser_context());
|
||||
const extensions::ExtensionSet extensions =
|
||||
registry->GenerateInstalledExtensionsSet();
|
||||
std::vector<extensions::ElectronExtensionInfo> extensions_vector;
|
||||
std::vector<const extensions::Extension*> extensions_vector;
|
||||
for (const auto& extension : extensions) {
|
||||
if (extension->location() !=
|
||||
extensions::mojom::ManifestLocation::kComponent) {
|
||||
const auto& extension_info =
|
||||
extensions::ElectronExtensionInfo(extension.get(), browser_context());
|
||||
extensions_vector.emplace_back(extension_info);
|
||||
}
|
||||
extensions::mojom::ManifestLocation::kComponent)
|
||||
extensions_vector.emplace_back(extension.get());
|
||||
}
|
||||
return gin::ConvertToV8(isolate_, extensions_vector);
|
||||
}
|
||||
|
||||
void Session::OnExtensionLoaded(
|
||||
content::BrowserContext* content_browser_context,
|
||||
const extensions::Extension* extension) {
|
||||
const auto& extension_info =
|
||||
extensions::ElectronExtensionInfo(extension, browser_context());
|
||||
Emit("extension-loaded", extension_info);
|
||||
void Session::OnExtensionLoaded(content::BrowserContext* browser_context,
|
||||
const extensions::Extension* extension) {
|
||||
Emit("extension-loaded", extension);
|
||||
}
|
||||
|
||||
void Session::OnExtensionUnloaded(
|
||||
content::BrowserContext* content_browser_context,
|
||||
const extensions::Extension* extension,
|
||||
extensions::UnloadedExtensionReason reason) {
|
||||
const auto& extension_info =
|
||||
extensions::ElectronExtensionInfo(extension, browser_context());
|
||||
Emit("extension-unloaded", extension_info);
|
||||
void Session::OnExtensionUnloaded(content::BrowserContext* browser_context,
|
||||
const extensions::Extension* extension,
|
||||
extensions::UnloadedExtensionReason reason) {
|
||||
Emit("extension-unloaded", extension);
|
||||
}
|
||||
|
||||
void Session::OnExtensionReady(content::BrowserContext* content_browser_context,
|
||||
void Session::OnExtensionReady(content::BrowserContext* browser_context,
|
||||
const extensions::Extension* extension) {
|
||||
const auto& extension_info =
|
||||
extensions::ElectronExtensionInfo(extension, browser_context());
|
||||
Emit("extension-ready", extension_info);
|
||||
Emit("extension-ready", extension);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1900,8 +1875,6 @@ void Session::FillObjectTemplate(v8::Isolate* isolate,
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
.SetMethod("loadExtension", &Session::LoadExtension)
|
||||
.SetMethod("removeExtension", &Session::RemoveExtension)
|
||||
.SetMethod("enableExtension", &Session::EnableExtension)
|
||||
.SetMethod("disableExtension", &Session::DisableExtension)
|
||||
.SetMethod("getExtension", &Session::GetExtension)
|
||||
.SetMethod("getAllExtensions", &Session::GetAllExtensions)
|
||||
#endif
|
||||
|
||||
@@ -182,8 +182,6 @@ class Session final : public gin::Wrappable<Session>,
|
||||
v8::Local<v8::Promise> LoadExtension(const base::FilePath& extension_path,
|
||||
gin::Arguments* args);
|
||||
void RemoveExtension(const std::string& extension_id);
|
||||
void EnableExtension(const std::string& extension_id);
|
||||
void DisableExtension(const std::string& extension_id);
|
||||
v8::Local<v8::Value> GetExtension(const std::string& extension_id);
|
||||
v8::Local<v8::Value> GetAllExtensions();
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "content/public/browser/keyboard_event_processing_result.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/browser/navigation_entry_restore_context.h"
|
||||
#include "content/public/browser/navigation_handle.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
@@ -363,14 +364,60 @@ struct Converter<scoped_refptr<content::DevToolsAgentHost>> {
|
||||
|
||||
template <>
|
||||
struct Converter<content::NavigationEntry*> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::NavigationEntry** out) {
|
||||
gin_helper::Dictionary dict;
|
||||
if (!gin::ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
|
||||
std::string url_str;
|
||||
std::string title;
|
||||
std::string encoded_page_state;
|
||||
GURL url;
|
||||
|
||||
if (!dict.Get("url", &url) || !dict.Get("title", &title))
|
||||
return false;
|
||||
|
||||
auto entry = content::NavigationEntry::Create();
|
||||
entry->SetURL(url);
|
||||
entry->SetTitle(base::UTF8ToUTF16(title));
|
||||
|
||||
// Handle optional page state
|
||||
if (dict.Get("pageState", &encoded_page_state)) {
|
||||
std::string decoded_page_state;
|
||||
if (base::Base64Decode(encoded_page_state, &decoded_page_state)) {
|
||||
auto restore_context = content::NavigationEntryRestoreContext::Create();
|
||||
|
||||
auto page_state =
|
||||
blink::PageState::CreateFromEncodedData(decoded_page_state);
|
||||
if (!page_state.IsValid())
|
||||
return false;
|
||||
|
||||
entry->SetPageState(std::move(page_state), restore_context.get());
|
||||
}
|
||||
}
|
||||
|
||||
*out = entry.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
content::NavigationEntry* entry) {
|
||||
if (!entry) {
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
gin_helper::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
gin_helper::Dictionary dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("url", entry->GetURL().spec());
|
||||
dict.Set("title", entry->GetTitleForDisplay());
|
||||
|
||||
// Page state saves scroll position and values of any form fields
|
||||
const blink::PageState& page_state = entry->GetPageState();
|
||||
if (page_state.IsValid()) {
|
||||
std::string encoded_data = base::Base64Encode(page_state.ToEncodedData());
|
||||
dict.Set("pageState", encoded_data);
|
||||
}
|
||||
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
@@ -2572,6 +2619,47 @@ std::vector<content::NavigationEntry*> WebContents::GetHistory() const {
|
||||
return history;
|
||||
}
|
||||
|
||||
void WebContents::RestoreHistory(
|
||||
v8::Isolate* isolate,
|
||||
gin_helper::ErrorThrower thrower,
|
||||
int index,
|
||||
const std::vector<v8::Local<v8::Value>>& entries) {
|
||||
if (!web_contents()
|
||||
->GetController()
|
||||
.GetLastCommittedEntry()
|
||||
->IsInitialEntry()) {
|
||||
thrower.ThrowError(
|
||||
"Cannot restore history on webContents that have previously loaded "
|
||||
"a page.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto navigation_entries = std::make_unique<
|
||||
std::vector<std::unique_ptr<content::NavigationEntry>>>();
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
content::NavigationEntry* nav_entry = nullptr;
|
||||
if (!gin::Converter<content::NavigationEntry*>::FromV8(isolate, entry,
|
||||
&nav_entry) ||
|
||||
!nav_entry) {
|
||||
// Invalid entry, bail out early
|
||||
thrower.ThrowError(
|
||||
"Failed to restore navigation history: Invalid navigation entry at "
|
||||
"index " +
|
||||
std::to_string(index) + ".");
|
||||
return;
|
||||
}
|
||||
navigation_entries->push_back(
|
||||
std::unique_ptr<content::NavigationEntry>(nav_entry));
|
||||
}
|
||||
|
||||
if (!navigation_entries->empty()) {
|
||||
web_contents()->GetController().Restore(
|
||||
index, content::RestoreType::kRestored, navigation_entries.get());
|
||||
web_contents()->GetController().LoadIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::ClearHistory() {
|
||||
// In some rare cases (normally while there is no real history) we are in a
|
||||
// state where we can't prune navigation entries
|
||||
@@ -4397,6 +4485,7 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
|
||||
&WebContents::RemoveNavigationEntryAtIndex)
|
||||
.SetMethod("_getHistory", &WebContents::GetHistory)
|
||||
.SetMethod("_clearHistory", &WebContents::ClearHistory)
|
||||
.SetMethod("_restoreHistory", &WebContents::RestoreHistory)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
.SetMethod("forcefullyCrashRenderer",
|
||||
&WebContents::ForcefullyCrashRenderer)
|
||||
|
||||
@@ -219,6 +219,10 @@ class WebContents final : public ExclusiveAccessContext,
|
||||
bool RemoveNavigationEntryAtIndex(int index);
|
||||
std::vector<content::NavigationEntry*> GetHistory() const;
|
||||
void ClearHistory();
|
||||
void RestoreHistory(v8::Isolate* isolate,
|
||||
gin_helper::ErrorThrower thrower,
|
||||
int index,
|
||||
const std::vector<v8::Local<v8::Value>>& entries);
|
||||
int GetHistoryLength() const;
|
||||
const std::string GetWebRTCIPHandlingPolicy() const;
|
||||
void SetWebRTCIPHandlingPolicy(const std::string& webrtc_ip_handling_policy);
|
||||
|
||||
@@ -70,6 +70,7 @@ class BrowserProcessImpl : public BrowserProcess {
|
||||
// BrowserProcess
|
||||
BuildState* GetBuildState() override;
|
||||
GlobalFeatures* GetFeatures() override;
|
||||
void CreateGlobalFeaturesForTesting() override {}
|
||||
void EndSession() override {}
|
||||
void FlushLocalStateAndReply(base::OnceClosure reply) override {}
|
||||
bool IsShuttingDown() override;
|
||||
|
||||
@@ -155,7 +155,10 @@ class ElectronBrowserContext : public content::BrowserContext {
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
extensions::ElectronExtensionSystem* extension_system() const {
|
||||
extensions::ElectronExtensionSystem* extension_system() {
|
||||
// Guard usages of extension_system() with !IsOffTheRecord()
|
||||
// There is no extension system for in-memory sessions
|
||||
DCHECK(!IsOffTheRecord());
|
||||
return extension_system_;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,6 @@ class ElectronPDFDocumentHelperClient : public pdf::PDFDocumentHelperClient {
|
||||
// pdf::PDFDocumentHelperClient
|
||||
void UpdateContentRestrictions(content::RenderFrameHost* render_frame_host,
|
||||
int content_restrictions) override;
|
||||
void OnPDFHasUnsupportedFeature(content::WebContents* contents) override {}
|
||||
void OnSaveURL(content::WebContents* contents) override {}
|
||||
void SetPluginCanSave(content::RenderFrameHost* render_frame_host,
|
||||
bool can_save) override;
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_INFO_H_
|
||||
#define ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_INFO_H_
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
|
||||
namespace electron {
|
||||
class ElectronBrowserContext;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class Extension;
|
||||
|
||||
struct ElectronExtensionInfo {
|
||||
explicit ElectronExtensionInfo(
|
||||
const Extension* extension_in,
|
||||
const electron::ElectronBrowserContext* browser_context_in)
|
||||
: extension(extension_in), browser_context(browser_context_in) {
|
||||
DCHECK(extension_in);
|
||||
DCHECK(browser_context_in);
|
||||
}
|
||||
|
||||
raw_ptr<const Extension> extension;
|
||||
raw_ptr<const electron::ElectronBrowserContext> browser_context;
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_INFO_H_
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/auto_reset.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
@@ -16,14 +17,16 @@
|
||||
#include "base/time/time.h"
|
||||
#include "extensions/browser/extension_file_task_runner.h"
|
||||
#include "extensions/browser/extension_prefs.h"
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "extensions/browser/pref_names.h"
|
||||
#include "extensions/common/error_utils.h"
|
||||
#include "extensions/common/file_util.h"
|
||||
#include "extensions/common/manifest_constants.h"
|
||||
#include "shell/browser/extensions/electron_extension_system.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
|
||||
|
||||
namespace {
|
||||
|
||||
std::pair<scoped_refptr<const Extension>, std::string> LoadUnpacked(
|
||||
@@ -89,9 +92,9 @@ std::pair<scoped_refptr<const Extension>, std::string> LoadUnpacked(
|
||||
} // namespace
|
||||
|
||||
ElectronExtensionLoader::ElectronExtensionLoader(
|
||||
content::BrowserContext* browser_context,
|
||||
ElectronExtensionSystem* extension_system)
|
||||
: browser_context_(browser_context), extension_system_(extension_system) {}
|
||||
content::BrowserContext* browser_context)
|
||||
: browser_context_(browser_context),
|
||||
extension_registrar_(browser_context, this) {}
|
||||
|
||||
ElectronExtensionLoader::~ElectronExtensionLoader() = default;
|
||||
|
||||
@@ -105,12 +108,34 @@ void ElectronExtensionLoader::LoadExtension(
|
||||
weak_factory_.GetWeakPtr(), std::move(cb)));
|
||||
}
|
||||
|
||||
void ElectronExtensionLoader::ReloadExtension(const ExtensionId& extension_id) {
|
||||
const Extension* extension = ExtensionRegistry::Get(browser_context_)
|
||||
->GetInstalledExtension(extension_id);
|
||||
// We shouldn't be trying to reload extensions that haven't been added.
|
||||
DCHECK(extension);
|
||||
|
||||
// This should always start false since it's only set here, or in
|
||||
// LoadExtensionForReload() as a result of the call below.
|
||||
DCHECK_EQ(false, did_schedule_reload_);
|
||||
base::AutoReset<bool> reset_did_schedule_reload(&did_schedule_reload_, false);
|
||||
|
||||
extension_registrar_.ReloadExtension(extension_id, LoadErrorBehavior::kQuiet);
|
||||
if (did_schedule_reload_)
|
||||
return;
|
||||
}
|
||||
|
||||
void ElectronExtensionLoader::UnloadExtension(
|
||||
const ExtensionId& extension_id,
|
||||
extensions::UnloadedExtensionReason reason) {
|
||||
extension_registrar_.RemoveExtension(extension_id, reason);
|
||||
}
|
||||
|
||||
void ElectronExtensionLoader::FinishExtensionLoad(
|
||||
base::OnceCallback<void(const Extension*, const std::string&)> cb,
|
||||
std::pair<scoped_refptr<const Extension>, std::string> result) {
|
||||
scoped_refptr<const Extension> extension = result.first;
|
||||
if (extension) {
|
||||
extension_system_->AddExtension(extension.get());
|
||||
extension_registrar_.AddExtension(extension);
|
||||
|
||||
// Write extension install time to ExtensionPrefs. This is required by
|
||||
// WebRequestAPI which calls extensions::ExtensionPrefs::GetInstallTime.
|
||||
@@ -133,4 +158,89 @@ void ElectronExtensionLoader::FinishExtensionLoad(
|
||||
std::move(cb).Run(extension.get(), result.second);
|
||||
}
|
||||
|
||||
void ElectronExtensionLoader::FinishExtensionReload(
|
||||
const ExtensionId& old_extension_id,
|
||||
std::pair<scoped_refptr<const Extension>, std::string> result) {
|
||||
scoped_refptr<const Extension> extension = result.first;
|
||||
if (extension) {
|
||||
extension_registrar_.AddExtension(extension);
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronExtensionLoader::PreAddExtension(const Extension* extension,
|
||||
const Extension* old_extension) {
|
||||
if (old_extension)
|
||||
return;
|
||||
|
||||
// The extension might be disabled if a previous reload attempt failed. In
|
||||
// that case, we want to remove that disable reason.
|
||||
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
|
||||
if (extension_prefs->IsExtensionDisabled(extension->id()) &&
|
||||
extension_prefs->HasDisableReason(extension->id(),
|
||||
disable_reason::DISABLE_RELOAD)) {
|
||||
extension_prefs->RemoveDisableReason(extension->id(),
|
||||
disable_reason::DISABLE_RELOAD);
|
||||
// Only re-enable the extension if there are no other disable reasons.
|
||||
if (extension_prefs->GetDisableReasons(extension->id()).empty()) {
|
||||
extension_prefs->SetExtensionEnabled(extension->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronExtensionLoader::PostActivateExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionLoader::PostDeactivateExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionLoader::PreUninstallExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionLoader::PostUninstallExtension(
|
||||
scoped_refptr<const Extension> extension,
|
||||
base::OnceClosure done_callback) {}
|
||||
|
||||
void ElectronExtensionLoader::PostNotifyUninstallExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionLoader::LoadExtensionForReload(
|
||||
const ExtensionId& extension_id,
|
||||
const base::FilePath& path,
|
||||
LoadErrorBehavior load_error_behavior) {
|
||||
CHECK(!path.empty());
|
||||
|
||||
// TODO(nornagon): we should save whether file access was granted
|
||||
// when loading this extension and retain it here. As is, reloading an
|
||||
// extension will cause the file access permission to be dropped.
|
||||
int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE;
|
||||
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
|
||||
FROM_HERE, base::BindOnce(&LoadUnpacked, path, load_flags),
|
||||
base::BindOnce(&ElectronExtensionLoader::FinishExtensionReload,
|
||||
weak_factory_.GetWeakPtr(), extension_id));
|
||||
did_schedule_reload_ = true;
|
||||
}
|
||||
|
||||
void ElectronExtensionLoader::ShowExtensionDisabledError(
|
||||
const Extension* extension,
|
||||
bool is_remote_install) {}
|
||||
|
||||
void ElectronExtensionLoader::FinishDelayedInstallationsIfAny() {}
|
||||
|
||||
bool ElectronExtensionLoader::CanAddExtension(const Extension* extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElectronExtensionLoader::CanEnableExtension(const Extension* extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElectronExtensionLoader::CanDisableExtension(const Extension* extension) {
|
||||
// Extensions cannot be disabled by the user.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ElectronExtensionLoader::ShouldBlockExtension(const Extension* extension) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "extensions/browser/extension_registrar.h"
|
||||
#include "extensions/common/extension_id.h"
|
||||
|
||||
namespace base {
|
||||
@@ -24,14 +25,12 @@ class BrowserContext;
|
||||
namespace extensions {
|
||||
|
||||
class Extension;
|
||||
class ElectronExtensionSystem;
|
||||
|
||||
// Handles extension loading.
|
||||
class ElectronExtensionLoader {
|
||||
// Handles extension loading and reloading using ExtensionRegistrar.
|
||||
class ElectronExtensionLoader : public ExtensionRegistrar::Delegate {
|
||||
public:
|
||||
explicit ElectronExtensionLoader(content::BrowserContext* browser_context,
|
||||
ElectronExtensionSystem* extension_system);
|
||||
~ElectronExtensionLoader();
|
||||
explicit ElectronExtensionLoader(content::BrowserContext* browser_context);
|
||||
~ElectronExtensionLoader() override;
|
||||
|
||||
// disable copy
|
||||
ElectronExtensionLoader(const ElectronExtensionLoader&) = delete;
|
||||
@@ -44,13 +43,64 @@ class ElectronExtensionLoader {
|
||||
base::OnceCallback<void(const Extension* extension,
|
||||
const std::string&)> cb);
|
||||
|
||||
// Starts reloading the extension. A keep-alive is maintained until the
|
||||
// reload succeeds/fails. If the extension is an app, it will be launched upon
|
||||
// reloading.
|
||||
// This may invalidate references to the old Extension object, so it takes the
|
||||
// ID by value.
|
||||
void ReloadExtension(const ExtensionId& extension_id);
|
||||
|
||||
void UnloadExtension(const ExtensionId& extension_id,
|
||||
extensions::UnloadedExtensionReason reason);
|
||||
|
||||
ExtensionRegistrar* registrar() { return &extension_registrar_; }
|
||||
|
||||
private:
|
||||
// If the extension loaded successfully, enables it. If it's an app, launches
|
||||
// it. If the load failed, updates ShellKeepAliveRequester.
|
||||
void FinishExtensionReload(
|
||||
const ExtensionId& old_extension_id,
|
||||
std::pair<scoped_refptr<const Extension>, std::string> result);
|
||||
|
||||
void FinishExtensionLoad(
|
||||
base::OnceCallback<void(const Extension*, const std::string&)> cb,
|
||||
std::pair<scoped_refptr<const Extension>, std::string> result);
|
||||
|
||||
raw_ptr<content::BrowserContext> browser_context_; // Not owned.
|
||||
raw_ptr<ElectronExtensionSystem> extension_system_; // Not owned.
|
||||
// ExtensionRegistrar::Delegate:
|
||||
void PreAddExtension(const Extension* extension,
|
||||
const Extension* old_extension) override;
|
||||
void PostActivateExtension(scoped_refptr<const Extension> extension) override;
|
||||
void PostDeactivateExtension(
|
||||
scoped_refptr<const Extension> extension) override;
|
||||
void PreUninstallExtension(scoped_refptr<const Extension> extension) override;
|
||||
void PostUninstallExtension(scoped_refptr<const Extension> extension,
|
||||
base::OnceClosure done_callback) override;
|
||||
void PostNotifyUninstallExtension(
|
||||
scoped_refptr<const Extension> extension) override;
|
||||
void LoadExtensionForReload(
|
||||
const ExtensionId& extension_id,
|
||||
const base::FilePath& path,
|
||||
ExtensionRegistrar::LoadErrorBehavior load_error_behavior) override;
|
||||
void ShowExtensionDisabledError(const Extension* extension,
|
||||
bool is_remote_install) override;
|
||||
void FinishDelayedInstallationsIfAny() override;
|
||||
bool CanAddExtension(const Extension* extension) override;
|
||||
bool CanEnableExtension(const Extension* extension) override;
|
||||
bool CanDisableExtension(const Extension* extension) override;
|
||||
bool ShouldBlockExtension(const Extension* extension) override;
|
||||
|
||||
raw_ptr<content::BrowserContext> browser_context_; // Not owned.
|
||||
|
||||
// Registers and unregisters extensions.
|
||||
ExtensionRegistrar extension_registrar_;
|
||||
|
||||
// Holds keep-alives for relaunching apps.
|
||||
// ShellKeepAliveRequester keep_alive_requester_;
|
||||
|
||||
// Indicates that we posted the (asynchronous) task to start reloading.
|
||||
// Used by ReloadExtension() to check whether ExtensionRegistrar calls
|
||||
// LoadExtensionForReload().
|
||||
bool did_schedule_reload_ = false;
|
||||
|
||||
base::WeakPtrFactory<ElectronExtensionLoader> weak_factory_{this};
|
||||
};
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/extensions/electron_extension_registrar_delegate.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/auto_reset.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "extensions/browser/extension_file_task_runner.h"
|
||||
#include "extensions/browser/extension_prefs.h"
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "extensions/browser/pref_names.h"
|
||||
#include "extensions/common/error_utils.h"
|
||||
#include "extensions/common/file_util.h"
|
||||
#include "extensions/common/manifest_constants.h"
|
||||
#include "shell/browser/extensions/electron_extension_system.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
|
||||
|
||||
ElectronExtensionRegistrarDelegate::ElectronExtensionRegistrarDelegate(
|
||||
content::BrowserContext* browser_context,
|
||||
ElectronExtensionSystem* extension_system)
|
||||
: browser_context_(browser_context), extension_system_(extension_system) {}
|
||||
|
||||
ElectronExtensionRegistrarDelegate::~ElectronExtensionRegistrarDelegate() =
|
||||
default;
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::PreAddExtension(
|
||||
const Extension* extension,
|
||||
const Extension* old_extension) {
|
||||
if (old_extension)
|
||||
return;
|
||||
|
||||
// The extension might be disabled if a previous reload attempt failed. In
|
||||
// that case, we want to remove that disable reason.
|
||||
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
|
||||
if (extension_prefs->IsExtensionDisabled(extension->id()) &&
|
||||
extension_prefs->HasDisableReason(extension->id(),
|
||||
disable_reason::DISABLE_RELOAD)) {
|
||||
extension_prefs->RemoveDisableReason(extension->id(),
|
||||
disable_reason::DISABLE_RELOAD);
|
||||
// Only re-enable the extension if there are no other disable reasons.
|
||||
if (extension_prefs->GetDisableReasons(extension->id()) ==
|
||||
disable_reason::DISABLE_NONE) {
|
||||
extension_prefs->SetExtensionEnabled(extension->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::PostActivateExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::PostDeactivateExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::PreUninstallExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::PostUninstallExtension(
|
||||
scoped_refptr<const Extension> extension,
|
||||
base::OnceClosure done_callback) {}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::PostNotifyUninstallExtension(
|
||||
scoped_refptr<const Extension> extension) {}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::LoadExtensionForReload(
|
||||
const ExtensionId& extension_id,
|
||||
const base::FilePath& path,
|
||||
LoadErrorBehavior load_error_behavior) {
|
||||
CHECK(!path.empty());
|
||||
|
||||
// TODO(nornagon): we should save whether file access was granted
|
||||
// when loading this extension and retain it here. As is, reloading an
|
||||
// extension will cause the file access permission to be dropped.
|
||||
int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE;
|
||||
extension_system_->LoadExtension(
|
||||
path, load_flags,
|
||||
base::BindOnce(&ElectronExtensionRegistrarDelegate::FinishExtensionReload,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::FinishExtensionReload(
|
||||
const Extension* extension,
|
||||
const ExtensionId& extension_id) {
|
||||
if (extension) {
|
||||
extension_system_->AddExtension(extension);
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::ShowExtensionDisabledError(
|
||||
const Extension* extension,
|
||||
bool is_remote_install) {}
|
||||
|
||||
void ElectronExtensionRegistrarDelegate::FinishDelayedInstallationsIfAny() {}
|
||||
|
||||
bool ElectronExtensionRegistrarDelegate::CanAddExtension(
|
||||
const Extension* extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElectronExtensionRegistrarDelegate::CanEnableExtension(
|
||||
const Extension* extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElectronExtensionRegistrarDelegate::CanDisableExtension(
|
||||
const Extension* extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElectronExtensionRegistrarDelegate::ShouldBlockExtension(
|
||||
const Extension* extension) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
@@ -1,86 +0,0 @@
|
||||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_REGISTRAR_DELEGATE_H_
|
||||
#define ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_REGISTRAR_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "extensions/browser/extension_registrar.h"
|
||||
#include "extensions/common/extension_id.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class Extension;
|
||||
class ElectronExtensionSystem;
|
||||
|
||||
// Handles extension loading and reloading using ExtensionRegistrar.
|
||||
class ElectronExtensionRegistrarDelegate : public ExtensionRegistrar::Delegate {
|
||||
public:
|
||||
explicit ElectronExtensionRegistrarDelegate(
|
||||
content::BrowserContext* browser_context,
|
||||
ElectronExtensionSystem* extension_system);
|
||||
~ElectronExtensionRegistrarDelegate() override;
|
||||
|
||||
// disable copy
|
||||
ElectronExtensionRegistrarDelegate(
|
||||
const ElectronExtensionRegistrarDelegate&) = delete;
|
||||
ElectronExtensionRegistrarDelegate& operator=(
|
||||
const ElectronExtensionRegistrarDelegate&) = delete;
|
||||
|
||||
void set_extension_registrar(ExtensionRegistrar* registrar) {
|
||||
extension_registrar_ = registrar;
|
||||
}
|
||||
|
||||
private:
|
||||
// ExtensionRegistrar::Delegate:
|
||||
void PreAddExtension(const Extension* extension,
|
||||
const Extension* old_extension) override;
|
||||
void PostActivateExtension(scoped_refptr<const Extension> extension) override;
|
||||
void PostDeactivateExtension(
|
||||
scoped_refptr<const Extension> extension) override;
|
||||
void PreUninstallExtension(scoped_refptr<const Extension> extension) override;
|
||||
void PostUninstallExtension(scoped_refptr<const Extension> extension,
|
||||
base::OnceClosure done_callback) override;
|
||||
void PostNotifyUninstallExtension(
|
||||
scoped_refptr<const Extension> extension) override;
|
||||
void LoadExtensionForReload(
|
||||
const ExtensionId& extension_id,
|
||||
const base::FilePath& path,
|
||||
ExtensionRegistrar::LoadErrorBehavior load_error_behavior) override;
|
||||
void ShowExtensionDisabledError(const Extension* extension,
|
||||
bool is_remote_install) override;
|
||||
void FinishDelayedInstallationsIfAny() override;
|
||||
bool CanAddExtension(const Extension* extension) override;
|
||||
bool CanEnableExtension(const Extension* extension) override;
|
||||
bool CanDisableExtension(const Extension* extension) override;
|
||||
bool ShouldBlockExtension(const Extension* extension) override;
|
||||
|
||||
// If the extension loaded successfully, enables it. If it's an app, launches
|
||||
// it. If the load failed, updates ShellKeepAliveRequester.
|
||||
void FinishExtensionReload(const Extension* extension,
|
||||
const ExtensionId& extension_id);
|
||||
|
||||
raw_ptr<content::BrowserContext> browser_context_; // Not owned.
|
||||
raw_ptr<ElectronExtensionSystem> extension_system_; // Not owned.
|
||||
raw_ptr<ExtensionRegistrar> extension_registrar_ = nullptr;
|
||||
|
||||
base::WeakPtrFactory<ElectronExtensionRegistrarDelegate> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_REGISTRAR_DELEGATE_H_
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "extensions/browser/user_script_manager.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "shell/browser/extensions/electron_extension_loader.h"
|
||||
#include "shell/browser/extensions/electron_extension_registrar_delegate.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
#include "chrome/browser/pdf/pdf_extension_util.h" // nogncheck
|
||||
@@ -40,8 +39,6 @@ using content::BrowserThread;
|
||||
|
||||
namespace extensions {
|
||||
|
||||
using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
|
||||
|
||||
ElectronExtensionSystem::ElectronExtensionSystem(
|
||||
BrowserContext* browser_context)
|
||||
: browser_context_(browser_context),
|
||||
@@ -50,10 +47,6 @@ ElectronExtensionSystem::ElectronExtensionSystem(
|
||||
|
||||
ElectronExtensionSystem::~ElectronExtensionSystem() = default;
|
||||
|
||||
void ElectronExtensionSystem::AddExtension(const Extension* extension) {
|
||||
extension_registrar_->AddExtension(extension);
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::LoadExtension(
|
||||
const base::FilePath& extension_dir,
|
||||
int load_flags,
|
||||
@@ -67,56 +60,26 @@ void ElectronExtensionSystem::FinishInitialization() {
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::ReloadExtension(const ExtensionId& extension_id) {
|
||||
const Extension* extension = ExtensionRegistry::Get(browser_context_)
|
||||
->GetInstalledExtension(extension_id);
|
||||
// We shouldn't be trying to reload extensions that haven't been added.
|
||||
DCHECK(extension);
|
||||
|
||||
extension_registrar_->ReloadExtension(extension_id,
|
||||
LoadErrorBehavior::kQuiet);
|
||||
extension_loader_->ReloadExtension(extension_id);
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::RemoveExtension(const ExtensionId& extension_id) {
|
||||
extension_registrar_->RemoveExtension(
|
||||
extension_loader_->UnloadExtension(
|
||||
extension_id, extensions::UnloadedExtensionReason::UNINSTALL);
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::EnableExtension(const std::string& extension_id) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
extension_registrar_->EnableExtension(extension_id);
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::DisableExtension(
|
||||
const ExtensionId& extension_id) {
|
||||
extension_registrar_->DisableExtension(
|
||||
extension_id, disable_reason::DisableReason::DISABLE_USER_ACTION);
|
||||
}
|
||||
|
||||
bool ElectronExtensionSystem::IsExtensionEnabled(
|
||||
const ExtensionId& extension_id) const {
|
||||
return extension_registrar_->IsExtensionEnabled(extension_id);
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::Shutdown() {
|
||||
extension_loader_.reset();
|
||||
}
|
||||
|
||||
void ElectronExtensionSystem::InitForRegularProfile(bool extensions_enabled) {
|
||||
extension_registrar_delegate_ =
|
||||
std::make_unique<ElectronExtensionRegistrarDelegate>(browser_context_,
|
||||
this);
|
||||
extension_registrar_ = std::make_unique<ExtensionRegistrar>(
|
||||
browser_context_, extension_registrar_delegate_.get());
|
||||
extension_registrar_delegate_->set_extension_registrar(
|
||||
extension_registrar_.get());
|
||||
|
||||
service_worker_manager_ =
|
||||
std::make_unique<ServiceWorkerManager>(browser_context_);
|
||||
quota_service_ = std::make_unique<QuotaService>();
|
||||
user_script_manager_ = std::make_unique<UserScriptManager>(browser_context_);
|
||||
app_sorting_ = std::make_unique<NullAppSorting>();
|
||||
extension_loader_ =
|
||||
std::make_unique<ElectronExtensionLoader>(browser_context_, this);
|
||||
std::make_unique<ElectronExtensionLoader>(browser_context_);
|
||||
|
||||
if (!browser_context_->IsOffTheRecord())
|
||||
LoadComponentExtensions();
|
||||
@@ -157,7 +120,7 @@ void ElectronExtensionSystem::LoadComponentExtensions() {
|
||||
extensions::Extension::Create(
|
||||
root_directory, extensions::mojom::ManifestLocation::kComponent,
|
||||
*pdf_manifest, extensions::Extension::REQUIRE_KEY, &utf8_error);
|
||||
AddExtension(pdf_extension.get());
|
||||
extension_loader_->registrar()->AddExtension(pdf_extension);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
#include "base/one_shot_event.h"
|
||||
#include "components/value_store/value_store_factory.h"
|
||||
#include "components/value_store/value_store_factory_impl.h"
|
||||
#include "extensions/browser/disable_reason.h"
|
||||
#include "extensions/browser/extension_registrar.h"
|
||||
#include "extensions/browser/extension_system.h"
|
||||
|
||||
namespace base {
|
||||
@@ -28,7 +26,6 @@ class BrowserContext;
|
||||
namespace extensions {
|
||||
|
||||
class ElectronExtensionLoader;
|
||||
class ElectronExtensionRegistrarDelegate;
|
||||
class ValueStoreFactory;
|
||||
|
||||
// A simplified version of ExtensionSystem for app_shell. Allows
|
||||
@@ -43,10 +40,6 @@ class ElectronExtensionSystem : public ExtensionSystem {
|
||||
ElectronExtensionSystem(const ElectronExtensionSystem&) = delete;
|
||||
ElectronExtensionSystem& operator=(const ElectronExtensionSystem&) = delete;
|
||||
|
||||
// Adds |extension| to this ExtensionService and notifies observers that the
|
||||
// extension has been loaded.
|
||||
void AddExtension(const Extension* extension);
|
||||
|
||||
// Loads an unpacked extension from a directory. Returns the extension on
|
||||
// success, or nullptr otherwise.
|
||||
void LoadExtension(
|
||||
@@ -62,17 +55,6 @@ class ElectronExtensionSystem : public ExtensionSystem {
|
||||
|
||||
void RemoveExtension(const ExtensionId& extension_id);
|
||||
|
||||
// Enables the extension. If the extension is already enabled, does
|
||||
// nothing.
|
||||
void EnableExtension(const ExtensionId& extension_id);
|
||||
|
||||
// Disables the extension. If the extension is already disabled, just adds
|
||||
// the incoming disable reason(s). If the extension cannot be disabled (due to
|
||||
// policy), does nothing.
|
||||
void DisableExtension(const ExtensionId& extension_id);
|
||||
|
||||
bool IsExtensionEnabled(const ExtensionId& extension_id) const;
|
||||
|
||||
// KeyedService implementation:
|
||||
void Shutdown() override;
|
||||
|
||||
@@ -104,10 +86,6 @@ class ElectronExtensionSystem : public ExtensionSystem {
|
||||
const std::string& extension_id,
|
||||
const base::Value::Dict& attributes) override;
|
||||
|
||||
base::WeakPtr<ElectronExtensionSystem> GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
private:
|
||||
void OnExtensionRegisteredWithRequestContexts(
|
||||
scoped_refptr<Extension> extension);
|
||||
@@ -121,12 +99,6 @@ class ElectronExtensionSystem : public ExtensionSystem {
|
||||
std::unique_ptr<AppSorting> app_sorting_;
|
||||
std::unique_ptr<ManagementPolicy> management_policy_;
|
||||
|
||||
std::unique_ptr<ElectronExtensionRegistrarDelegate>
|
||||
extension_registrar_delegate_;
|
||||
|
||||
// Helper to register and unregister extensions.
|
||||
std::unique_ptr<ExtensionRegistrar> extension_registrar_;
|
||||
|
||||
std::unique_ptr<ElectronExtensionLoader> extension_loader_;
|
||||
|
||||
scoped_refptr<value_store::ValueStoreFactory> store_factory_;
|
||||
|
||||
@@ -1636,8 +1636,8 @@ gfx::Rect NativeWindowViews::WindowBoundsToContentBounds(
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
void NativeWindowViews::SetIcon(HICON window_icon, HICON app_icon) {
|
||||
// We are responsible for storing the images.
|
||||
window_icon_ = base::win::ScopedHICON(CopyIcon(window_icon));
|
||||
app_icon_ = base::win::ScopedHICON(CopyIcon(app_icon));
|
||||
window_icon_ = base::win::ScopedGDIObject<HICON>(CopyIcon(window_icon));
|
||||
app_icon_ = base::win::ScopedGDIObject<HICON>(CopyIcon(app_icon));
|
||||
|
||||
HWND hwnd = GetAcceleratedWidget();
|
||||
SendMessage(hwnd, WM_SETICON, ICON_SMALL,
|
||||
|
||||
@@ -277,8 +277,8 @@ class NativeWindowViews : public NativeWindow,
|
||||
gfx::Rect restore_bounds_;
|
||||
|
||||
// The icons of window and taskbar.
|
||||
base::win::ScopedHICON window_icon_;
|
||||
base::win::ScopedHICON app_icon_;
|
||||
base::win::ScopedGDIObject<HICON> window_icon_;
|
||||
base::win::ScopedGDIObject<HICON> app_icon_;
|
||||
|
||||
// The set of windows currently forwarding mouse messages.
|
||||
static std::set<NativeWindowViews*> forwarding_windows_;
|
||||
|
||||
@@ -99,7 +99,7 @@ void OffScreenVideoConsumer::OnFrameCaptured(
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
texture.shared_texture_handle =
|
||||
reinterpret_cast<uintptr_t>(gmb_handle.dxgi_handle.Get());
|
||||
reinterpret_cast<uintptr_t>(gmb_handle.dxgi_handle().buffer_handle());
|
||||
#elif BUILDFLAG(IS_APPLE)
|
||||
texture.shared_texture_handle =
|
||||
reinterpret_cast<uintptr_t>(gmb_handle.io_surface.get());
|
||||
|
||||
@@ -176,7 +176,7 @@ DialogResult ShowTaskDialogWstr(gfx::AcceleratedWidget parent,
|
||||
config.pszWindowTitle = base::as_wcstr(title);
|
||||
}
|
||||
|
||||
base::win::ScopedHICON hicon;
|
||||
base::win::ScopedGDIObject<HICON> hicon;
|
||||
if (!icon.isNull()) {
|
||||
hicon = IconUtil::CreateHICONFromSkBitmap(*icon.bitmap());
|
||||
config.dwFlags |= TDF_USE_HICON_MAIN;
|
||||
|
||||
@@ -129,7 +129,7 @@ void NotifyIcon::ResetIcon() {
|
||||
}
|
||||
|
||||
void NotifyIcon::SetImage(HICON image) {
|
||||
icon_ = base::win::ScopedHICON(CopyIcon(image));
|
||||
icon_ = base::win::ScopedGDIObject<HICON>(CopyIcon(image));
|
||||
|
||||
// Create the icon.
|
||||
NOTIFYICONDATA icon_data;
|
||||
|
||||
@@ -91,7 +91,7 @@ class NotifyIcon : public TrayIcon {
|
||||
UINT message_id_;
|
||||
|
||||
// The currently-displayed icon for the window.
|
||||
base::win::ScopedHICON icon_;
|
||||
base::win::ScopedGDIObject<HICON> icon_;
|
||||
|
||||
// The context menu.
|
||||
raw_ptr<ElectronMenuModel> menu_model_ = nullptr;
|
||||
|
||||
@@ -73,7 +73,8 @@ bool TaskbarHost::SetThumbarButtons(HWND window,
|
||||
// The number of buttons in thumbar can not be changed once it is created,
|
||||
// so we have to claim kMaxButtonsCount buttons initially in case users add
|
||||
// more buttons later.
|
||||
auto icons = std::array<base::win::ScopedHICON, kMaxButtonsCount>{};
|
||||
auto icons =
|
||||
std::array<base::win::ScopedGDIObject<HICON>, kMaxButtonsCount>{};
|
||||
auto thumb_buttons = std::array<THUMBBUTTON, kMaxButtonsCount>{};
|
||||
|
||||
for (size_t i = 0U; i < kMaxButtonsCount; ++i) {
|
||||
|
||||
@@ -102,7 +102,8 @@ bool IsTemplateFilename(const base::FilePath& path) {
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) {
|
||||
base::win::ScopedGDIObject<HICON> ReadICOFromPath(int size,
|
||||
const base::FilePath& path) {
|
||||
// If file is in asar archive, we extract it to a temp file so LoadImage can
|
||||
// load it.
|
||||
base::FilePath asar_path, relative_path;
|
||||
@@ -115,7 +116,7 @@ base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) {
|
||||
}
|
||||
|
||||
// Load the icon from file.
|
||||
return base::win::ScopedHICON(
|
||||
return base::win::ScopedGDIObject<HICON>(
|
||||
static_cast<HICON>(LoadImage(nullptr, image_path.value().c_str(),
|
||||
IMAGE_ICON, size, size, LR_LOADFROMFILE)));
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ class NativeImage final : public gin::Wrappable<NativeImage> {
|
||||
base::FilePath hicon_path_;
|
||||
|
||||
// size -> hicon
|
||||
base::flat_map<int, base::win::ScopedHICON> hicons_;
|
||||
base::flat_map<int, base::win::ScopedGDIObject<HICON>> hicons_;
|
||||
#endif
|
||||
|
||||
gfx::Image image_;
|
||||
|
||||
@@ -90,7 +90,7 @@ v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath(
|
||||
icon_info.hbmMask = hBitmap;
|
||||
icon_info.hbmColor = hBitmap;
|
||||
|
||||
base::win::ScopedHICON icon(CreateIconIndirect(&icon_info));
|
||||
base::win::ScopedGDIObject<HICON> icon(CreateIconIndirect(&icon_info));
|
||||
SkBitmap skbitmap = IconUtil::CreateSkBitmapFromHICON(icon.get());
|
||||
gfx::ImageSkia image_skia =
|
||||
gfx::ImageSkia::CreateFromBitmap(skbitmap, 1.0 /*scale factor*/);
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
#include "extensions/common/extension.h"
|
||||
#include "gin/dictionary.h"
|
||||
#include "shell/browser/electron_browser_context.h"
|
||||
#include "shell/browser/extensions/electron_extension_info.h"
|
||||
#include "shell/browser/extensions/electron_extension_system.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_converters/gurl_converter.h"
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
@@ -16,20 +13,16 @@
|
||||
namespace gin {
|
||||
|
||||
// static
|
||||
v8::Local<v8::Value> Converter<extensions::ElectronExtensionInfo>::ToV8(
|
||||
v8::Local<v8::Value> Converter<const extensions::Extension*>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const extensions::ElectronExtensionInfo& info) {
|
||||
auto extension_id = info.extension->id();
|
||||
const extensions::Extension* extension) {
|
||||
auto dict = gin::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("id", extension_id);
|
||||
dict.Set("name", info.extension->name());
|
||||
dict.Set("path", info.extension->path());
|
||||
dict.Set("url", info.extension->url());
|
||||
dict.Set("version", info.extension->VersionString());
|
||||
dict.Set("manifest", *info.extension->manifest()->value());
|
||||
|
||||
auto* ext_system = info.browser_context->extension_system();
|
||||
dict.Set("enabled", ext_system->IsExtensionEnabled(extension_id));
|
||||
dict.Set("id", extension->id());
|
||||
dict.Set("name", extension->name());
|
||||
dict.Set("path", extension->path());
|
||||
dict.Set("url", extension->url());
|
||||
dict.Set("version", extension->VersionString());
|
||||
dict.Set("manifest", *extension->manifest()->value());
|
||||
|
||||
return gin::ConvertToV8(isolate, dict);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2025 Salesforce, Inc.
|
||||
// Copyright (c) 2019 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@@ -8,16 +8,15 @@
|
||||
#include "gin/converter.h"
|
||||
|
||||
namespace extensions {
|
||||
struct ElectronExtensionInfo;
|
||||
class Extension;
|
||||
}
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <>
|
||||
struct Converter<extensions::ElectronExtensionInfo> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const extensions::ElectronExtensionInfo& val);
|
||||
struct Converter<const extensions::Extension*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const extensions::Extension* val);
|
||||
};
|
||||
|
||||
} // namespace gin
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
|
||||
import { ifdescribe } from './lib/spec-helpers';
|
||||
import { ifdescribe, ifit } from './lib/spec-helpers';
|
||||
|
||||
// FIXME: The tests are skipped on linux arm/arm64
|
||||
ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== 'linux'))('contentTracing', () => {
|
||||
@@ -112,7 +112,8 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
|
||||
expect(fs.statSync(path).isFile()).to.be.true('output exists');
|
||||
});
|
||||
|
||||
it('calls its callback with a result file path', async () => {
|
||||
// FIXME(ckerr): this test regularly flakes
|
||||
ifit(process.platform !== 'linux')('calls its callback with a result file path', async () => {
|
||||
const resultFilePath = await record(/* options */ {}, outputFilePath);
|
||||
expect(resultFilePath).to.be.a('string').and.be.equal(outputFilePath);
|
||||
});
|
||||
|
||||
@@ -699,12 +699,14 @@ describe('webContents module', () => {
|
||||
describe('navigationHistory.getEntryAtIndex(index) API ', () => {
|
||||
it('should fetch default navigation entry when no urls are loaded', async () => {
|
||||
const result = w.webContents.navigationHistory.getEntryAtIndex(0);
|
||||
expect(result).to.deep.equal({ url: '', title: '' });
|
||||
expect(result.url).to.equal('');
|
||||
expect(result.title).to.equal('');
|
||||
});
|
||||
it('should fetch navigation entry given a valid index', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
const result = w.webContents.navigationHistory.getEntryAtIndex(0);
|
||||
expect(result).to.deep.equal({ url: urlPage1, title: 'Page 1' });
|
||||
expect(result.url).to.equal(urlPage1);
|
||||
expect(result.title).to.equal('Page 1');
|
||||
});
|
||||
it('should return null given an invalid index larger than history length', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
@@ -763,7 +765,10 @@ describe('webContents module', () => {
|
||||
await w.loadURL(urlPage1);
|
||||
await w.loadURL(urlPage2);
|
||||
await w.loadURL(urlPage3);
|
||||
const entries = w.webContents.navigationHistory.getAllEntries();
|
||||
const entries = w.webContents.navigationHistory.getAllEntries().map(entry => ({
|
||||
url: entry.url,
|
||||
title: entry.title
|
||||
}));
|
||||
expect(entries.length).to.equal(3);
|
||||
expect(entries[0]).to.deep.equal({ url: urlPage1, title: 'Page 1' });
|
||||
expect(entries[1]).to.deep.equal({ url: urlPage2, title: 'Page 2' });
|
||||
@@ -774,6 +779,92 @@ describe('webContents module', () => {
|
||||
const entries = w.webContents.navigationHistory.getAllEntries();
|
||||
expect(entries.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('should create a NavigationEntry with PageState that can be serialized/deserialized with JSON', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
await w.loadURL(urlPage2);
|
||||
await w.loadURL(urlPage3);
|
||||
|
||||
const entries = w.webContents.navigationHistory.getAllEntries();
|
||||
const serialized = JSON.stringify(entries);
|
||||
const deserialized = JSON.parse(serialized);
|
||||
expect(deserialized).to.deep.equal(entries);
|
||||
});
|
||||
});
|
||||
|
||||
describe('navigationHistory.restore({ index, entries }) API', () => {
|
||||
let server: http.Server;
|
||||
let serverUrl: string;
|
||||
|
||||
before(async () => {
|
||||
server = http.createServer((req, res) => {
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('<html><head><title>Form</title></head><body><form><input type="text" value="value" /></form></body></html>');
|
||||
});
|
||||
serverUrl = (await listen(server)).url;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
if (server) await new Promise(resolve => server.close(resolve));
|
||||
server = null as any;
|
||||
});
|
||||
|
||||
it('should restore navigation history with PageState', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
await w.loadURL(urlPage2);
|
||||
await w.loadURL(serverUrl);
|
||||
|
||||
// Fill out the form on the page
|
||||
await w.webContents.executeJavaScript('document.querySelector("input").value = "Hi!";');
|
||||
|
||||
// PageState is committed:
|
||||
// 1) When the page receives an unload event
|
||||
// 2) During periodic serialization of page state
|
||||
// To not wait randomly for the second option, we'll trigger another load
|
||||
await w.loadURL(urlPage3);
|
||||
|
||||
// Save the navigation state
|
||||
const entries = w.webContents.navigationHistory.getAllEntries();
|
||||
|
||||
// Close the window, make a new one
|
||||
w.close();
|
||||
w = new BrowserWindow();
|
||||
|
||||
const formValue = await new Promise<string>(resolve => {
|
||||
w.webContents.once('dom-ready', () => resolve(w.webContents.executeJavaScript('document.querySelector("input").value')));
|
||||
|
||||
// Restore the navigation history
|
||||
return w.webContents.navigationHistory.restore({ index: 2, entries });
|
||||
});
|
||||
|
||||
expect(formValue).to.equal('Hi!');
|
||||
});
|
||||
|
||||
it('should handle invalid base64 pageState', async () => {
|
||||
await w.loadURL(urlPage1);
|
||||
await w.loadURL(urlPage2);
|
||||
await w.loadURL(urlPage3);
|
||||
|
||||
const brokenEntries = w.webContents.navigationHistory.getAllEntries().map(entry => ({
|
||||
...entry,
|
||||
pageState: 'invalid base64'
|
||||
}));
|
||||
|
||||
// Close the window, make a new one
|
||||
w.close();
|
||||
w = new BrowserWindow();
|
||||
await w.webContents.navigationHistory.restore({ index: 2, entries: brokenEntries });
|
||||
|
||||
const entries = w.webContents.navigationHistory.getAllEntries();
|
||||
|
||||
// Check that we used the original url and titles but threw away the broken
|
||||
// pageState
|
||||
entries.forEach((entry, index) => {
|
||||
expect(entry.url).to.equal(brokenEntries[index].url);
|
||||
expect(entry.title).to.equal(brokenEntries[index].title);
|
||||
expect(entry.pageState?.length).to.be.greaterThanOrEqual(100);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { app, session, BrowserWindow, ipcMain, WebContents, Extension, Session }
|
||||
import { expect } from 'chai';
|
||||
import * as WebSocket from 'ws';
|
||||
|
||||
import { spawn } from 'node:child_process';
|
||||
import { once } from 'node:events';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import * as http from 'node:http';
|
||||
@@ -224,57 +223,6 @@ describe('chrome extensions', () => {
|
||||
}
|
||||
});
|
||||
|
||||
describe('enable/disable', () => {
|
||||
it('disables an extension', async () => {
|
||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||
const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'mv3-service-worker'));
|
||||
|
||||
expect(extension.enabled).to.be.true();
|
||||
customSession.disableExtension(extension.id);
|
||||
|
||||
expect(customSession.getExtension(extension.id)!.enabled).to.be.false();
|
||||
});
|
||||
|
||||
it('enables a previously disabled extension', async () => {
|
||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||
const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'mv3-service-worker'));
|
||||
|
||||
expect(extension.enabled).to.be.true();
|
||||
customSession.disableExtension(extension.id);
|
||||
expect(customSession.getExtension(extension.id)!.enabled).to.be.false();
|
||||
|
||||
customSession.enableExtension(extension.id);
|
||||
expect(customSession.getExtension(extension.id)!.enabled).to.be.true();
|
||||
});
|
||||
|
||||
it('persists disabled extensions', async () => {
|
||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||
const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'mv3-service-worker'));
|
||||
customSession.disableExtension(extension.id);
|
||||
customSession.removeExtension(extension.id);
|
||||
|
||||
const extension2 = await customSession.loadExtension(path.join(fixtures, 'extensions', 'mv3-service-worker'));
|
||||
expect(extension2.enabled).to.be.false();
|
||||
});
|
||||
|
||||
it('activates extension when enabled', async () => {
|
||||
const runActivateExtensionTest = async () => {
|
||||
const appPath = path.join(fixtures, 'apps', 'activate-extension', 'main.js');
|
||||
const appProcess = spawn(process.execPath, [appPath], {
|
||||
cwd: path.join(fixtures, 'apps', 'activate-extension'),
|
||||
stdio: 'inherit'
|
||||
});
|
||||
const [code] = await once(appProcess, 'close');
|
||||
expect(code).to.equal(0);
|
||||
};
|
||||
|
||||
console.log('running test 1');
|
||||
await runActivateExtensionTest();
|
||||
console.log('running test 2');
|
||||
await runActivateExtensionTest();
|
||||
});
|
||||
});
|
||||
|
||||
it('emits extension lifecycle events', async () => {
|
||||
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||
|
||||
|
||||
27
spec/fixtures/apps/activate-extension/main.js
vendored
27
spec/fixtures/apps/activate-extension/main.js
vendored
@@ -1,27 +0,0 @@
|
||||
const { app, session } = require('electron');
|
||||
|
||||
const path = require('node:path');
|
||||
const { setTimeout } = require('node:timers/promises');
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
const ses = session.defaultSession;
|
||||
const fixtures = path.join(__dirname, '..', '..');
|
||||
const extPath = path.join(fixtures, 'extensions', 'simple-background-sw');
|
||||
|
||||
const activatedPromise = new Promise((resolve) => {
|
||||
ses.serviceWorkers.on('running-status-changed', ({ versionId, runningStatus }) => {
|
||||
console.log(`service worker ${versionId} now ${runningStatus}`);
|
||||
if (runningStatus === 'running') {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await ses.loadExtension(extPath);
|
||||
await activatedPromise;
|
||||
|
||||
// Need to wait for data to be flushed?
|
||||
await setTimeout(1000);
|
||||
|
||||
app.exit(0);
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
console.log('started');
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "Simple background sw",
|
||||
"description": "just a lil service worker",
|
||||
"version": "1.0",
|
||||
"manifest_version": 3,
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
}
|
||||
}
|
||||
2
typings/internal-electron.d.ts
vendored
2
typings/internal-electron.d.ts
vendored
@@ -87,6 +87,7 @@ declare namespace Electron {
|
||||
}
|
||||
|
||||
interface WebContents {
|
||||
_awaitNextLoad(expectedUrl: string): Promise<void>;
|
||||
_loadURL(url: string, options: ElectronInternal.LoadURLOptions): void;
|
||||
getOwnerBrowserWindow(): Electron.BrowserWindow | null;
|
||||
getLastWebPreferences(): Electron.WebPreferences | null;
|
||||
@@ -115,6 +116,7 @@ declare namespace Electron {
|
||||
_goToIndex(index: number): void;
|
||||
_removeNavigationEntryAtIndex(index: number): boolean;
|
||||
_getHistory(): Electron.NavigationEntry[];
|
||||
_restoreHistory(index: number, entries: Electron.NavigationEntry[]): void
|
||||
_clearHistory():void
|
||||
canGoToIndex(index: number): boolean;
|
||||
destroy(): void;
|
||||
|
||||
Reference in New Issue
Block a user