refactor: only create webContents after 'will-attach-webview' (#32941)
This commit is contained in:
parent
7ae3025fd5
commit
d4e97483aa
9 changed files with 21 additions and 84 deletions
|
@ -7,7 +7,7 @@ import { webViewEvents } from '@electron/internal/browser/web-view-events';
|
||||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||||
|
|
||||||
interface GuestInstance {
|
interface GuestInstance {
|
||||||
elementInstanceId?: number;
|
elementInstanceId: number;
|
||||||
visibilityState?: VisibilityState;
|
visibilityState?: VisibilityState;
|
||||||
embedder: Electron.WebContents;
|
embedder: Electron.WebContents;
|
||||||
guest: Electron.WebContents;
|
guest: Electron.WebContents;
|
||||||
|
@ -46,6 +46,7 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record<stri
|
||||||
webSecurity: !params.disablewebsecurity,
|
webSecurity: !params.disablewebsecurity,
|
||||||
enableBlinkFeatures: params.blinkfeatures,
|
enableBlinkFeatures: params.blinkfeatures,
|
||||||
disableBlinkFeatures: params.disableblinkfeatures,
|
disableBlinkFeatures: params.disableblinkfeatures,
|
||||||
|
partition: params.partition,
|
||||||
...parsedWebPreferences
|
...parsedWebPreferences
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,14 +88,26 @@ function makeLoadURLOptions (params: Record<string, any>) {
|
||||||
|
|
||||||
// Create a new guest instance.
|
// Create a new guest instance.
|
||||||
const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record<string, any>) {
|
const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record<string, any>) {
|
||||||
|
const webPreferences = makeWebPreferences(embedder, params);
|
||||||
|
const event = eventBinding.createWithSender(embedder);
|
||||||
|
|
||||||
|
const { instanceId } = params;
|
||||||
|
|
||||||
|
embedder.emit('will-attach-webview', event, webPreferences, params);
|
||||||
|
if (event.defaultPrevented) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const guest = (webContents as typeof ElectronInternal.WebContents).create({
|
const guest = (webContents as typeof ElectronInternal.WebContents).create({
|
||||||
|
...webPreferences,
|
||||||
type: 'webview',
|
type: 'webview',
|
||||||
partition: params.partition,
|
|
||||||
embedder
|
embedder
|
||||||
});
|
});
|
||||||
|
|
||||||
const guestInstanceId = guest.id;
|
const guestInstanceId = guest.id;
|
||||||
guestInstances.set(guestInstanceId, {
|
guestInstances.set(guestInstanceId, {
|
||||||
|
elementInstanceId,
|
||||||
guest,
|
guest,
|
||||||
embedder
|
embedder
|
||||||
});
|
});
|
||||||
|
@ -108,11 +121,8 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||||
|
|
||||||
// Init guest web view after attached.
|
// Init guest web view after attached.
|
||||||
guest.once('did-attach' as any, function (this: Electron.WebContents, event: Electron.Event) {
|
guest.once('did-attach' as any, function (this: Electron.WebContents, event: Electron.Event) {
|
||||||
const params = this.attachParams!;
|
|
||||||
delete this.attachParams;
|
|
||||||
|
|
||||||
const previouslyAttached = this.viewInstanceId != null;
|
const previouslyAttached = this.viewInstanceId != null;
|
||||||
this.viewInstanceId = params.instanceId;
|
this.viewInstanceId = instanceId;
|
||||||
|
|
||||||
// Only load URL and set size on first attach
|
// Only load URL and set size on first attach
|
||||||
if (previouslyAttached) {
|
if (previouslyAttached) {
|
||||||
|
@ -120,7 +130,7 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.src) {
|
if (params.src) {
|
||||||
this.loadURL(params.src, params.opts);
|
this.loadURL(params.src, makeLoadURLOptions(params));
|
||||||
}
|
}
|
||||||
embedder.emit('did-attach-webview', event, guest);
|
embedder.emit('did-attach-webview', event, guest);
|
||||||
});
|
});
|
||||||
|
@ -173,78 +183,25 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (attachGuest(embedder, embedderFrameId, elementInstanceId, guestInstanceId, params)) {
|
|
||||||
return guestInstanceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Attach the guest to an element of embedder.
|
|
||||||
const attachGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, guestInstanceId: number, params: Record<string, any>) {
|
|
||||||
// Destroy the old guest when attaching.
|
// Destroy the old guest when attaching.
|
||||||
const key = `${embedder.id}-${elementInstanceId}`;
|
const key = `${embedder.id}-${elementInstanceId}`;
|
||||||
const oldGuestInstanceId = embedderElementsMap.get(key);
|
const oldGuestInstanceId = embedderElementsMap.get(key);
|
||||||
if (oldGuestInstanceId != null) {
|
if (oldGuestInstanceId != null) {
|
||||||
// Reattachment to the same guest is just a no-op.
|
|
||||||
if (oldGuestInstanceId === guestInstanceId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldGuestInstance = guestInstances.get(oldGuestInstanceId);
|
const oldGuestInstance = guestInstances.get(oldGuestInstanceId);
|
||||||
if (oldGuestInstance) {
|
if (oldGuestInstance) {
|
||||||
oldGuestInstance.guest.detachFromOuterFrame();
|
oldGuestInstance.guest.detachFromOuterFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const guestInstance = guestInstances.get(guestInstanceId);
|
|
||||||
// If this isn't a valid guest instance then do nothing.
|
|
||||||
if (!guestInstance) {
|
|
||||||
console.error(new Error(`Guest attach failed: Invalid guestInstanceId ${guestInstanceId}`));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const { guest } = guestInstance;
|
|
||||||
if (guest.hostWebContents !== embedder) {
|
|
||||||
console.error(new Error(`Guest attach failed: Access denied to guestInstanceId ${guestInstanceId}`));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { instanceId } = params;
|
|
||||||
|
|
||||||
// If this guest is already attached to an element then remove it
|
|
||||||
if (guestInstance.elementInstanceId) {
|
|
||||||
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`;
|
|
||||||
embedderElementsMap.delete(oldKey);
|
|
||||||
|
|
||||||
// Remove guest from embedder if moving across web views
|
|
||||||
if (guest.viewInstanceId !== instanceId) {
|
|
||||||
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId);
|
|
||||||
guestInstance.embedder._sendInternal(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${guest.viewInstanceId}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const webPreferences = makeWebPreferences(embedder, params);
|
|
||||||
|
|
||||||
const event = eventBinding.createWithSender(embedder);
|
|
||||||
embedder.emit('will-attach-webview', event, webPreferences, params);
|
|
||||||
if (event.defaultPrevented) {
|
|
||||||
if (guest.viewInstanceId == null) guest.viewInstanceId = instanceId;
|
|
||||||
guest.destroy();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
guest.attachParams = { instanceId, src: params.src, opts: makeLoadURLOptions(params) };
|
|
||||||
embedderElementsMap.set(key, guestInstanceId);
|
embedderElementsMap.set(key, guestInstanceId);
|
||||||
|
|
||||||
guest.setEmbedder(embedder);
|
guest.setEmbedder(embedder);
|
||||||
guestInstance.embedder = embedder;
|
|
||||||
guestInstance.elementInstanceId = elementInstanceId;
|
|
||||||
|
|
||||||
watchEmbedder(embedder);
|
watchEmbedder(embedder);
|
||||||
|
|
||||||
webViewManager.addGuest(guestInstanceId, embedder, guest, webPreferences);
|
webViewManager.addGuest(guestInstanceId, embedder, guest, webPreferences);
|
||||||
guest.attachToIframe(embedder, embedderFrameId);
|
guest.attachToIframe(embedder, embedderFrameId);
|
||||||
return true;
|
|
||||||
|
return guestInstanceId;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove an guest-embedder relationship.
|
// Remove an guest-embedder relationship.
|
||||||
|
|
|
@ -9,7 +9,6 @@ export const enum IPC_MESSAGES {
|
||||||
|
|
||||||
GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',
|
GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',
|
||||||
|
|
||||||
GUEST_VIEW_INTERNAL_DESTROY_GUEST = 'GUEST_VIEW_INTERNAL_DESTROY_GUEST',
|
|
||||||
GUEST_VIEW_INTERNAL_DISPATCH_EVENT = 'GUEST_VIEW_INTERNAL_DISPATCH_EVENT',
|
GUEST_VIEW_INTERNAL_DISPATCH_EVENT = 'GUEST_VIEW_INTERNAL_DISPATCH_EVENT',
|
||||||
|
|
||||||
GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST = 'GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST',
|
GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST = 'GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST',
|
||||||
|
|
|
@ -6,22 +6,15 @@ const { mainFrame: webFrame } = process._linkedBinding('electron_renderer_web_fr
|
||||||
|
|
||||||
export interface GuestViewDelegate {
|
export interface GuestViewDelegate {
|
||||||
dispatchEvent (eventName: string, props: Record<string, any>): void;
|
dispatchEvent (eventName: string, props: Record<string, any>): void;
|
||||||
reset(): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerEvents (viewInstanceId: number, delegate: GuestViewDelegate) {
|
export function registerEvents (viewInstanceId: number, delegate: GuestViewDelegate) {
|
||||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`, function () {
|
|
||||||
delegate.reset();
|
|
||||||
delegate.dispatchEvent('destroyed', {});
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, props) {
|
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, props) {
|
||||||
delegate.dispatchEvent(eventName, props);
|
delegate.dispatchEvent(eventName, props);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deregisterEvents (viewInstanceId: number) {
|
export function deregisterEvents (viewInstanceId: number) {
|
||||||
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`);
|
|
||||||
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`);
|
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,7 @@ const defineWebViewElement = (hooks: WebViewImplHooks) => {
|
||||||
}
|
}
|
||||||
if (!internal.elementAttached) {
|
if (!internal.elementAttached) {
|
||||||
hooks.guestViewInternal.registerEvents(internal.viewInstanceId, {
|
hooks.guestViewInternal.registerEvents(internal.viewInstanceId, {
|
||||||
dispatchEvent: internal.dispatchEvent.bind(internal),
|
dispatchEvent: internal.dispatchEvent.bind(internal)
|
||||||
reset: internal.reset.bind(internal)
|
|
||||||
});
|
});
|
||||||
internal.elementAttached = true;
|
internal.elementAttached = true;
|
||||||
(internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse();
|
(internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse();
|
||||||
|
|
|
@ -191,7 +191,7 @@ export class WebViewImpl {
|
||||||
|
|
||||||
attachGuestInstance (guestInstanceId: number) {
|
attachGuestInstance (guestInstanceId: number) {
|
||||||
if (guestInstanceId === -1) {
|
if (guestInstanceId === -1) {
|
||||||
// Do nothing
|
this.dispatchEvent('destroyed');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,6 @@ void AddGuest(int guest_instance_id,
|
||||||
electron::WebContentsZoomController::FromWebContents(guest_web_contents)
|
electron::WebContentsZoomController::FromWebContents(guest_web_contents)
|
||||||
->SetDefaultZoomFactor(zoom_factor);
|
->SetDefaultZoomFactor(zoom_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebContentsPreferences::From(guest_web_contents)->Merge(options);
|
|
||||||
// Trigger re-calculation of webkit prefs.
|
|
||||||
guest_web_contents->NotifyPreferencesChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {
|
void RemoveGuest(content::WebContents* embedder, int guest_instance_id) {
|
||||||
|
|
|
@ -176,11 +176,7 @@ void WebContentsPreferences::Clear() {
|
||||||
void WebContentsPreferences::SetFromDictionary(
|
void WebContentsPreferences::SetFromDictionary(
|
||||||
const gin_helper::Dictionary& web_preferences) {
|
const gin_helper::Dictionary& web_preferences) {
|
||||||
Clear();
|
Clear();
|
||||||
Merge(web_preferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebContentsPreferences::Merge(
|
|
||||||
const gin_helper::Dictionary& web_preferences) {
|
|
||||||
web_preferences.Get(options::kPlugins, &plugins_);
|
web_preferences.Get(options::kPlugins, &plugins_);
|
||||||
web_preferences.Get(options::kExperimentalFeatures, &experimental_features_);
|
web_preferences.Get(options::kExperimentalFeatures, &experimental_features_);
|
||||||
web_preferences.Get(options::kNodeIntegration, &node_integration_);
|
web_preferences.Get(options::kNodeIntegration, &node_integration_);
|
||||||
|
|
|
@ -40,8 +40,6 @@ class WebContentsPreferences
|
||||||
WebContentsPreferences(const WebContentsPreferences&) = delete;
|
WebContentsPreferences(const WebContentsPreferences&) = delete;
|
||||||
WebContentsPreferences& operator=(const WebContentsPreferences&) = delete;
|
WebContentsPreferences& operator=(const WebContentsPreferences&) = delete;
|
||||||
|
|
||||||
void Merge(const gin_helper::Dictionary& new_web_preferences);
|
|
||||||
|
|
||||||
void SetFromDictionary(const gin_helper::Dictionary& new_web_preferences);
|
void SetFromDictionary(const gin_helper::Dictionary& new_web_preferences);
|
||||||
|
|
||||||
// Append command parameters according to preferences.
|
// Append command parameters according to preferences.
|
||||||
|
|
1
typings/internal-electron.d.ts
vendored
1
typings/internal-electron.d.ts
vendored
|
@ -81,7 +81,6 @@ declare namespace Electron {
|
||||||
attachToIframe(embedderWebContents: Electron.WebContents, embedderFrameId: number): void;
|
attachToIframe(embedderWebContents: Electron.WebContents, embedderFrameId: number): void;
|
||||||
detachFromOuterFrame(): void;
|
detachFromOuterFrame(): void;
|
||||||
setEmbedder(embedder: Electron.WebContents): void;
|
setEmbedder(embedder: Electron.WebContents): void;
|
||||||
attachParams?: { instanceId: number; src: string, opts: LoadURLOptions };
|
|
||||||
viewInstanceId: number;
|
viewInstanceId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue