diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 8bf3ea9837cd..419fa4600677 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1826,11 +1826,6 @@ pref("media.videocontrols.picture-in-picture.audio-toggle.enabled", true); pref("media.videocontrols.picture-in-picture.video-toggle.enabled", true); pref("media.videocontrols.picture-in-picture.video-toggle.visibility-threshold", "1.0"); pref("media.videocontrols.picture-in-picture.keyboard-controls.enabled", true); -#ifdef NIGHTLY_BUILD - pref("media.videocontrols.picture-in-picture.urlbar-button.enabled", true); -#else - pref("media.videocontrols.picture-in-picture.urlbar-button.enabled", false); -#endif // Preferences for the older translation service backed by external services. This is // planned to be replaced with an integration of the Firefox Translations service. diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index a5b6df70d600..6c72f3966fa1 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -5359,8 +5359,6 @@ var XULBrowserWindow = { AboutReaderParent.updateReaderButton(gBrowser.selectedBrowser); - PictureInPicture.updateUrlbarToggle(gBrowser.selectedBrowser); - if (!gMultiProcessBrowser) { // Bug 1108553 - Cannot rotate images with e10s gGestureSupport.restoreRotationState(); diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml index e46b9581f05f..6aebd5548f39 100644 --- a/browser/base/content/navigator-toolbox.inc.xhtml +++ b/browser/base/content/navigator-toolbox.inc.xhtml @@ -365,15 +365,6 @@ - ` markup. diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css index 74d14e0aec37..b90e4fc42d7c 100644 --- a/browser/themes/shared/urlbar-searchbar.css +++ b/browser/themes/shared/urlbar-searchbar.css @@ -575,19 +575,6 @@ fill-opacity: 1; } -/* Picture-in-Picture icon */ -#picture-in-picture-button > .urlbar-icon { - list-style-image: url("chrome://global/skin/media/picture-in-picture-open.svg"); -} - -#picture-in-picture-button[pipactive] > .urlbar-icon { - list-style-image: url("chrome://global/skin/media/picture-in-picture-closed.svg"); -} - -#picture-in-picture-button:-moz-locale-dir(rtl) > .urlbar-icon { - transform: scaleX(-1); -} - /* Zoom button */ #urlbar-zoom-button { diff --git a/toolkit/actors/PictureInPictureChild.sys.mjs b/toolkit/actors/PictureInPictureChild.sys.mjs index c79c5d72b667..2f198df319c9 100644 --- a/toolkit/actors/PictureInPictureChild.sys.mjs +++ b/toolkit/actors/PictureInPictureChild.sys.mjs @@ -35,24 +35,6 @@ XPCOMUtils.defineLazyPreferenceGetter( "media.videocontrols.picture-in-picture.improved-video-controls.enabled", false ); -XPCOMUtils.defineLazyPreferenceGetter( - lazy, - "MIN_VIDEO_LENGTH", - "media.videocontrols.picture-in-picture.video-toggle.min-video-secs", - 45 -); -XPCOMUtils.defineLazyPreferenceGetter( - lazy, - "PIP_TOGGLE_ALWAYS_SHOW", - "media.videocontrols.picture-in-picture.video-toggle.always-show", - false -); -XPCOMUtils.defineLazyPreferenceGetter( - lazy, - "PIP_URLBAR_BUTTON", - "media.videocontrols.picture-in-picture.urlbar-button.enabled", - false -); const TOGGLE_ENABLED_PREF = "media.videocontrols.picture-in-picture.video-toggle.enabled"; @@ -278,18 +260,6 @@ export class PictureInPictureToggleChild extends JSWindowActorChild { Services.prefs.addObserver(TOGGLE_ENABLED_PREF, this.observerFunction); Services.prefs.addObserver(PIP_ENABLED_PREF, this.observerFunction); Services.cpmm.sharedData.addEventListener("change", this); - - this.eligiblePipVideos = new WeakSet(); - } - - receiveMessage(message) { - switch (message.name) { - case "PictureInPicture:UrlbarToggle": { - this.urlbarToggle(); - break; - } - } - return null; } didDestroy() { @@ -308,14 +278,6 @@ export class PictureInPictureToggleChild extends JSWindowActorChild { this.videoWrapper?.destroy(); this.videoWrapper = null; - for (let video of ChromeUtils.nondeterministicGetWeakSetKeys( - this.eligiblePipVideos - )) { - video.removeEventListener("emptied", this); - video.removeEventListener("loadedmetadata", this); - video.removeEventListener("durationchange", this); - } - // ensure we don't access the state this.isDestroyed = true; } @@ -514,14 +476,6 @@ export class PictureInPictureToggleChild extends JSWindowActorChild { this.onPageHide(event); break; } - case "durationchange": - // Intentional fall-through - case "emptied": - // Intentional fall-through - case "loadedmetadata": { - this.updatePipVideoEligibility(event.target); - break; - } } } @@ -544,87 +498,6 @@ export class PictureInPictureToggleChild extends JSWindowActorChild { } state.intersectionObserver.observe(video); - - this.updatePipVideoEligibility(video); - } - - updatePipVideoEligibility(video) { - if (this.isVideoPiPEligible(video)) { - if (!this.eligiblePipVideos.has(video)) { - this.eligiblePipVideos.add(video); - - let mutationObserver = new this.contentWindow.MutationObserver( - mutationList => { - this.handleEligiblePipVideoMutation(mutationList); - } - ); - mutationObserver.observe(video.parentElement, { childList: true }); - - this.sendAsyncMessage("PictureInPicture:UpdateEligiblePipVideoCount", { - count: ChromeUtils.nondeterministicGetWeakSetKeys( - this.eligiblePipVideos - ).length, - }); - } - } - } - - handleEligiblePipVideoMutation(mutationList) { - for (let mutationRecord of mutationList) { - let video = mutationRecord.removedNodes[0]; - this.eligiblePipVideos.delete(video); - } - - this.sendAsyncMessage("PictureInPicture:UpdateEligiblePipVideoCount", { - count: ChromeUtils.nondeterministicGetWeakSetKeys(this.eligiblePipVideos) - .length, - }); - } - - urlbarToggle() { - let video = ChromeUtils.nondeterministicGetWeakSetKeys( - this.eligiblePipVideos - )[0]; - if (video) { - let pipEvent = new this.contentWindow.CustomEvent( - "MozTogglePictureInPicture", - { - bubbles: true, - } - ); - video.dispatchEvent(pipEvent); - } - } - - isVideoPiPEligible(video) { - if (!lazy.PIP_URLBAR_BUTTON) { - return false; - } - - if (lazy.PIP_TOGGLE_ALWAYS_SHOW) { - return true; - } - - if (isNaN(video.duration)) { - video.addEventListener("emptied", this); - video.addEventListener("loadedmetadata", this); - video.addEventListener("durationchange", this); - return false; - } - - if (video.duration < lazy.MIN_VIDEO_LENGTH) { - return false; - } - - const MIN_VIDEO_DIMENSION = 140; // pixels - if ( - video.clientWidth < MIN_VIDEO_DIMENSION || - video.clientHeight < MIN_VIDEO_DIMENSION - ) { - return false; - } - - return true; } /** diff --git a/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs b/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs index 4c05ad339dd9..a2a3b7b70653 100644 --- a/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs +++ b/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs @@ -21,6 +21,7 @@ const PLAYER_URI = "chrome://global/content/pictureinpicture/player.xhtml"; const PLAYER_FEATURES = "chrome,titlebar=no,alwaysontop,lockaspectratio,resizable,dialog"; const WINDOW_TYPE = "Toolkit:PictureInPicture"; +const PIP_ENABLED_PREF = "media.videocontrols.picture-in-picture.enabled"; const TOGGLE_ENABLED_PREF = "media.videocontrols.picture-in-picture.video-toggle.enabled"; const TOGGLE_POSITION_PREF = @@ -33,19 +34,6 @@ const BACKGROUND_DURATION_HISTOGRAM_ID = const FOREGROUND_DURATION_HISTOGRAM_ID = "FX_PICTURE_IN_PICTURE_FOREGROUND_TAB_PLAYING_DURATION"; -XPCOMUtils.defineLazyPreferenceGetter( - lazy, - "PIP_ENABLED", - "media.videocontrols.picture-in-picture.enabled", - false -); -XPCOMUtils.defineLazyPreferenceGetter( - lazy, - "PIP_URLBAR_BUTTON", - "media.videocontrols.picture-in-picture.urlbar-button.enabled", - false -); - /** * Tracks the number of currently open player windows for Telemetry tracking */ @@ -79,11 +67,6 @@ export class PictureInPictureToggleParent extends JSWindowActorParent { PictureInPicture.openToggleContextMenu(win, aMessage.data); break; } - case "PictureInPicture:UpdateEligiblePipVideoCount": { - let { count } = aMessage.data; - PictureInPicture.updateEligiblePipVideoCount(browsingContext, count); - PictureInPicture.updateUrlbarToggle(browser); - } } } } @@ -178,9 +161,6 @@ export var PictureInPicture = { // Maps an AppWindow to the number of PiP windows it has originatingWinWeakMap: new WeakMap(), - // Maps a WindowGlobal to count of eligible PiP videos - weakGlobalToEligiblePipCount: new WeakMap(), - /** * Returns the player window if one exists and if it hasn't yet been closed. * @@ -358,7 +338,7 @@ export var PictureInPicture = { * @param {Event} event */ onCommand(event) { - if (!lazy.PIP_ENABLED) { + if (!Services.prefs.getBoolPref(PIP_ENABLED_PREF, false)) { return; } @@ -386,122 +366,6 @@ export var PictureInPicture = { await this.closeSinglePipWindow({ reason: "unpip", actorRef: pipActor }); }, - /** - * Updates the count of eligible PiP videos for a respective WindowGlobal. - * @param {BrowsingContext} browsingContext The BrowsingContext with eligible videos - * @param {Number} count The number of eligible videos for the respective WindowGlobal - */ - updateEligiblePipVideoCount(browsingContext, count) { - let windowGlobal = browsingContext.currentWindowGlobal; - - if (windowGlobal) { - this.weakGlobalToEligiblePipCount.set(windowGlobal, count); - } - }, - - /** - * A generator function that yeilds a WindowGlobal and it's respective PiP count. - * @param {Browser} browser The selected browser - */ - *windowGlobalPipCountGenerator(browser) { - let contextsToVisit = [browser.browsingContext]; - while (contextsToVisit.length) { - let currentBC = contextsToVisit.pop(); - let windowGlobal = currentBC.currentWindowGlobal; - - if (!windowGlobal) { - continue; - } - - let pipCountForGlobal = - this.weakGlobalToEligiblePipCount.get(windowGlobal) || 0; - - contextsToVisit.push(...currentBC.children); - - yield { windowGlobal, count: pipCountForGlobal }; - } - }, - - /** - * Gets the total eligible video count for a given browser. - * @param {Browser} browser The selected browser - * @returns Total count of eligible PiP videos for the selected broser - */ - getEligiblePipVideoCount(browser) { - let totalPipCount = 0; - - for (let { count } of this.windowGlobalPipCountGenerator(browser)) { - totalPipCount += count; - } - - return totalPipCount; - }, - - /** - * Toggles the visibility of the PiP urlbar button. If the total video count - * is 1, then we will show the button. Otherwise the button is hidden. - * @param {Browser} browser The selected browser - */ - updateUrlbarToggle(browser) { - if (!lazy.PIP_ENABLED || !lazy.PIP_URLBAR_BUTTON) { - return; - } - - let win = browser.ownerGlobal; - if (win.closed || win.gBrowser?.selectedBrowser !== browser) { - return; - } - - let totalPipCount = this.getEligiblePipVideoCount(browser); - - let pipToggle = win.document.getElementById("picture-in-picture-button"); - pipToggle.hidden = !(totalPipCount === 1); - }, - - /** - * Finds the correct WindowGlobal to open the eligible PiP video. - * @param {Event} event Event from clicking the PiP urlbar button - */ - toggleUrlbar(event) { - let win = event.target.ownerGlobal; - let browser = win.gBrowser.selectedBrowser; - - for (let { windowGlobal, count } of this.windowGlobalPipCountGenerator( - browser - )) { - if (count === 1) { - let actor = windowGlobal.getActor("PictureInPictureToggle"); - actor.sendAsyncMessage("PictureInPicture:UrlbarToggle"); - return; - } - } - }, - - /** - * Sets the PiP urlbar to an active state. This changes the icon in the - * urlbar button to the unpip icon. - * @param {Window} win The current Window - */ - setUrlbarPipIconActive(win) { - let pipToggle = win.document.getElementById("picture-in-picture-button"); - pipToggle.toggleAttribute("pipactive", true); - }, - - /** - * Sets the PiP urlbar to an inactive state. This changes the icon in the - * urlbar button to the open pip icon. - * @param {Window} pipWin The PiP window - */ - setUrlbarPipIconInactive(pipWin) { - let browser = this.weakWinToBrowser.get(pipWin); - if (!browser) { - return; - } - let win = browser.ownerGlobal; - let pipToggle = win.document.getElementById("picture-in-picture-button"); - pipToggle.toggleAttribute("pipactive", false); - }, - /** * Remove attribute which enables pip icon in tab * @@ -620,8 +484,6 @@ export var PictureInPicture = { let tab = parentWin.gBrowser.getTabForBrowser(browser); tab.setAttribute("pictureinpicture", true); - this.setUrlbarPipIconActive(parentWin); - tab.addEventListener("TabSwapPictureInPicture", this); let pipId = gNextWindowID.toString(); @@ -701,7 +563,6 @@ export var PictureInPicture = { // Saves the location of the Picture in Picture window this.savePosition(window); this.clearPipTabIcon(window); - this.setUrlbarPipIconInactive(window); }, /** diff --git a/toolkit/components/pictureinpicture/tests/browser.ini b/toolkit/components/pictureinpicture/tests/browser.ini index d15f152616f2..5717e16d0a4a 100644 --- a/toolkit/components/pictureinpicture/tests/browser.ini +++ b/toolkit/components/pictureinpicture/tests/browser.ini @@ -7,7 +7,6 @@ support-files = test-media-stream.html test-opaque-overlay.html test-page.html - test-page-multiple-contexts.html test-page-with-iframe.html test-page-with-sound.html test-page-with-webvtt.html @@ -141,6 +140,5 @@ skip-if = [browser_toggle_enabled.js] [browser_toggle_videocontrols.js] [browser_touch_toggle_enablepip.js] -[browser_urlbar_toggle.js] [browser_videoEmptied.js] [browser_videoSelection.js] \ No newline at end of file diff --git a/toolkit/components/pictureinpicture/tests/browser_multiPip.js b/toolkit/components/pictureinpicture/tests/browser_multiPip.js index b5e2863306c3..ef4dd8bdf4e7 100644 --- a/toolkit/components/pictureinpicture/tests/browser_multiPip.js +++ b/toolkit/components/pictureinpicture/tests/browser_multiPip.js @@ -110,7 +110,7 @@ add_task(async () => { await firstClosed; info("First PiP closed after closing the first tab"); - await assertVideoIsBeingCloned(secondTab.linkedBrowser, "#with-controls"); + await assertVideoIsBeingCloned(secondTab.linkedBrowser, "with-controls"); info("Second PiP is still open after first tab close"); let secondClosed = BrowserTestUtils.domWindowClosed(secondPip); diff --git a/toolkit/components/pictureinpicture/tests/browser_urlbar_toggle.js b/toolkit/components/pictureinpicture/tests/browser_urlbar_toggle.js deleted file mode 100644 index 12f8535517b3..000000000000 --- a/toolkit/components/pictureinpicture/tests/browser_urlbar_toggle.js +++ /dev/null @@ -1,86 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -add_task(async function test_urlbar_toggle_multiple_contexts() { - await BrowserTestUtils.withNewTab( - { - url: TEST_PAGE_MULTIPLE_CONTEXTS, - gBrowser, - }, - async browser => { - await ensureVideosReady(browser); - await ensureVideosReady(browser.browsingContext.children[0]); - - await TestUtils.waitForCondition( - () => PictureInPicture.getEligiblePipVideoCount(browser) === 2, - "Waiting for videos to register" - ); - - let totalPipCount = PictureInPicture.getEligiblePipVideoCount(browser); - is(totalPipCount, 2, "Total PiP count is 2"); - - let pipUrlbarToggle = document.getElementById( - "picture-in-picture-button" - ); - ok( - BrowserTestUtils.is_hidden(pipUrlbarToggle), - "PiP urlbar toggle is hidden because there is more than 1 video" - ); - - // Remove one video from page so urlbar toggle will show - await SpecialPowers.spawn(browser, [], async () => { - let video = content.document.getElementById("with-controls"); - video.remove(); - }); - - await BrowserTestUtils.waitForMutationCondition( - pipUrlbarToggle, - { attributeFilter: ["hidden"] }, - () => BrowserTestUtils.is_visible(pipUrlbarToggle) - ); - - ok( - BrowserTestUtils.is_visible(pipUrlbarToggle), - "PiP urlbar toggle is visible" - ); - - totalPipCount = PictureInPicture.getEligiblePipVideoCount(browser); - is(totalPipCount, 1, "Total PiP count is 1"); - - let domWindowOpened = BrowserTestUtils.domWindowOpenedAndLoaded(null); - pipUrlbarToggle.click(); - let win = await domWindowOpened; - ok(win, "A Picture-in-Picture window opened."); - - await assertVideoIsBeingCloned( - browser.browsingContext.children[0], - "video" - ); - - let domWindowClosed = BrowserTestUtils.domWindowClosed(win); - pipUrlbarToggle.click(); - await domWindowClosed; - - await SpecialPowers.spawn(browser, [], async () => { - let iframe = content.document.getElementById("iframe"); - iframe.remove(); - }); - - await BrowserTestUtils.waitForMutationCondition( - pipUrlbarToggle, - { attributeFilter: ["hidden"] }, - () => BrowserTestUtils.is_hidden(pipUrlbarToggle) - ); - - ok( - BrowserTestUtils.is_hidden(pipUrlbarToggle), - "PiP urlbar toggle is hidden because there are no videos on the page" - ); - - totalPipCount = PictureInPicture.getEligiblePipVideoCount(browser); - is(totalPipCount, 0, "Total PiP count is 0"); - } - ); -}); diff --git a/toolkit/components/pictureinpicture/tests/head.js b/toolkit/components/pictureinpicture/tests/head.js index b426f63fb55c..91afc00cdb44 100644 --- a/toolkit/components/pictureinpicture/tests/head.js +++ b/toolkit/components/pictureinpicture/tests/head.js @@ -22,8 +22,6 @@ const TEST_PAGE_WITH_SOUND = TEST_ROOT + "test-page-with-sound.html"; const TEST_PAGE_WITH_NAN_VIDEO_DURATION = TEST_ROOT + "test-page-with-nan-video-duration.html"; const TEST_PAGE_WITH_WEBVTT = TEST_ROOT + "test-page-with-webvtt.html"; -const TEST_PAGE_MULTIPLE_CONTEXTS = - TEST_ROOT + "test-page-multiple-contexts.html"; const WINDOW_TYPE = "Toolkit:PictureInPicture"; const TOGGLE_POSITION_PREF = "media.videocontrols.picture-in-picture.video-toggle.position"; @@ -188,16 +186,16 @@ async function assertShowingMessage(browser, videoID, expected) { * good indicator for answering if this video is currently open in PiP. * * @param {Browser} browser - * The content browser or browsing contect that the video lives in + * The content browser that the video lives in * @param {string} videoId * The id associated with the video * * @returns {bool} * Whether the video is currently being cloned (And is most likely open in PiP) */ -function assertVideoIsBeingCloned(browser, selector) { - return SpecialPowers.spawn(browser, [selector], async slctr => { - let video = content.document.querySelector(slctr); +function assertVideoIsBeingCloned(browser, videoId) { + return SpecialPowers.spawn(browser, [videoId], async videoID => { + let video = content.document.getElementById(videoID); await ContentTaskUtils.waitForCondition(() => { return video.isCloningElementVisually; }, "Video is being cloned visually."); @@ -208,7 +206,7 @@ function assertVideoIsBeingCloned(browser, selector) { * Ensures that each of the videos loaded inside of a document in a * have reached the HAVE_ENOUGH_DATA readyState. * - * @param {Element} browser The hosting the