diff --git a/browser/base/content/pictureInPicture.css b/browser/base/content/pictureInPicture.css index 6403392694..ca99293f6c 100644 --- a/browser/base/content/pictureInPicture.css +++ b/browser/base/content/pictureInPicture.css @@ -11,14 +11,53 @@ browser[remote="true"] { min-height: 170px; background: black; color: white; + overflow: hidden; +} + +#player-stack { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: hidden; + -moz-user-select: none; +} + +#player-container, +#player-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + min-width: 0; + min-height: 0; } #player-container { background: black; } +#player-container > browser { + display: -moz-box; + width: 100%; + height: 100%; + min-width: 0; + min-height: 0; + border: 0; +} + #player-overlay { - -moz-window-dragging: drag; + display: flex; + flex-direction: column; + -moz-window-dragging: no-drag; +} + +#drag-area { + flex: 1; + min-height: 0; + cursor: move; } .pip-controls { @@ -29,22 +68,33 @@ browser[remote="true"] { #player-overlay:hover .pip-controls, #player-overlay[keyboard] .pip-controls, -#player-overlay[seeking] .pip-controls { +#player-overlay[seeking] .pip-controls, +#player-stack[dragging] .pip-controls { opacity: 1; pointer-events: auto; } #top-controls { + display: flex; + flex-shrink: 0; + justify-content: flex-end; padding: 8px; background: linear-gradient(rgba(0, 0, 0, .55), transparent); } #playback-controls { + flex-shrink: 0; padding: 12px 10px 8px; background: linear-gradient(transparent, rgba(0, 0, 0, .85)); -moz-window-dragging: no-drag; } +#button-row { + display: flex; + align-items: center; + min-width: 0; +} + .pip-controls button { -moz-appearance: none; -moz-window-dragging: no-drag; @@ -72,6 +122,7 @@ browser[remote="true"] { } #seek { + box-sizing: border-box; display: block; width: 100%; margin: 0 0 6px; @@ -85,20 +136,56 @@ browser[remote="true"] { } #time { + flex: 1; + min-width: 0; margin: 0 6px; font-variant-numeric: tabular-nums; } -#resize { - justify-self: end; - align-self: end; - width: 14px; - height: 14px; - cursor: se-resize; +.resize-edge, +.resize-corner { + position: absolute; + z-index: 2; -moz-window-dragging: no-drag; - opacity: 0; } -#resize:hover { - opacity: 1; +.resize-edge[data-resize="n"], +.resize-edge[data-resize="s"] { + left: 14px; + right: 14px; + height: 6px; + cursor: ns-resize; +} + +.resize-edge[data-resize="e"], +.resize-edge[data-resize="w"] { + top: 14px; + bottom: 14px; + width: 6px; + cursor: ew-resize; +} + +.resize-corner { + width: 14px; + height: 14px; +} + +[data-resize*="n"] { top: 0; } +[data-resize*="s"] { bottom: 0; } +[data-resize*="e"] { right: 0; } +[data-resize*="w"] { left: 0; } +[data-resize="nw"], [data-resize="se"] { cursor: nwse-resize; } +[data-resize="ne"], [data-resize="sw"] { cursor: nesw-resize; } + +@media (min-width: 700px) { + #playback-controls { + padding: 20px 20px 14px; + } + .pip-controls button { + padding: 8px 12px; + font-size: 14px; + } + #time { + font-size: 14px; + } } diff --git a/browser/base/content/pictureInPicture.js b/browser/base/content/pictureInPicture.js index 7f3df38927..aaaf3d0114 100644 --- a/browser/base/content/pictureInPicture.js +++ b/browser/base/content/pictureInPicture.js @@ -13,6 +13,71 @@ var Player = { sourceTab: null, seeking: false, state: null, + drag: null, + + startDrag(event) { + if (event.button != 0 || + event.target.closest("button, input, #playback-controls")) { + return; + } + let stack = document.getElementById("player-stack"); + if (!stack.contains(event.target)) { + return; + } + event.preventDefault(); + this.drag = { + direction: event.target.getAttribute("data-resize") || "", + pointerX: event.screenX, + pointerY: event.screenY, + x: window.screenX, + y: window.screenY, + width: window.outerWidth, + height: window.outerHeight, + }; + // Capture keeps the gesture working after the pointer leaves the window. + stack.setCapture(true); + stack.setAttribute("dragging", "true"); + }, + + moveDrag(event) { + let drag = this.drag; + if (!drag) { + return; + } + if (!(event.buttons & 1)) { + this.endDrag(); + return; + } + event.preventDefault(); + let dx = event.screenX - drag.pointerX; + let dy = event.screenY - drag.pointerY; + if (!drag.direction) { + window.moveTo(drag.x + dx, drag.y + dy); + return; + } + let west = drag.direction.includes("w"); + let east = drag.direction.includes("e"); + let north = drag.direction.includes("n"); + let south = drag.direction.includes("s"); + let width = Math.max(300, drag.width + (west ? -dx : east ? dx : 0)); + let height = Math.max(170, drag.height + (north ? -dy : south ? dy : 0)); + window.resizeTo(width, height); + // Anchor the opposite edge, using the actual size in case the platform + // imposed a constraint (for example, at a monitor boundary). + if (west || north) { + window.moveTo(west ? drag.x + drag.width - window.outerWidth : drag.x, + north ? drag.y + drag.height - window.outerHeight : drag.y); + } + }, + + endDrag() { + if (this.drag) { + this.drag = null; + let stack = document.getElementById("player-stack"); + stack.releaseCapture(); + stack.removeAttribute("dragging"); + } + }, init() { if (this.browser) { @@ -129,6 +194,7 @@ var Player = { }, destroy() { + this.endDrag(); if (this.sourceTab) { this.sourceTab.removeEventListener("TabClose", this.close); this.source.removeEventListener("oop-browser-crashed", this.close); @@ -171,6 +237,14 @@ window.addEventListener("keydown", event => { } } }); -window.addEventListener("mousemove", () => { +window.addEventListener("mousedown", event => Player.startDrag(event)); +window.addEventListener("mousemove", event => { + Player.moveDrag(event); document.getElementById("player-overlay").removeAttribute("keyboard"); }); +window.addEventListener("mouseup", () => Player.endDrag()); +window.addEventListener("blur", event => { + if (event.target == window) { + Player.endDrag(); + } +}); diff --git a/browser/base/content/pictureInPicture.xul b/browser/base/content/pictureInPicture.xul index 9c37362607..cca7a7050a 100644 --- a/browser/base/content/pictureInPicture.xul +++ b/browser/base/content/pictureInPicture.xul @@ -12,28 +12,35 @@ hidechrome="true" persist="screenX screenY width height">