fix: use OOPIF for webview tag (#13869)
* fix: use OOIF for webview tag * fix: do not call GetNativeView for webview * fix: OOIPF webview's WebContents is managed by embedder frame * fix: guest view can not be focused * fix: clear zoom controller when guest is destroyed * fix: implement the webview resize event The webview is no longer a browser plugin with the resize event, use ResizeObserver instead. * test: disable failed tests due to OOPIF webview * fix: embedder can be destroyed earlier than guest This happens when embedder is manually destroyed. * fix: don't double attach * fix: recreate iframe when webview is reattached * fix: resize event may happen very early * test: some tests are working after OOPIF webview * chore: remove unused browser plugin webview code * fix: get embedder via closure When the "destroyed" event is emitted, the entry in guestInstances would be cleared. * chore: rename browserPluginNode to internalElement * test: make the visibilityState test more robust * chore: guestinstance can not work with OOPIF webview * fix: element could be detached before got response from browser
This commit is contained in:
parent
48407c5b93
commit
dd5b8769be
28 changed files with 268 additions and 1008 deletions
|
@ -46,11 +46,6 @@ let nextGuestInstanceId = 0
|
|||
const guestInstances = {}
|
||||
const embedderElementsMap = {}
|
||||
|
||||
// Moves the last element of array to the first one.
|
||||
const moveLastToFirst = function (list) {
|
||||
list.unshift(list.pop())
|
||||
}
|
||||
|
||||
// Generate guestInstanceId.
|
||||
const getNextGuestInstanceId = function () {
|
||||
return ++nextGuestInstanceId
|
||||
|
@ -73,10 +68,15 @@ const createGuest = function (embedder, params) {
|
|||
embedder: embedder
|
||||
}
|
||||
|
||||
watchEmbedder(embedder)
|
||||
// Clear the guest from map when it is destroyed.
|
||||
guest.once('destroyed', () => {
|
||||
if (guestInstanceId in guestInstances) {
|
||||
detachGuest(embedder, guestInstanceId)
|
||||
}
|
||||
})
|
||||
|
||||
// Init guest web view after attached.
|
||||
guest.on('did-attach', function (event) {
|
||||
guest.once('did-attach', function (event) {
|
||||
params = this.attachParams
|
||||
delete this.attachParams
|
||||
|
||||
|
@ -88,21 +88,6 @@ const createGuest = function (embedder, params) {
|
|||
return
|
||||
}
|
||||
|
||||
this.setSize({
|
||||
normal: {
|
||||
width: params.elementWidth,
|
||||
height: params.elementHeight
|
||||
},
|
||||
enableAutoSize: params.autosize,
|
||||
min: {
|
||||
width: params.minwidth,
|
||||
height: params.minheight
|
||||
},
|
||||
max: {
|
||||
width: params.maxwidth,
|
||||
height: params.maxheight
|
||||
}
|
||||
})
|
||||
if (params.src) {
|
||||
const opts = {}
|
||||
if (params.httpreferrer) {
|
||||
|
@ -118,8 +103,7 @@ const createGuest = function (embedder, params) {
|
|||
})
|
||||
|
||||
const sendToEmbedder = (channel, ...args) => {
|
||||
const embedder = getEmbedder(guestInstanceId)
|
||||
if (embedder != null) {
|
||||
if (!embedder.isDestroyed()) {
|
||||
embedder.send(`${channel}-${guest.viewInstanceId}`, ...args)
|
||||
}
|
||||
}
|
||||
|
@ -139,11 +123,6 @@ const createGuest = function (embedder, params) {
|
|||
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE', channel, ...args)
|
||||
})
|
||||
|
||||
// Autosize.
|
||||
guest.on('size-changed', function (_, ...args) {
|
||||
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED', ...args)
|
||||
})
|
||||
|
||||
// Notify guest of embedder window visibility when it is ready
|
||||
// FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
|
||||
guest.on('dom-ready', function () {
|
||||
|
@ -176,7 +155,7 @@ const createGuest = function (embedder, params) {
|
|||
}
|
||||
|
||||
// Attach the guest to an element of embedder.
|
||||
const attachGuest = function (event, elementInstanceId, guestInstanceId, params) {
|
||||
const attachGuest = function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
|
||||
const embedder = event.sender
|
||||
// Destroy the old guest when attaching.
|
||||
const key = `${embedder.id}-${elementInstanceId}`
|
||||
|
@ -187,7 +166,10 @@ const attachGuest = function (event, elementInstanceId, guestInstanceId, params)
|
|||
return
|
||||
}
|
||||
|
||||
destroyGuest(embedder, oldGuestInstanceId)
|
||||
const oldGuestInstance = guestInstances[oldGuestInstanceId]
|
||||
if (oldGuestInstance) {
|
||||
oldGuestInstance.guest.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
const guestInstance = guestInstances[guestInstanceId]
|
||||
|
@ -260,11 +242,10 @@ const attachGuest = function (event, elementInstanceId, guestInstanceId, params)
|
|||
embedder.emit('will-attach-webview', event, webPreferences, params)
|
||||
if (event.defaultPrevented) {
|
||||
if (guest.viewInstanceId == null) guest.viewInstanceId = params.instanceId
|
||||
destroyGuest(embedder, guestInstanceId)
|
||||
guest.destroy()
|
||||
return
|
||||
}
|
||||
|
||||
webViewManager.addGuest(guestInstanceId, elementInstanceId, embedder, guest, webPreferences)
|
||||
guest.attachParams = params
|
||||
embedderElementsMap[key] = guestInstanceId
|
||||
|
||||
|
@ -273,21 +254,19 @@ const attachGuest = function (event, elementInstanceId, guestInstanceId, params)
|
|||
guestInstance.elementInstanceId = elementInstanceId
|
||||
|
||||
watchEmbedder(embedder)
|
||||
|
||||
webViewManager.addGuest(guestInstanceId, elementInstanceId, embedder, guest, webPreferences)
|
||||
guest.attachToIframe(embedder, embedderFrameId)
|
||||
}
|
||||
|
||||
// Destroy an existing guest instance.
|
||||
const destroyGuest = function (embedder, guestInstanceId) {
|
||||
if (!(guestInstanceId in guestInstances)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Remove an guest-embedder relationship.
|
||||
const detachGuest = function (embedder, guestInstanceId) {
|
||||
const guestInstance = guestInstances[guestInstanceId]
|
||||
if (embedder !== guestInstance.embedder) {
|
||||
return
|
||||
}
|
||||
|
||||
webViewManager.removeGuest(embedder, guestInstanceId)
|
||||
guestInstance.guest.destroy()
|
||||
delete guestInstances[guestInstanceId]
|
||||
|
||||
const key = `${embedder.id}-${guestInstance.elementInstanceId}`
|
||||
|
@ -305,7 +284,7 @@ const watchEmbedder = function (embedder) {
|
|||
|
||||
// Forward embedder window visiblity change events to guest
|
||||
const onVisibilityChange = function (visibilityState) {
|
||||
for (const guestInstanceId of Object.keys(guestInstances)) {
|
||||
for (const guestInstanceId in guestInstances) {
|
||||
const guestInstance = guestInstances[guestInstanceId]
|
||||
guestInstance.visibilityState = visibilityState
|
||||
if (guestInstance.embedder === embedder) {
|
||||
|
@ -315,33 +294,20 @@ const watchEmbedder = function (embedder) {
|
|||
}
|
||||
embedder.on('-window-visibility-change', onVisibilityChange)
|
||||
|
||||
const destroyEvents = ['will-destroy', 'crashed', 'did-navigate']
|
||||
const destroy = function () {
|
||||
for (const guestInstanceId of Object.keys(guestInstances)) {
|
||||
if (guestInstances[guestInstanceId].embedder === embedder) {
|
||||
destroyGuest(embedder, parseInt(guestInstanceId))
|
||||
embedder.once('will-destroy', () => {
|
||||
// Usually the guestInstances is cleared when guest is destroyed, but it
|
||||
// may happen that the embedder gets manually destroyed earlier than guest,
|
||||
// and the embedder will be invalid in the usual code path.
|
||||
for (const guestInstanceId in guestInstances) {
|
||||
const guestInstance = guestInstances[guestInstanceId]
|
||||
if (guestInstance.embedder === embedder) {
|
||||
detachGuest(embedder, parseInt(guestInstanceId))
|
||||
}
|
||||
}
|
||||
|
||||
for (const event of destroyEvents) {
|
||||
embedder.removeListener(event, destroy)
|
||||
}
|
||||
// Clear the listeners.
|
||||
embedder.removeListener('-window-visibility-change', onVisibilityChange)
|
||||
|
||||
watchedEmbedders.delete(embedder)
|
||||
}
|
||||
|
||||
for (const event of destroyEvents) {
|
||||
embedder.once(event, destroy)
|
||||
|
||||
// Users might also listen to the crashed event, so we must ensure the guest
|
||||
// is destroyed before users' listener gets called. It is done by moving our
|
||||
// listener to the first one in queue.
|
||||
const listeners = embedder._events[event]
|
||||
if (Array.isArray(listeners)) {
|
||||
moveLastToFirst(listeners)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params, requestId) {
|
||||
|
@ -352,17 +318,8 @@ ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST_SYNC', function (event, par
|
|||
event.returnValue = createGuest(event.sender, params)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, elementInstanceId, guestInstanceId, params) {
|
||||
attachGuest(event, elementInstanceId, guestInstanceId, params)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', function (event, guestInstanceId) {
|
||||
destroyGuest(event.sender, guestInstanceId)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_SET_SIZE', function (event, guestInstanceId, params) {
|
||||
const guest = getGuest(guestInstanceId)
|
||||
if (guest != null) guest.setSize(params)
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
|
||||
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params)
|
||||
})
|
||||
|
||||
// Returns WebContents from its guest id.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue