refactor: use WeakMap instead of hidden V8 properties to store WebViewImpl (#29049)

This commit is contained in:
Milan Burda 2021-05-08 02:56:22 +02:00 committed by GitHub
parent de55bf8459
commit 49ef1fe342
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 23 additions and 21 deletions

View file

@ -11,5 +11,5 @@ const webViewImpl = v8Util.getHiddenValue(isolatedWorld, 'web-view-impl');
if (webViewImpl) { if (webViewImpl) {
// Must setup the WebView element in main world. // Must setup the WebView element in main world.
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element') as typeof webViewElementModule; const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element') as typeof webViewElementModule;
setupWebView(v8Util, webViewImpl as any); setupWebView(webViewImpl as any);
} }

View file

@ -18,5 +18,6 @@ export const enum WEB_VIEW_CONSTANTS {
// Error messages. // Error messages.
ERROR_MSG_ALREADY_NAVIGATED = 'The object has already navigated, so its partition cannot be changed.', ERROR_MSG_ALREADY_NAVIGATED = 'The object has already navigated, so its partition cannot be changed.',
ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.', ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.',
ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE = 'Only "file:" protocol is supported in "preload" attribute.' ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE = 'Only "file:" protocol is supported in "preload" attribute.',
ERROR_MSG_NOT_ATTACHED = 'The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.'
} }

View file

@ -12,10 +12,10 @@ import { WEB_VIEW_CONSTANTS } from '@electron/internal/renderer/web-view/web-vie
import type * as webViewImplModule from '@electron/internal/renderer/web-view/web-view-impl'; import type * as webViewImplModule from '@electron/internal/renderer/web-view/web-view-impl';
import type { SrcAttribute } from '@electron/internal/renderer/web-view/web-view-attributes'; import type { SrcAttribute } from '@electron/internal/renderer/web-view/web-view-attributes';
type IWebViewImpl = webViewImplModule.WebViewImpl; const internals = new WeakMap<HTMLElement, webViewImplModule.WebViewImpl>();
// Return a WebViewElement class that is defined in this context. // Return a WebViewElement class that is defined in this context.
const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof webViewImplModule) => { const defineWebViewElement = (webViewImpl: typeof webViewImplModule) => {
const { guestViewInternal, WebViewImpl } = webViewImpl; const { guestViewInternal, WebViewImpl } = webViewImpl;
return class WebViewElement extends HTMLElement { return class WebViewElement extends HTMLElement {
static get observedAttributes () { static get observedAttributes () {
@ -44,11 +44,19 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof
Object.assign(event, props); Object.assign(event, props);
return internal.webviewNode.dispatchEvent(event); return internal.webviewNode.dispatchEvent(event);
}; };
v8Util.setHiddenValue(this, 'internal', internal); internals.set(this, internal);
}
getWebContentsId () {
const internal = internals.get(this);
if (!internal || !internal.guestInstanceId) {
throw new Error(WEB_VIEW_CONSTANTS.ERROR_MSG_NOT_ATTACHED);
}
return internal.guestInstanceId;
} }
connectedCallback () { connectedCallback () {
const internal = v8Util.getHiddenValue<IWebViewImpl>(this, 'internal'); const internal = internals.get(this);
if (!internal) { if (!internal) {
return; return;
} }
@ -60,14 +68,14 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof
} }
attributeChangedCallback (name: string, oldValue: any, newValue: any) { attributeChangedCallback (name: string, oldValue: any, newValue: any) {
const internal = v8Util.getHiddenValue<IWebViewImpl>(this, 'internal'); const internal = internals.get(this);
if (internal) { if (internal) {
internal.handleWebviewAttributeMutation(name, oldValue, newValue); internal.handleWebviewAttributeMutation(name, oldValue, newValue);
} }
} }
disconnectedCallback () { disconnectedCallback () {
const internal = v8Util.getHiddenValue<IWebViewImpl>(this, 'internal'); const internal = internals.get(this);
if (!internal) { if (!internal) {
return; return;
} }
@ -82,10 +90,10 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof
}; };
// Register <webview> custom element. // Register <webview> custom element.
const registerWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof webViewImplModule) => { const registerWebViewElement = (webViewImpl: typeof webViewImplModule) => {
// I wish eslint wasn't so stupid, but it is // I wish eslint wasn't so stupid, but it is
// eslint-disable-next-line // eslint-disable-next-line
const WebViewElement = defineWebViewElement(v8Util, webViewImpl) as unknown as typeof ElectronInternal.WebViewElement const WebViewElement = defineWebViewElement(webViewImpl) as unknown as typeof ElectronInternal.WebViewElement
webViewImpl.setupMethods(WebViewElement); webViewImpl.setupMethods(WebViewElement);
@ -108,14 +116,14 @@ const registerWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeo
}; };
// Prepare to register the <webview> element. // Prepare to register the <webview> element.
export const setupWebView = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof webViewImplModule) => { export const setupWebView = (webViewImpl: typeof webViewImplModule) => {
const useCapture = true; const useCapture = true;
const listener = (event: Event) => { const listener = (event: Event) => {
if (document.readyState === 'loading') { if (document.readyState === 'loading') {
return; return;
} }
registerWebViewElement(v8Util, webViewImpl); registerWebViewElement(webViewImpl);
window.removeEventListener(event.type, listener, useCapture); window.removeEventListener(event.type, listener, useCapture);
}; };

View file

@ -64,6 +64,7 @@ export class WebViewImpl {
iframeElement.style.flex = '1 1 auto'; iframeElement.style.flex = '1 1 auto';
iframeElement.style.width = '100%'; iframeElement.style.width = '100%';
iframeElement.style.border = '0'; iframeElement.style.border = '0';
// used by RendererClientBase::IsWebViewFrame
v8Util.setHiddenValue(iframeElement, 'internal', this); v8Util.setHiddenValue(iframeElement, 'internal', this);
return iframeElement; return iframeElement;
} }
@ -210,14 +211,6 @@ export class WebViewImpl {
// I wish eslint wasn't so stupid, but it is // I wish eslint wasn't so stupid, but it is
// eslint-disable-next-line // eslint-disable-next-line
export const setupMethods = (WebViewElement: typeof ElectronInternal.WebViewElement) => { export const setupMethods = (WebViewElement: typeof ElectronInternal.WebViewElement) => {
WebViewElement.prototype.getWebContentsId = function () {
const internal = v8Util.getHiddenValue<WebViewImpl>(this, 'internal');
if (!internal.guestInstanceId) {
throw new Error('The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.');
}
return internal.guestInstanceId;
};
// Focusing the webview should move page focus to the underlying iframe. // Focusing the webview should move page focus to the underlying iframe.
WebViewElement.prototype.focus = function () { WebViewElement.prototype.focus = function () {
this.contentWindow.focus(); this.contentWindow.focus();

View file

@ -27,7 +27,7 @@ export function webViewInit (contextIsolation: boolean, webviewTag: boolean, gue
v8Util.setHiddenValue(window, 'web-view-impl', webViewImplModule); v8Util.setHiddenValue(window, 'web-view-impl', webViewImplModule);
} else { } else {
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element') as typeof webViewElement; const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element') as typeof webViewElement;
setupWebView(v8Util, webViewImplModule); setupWebView(webViewImplModule);
} }
} }