refactor: only create webContents after 'will-attach-webview' (#30311)

This commit is contained in:
Milan Burda 2021-08-03 19:08:49 +02:00 committed by GitHub
parent 4519bc3cd1
commit 6e43b0bcbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 17 additions and 80 deletions

View file

@ -8,7 +8,7 @@ import { serialize } from '@electron/internal/common/type-utils';
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
}; };
@ -77,14 +78,24 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record<stri
// 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);
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
}); });
@ -98,9 +109,6 @@ 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) {
params = this.attachParams!;
delete this.attachParams;
const previouslyAttached = this.viewInstanceId != null; const previouslyAttached = this.viewInstanceId != null;
this.viewInstanceId = params.instanceId; this.viewInstanceId = params.instanceId;
@ -160,76 +168,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;
}
// 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 !== params.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 = params.instanceId;
guest.destroy();
return false;
}
guest.attachParams = 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.

View file

@ -7,7 +7,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_INTERNAL_IPC_MESSAGE = 'GUEST_VIEW_INTERNAL_IPC_MESSAGE', GUEST_VIEW_INTERNAL_IPC_MESSAGE = 'GUEST_VIEW_INTERNAL_IPC_MESSAGE',

View file

@ -7,7 +7,6 @@ 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;
} }
const DEPRECATED_EVENTS: Record<string, string> = { const DEPRECATED_EVENTS: Record<string, string> = {
@ -28,11 +27,6 @@ const dispatchEvent = function (delegate: GuestViewDelegate, eventName: string,
}; };
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, ...args) { ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, ...args) {
dispatchEvent(delegate, eventName, eventName, ...args); dispatchEvent(delegate, eventName, eventName, ...args);
}); });
@ -43,7 +37,6 @@ export function registerEvents (viewInstanceId: number, delegate: GuestViewDeleg
} }
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}`);
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_IPC_MESSAGE}-${viewInstanceId}`); ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_IPC_MESSAGE}-${viewInstanceId}`);
} }

View file

@ -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();

View file

@ -195,7 +195,7 @@ export class WebViewImpl {
attachGuestInstance (guestInstanceId: number) { attachGuestInstance (guestInstanceId: number) {
if (guestInstanceId === -1) { if (guestInstanceId === -1) {
// Do nothing this.dispatchEvent('destroyed');
return; return;
} }

View file

@ -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) {

View file

@ -174,11 +174,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_);

View file

@ -36,8 +36,6 @@ class WebContentsPreferences
const gin_helper::Dictionary& web_preferences); const gin_helper::Dictionary& web_preferences);
~WebContentsPreferences() override; ~WebContentsPreferences() override;
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 paramters according to preferences. // Append command paramters according to preferences.

View file

@ -79,7 +79,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?: Record<string, any>;
viewInstanceId: number; viewInstanceId: number;
} }