Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: only create webContents after 'will-attach-webview' #35016

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
81 changes: 19 additions & 62 deletions lib/browser/guest-view-manager.ts
Expand Up @@ -7,7 +7,7 @@ import { webViewEvents } from '@electron/internal/browser/web-view-events';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';

interface GuestInstance {
elementInstanceId?: number;
elementInstanceId: number;
visibilityState?: VisibilityState;
embedder: Electron.WebContents;
guest: Electron.WebContents;
Expand Down Expand Up @@ -46,6 +46,7 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record<stri
webSecurity: !params.disablewebsecurity,
enableBlinkFeatures: params.blinkfeatures,
disableBlinkFeatures: params.disableblinkfeatures,
partition: params.partition,
...parsedWebPreferences
};

Expand Down Expand Up @@ -87,14 +88,26 @@ function makeLoadURLOptions (params: Record<string, any>) {

// Create a new guest instance.
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
const guest = (webContents as typeof ElectronInternal.WebContents).create({
...webPreferences,
type: 'webview',
partition: params.partition,
embedder
});

const guestInstanceId = guest.id;
guestInstances.set(guestInstanceId, {
elementInstanceId,
guest,
embedder
});
Expand All @@ -108,19 +121,16 @@ const createGuest = function (embedder: Electron.WebContents, embedderFrameId: n

// Init guest web view after attached.
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;
this.viewInstanceId = params.instanceId;
this.viewInstanceId = instanceId;

// Only load URL and set size on first attach
if (previouslyAttached) {
return;
}

if (params.src) {
this.loadURL(params.src, params.opts);
this.loadURL(params.src, makeLoadURLOptions(params));
}
embedder.emit('did-attach-webview', event, guest);
});
Expand Down Expand Up @@ -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.
const key = `${embedder.id}-${elementInstanceId}`;
const oldGuestInstanceId = embedderElementsMap.get(key);
if (oldGuestInstanceId != null) {
// Reattachment to the same guest is just a no-op.
if (oldGuestInstanceId === guestInstanceId) {
return false;
}

const oldGuestInstance = guestInstances.get(oldGuestInstanceId);
if (oldGuestInstance) {
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);

guest.setEmbedder(embedder);
guestInstance.embedder = embedder;
guestInstance.elementInstanceId = elementInstanceId;

watchEmbedder(embedder);

webViewManager.addGuest(guestInstanceId, embedder, guest, webPreferences);
guest.attachToIframe(embedder, embedderFrameId);
return true;

return guestInstanceId;
};

// Remove an guest-embedder relationship.
Expand Down
1 change: 0 additions & 1 deletion lib/common/ipc-messages.ts
Expand Up @@ -9,7 +9,6 @@ export const enum IPC_MESSAGES {

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_MANAGER_CREATE_AND_ATTACH_GUEST = 'GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST',
Expand Down
7 changes: 0 additions & 7 deletions lib/renderer/web-view/guest-view-internal.ts
Expand Up @@ -6,19 +6,13 @@ const { mainFrame: webFrame } = process._linkedBinding('electron_renderer_web_fr

export interface GuestViewDelegate {
dispatchEvent (eventName: string, props: Record<string, any>): void;
reset(): void;
}

const DEPRECATED_EVENTS: Record<string, string> = {
'page-title-updated': 'page-title-set'
} as const;

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) {
if (DEPRECATED_EVENTS[eventName] != null) {
delegate.dispatchEvent(DEPRECATED_EVENTS[eventName], props);
Expand All @@ -29,7 +23,6 @@ export function registerEvents (viewInstanceId: number, delegate: GuestViewDeleg
}

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}`);
}

Expand Down
3 changes: 1 addition & 2 deletions lib/renderer/web-view/web-view-element.ts
Expand Up @@ -55,8 +55,7 @@ const defineWebViewElement = (hooks: WebViewImplHooks) => {
}
if (!internal.elementAttached) {
hooks.guestViewInternal.registerEvents(internal.viewInstanceId, {
dispatchEvent: internal.dispatchEvent.bind(internal),
reset: internal.reset.bind(internal)
dispatchEvent: internal.dispatchEvent.bind(internal)
});
internal.elementAttached = true;
(internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse();
Expand Down
2 changes: 1 addition & 1 deletion lib/renderer/web-view/web-view-impl.ts
Expand Up @@ -191,7 +191,7 @@ export class WebViewImpl {

attachGuestInstance (guestInstanceId: number) {
if (guestInstanceId === -1) {
// Do nothing
this.dispatchEvent('destroyed');
return;
}

Expand Down
4 changes: 0 additions & 4 deletions shell/browser/api/electron_api_web_view_manager.cc
Expand Up @@ -28,10 +28,6 @@ void AddGuest(int guest_instance_id,
electron::WebContentsZoomController::FromWebContents(guest_web_contents)
->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) {
Expand Down
4 changes: 0 additions & 4 deletions shell/browser/web_contents_preferences.cc
Expand Up @@ -176,11 +176,7 @@ void WebContentsPreferences::Clear() {
void WebContentsPreferences::SetFromDictionary(
const gin_helper::Dictionary& web_preferences) {
Clear();
Merge(web_preferences);
}

void WebContentsPreferences::Merge(
const gin_helper::Dictionary& web_preferences) {
web_preferences.Get(options::kPlugins, &plugins_);
web_preferences.Get(options::kExperimentalFeatures, &experimental_features_);
web_preferences.Get(options::kNodeIntegration, &node_integration_);
Expand Down
2 changes: 0 additions & 2 deletions shell/browser/web_contents_preferences.h
Expand Up @@ -40,8 +40,6 @@ class WebContentsPreferences
WebContentsPreferences(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);

// Append command paramters according to preferences.
Expand Down
1 change: 0 additions & 1 deletion typings/internal-electron.d.ts
Expand Up @@ -81,7 +81,6 @@ declare namespace Electron {
attachToIframe(embedderWebContents: Electron.WebContents, embedderFrameId: number): void;
detachFromOuterFrame(): void;
setEmbedder(embedder: Electron.WebContents): void;
attachParams?: { instanceId: number; src: string, opts: LoadURLOptions };
viewInstanceId: number;
}

Expand Down