Document Picture-in-Picture Specification

Draft Community Group Report,

This version:
https://wicg.github.io/document-picture-in-picture/
Issue Tracking:
GitHub
Inline In Spec
Editor:
(Google Inc.)

Abstract

This specification enables web developers to populate an HTMLDocument in an always-on-top window.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

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:

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 width = 0;
  [EnforceRange] unsigned long long height = 0;
  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;
};
A 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.

The documentPictureInPicture getter steps are:
  1. 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.

The window getter steps are:
  1. Let win be this’s last-opened window.

  2. If win is not null and win’s closed attribute is false, return win.

  3. Return null.

The requestWindow(options) method steps are:
  1. If Document Picture-in-Picture support is false, throw a "NotSupportedError" DOMException.

  2. If this’s relevant global object’s navigable is not a top-level traversable, throw a "NotAllowedError" DOMException.

  3. If this’s relevant global object’s navigable’s Is Document Picture-in-Picture boolean is true, throw a "NotAllowedError" DOMException.

  4. If this’s relevant global object does not have transient activation, throw a "NotAllowedError" DOMException.

  5. If options["width"] exists and is greater than zero, but options["height"] does not exist or is zero, throw a RangeError.

  6. If options["height"] exists and is greater than zero, but options["width"] does not exist or is zero, throw a RangeError.

  7. Consume user activation given this’s relevant global object.

  8. Let win be this’s last-opened window. If win is not null and win’s closed attribute is false, then close win’s navigable.

  9. Optionally, the user agent can close any existing picture-in-picture windows.

  10. 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.

  1. Set pip traversable’s active document’s mode to this’s relevant global object’s associated Document’s mode.

  2. Set pip traversable’s Is Document Picture-in-Picture boolean to true.

  3. If options["width"] exists and is greater than zero:

    1. Optionally, clamp or ignore options["width"] if it is too large or too small in order to fit a user-friendly window size.

    2. 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.

  4. If options["height"] exists and is greater than zero:

    1. Optionally, clamp or ignore options["height"] if it is too large or too small in order to fit a user-friendly window size.

    2. 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.

  1. If options["disallowReturnToOpener"] exists and is true, 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.

  1. Configure pip traversable’s active browsing context’s window to float on top of other windows.

  2. Set this’s last-opened window to pip traversable’s active window.

  3. Queue a global task on the DOM manipulation task source given this’s relevant global object to fire an event named enter using DocumentPictureInPictureEvent on this with its window attribute initialized to pip traversable’s active window.

  4. 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 DocumentPictureInPicture when 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:

  1. 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:

  1. For each top-level traversable of the user agent’s top-level traversable set:

    1. If top-level traversable’s Is Document Picture-in-Picture boolean is true, then close top-level traversable.

    2. 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.

    3. For each navigable of top-level traversable’s active document’s descendant navigables:

      1. 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:

  1. Let navigable be document’s node navigable.

  2. If navigable is not a top-level traversable, abort these steps.

  3. If navigable’s Is Document Picture-in-Picture boolean is true, then close navigable and abort these steps.

  4. Let win be navigable’s active window’s documentPictureInPicture API’s last-opened window.