diff --git a/browser/base/content/pictureInPicture.css b/browser/base/content/pictureInPicture.css new file mode 100644 index 0000000000..2055477436 --- /dev/null +++ b/browser/base/content/pictureInPicture.css @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +browser[remote="true"] { + -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser"); +} diff --git a/browser/base/content/pictureInPicture.js b/browser/base/content/pictureInPicture.js index e48578cea2..99715d2a28 100644 --- a/browser/base/content/pictureInPicture.js +++ b/browser/base/content/pictureInPicture.js @@ -13,6 +13,9 @@ var Player = { sourceTab: null, init() { + if (this.browser) { + return; + } let args = window.arguments[0]; this.source = args.browser; if (!this.source || !this.source.isConnected) { @@ -38,9 +41,16 @@ var Player = { browser.relatedBrowser = this.source; document.getElementById("player-container").appendChild(browser); let mm = browser.messageManager; - mm.addMessageListener("PictureInPicture:Ready", () => { + let initialized = false; + let ready = () => { + if (initialized) { + return; + } + initialized = true; + mm.removeMessageListener("PictureInPicture:Ready", ready); mm.sendAsyncMessage("PictureInPicture:Init", {id: args.id}); - }); + }; + mm.addMessageListener("PictureInPicture:Ready", ready); mm.addMessageListener("PictureInPicture:Close", this.close); mm.addMessageListener("PictureInPicture:State", message => { document.getElementById("play").label = message.data.paused ? @@ -79,8 +89,20 @@ var Player = { }, }; -window.addEventListener("load", () => Player.init(), {once: true}); -window.addEventListener("unload", () => Player.destroy(), {once: true}); +// Only consume the listener for the player document's own load, rather than +// a load from the embedded browser. +window.addEventListener("load", function onLoad(event) { + if (event.target == document) { + window.removeEventListener("load", onLoad); + Player.init(); + } +}); +window.addEventListener("unload", function onUnload(event) { + if (event.target == document) { + window.removeEventListener("unload", onUnload); + Player.destroy(); + } +}); window.addEventListener("keydown", event => { if (event.key == "Escape") { window.close(); diff --git a/browser/base/content/pictureInPicture.xul b/browser/base/content/pictureInPicture.xul index c8d23854e9..865f05e645 100644 --- a/browser/base/content/pictureInPicture.xul +++ b/browser/base/content/pictureInPicture.xul @@ -3,6 +3,7 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + { + // takeSource consumes the handoff. A duplicate initialization must not + // consume it again or close an already playing window. + if (initialized) { + return; + } + initialized = true; try { source = PictureInPicture.takeSource(message.data.id); sourceWindow = source.ownerGlobal; diff --git a/browser/base/jar.mn b/browser/base/jar.mn index 9e1ab30e31..30a4e26d06 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -4,6 +4,7 @@ browser.jar: content/browser/pictureInPicture.xul (content/pictureInPicture.xul) content/browser/pictureInPicture.js (content/pictureInPicture.js) + content/browser/pictureInPicture.css (content/pictureInPicture.css) content/browser/pictureInPictureContent.js (content/pictureInPictureContent.js) % content browser %content/browser/ contentaccessible=yes #ifdef XP_MACOSX diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 2d02593dd2..d0d71e2475 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -881,9 +881,20 @@ ContentParent::CreateBrowser(const TabContext& aContext, constructorSender = CreateContentBridgeParent(aContext, initialPriority, openerTabId, &tabId); } else { - constructorSender = - GetNewOrUsedBrowserProcess(aContext.IsMozBrowserElement(), - initialPriority, nullptr, aFreshProcess); + if (aOpenerContentParent && !aFreshProcess) { + // relatedBrowser requires the same process, not another process from + // the pool. Picture-in-Picture shares a video through a process-local + // module, and cannot use a randomly selected content process. + if (!aOpenerContentParent->IsAlive() || + aOpenerContentParent->IsForBrowser() != aContext.IsMozBrowserElement()) { + return nullptr; + } + constructorSender = aOpenerContentParent; + } else { + constructorSender = + GetNewOrUsedBrowserProcess(aContext.IsMozBrowserElement(), + initialPriority, nullptr, aFreshProcess); + } if (!constructorSender) { return nullptr; }