From 0d4c6d6c76280ae8ffd43e9645a9c9298914a791 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Tue, 7 Feb 2017 18:11:49 -0500 Subject: [PATCH] Add img.decode() API for "predecoding" images Closes #2037. --- source | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/source b/source index 109c66dba59..3405c20b851 100644 --- a/source +++ b/source @@ -14850,7 +14850,7 @@ c-end = "-->" If the style sheet referenced no other resources (e.g. it was an internal style sheet given by a style element with no @import rules), then the style rules must be immediately made available to script; otherwise, the style rules must only be made available - to script once the event loop reaches its update the rendering step.

+ to script once the event loop reaches its update the rendering step.

A style sheet in the context of the Document of an HTML parser or XML parser is said to be a style sheet that is blocking scripts if the @@ -25151,6 +25151,8 @@ interface HTMLImageElement : HTMLElement { readonly attribute boolean complete; readonly attribute USVString currentSrc; [CEReactions] attribute DOMString referrerPolicy; + + Promise<void> decode(); }; @@ -25448,6 +25450,20 @@ interface HTMLImageElement : HTMLElement { +

image . decode()
+ +
+ +

Causes the user agent to decode the image, returning a promise that fulfills when decoding is + complete. The decoded image data will then be readily available for at least one frame after the + fulfillment, ensuring that attempting to display the image will complete quickly, without any + decoding delay.

+ +

The promise will be rejected with a "EncodingError" + DOMException if the image cannot be decoded.

+ +
+
image = new Image( [ width [, height ] ] )
@@ -25516,6 +25532,111 @@ interface HTMLImageElement : HTMLElement {

The currentSrc IDL attribute must return the img element's current request's current URL.

+

The decode() method, when invoked, must perform + the following steps:

+ +
    + + +
  1. If this img element's current request's state is broken, return a promise + rejected with an "EncodingError" DOMException.

  2. + +
  3. Let promise be a new promise.

  4. + +
  5. +

    In parallel, wait for one of the following cases to occur, and perform the + listed steps in reaction:

    + +
    +
    This img element's current request changes
    +
    This img element's current request's state becomes broken
    + +
    +
      +
    1. Reject promise with an "EncodingError" + DOMException.

    2. +
    +
    + +
    This img element becomes completely + available
    + +
    +
      +
    1. +

      Decode the image's media data entirely into its bitmap form, suitable for rapid + painting to the screen. If this cannot be done (e.g. due to invalid image data), reject + promise with an "EncodingError" + DOMException and abort these substeps.

      + +

      User agents should ensure that the decoded media data stays readily available until at + least the end of the next update the rendering step in the + event loop. This is an important part of the API contract, and should not be + broken if at all possible. (Typically, this would only be violated in low-memory situations + that require evicting decoded image data, or when the image is too large to keep in decoded + form for this period of time.)

      +
    2. + +
    3. Resolve promise with undefined.

    4. +
    +
    +
    +
  6. + +
  7. Return promise.

  8. +
+ + + +
+

Without the decode() method, the process of loading an + img element and then displaying it might look like the following:

+ +
const img = new Image();
+img.src = "nebula.jpg";
+img.onload = () => {
+    document.body.appendChild(img);
+};
+img.onerror = () => {
+ document.body.appendChild(new Text("Could not load the nebula :("));
+};
+
+ +

However, this can cause notable dropped frames ("jank"), as inserting the image into the DOM + causes a synchronous decode on the main thread.

+ +

This can instead be rewritten using the decode() method:

+ +
const img = new Image();
+img.src = "nebula.jpg";
+img.decode().then(() => {
+    document.body.appendChild(img);
+}).catch(() => {
+    document.body.appendChild(new Text("Could not load the nebula :("));
+});
+ +

This latter form avoids the jank of the original, by allowing the user agent to decode the + image in parallel, and only inserting it into the DOM once the decoding process is + complete.

+
+ +
+

Because the decode() method attempts to ensure that the + decoded image data is available for at least one frame, it can be combined with the requestAnimationFrame() API to get that API's + usual benefits around batching together different rendering tasks:

+ +
const img = new Image();
+img.src = "supernova.jpg";
+img.decode().then(() => {
+    requstAnimationFrame(() => document.body.appendChild(img));
+});
+
+ +
+

A constructor is provided for creating HTMLImageElement objects (in addition to the factory methods from DOM such as createElement()):

  • Inform the user that the focus is at the location given by the intended path. User agents may wait until the next time the event loop reaches its - update the rendering step to optionally inform the user.

  • + update the rendering step to optionally inform the user.

    @@ -63935,7 +64056,7 @@ v6DVT (also check for '- -' bits in the part above) -->
  • Optionally, inform the user that the caret or selection (or both) cover the specified rectangle of the canvas. The user agent may wait until the next - time the event loop reaches its update the rendering step to + time the event loop reaches its update the rendering step to optionally inform the user.

  • @@ -88912,7 +89033,7 @@ dictionary PromiseRejectionEventInit : EventInit {
  • -

    Update the rendering: If this event loop is a browsing +

    Update the rendering: If this event loop is a browsing context event loop (as opposed to a worker event loop), then run the following substeps.

    @@ -120600,6 +120721,7 @@ INSERT INTERFACES HERE Silver Ghost, Silvia Pfeiffer, Šime Vidas, + Simon Fraser, Simon Montagu, Simon Sapin, Simon Spiegel, @@ -120674,6 +120796,7 @@ INSERT INTERFACES HERE Victor Costan, Vipul Snehadeep Chawathe, Vitya Muhachev, + Vlad Levin, Vladimir Katardjiev, Vladimir Vukićević, Vyacheslav Aristov,