зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1578985 - Saving the last location and size of Picture in Picture window and opening there the next time. r=mconley
Differential Revision: https://phabricator.services.mozilla.com/D90813
This commit is contained in:
Родитель
a5d95630e1
Коммит
ce9cac5aae
|
@ -39,12 +39,19 @@ add_task(async function testNoSrcOrErrorMediaEntersPIPMode() {
|
|||
tab.linkedBrowser,
|
||||
testVideoId
|
||||
);
|
||||
await BrowserTestUtils.closeWindow(winPIP);
|
||||
|
||||
await ensureMessageAndClosePiP(
|
||||
tab.linkedBrowser,
|
||||
testVideoId,
|
||||
winPIP,
|
||||
false
|
||||
);
|
||||
}
|
||||
ok(!controller.isActive, "controller is still inactive");
|
||||
|
||||
info(`remove tab`);
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
await SimpleTest.promiseFocus(window);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -271,7 +271,8 @@ var PictureInPicture = {
|
|||
reason,
|
||||
1
|
||||
);
|
||||
|
||||
// Saves the location of the Picture in Picture window
|
||||
this.savePosition(window);
|
||||
this.clearPipTabIcon();
|
||||
delete this._weakPipPlayer;
|
||||
delete this.browser;
|
||||
|
@ -332,8 +333,9 @@ var PictureInPicture = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Calculate the desired size and position for a Picture in Picture window
|
||||
* for the provided window and videoData.
|
||||
* This function tries to restore the last known Picture-in-Picture location
|
||||
* and size. If those values are unknown or offscreen, then a default
|
||||
* location and size is used.
|
||||
*
|
||||
* @param windowOrPlayer (chrome window|player window)
|
||||
* The window hosting the browser that requested the Picture in
|
||||
|
@ -350,7 +352,7 @@ var PictureInPicture = {
|
|||
* videoWidth (int):
|
||||
* The preferred width of the video.
|
||||
*
|
||||
* @returns object
|
||||
* @returns (object)
|
||||
* The size and position for the player window.
|
||||
*
|
||||
* top (int):
|
||||
|
@ -367,74 +369,121 @@ var PictureInPicture = {
|
|||
*/
|
||||
fitToScreen(windowOrPlayer, videoData) {
|
||||
let { videoHeight, videoWidth } = videoData;
|
||||
|
||||
// if current PiP window is being resized, the underlying video is changing,
|
||||
// then save the location and size for opening the new window
|
||||
let isPlayerWindow = windowOrPlayer == this.getWeakPipPlayer();
|
||||
if (isPlayerWindow) {
|
||||
this.savePosition(windowOrPlayer);
|
||||
}
|
||||
|
||||
// The Picture in Picture window will open on the same display as the
|
||||
// originating window, and anchor to the bottom right.
|
||||
let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"].getService(
|
||||
Ci.nsIScreenManager
|
||||
);
|
||||
let screen = screenManager.screenForRect(
|
||||
// The last PiP location and size
|
||||
let { top, left, width, height } = this.loadPosition();
|
||||
|
||||
// Check that previous location and size were loaded
|
||||
if (!isNaN(top) && !isNaN(left) && !isNaN(width) && !isNaN(height)) {
|
||||
// Center position of PiP window
|
||||
let centerX = left + width / 2;
|
||||
let centerY = top + height / 2;
|
||||
|
||||
// Get the screen of the last PiP using the center of the PiP
|
||||
// window to check.
|
||||
// PiP screen will be the default screen if the center was
|
||||
// not on a screen.
|
||||
let PiPScreen = this.getWorkingScreen(centerX, centerY);
|
||||
|
||||
// We have the screen, now we will get the dimensions of the screen
|
||||
let [
|
||||
PiPScreenLeft,
|
||||
PiPScreenTop,
|
||||
PiPScreenWidth,
|
||||
PiPScreenHeight,
|
||||
] = this.getAvailScreenSize(PiPScreen);
|
||||
|
||||
// Check that the center of the last PiP location is within the screen limits
|
||||
// If it's not, then we will use the default size and position
|
||||
if (
|
||||
PiPScreenLeft <= centerX &&
|
||||
centerX <= PiPScreenLeft + PiPScreenWidth &&
|
||||
PiPScreenTop <= centerY &&
|
||||
centerY <= PiPScreenTop + PiPScreenHeight
|
||||
) {
|
||||
let oldWidth = width;
|
||||
|
||||
// The new PiP window will keep the height of the old
|
||||
// PiP window and adjust the width to the correct ratio
|
||||
width = Math.round((height * videoWidth) / videoHeight);
|
||||
|
||||
// Minimum window size on Windows is 136
|
||||
if (AppConstants.platform == "win") {
|
||||
width = 136 > width ? 136 : width;
|
||||
}
|
||||
|
||||
// WIGGLE_ROOM allows the PiP window to be within 5 pixels of the right
|
||||
// side of the screen to stay snapped to the right side
|
||||
const WIGGLE_ROOM = 5;
|
||||
// If the PiP window was right next to the right side of the screen
|
||||
// then move the PiP window to the right the same distance that
|
||||
// the width changes from previous width to current width
|
||||
let rightScreen = PiPScreenLeft + PiPScreenWidth;
|
||||
let distFromRight = rightScreen - (left + width);
|
||||
if (
|
||||
0 < distFromRight &&
|
||||
distFromRight <= WIGGLE_ROOM + (oldWidth - width)
|
||||
) {
|
||||
left += distFromRight;
|
||||
}
|
||||
|
||||
// Checks if some of the PiP window is off screen and
|
||||
// if so it will adjust to move everything on screen
|
||||
if (left < PiPScreenLeft) {
|
||||
// off the left of the screen
|
||||
// slide right
|
||||
left += PiPScreenLeft - left;
|
||||
}
|
||||
if (top < PiPScreenTop) {
|
||||
// off the top of the screen
|
||||
// slide down
|
||||
top += PiPScreenTop - top;
|
||||
}
|
||||
if (left + width > PiPScreenLeft + PiPScreenWidth) {
|
||||
// off the right of the screen
|
||||
// slide left
|
||||
left += PiPScreenLeft + PiPScreenWidth - left - width;
|
||||
}
|
||||
if (top + height > PiPScreenTop + PiPScreenHeight) {
|
||||
// off the bottom of the screen
|
||||
// slide up
|
||||
top += PiPScreenTop + PiPScreenHeight - top - height;
|
||||
}
|
||||
return { top, left, width, height };
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have the size or position of the last PiP window, so fall
|
||||
// back to calculating the default location.
|
||||
let screen = this.getWorkingScreen(
|
||||
windowOrPlayer.screenX,
|
||||
windowOrPlayer.screenY,
|
||||
1,
|
||||
1
|
||||
windowOrPlayer.screenY
|
||||
);
|
||||
|
||||
// Now that we have the right screen, let's see how much available
|
||||
// real-estate there is for us to work with.
|
||||
let screenLeft = {},
|
||||
screenTop = {},
|
||||
screenWidth = {},
|
||||
screenHeight = {};
|
||||
screen.GetAvailRectDisplayPix(
|
||||
let [
|
||||
screenLeft,
|
||||
screenTop,
|
||||
screenWidth,
|
||||
screenHeight
|
||||
);
|
||||
let fullLeft = {},
|
||||
fullTop = {},
|
||||
fullWidth = {},
|
||||
fullHeight = {};
|
||||
screen.GetRectDisplayPix(fullLeft, fullTop, fullWidth, fullHeight);
|
||||
screenHeight,
|
||||
] = this.getAvailScreenSize(screen);
|
||||
|
||||
// We have to divide these dimensions by the CSS scale factor for the
|
||||
// display in order for the video to be positioned correctly on displays
|
||||
// that are not at a 1.0 scaling.
|
||||
let scaleFactor = screen.contentsScaleFactor / screen.defaultCSSScaleFactor;
|
||||
screenWidth.value *= scaleFactor;
|
||||
screenHeight.value *= scaleFactor;
|
||||
screenLeft.value =
|
||||
(screenLeft.value - fullLeft.value) * scaleFactor + fullLeft.value;
|
||||
screenTop.value =
|
||||
(screenTop.value - fullTop.value) * scaleFactor + fullTop.value;
|
||||
|
||||
// If we have a player window, maintain the previous player window's size by
|
||||
// clamping the new video's largest dimension to the player window's
|
||||
// largest dimension.
|
||||
//
|
||||
// Otherwise the Picture in Picture window will be a maximum of a quarter of
|
||||
// The Picture in Picture window will be a maximum of a quarter of
|
||||
// the screen height, and a third of the screen width.
|
||||
let preferredSize;
|
||||
if (isPlayerWindow) {
|
||||
let prevWidth = windowOrPlayer.innerWidth;
|
||||
let prevHeight = windowOrPlayer.innerHeight;
|
||||
preferredSize = prevWidth >= prevHeight ? prevWidth : prevHeight;
|
||||
}
|
||||
const MAX_HEIGHT = preferredSize || screenHeight.value / 4;
|
||||
const MAX_WIDTH = preferredSize || screenWidth.value / 3;
|
||||
const MAX_HEIGHT = screenHeight / 4;
|
||||
const MAX_WIDTH = screenWidth / 3;
|
||||
|
||||
let width = videoWidth;
|
||||
let height = videoHeight;
|
||||
width = videoWidth;
|
||||
height = videoHeight;
|
||||
let aspectRatio = videoWidth / videoHeight;
|
||||
|
||||
if (
|
||||
videoHeight > MAX_HEIGHT ||
|
||||
videoWidth > MAX_WIDTH ||
|
||||
(isPlayerWindow && videoHeight < MAX_HEIGHT && videoWidth < MAX_WIDTH)
|
||||
) {
|
||||
// We're bigger than the max, or smaller than the previous player window.
|
||||
if (videoHeight > MAX_HEIGHT || videoWidth > MAX_WIDTH) {
|
||||
// We're bigger than the max.
|
||||
// Take the largest dimension and clamp it to the associated max.
|
||||
// Recalculate the other dimension to maintain aspect ratio.
|
||||
if (videoWidth >= videoHeight) {
|
||||
|
@ -454,43 +503,6 @@ var PictureInPicture = {
|
|||
}
|
||||
}
|
||||
|
||||
// Figure out where to position the window on screen. If we have a player
|
||||
// window this will account for any change in video size. Otherwise the
|
||||
// video will be positioned in the bottom right.
|
||||
|
||||
if (isPlayerWindow) {
|
||||
// We might need to move the window to keep its positioning in a similar
|
||||
// part of the screen.
|
||||
//
|
||||
// Find the distance from each edge of the screen of the old video, we'll
|
||||
// keep the closest edge in the same spot.
|
||||
let prevWidth = windowOrPlayer.innerWidth;
|
||||
let prevHeight = windowOrPlayer.innerHeight;
|
||||
let distanceLeft = windowOrPlayer.screenX;
|
||||
let distanceRight =
|
||||
screenWidth.value - windowOrPlayer.screenX - prevWidth;
|
||||
let distanceTop = windowOrPlayer.screenY;
|
||||
let distanceBottom =
|
||||
screenHeight.value - windowOrPlayer.screenY - prevHeight;
|
||||
|
||||
let left = windowOrPlayer.screenX;
|
||||
let top = windowOrPlayer.screenY;
|
||||
|
||||
if (distanceRight < distanceLeft) {
|
||||
// Closer to the right edge than the left. Move the window right by
|
||||
// the difference in the video widths.
|
||||
left += prevWidth - width;
|
||||
}
|
||||
|
||||
if (distanceBottom < distanceTop) {
|
||||
// Closer to the bottom edge than the top. Move the window down by
|
||||
// the difference in the video heights.
|
||||
top += prevHeight - height;
|
||||
}
|
||||
|
||||
return { top, left, width, height };
|
||||
}
|
||||
|
||||
// Now that we have the dimensions of the video, we need to figure out how
|
||||
// to position it in the bottom right corner. Since we know the width of the
|
||||
// available rect, we need to subtract the dimensions of the window we're
|
||||
|
@ -506,10 +518,8 @@ var PictureInPicture = {
|
|||
// the screenLeft and screenTop values, which tell us where this screen is
|
||||
// located relative to the "origin" in absolute coordinates.
|
||||
let isRTL = Services.locale.isAppLocaleRTL;
|
||||
let left = isRTL
|
||||
? screenLeft.value
|
||||
: screenLeft.value + screenWidth.value - width;
|
||||
let top = screenTop.value + screenHeight.value - height;
|
||||
left = isRTL ? screenLeft : screenLeft + screenWidth - width;
|
||||
top = screenTop + screenHeight - height;
|
||||
|
||||
return { top, left, width, height };
|
||||
},
|
||||
|
@ -558,4 +568,145 @@ var PictureInPicture = {
|
|||
hideToggle() {
|
||||
Services.prefs.setBoolPref(TOGGLE_ENABLED_PREF, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function takes a screen and will return the left, top, width and
|
||||
* height of the screen
|
||||
* @param screen
|
||||
* The screen we need to get the sizec and coordinates of
|
||||
*
|
||||
* @returns array
|
||||
* Size and location of screen
|
||||
*
|
||||
* screenLeft.value (int):
|
||||
* The left position for the screen.
|
||||
*
|
||||
* screenTop.value (int):
|
||||
* The top position for the screen.
|
||||
*
|
||||
* screenWidth.value (int):
|
||||
* The width of the screen.
|
||||
*
|
||||
* screenHeight.value (int):
|
||||
* The height of the screen.
|
||||
*/
|
||||
getAvailScreenSize(screen) {
|
||||
let screenLeft = {},
|
||||
screenTop = {},
|
||||
screenWidth = {},
|
||||
screenHeight = {};
|
||||
screen.GetAvailRectDisplayPix(
|
||||
screenLeft,
|
||||
screenTop,
|
||||
screenWidth,
|
||||
screenHeight
|
||||
);
|
||||
let fullLeft = {},
|
||||
fullTop = {},
|
||||
fullWidth = {},
|
||||
fullHeight = {};
|
||||
screen.GetRectDisplayPix(fullLeft, fullTop, fullWidth, fullHeight);
|
||||
|
||||
// We have to divide these dimensions by the CSS scale factor for the
|
||||
// display in order for the video to be positioned correctly on displays
|
||||
// that are not at a 1.0 scaling.
|
||||
let scaleFactor = screen.contentsScaleFactor / screen.defaultCSSScaleFactor;
|
||||
screenWidth.value *= scaleFactor;
|
||||
screenHeight.value *= scaleFactor;
|
||||
screenLeft.value =
|
||||
(screenLeft.value - fullLeft.value) * scaleFactor + fullLeft.value;
|
||||
screenTop.value =
|
||||
(screenTop.value - fullTop.value) * scaleFactor + fullTop.value;
|
||||
|
||||
return [
|
||||
screenLeft.value,
|
||||
screenTop.value,
|
||||
screenWidth.value,
|
||||
screenHeight.value,
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* This function takes in a left and top value and returns the screen they
|
||||
* are located on.
|
||||
* If the left and top are not on any screen, it will return the
|
||||
* default screen
|
||||
* @param left
|
||||
* left or x coordinate
|
||||
* @param top
|
||||
* top or y coordinate
|
||||
*
|
||||
* @returns screen
|
||||
* the screen the left and top are on otherwise, default screen
|
||||
*/
|
||||
getWorkingScreen(left, top) {
|
||||
// Get the screen manager
|
||||
let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"].getService(
|
||||
Ci.nsIScreenManager
|
||||
);
|
||||
// use screenForRect to get screen
|
||||
// this returns the default screen if left and top are not
|
||||
// on any screen
|
||||
let screen = screenManager.screenForRect(left, top, 1, 1);
|
||||
|
||||
return screen;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves position and size of Picture-in-Picture window
|
||||
* @param win The Picture-in-Picture window
|
||||
*/
|
||||
savePosition(win) {
|
||||
let xulStore = Services.xulStore;
|
||||
|
||||
let left = win.screenX;
|
||||
let top = win.screenY;
|
||||
let width = win.innerWidth;
|
||||
let height = win.innerHeight;
|
||||
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "left", left);
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "top", top);
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "width", width);
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "height", height);
|
||||
},
|
||||
|
||||
/**
|
||||
* Load last Picture in Picture location and size
|
||||
* @returns object
|
||||
* The size and position of the last Picture in Picture window.
|
||||
*
|
||||
* top (int):
|
||||
* The top position for the last player window.
|
||||
* Otherwise NaN
|
||||
*
|
||||
* left (int):
|
||||
* The left position for the last player window.
|
||||
* Otherwise NaN
|
||||
*
|
||||
* width (int):
|
||||
* The width of the player last window.
|
||||
* Otherwise NaN
|
||||
*
|
||||
* height (int):
|
||||
* The height of the player last window.
|
||||
* Otherwise NaN
|
||||
*/
|
||||
loadPosition() {
|
||||
let xulStore = Services.xulStore;
|
||||
|
||||
let left = parseInt(
|
||||
xulStore.getValue(PLAYER_URI, "picture-in-picture", "left")
|
||||
);
|
||||
let top = parseInt(
|
||||
xulStore.getValue(PLAYER_URI, "picture-in-picture", "top")
|
||||
);
|
||||
let width = parseInt(
|
||||
xulStore.getValue(PLAYER_URI, "picture-in-picture", "width")
|
||||
);
|
||||
let height = parseInt(
|
||||
xulStore.getValue(PLAYER_URI, "picture-in-picture", "height")
|
||||
);
|
||||
|
||||
return { top, left, width, height };
|
||||
},
|
||||
};
|
||||
|
|
|
@ -47,6 +47,8 @@ skip-if = debug
|
|||
[browser_rerequestPiP.js]
|
||||
[browser_resizeVideo.js]
|
||||
skip-if = os == 'linux' # Bug 1594223
|
||||
[browser_saveLastPiPLoc.js]
|
||||
skip-if = os == 'linux' # Bug 1673465
|
||||
[browser_shortcutsAfterFocus.js]
|
||||
[browser_showMessage.js]
|
||||
[browser_smallVideoLayout.js]
|
||||
|
|
|
@ -59,17 +59,17 @@ async function testVideo(browser, videoID, pipWin, { pinX, pinY } = {}) {
|
|||
newWidth,
|
||||
newHeight
|
||||
) {
|
||||
if (pinX) {
|
||||
if (pinX || previousScreenX == 0) {
|
||||
Assert.equal(
|
||||
previousScreenX,
|
||||
newScreenX,
|
||||
"New video is still in the same X position"
|
||||
);
|
||||
} else {
|
||||
Assert.equal(
|
||||
previousScreenX + previousWidth,
|
||||
newScreenX + newWidth,
|
||||
"New video ends at the same screen X position"
|
||||
Assert.less(
|
||||
Math.abs(previousScreenX + previousWidth - (newScreenX + newWidth)),
|
||||
2,
|
||||
"New video ends at the same screen X position (within 1 pixel)"
|
||||
);
|
||||
}
|
||||
if (pinY) {
|
||||
|
@ -112,8 +112,12 @@ async function testVideo(browser, videoID, pipWin, { pinX, pinY } = {}) {
|
|||
133, // 4 / 3 = 1.333333333
|
||||
"Resized aspect ratio is 4:3"
|
||||
);
|
||||
Assert.equal(initialWidth, resizedWidth, "Resized video has the same width");
|
||||
Assert.greater(resizedHeight, initialHeight, "Resized video grew vertically");
|
||||
Assert.less(resizedWidth, initialWidth, "Resized video has smaller width");
|
||||
Assert.equal(
|
||||
resizedHeight,
|
||||
initialHeight,
|
||||
"Resized video is the same vertically"
|
||||
);
|
||||
|
||||
let resizedScreenX = pipWin.mozInnerScreenX;
|
||||
let resizedScreenY = pipWin.mozInnerScreenY;
|
||||
|
@ -133,16 +137,27 @@ async function testVideo(browser, videoID, pipWin, { pinX, pinY } = {}) {
|
|||
let verticalWidth = pipWin.innerWidth;
|
||||
let verticalHeight = pipWin.innerHeight;
|
||||
let verticalAspectRatio = verticalWidth / verticalHeight;
|
||||
Assert.equal(
|
||||
Math.floor(verticalAspectRatio * 100),
|
||||
50, // 1 / 2 = 0.5
|
||||
"Vertical aspect ratio is 1:2"
|
||||
);
|
||||
|
||||
if (verticalWidth == 136) {
|
||||
// The video is minimun width allowed
|
||||
Assert.equal(
|
||||
Math.floor(verticalAspectRatio * 100),
|
||||
56, // 1 / 2 = 0.5
|
||||
"Vertical aspect ratio is 1:2"
|
||||
);
|
||||
} else {
|
||||
Assert.equal(
|
||||
Math.floor(verticalAspectRatio * 100),
|
||||
50, // 1 / 2 = 0.5
|
||||
"Vertical aspect ratio is 1:2"
|
||||
);
|
||||
}
|
||||
|
||||
Assert.less(verticalWidth, resizedWidth, "Vertical video width shrunk");
|
||||
Assert.equal(
|
||||
resizedWidth,
|
||||
verticalHeight,
|
||||
"Vertical video height matches previous width"
|
||||
initialHeight,
|
||||
"Vertical video height matches previous height"
|
||||
);
|
||||
|
||||
let verticalScreenX = pipWin.mozInnerScreenX;
|
||||
|
@ -168,9 +183,9 @@ async function testVideo(browser, videoID, pipWin, { pinX, pinY } = {}) {
|
|||
177,
|
||||
"Restored aspect ratio is still 16:9"
|
||||
);
|
||||
Assert.equal(
|
||||
initialWidth,
|
||||
pipWin.innerWidth,
|
||||
Assert.less(
|
||||
Math.abs(initialWidth - pipWin.innerWidth),
|
||||
2,
|
||||
"Restored video has its original width"
|
||||
);
|
||||
Assert.equal(
|
||||
|
@ -244,6 +259,5 @@ add_task(async () => {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This function tests that the browser saves the last location of size of
|
||||
* the PiP window and will open the next PiP window in the same location
|
||||
* with the size. It adjusts for aspect ratio by keeping the same height and
|
||||
* adjusting the width of the PiP window.
|
||||
*/
|
||||
|
||||
add_task(async () => {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
url: TEST_PAGE,
|
||||
gBrowser,
|
||||
},
|
||||
// Function to switch video source.
|
||||
async browser => {
|
||||
async function switchVideoSource(src) {
|
||||
let videoResized = BrowserTestUtils.waitForEvent(pipWin, "resize");
|
||||
await ContentTask.spawn(browser, { src }, async ({ src }) => {
|
||||
let doc = content.document;
|
||||
let video = doc.getElementById("with-controls");
|
||||
video.src = src;
|
||||
});
|
||||
await videoResized;
|
||||
}
|
||||
// This function is used because the rounding of the width can be off
|
||||
// by about 1 pixel sometimes so this checks that val1 and val2 are
|
||||
// within 1 pixel
|
||||
function checkIfEqual(val1, val2, str) {
|
||||
let equal = Math.abs(val1 - val2);
|
||||
if (equal <= 1) {
|
||||
is(equal <= 1, true, str);
|
||||
} else {
|
||||
is(val1, val2, str);
|
||||
}
|
||||
}
|
||||
|
||||
// Used for clearing the size and location of the PiP window
|
||||
const PLAYER_URI =
|
||||
"chrome://global/content/pictureinpicture/player.xhtml";
|
||||
|
||||
// The PiP window now stores information between tests and needs to be
|
||||
// cleared before the test begins
|
||||
function clearSaved() {
|
||||
let xulStore = Services.xulStore;
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "left", NaN);
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "top", NaN);
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "width", NaN);
|
||||
xulStore.setValue(PLAYER_URI, "picture-in-picture", "height", NaN);
|
||||
}
|
||||
|
||||
function getAvailScreenSize(screen) {
|
||||
let screenLeft = {},
|
||||
screenTop = {},
|
||||
screenWidth = {},
|
||||
screenHeight = {};
|
||||
screen.GetAvailRectDisplayPix(
|
||||
screenLeft,
|
||||
screenTop,
|
||||
screenWidth,
|
||||
screenHeight
|
||||
);
|
||||
let fullLeft = {},
|
||||
fullTop = {},
|
||||
fullWidth = {},
|
||||
fullHeight = {};
|
||||
screen.GetRectDisplayPix(fullLeft, fullTop, fullWidth, fullHeight);
|
||||
|
||||
// We have to divide these dimensions by the CSS scale factor for the
|
||||
// display in order for the video to be positioned correctly on displays
|
||||
// that are not at a 1.0 scaling.
|
||||
let scaleFactor =
|
||||
screen.contentsScaleFactor / screen.defaultCSSScaleFactor;
|
||||
screenWidth.value *= scaleFactor;
|
||||
screenHeight.value *= scaleFactor;
|
||||
screenLeft.value =
|
||||
(screenLeft.value - fullLeft.value) * scaleFactor + fullLeft.value;
|
||||
screenTop.value =
|
||||
(screenTop.value - fullTop.value) * scaleFactor + fullTop.value;
|
||||
|
||||
return [
|
||||
screenLeft.value,
|
||||
screenTop.value,
|
||||
screenWidth.value,
|
||||
screenHeight.value,
|
||||
];
|
||||
}
|
||||
|
||||
let screen = Cc["@mozilla.org/gfx/screenmanager;1"]
|
||||
.getService(Ci.nsIScreenManager)
|
||||
.screenForRect(1, 1, 1, 1);
|
||||
|
||||
let [
|
||||
defaultX,
|
||||
defaultY,
|
||||
defaultWidth,
|
||||
defaultHeight,
|
||||
] = getAvailScreenSize(screen);
|
||||
|
||||
// Default size of PiP window
|
||||
let rightEdge = defaultX + defaultWidth;
|
||||
let bottomEdge = defaultY + defaultHeight;
|
||||
|
||||
// tab height
|
||||
// Used only for Linux as the PiP window has a tab
|
||||
let tabHeight = 35;
|
||||
|
||||
// clear already saved information
|
||||
clearSaved();
|
||||
|
||||
// Open PiP
|
||||
let pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
let defaultPiPWidth = pipWin.innerWidth;
|
||||
let defaultPiPHeight = pipWin.innerHeight;
|
||||
|
||||
// Check that it is opened at default location
|
||||
checkIfEqual(
|
||||
pipWin.screenX,
|
||||
rightEdge - defaultPiPWidth,
|
||||
"Default PiP X location"
|
||||
);
|
||||
if (AppConstants.platform == "linux") {
|
||||
checkIfEqual(
|
||||
pipWin.screenY,
|
||||
bottomEdge - defaultPiPHeight - tabHeight,
|
||||
"Default PiP Y location"
|
||||
);
|
||||
} else {
|
||||
checkIfEqual(
|
||||
pipWin.screenY,
|
||||
bottomEdge - defaultPiPHeight,
|
||||
"Default PiP Y location"
|
||||
);
|
||||
}
|
||||
checkIfEqual(pipWin.innerHeight, defaultPiPHeight, "Default PiP height");
|
||||
checkIfEqual(pipWin.innerWidth, defaultPiPWidth, "Default PiP width");
|
||||
|
||||
let top = defaultY;
|
||||
let left = defaultX;
|
||||
pipWin.moveTo(left, top);
|
||||
let height = pipWin.innerHeight / 2;
|
||||
let width = pipWin.innerWidth / 2;
|
||||
pipWin.resizeTo(width, height);
|
||||
|
||||
// CLose first PiP window and open another
|
||||
await ensureMessageAndClosePiP(browser, "with-controls", pipWin, true);
|
||||
pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
// PiP is opened at 0, 0 with size 1/4 default width and 1/4 default height
|
||||
checkIfEqual(pipWin.screenX, left, "Opened at last X location");
|
||||
checkIfEqual(pipWin.screenY, top, "Opened at last Y location");
|
||||
checkIfEqual(
|
||||
pipWin.innerHeight,
|
||||
height,
|
||||
"Opened with 1/2 default height"
|
||||
);
|
||||
checkIfEqual(pipWin.innerWidth, width, "Opened with 1/2 default width");
|
||||
|
||||
// Mac and Linux did not allow moving to coordinates offscreen so this
|
||||
// test is skipped on those platforms
|
||||
if (AppConstants.platform == "win") {
|
||||
// Move to -1111, -1111 and adjust size to 1/4 width and 1/4 height
|
||||
left = -11111;
|
||||
top = -11111;
|
||||
pipWin.moveTo(left, top);
|
||||
pipWin.resizeTo(pipWin.innerWidth / 4, pipWin.innerHeight / 4);
|
||||
|
||||
await ensureMessageAndClosePiP(browser, "with-controls", pipWin, true);
|
||||
pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
// because the coordinates are off screen, the default size and location will be used
|
||||
checkIfEqual(
|
||||
pipWin.screenX,
|
||||
rightEdge - defaultPiPWidth,
|
||||
"Opened at default X location"
|
||||
);
|
||||
checkIfEqual(
|
||||
pipWin.screenY,
|
||||
bottomEdge - defaultPiPHeight,
|
||||
"Opened at default Y location"
|
||||
);
|
||||
checkIfEqual(
|
||||
pipWin.innerWidth,
|
||||
defaultPiPWidth,
|
||||
"Opened at default PiP width"
|
||||
);
|
||||
checkIfEqual(
|
||||
pipWin.innerHeight,
|
||||
defaultPiPHeight,
|
||||
"Opened at default PiP height"
|
||||
);
|
||||
}
|
||||
|
||||
// Linux doesn't handle switching the video source well and it will
|
||||
// cause the tests to failed in unexpected ways. Possibly caused by
|
||||
// bug 1594223 https://bugzilla.mozilla.org/show_bug.cgi?id=1594223
|
||||
if (AppConstants.platform != "linux") {
|
||||
// Save width and height for when aspect ratio is changed
|
||||
height = pipWin.innerHeight;
|
||||
width = pipWin.innerWidth;
|
||||
|
||||
left = 200;
|
||||
top = 100;
|
||||
pipWin.moveTo(left, top);
|
||||
|
||||
// Now switch the video so the video ratio is different
|
||||
await switchVideoSource("test-video-cropped.mp4");
|
||||
await ensureMessageAndClosePiP(browser, "with-controls", pipWin, true);
|
||||
pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
checkIfEqual(pipWin.screenX, left, "Opened at last X location");
|
||||
checkIfEqual(pipWin.screenY, top, "Opened at last Y location");
|
||||
checkIfEqual(
|
||||
pipWin.innerHeight,
|
||||
height,
|
||||
"Opened height with previous width"
|
||||
);
|
||||
checkIfEqual(
|
||||
pipWin.innerWidth,
|
||||
height * (pipWin.innerWidth / pipWin.innerHeight),
|
||||
"Width is changed to adjust for aspect ration"
|
||||
);
|
||||
|
||||
left = 300;
|
||||
top = 300;
|
||||
pipWin.moveTo(left, top);
|
||||
pipWin.resizeTo(defaultPiPWidth / 2, defaultPiPHeight / 2);
|
||||
|
||||
// Save height for when aspect ratio is changed
|
||||
height = pipWin.innerHeight;
|
||||
|
||||
// Now switch the video so the video ratio is different
|
||||
await switchVideoSource("test-video.mp4");
|
||||
await ensureMessageAndClosePiP(browser, "with-controls", pipWin, true);
|
||||
pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
checkIfEqual(pipWin.screenX, left, "Opened at last X location");
|
||||
checkIfEqual(pipWin.screenY, top, "Opened at last Y location");
|
||||
checkIfEqual(pipWin.innerHeight, height, "Opened with previous height");
|
||||
checkIfEqual(
|
||||
pipWin.innerWidth,
|
||||
height * (pipWin.innerWidth / pipWin.innerHeight),
|
||||
"Width is changed to adjust for aspect ration"
|
||||
);
|
||||
}
|
||||
|
||||
// Move so that part of PiP is off screen (bottom right)
|
||||
|
||||
left = rightEdge - Math.round((3 * pipWin.innerWidth) / 4);
|
||||
top = bottomEdge - Math.round((3 * pipWin.innerHeight) / 4);
|
||||
|
||||
let movePromise = BrowserTestUtils.waitForEvent(
|
||||
pipWin.windowRoot,
|
||||
"MozUpdateWindowPos"
|
||||
);
|
||||
pipWin.moveTo(left, top);
|
||||
await movePromise;
|
||||
|
||||
await ensureMessageAndClosePiP(browser, "with-controls", pipWin, true);
|
||||
pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
// Redefine top and left to where the PiP windop will open
|
||||
left = rightEdge - pipWin.innerWidth;
|
||||
top = bottomEdge - pipWin.innerHeight;
|
||||
|
||||
// await new Promise(r => setTimeout(r, 5000));
|
||||
// PiP is opened bottom right but not off screen
|
||||
checkIfEqual(
|
||||
pipWin.screenX,
|
||||
left,
|
||||
"Opened at last X location but shifted back on screen"
|
||||
);
|
||||
if (AppConstants.platform == "linux") {
|
||||
checkIfEqual(
|
||||
pipWin.screenY,
|
||||
top - tabHeight,
|
||||
"Opened at last Y location but shifted back on screen"
|
||||
);
|
||||
} else {
|
||||
checkIfEqual(
|
||||
pipWin.screenY,
|
||||
top,
|
||||
"Opened at last Y location but shifted back on screen"
|
||||
);
|
||||
}
|
||||
|
||||
// Move so that part of PiP is off screen (top left)
|
||||
left = defaultX - Math.round(pipWin.innerWidth / 4);
|
||||
top = defaultY - Math.round(pipWin.innerHeight / 4);
|
||||
|
||||
movePromise = BrowserTestUtils.waitForEvent(
|
||||
pipWin.windowRoot,
|
||||
"MozUpdateWindowPos"
|
||||
);
|
||||
pipWin.moveTo(left, top);
|
||||
await movePromise;
|
||||
|
||||
await ensureMessageAndClosePiP(browser, "with-controls", pipWin, true);
|
||||
pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
// PiP is opened top left on screen
|
||||
checkIfEqual(
|
||||
pipWin.screenX,
|
||||
defaultX,
|
||||
"Opened at last X location but shifted back on screen"
|
||||
);
|
||||
checkIfEqual(
|
||||
pipWin.screenY,
|
||||
defaultY,
|
||||
"Opened at last Y location but shifted back on screen"
|
||||
);
|
||||
|
||||
if (AppConstants.platform != "linux") {
|
||||
// test that if video is on right edge and new video with smaller width
|
||||
// is opened next, it is still on the right edge
|
||||
left = rightEdge - pipWin.innerWidth;
|
||||
top = Math.round(bottomEdge / 4);
|
||||
|
||||
pipWin.moveTo(left, top);
|
||||
|
||||
// Used to ensure that video width decreases for next PiP window
|
||||
width = pipWin.innerWidth;
|
||||
checkIfEqual(
|
||||
pipWin.innerWidth + pipWin.screenX,
|
||||
rightEdge,
|
||||
"Video is on right edge before video is changed"
|
||||
);
|
||||
|
||||
// Now switch the video so the video width is smaller
|
||||
await switchVideoSource("test-video-cropped.mp4");
|
||||
await ensureMessageAndClosePiP(browser, "with-controls", pipWin, true);
|
||||
pipWin = await triggerPictureInPicture(browser, "with-controls");
|
||||
ok(pipWin, "Got Picture-in-Picture window.");
|
||||
|
||||
checkIfEqual(
|
||||
pipWin.innerWidth < width,
|
||||
true,
|
||||
"New video width is smaller"
|
||||
);
|
||||
checkIfEqual(
|
||||
pipWin.innerWidth + pipWin.screenX,
|
||||
rightEdge,
|
||||
"Video is on right edge after video is changed"
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
Загрузка…
Ссылка в новой задаче