1. Introduction
This section is non-normative.
There currently exists a Web API for putting an HTMLVideoElement into a
Picture-in-Picture window (requestPictureInPicture()). This limits
a website’s ability to provide a custom picture-in-picture experience (PiP). We
want to expand upon that functionality by providing the website with a full
Document on an always-on-top window.
This new window will be much like a blank same-origin window opened via the
existing open() method on Window, with some minor
differences:
-
The PiP window will float on top of other windows.
-
The PiP window will never outlive the opening window.
-
The website cannot set the position of the PiP window.
-
The PiP window cannot be navigated (any `window.history` or `window.location` calls that change to a new document will close the PiP window).
2. Dependencies
The IDL fragments in this specification must be interpreted as required for conforming IDL fragments, as described in the Web IDL specification. [WEBIDL]
3. Security Considerations
3.1. Secure Context
The API is limited to [SECURE-CONTEXTS].
3.2. Spoofing
It is required that the user agent provides enough UI on the
DocumentPictureInPicture window to prevent malicious websites from abusing
the ability to float on top of other windows to spoof other websites or system
UI.
3.2.1. Positioning
The user agent must prevent the website from setting the position of the window
in order to prevent the website from purposefully positioning the window in a
location that may trick a user into thinking it is part of another page’s UI. In
particular, this means the moveTo() and moveBy() APIs must
be disabled for document picture-in-picture windows.
3.2.2. Origin Visibility
It is required that the user agent makes it clear to the user which origin is
controlling the DocumentPictureInPicture window at all times to ensure that
the user is aware of where the content is coming from. For example, the user
agent may display the origin of the website in a titlebar on the window.
3.2.3. Maximum size
The user agent should restrict the maximum size of the document picture-in-picture window to prevent the website from covering the screen with an always-on-top window and locking the user in the picture-in-picture window. This also helps prevent spoofing the user’s desktop.
3.2.4. Fullscreen
The user agent must prevent the document picture-in-picture window from entering
fullscreen with the same reasoning as stated for the maximum size
restriction. In particular, this means the requestFullscreen() API must be
disabled for all elements in document picture-in-picture windows.
3.3. IFrames
This API is only available on a top-level traversable. However, the
DocumentPictureInPicture Window itself may contain HTMLIFrameElements, even
cross-origin
HTMLIFrameElements.
4. Privacy Considerations
4.1. Fingerprinting
When a PiP window is closed and then later re-opened, it can be useful for the user agent to re-use size and location of the previous PiP window to provide a smoother user experience. However, it is recommended that the user agent does not re-use size/location across different origins as this may provide malicious websites an avenue for fingerprinting a user.
5. API
[Exposed =Window ]partial interface Window { [SameObject ,SecureContext ]readonly attribute DocumentPictureInPicture documentPictureInPicture ; }; [Exposed =Window ,SecureContext ]interface :DocumentPictureInPicture EventTarget { [NewObject ]Promise <Window >requestWindow (optional DocumentPictureInPictureOptions = {});options readonly attribute Window window ;attribute EventHandler ; };onenter dictionary { [DocumentPictureInPictureOptions EnforceRange ]unsigned long long = 0; [width EnforceRange ]unsigned long long = 0;height boolean =disallowReturnToOpener false ;boolean =preferInitialWindowPlacement false ; }; [Exposed =Window ,SecureContext ]interface :DocumentPictureInPictureEvent Event {(constructor DOMString ,type DocumentPictureInPictureEventInit ); [eventInitDict SameObject ]readonly attribute Window ; };window dictionary :DocumentPictureInPictureEventInit EventInit {required Window ; };window
DocumentPictureInPicture object allows websites to create and open a new
always-on-top Window as well as listen for events related to opening and
closing that Window.
Each Window object has an associated documentPictureInPicture API,
which is a new DocumentPictureInPicture instance created alongside the Window.
documentPictureInPicture getter steps are:
-
Return this’s documentPictureInPicture API.
Each DocumentPictureInPicture object has an associated
last-opened window which is a
Window object that is initially null and is set as part of the
requestWindow() method steps.
window getter steps are:
-
Let win be this’s last-opened window.
-
If win is not
nulland win’s closed attribute isfalse, return win. -
Return
null.
requestWindow(options) method steps are:
-
If Document Picture-in-Picture support is
false, throw a "NotSupportedError"DOMException. -
If this’s relevant global object’s navigable is not a top-level traversable, throw a "
NotAllowedError"DOMException. -
If this’s relevant global object’s navigable’s Is Document Picture-in-Picture boolean is
true, throw a "NotAllowedError"DOMException. -
If this’s relevant global object does not have transient activation, throw a "
NotAllowedError"DOMException. -
If options["
width"] exists and is greater than zero, but options["height"] does not exist or is zero, throw aRangeError. -
If options["
height"] exists and is greater than zero, but options["width"] does not exist or is zero, throw aRangeError. -
Consume user activation given this’s relevant global object.
-
Let win be this’s last-opened window. If win is not
nulland win’s closed attribute isfalse, then close win’s navigable. -
Optionally, the user agent can close any existing picture-in-picture windows.
-
Set pip traversable to be the result of creating a new top-level traversable given this’s relevant global object’s navigable’s active browsing context and "
_blank".
The resulting Document’s URL will be `about:blank`, but its
document base URL will fall back to be that of the initiator that called
requestWindow(). Some browsers do not implement
this fallback behavior for normal `about:blank` popups; see
whatwg/html#421 for
discussion. Implementers are advised to make sure this inheritance happens as
specified for document picture-in-picture windows, to avoid further interop
problems.
-
Set pip traversable’s active document’s mode to this’s relevant global object’s associated Document’s mode.
-
Set pip traversable’s Is Document Picture-in-Picture boolean to
true. -
If options["
width"] exists and is greater than zero:-
Optionally, clamp or ignore options["
width"] if it is too large or too small in order to fit a user-friendly window size. -
Optionally, size pip traversable’s active browsing context’s window such that the distance between the left and right edges of the viewport are options["
width"] pixels.
-
-
If options["
height"] exists and is greater than zero:-
Optionally, clamp or ignore options["
height"] if it is too large or too small in order to fit a user-friendly window size. -
Optionally, size pip traversable’s active browsing context’s window such that the distance between the top and bottom edges of the viewport are options["
height"] pixels.
-
If options["preferInitialWindowPlacement"]
exists and is true, then the user agent may use this hint to prefer behavior
that is similar that is similar to steps 13 and 14, rather than considering any
previous position or size of any previously closed pip traversable window.
-
If options["
disallowReturnToOpener"] exists and istrue, the user agent should not display UI affordances on the picture-in-picture window that allow the user to return to the opener window.
For both video and document picture-in-picture, user agents often display a
button for the user to return to the original page and close the
picture-in-picture window. While this action makes sense in most cases
(especially for a video picture-in-picture window that returns the video to the
main document), it does not always make sense for document picture-in-picture
windows. disallowReturnToOpener is a hint to
the user agent from the website as to whether that action makes sense for their
particular document picture-in-picture experience.
-
Configure pip traversable’s active browsing context’s window to float on top of other windows.
-
Set this’s last-opened window to pip traversable’s active window.
-
Queue a global task on the DOM manipulation task source given this’s relevant global object to fire an event named
enterusingDocumentPictureInPictureEventon this with itswindowattribute initialized to pip traversable’s active window. -
Return a promise resolved with pip traversable’s active window.
While the size of the window can be configured by the website, the initial position is left to the discretion of the user agent.
enter-
Fired on
DocumentPictureInPicturewhen a PiP window is opened.
6. Concepts
6.1. Document Picture-in-Picture Support
Each user agent has a Document Picture-in-Picture Support boolean, whose value is implementation-defined (and might vary according to user preferences).
6.2. DocumentPictureInPicture Window
Each top-level traversable has an Is Document Picture-in-Picture
boolean, whose value defaults to false, but can be set to
true in the requestWindow() method steps.
User agents typically suspend rendering and throttle script execution in windows that are minimized or otherwise not visible to the user. When a document picture-in-picture window is open, the opener window might execute scripts that affect the content of the document picture-in-picture window.
Implementers are encouraged to consider the implications of throttling such opener windows, and developers are encouraged to execute application logic within the picture-in-picture window itself.
6.3. Closing a Document Picture-in-Picture window
Merge this into definitely close once it has enough consensus.
Modify step 2 of definitely close, "If the result of checking if unloading is user-canceled for toUnload is not "continue", then return." to be:
-
If traversable’s Is Document Picture-in-Picture boolean is true, then skip this step. Otherwise, if the result of checking if unloading is user-canceled for toUnload is not "continue", then return.
6.4. Close any existing PiP windows
To close any existing picture-in-picture windows:
-
For each top-level traversable of the user agent’s top-level traversable set:
-
If top-level traversable’s Is Document Picture-in-Picture boolean is
true, then close top-level traversable. -
If top-level traversable’s active document’s pictureInPictureElement is not
null, run the exit Picture-in-Picture algorithm with top-level traversable’s active document. -
For each navigable of top-level traversable’s active document’s descendant navigables:
-
If navigable’s active document’s pictureInPictureElement is not
null, run the exit Picture-in-Picture algorithm with navigable’s active document.
-
-
6.5. One PiP Window
Any top-level traversable must have at most one document
picture-in-picture window open at a time. If a top-level traversable
whose active window’s documentPictureInPicture API’s
last-opened window is not null tries to open another
document picture-in-picture window, the user agent must close the existing
last-opened window as described in the requestWindow() method
steps.
However, whether only one window is allowed in Picture-in-Picture mode across
all top-level traversables is left to the implementation and the platform.
As such, what happens when there is a Picture-in-Picture request while there is
a top-level traversable whose Is Document Picture-in-Picture
boolean is true or whose active document’s
pictureInPictureElement
is not null will be left as an implementation detail: the user
agent could close any existing picture-in-picture windows or multiple
Picture-in-Picture windows could be created.
6.6. Closing the PiP window when either the original or PiP document is destroyed
To close any associated Document Picture-in-Picture windows given a
Document document:
-
Let navigable be document’s node navigable.
-
If navigable is not a top-level traversable, abort these steps.
-
If navigable’s Is Document Picture-in-Picture boolean is
true, then close navigable and abort these steps. -
Let win be navigable’s active window’s documentPictureInPicture API’s last-opened window.