Skip to content

Commit

Permalink
Add img.decode() API for "predecoding" images
Browse files Browse the repository at this point in the history
Closes #2037.
  • Loading branch information
domenic committed Apr 18, 2017
1 parent e1c9c2a commit 0d4c6d6
Showing 1 changed file with 127 additions and 4 deletions.
131 changes: 127 additions & 4 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -14850,7 +14850,7 @@ c-end = "-->"</pre>
If the style sheet referenced no other resources (e.g. it was an internal style sheet given by a
<code>style</code> element with no <code data-x="">@import</code> rules), then the style rules must
be <span>immediately</span> made available to script; otherwise, the style rules must only be made available
to script once the <span>event loop</span> reaches its <i>update the rendering</i> step.</p>
to script once the <span>event loop</span> reaches its <span>update the rendering</span> step.</p>

<p>A style sheet in the context of the <code>Document</code> of an <span>HTML parser</span> or
<span>XML parser</span> is said to be <dfn>a style sheet that is blocking scripts</dfn> if the
Expand Down Expand Up @@ -25151,6 +25151,8 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> {
readonly attribute boolean <span data-x="dom-img-complete">complete</span>;
readonly attribute USVString <span data-x="dom-img-currentSrc">currentSrc</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-img-referrerPolicy">referrerPolicy</span>;

Promise&lt;void&gt; <span data-x="dom-img-decode">decode</span>();
};</pre>
</dd>
</dl><!--TOPIC:HTML-->
Expand Down Expand Up @@ -25448,6 +25450,20 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> {

</dd>

<dt><var>image</var> . <code data-x="dom-img-decode">decode</code>()</dt>

<dd>

<p>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.</p>

<p>The promise will be rejected with a <span>"<code>EncodingError</code>"</span>
<code>DOMException</code> if the image cannot be decoded.</p>

</dd>

<dt><var>image</var> = new <code data-x="dom-image">Image</code>( [ <var>width</var> [, <var>height</var> ] ] )</dt>

<dd>
Expand Down Expand Up @@ -25516,6 +25532,111 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> {
<p>The <dfn data-x="dom-img-currentSrc"><code>currentSrc</code></dfn> IDL attribute
must return the <code>img</code> element's <span>current request</span>'s <span data-x="img-req-url">current URL</span>.</p>

<p>The <dfn data-x="dom-img-decode"><code>decode</code></dfn>() method, when invoked, must perform
the following steps:</p>

<ol>
<!-- TODO pending request!?! -->

<li><p>If this <code>img</code> element's <span>current request</span>'s <span
data-x="img-req-state">state</span> is <span data-x="img-error">broken</span>, return a promise
rejected with an <span>"<code>EncodingError</code>"</span> <code>DOMException</code>.</p></li>

<li><p>Let <var>promise</var> be a new promise.</p></li>

<li>
<p><span>In parallel</span>, wait for one of the following cases to occur, and perform the
listed steps in reaction:</p>

<dl class="switch">
<dt>This <code>img</code> element's <span>current request</span> changes</dt>
<dt>This <code>img</code> element's <span>current request</span>'s <span
data-x="img-req-state">state</span> becomes <span data-x="img-error">broken</span></dt>

<dd>
<ol>
<li><p>Reject <var>promise</var> with an <span>"<code>EncodingError</code>"</span>
<code>DOMException</code>.</p></li>
</ol>
</dd>

<dt>This <code>img</code> element becomes <span data-x="img-all">completely
available</span></dt>

<dd>
<ol>
<li>
<p>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
<var>promise</var> with an <span>"<code>EncodingError</code>"</span>
<code>DOMException</code> and abort these substeps.</p>

<p>User agents should ensure that the decoded media data stays readily available until at
least the end of the next <span>update the rendering</span> step in the
<span>event loop</span>. 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.)</p>
</li>

<li><p>Resolve <var>promise</var> with undefined.</p></li>
</ol>
</dd>
</dl>
</li>

<li><p>Return <var>promise</var>.</p></li>
</ol>

</div>

<div class="example">
<p>Without the <code data-x="dom-img-decode">decode()</code> method, the process of loading an
<code>img</code> element and then displaying it might look like the following:</p>

<pre>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 :("));
};
</pre>

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

<p>This can instead be rewritten using the <code data-x="dom-img-decode">decode()</code> method:</p>

<pre>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 :("));
});</pre>

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

<div class="example">
<p>Because the <code data-x="dom-img-decode">decode()</code> method attempts to ensure that the
decoded image data is available for at least one frame, it can be combined with the <code
data-x="dom-window-requestAnimationFrame">requestAnimationFrame()</code> API to get that API's
usual benefits around batching together different rendering tasks:</p>

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

<div w-nodev>

<p>A constructor is provided for creating <code>HTMLImageElement</code> objects (in addition to
the factory methods from DOM such as <code
data-x="dom-Document-createElement">createElement()</code>): <dfn
Expand Down Expand Up @@ -63903,7 +64024,7 @@ v6DVT (also check for '- -' bits in the part above) -->

<li><p><a href="#inform">Inform the user</a> that the focus is at the location given by the
intended path. User agents may wait until the next time the <span>event loop</span> reaches its
<i>update the rendering</i> step to optionally inform the user.</p></li>
<span>update the rendering</span> step to optionally inform the user.</p></li>

</ol>

Expand Down Expand Up @@ -63935,7 +64056,7 @@ v6DVT (also check for '- -' bits in the part above) -->

<li><p>Optionally, <a href="#inform">inform the user</a> that the caret or selection (or both)
cover <var>the specified rectangle</var> of the canvas. The user agent may wait until the next
time the <span>event loop</span> reaches its <i>update the rendering</i> step to
time the <span>event loop</span> reaches its <span>update the rendering</span> step to
optionally inform the user.</p></li>

</ol>
Expand Down Expand Up @@ -88912,7 +89033,7 @@ dictionary <dfn>PromiseRejectionEventInit</dfn> : <span>EventInit</span> {

<li>

<p><i>Update the rendering</i>: If this <span>event loop</span> is a <span>browsing
<p><dfn>Update the rendering</dfn>: If this <span>event loop</span> is a <span>browsing
context</span> <span>event loop</span> (as opposed to a <a href="#workers">worker</a>
<span>event loop</span>), then run the following substeps.</p>

Expand Down Expand Up @@ -120600,6 +120721,7 @@ INSERT INTERFACES HERE
Silver Ghost, <!-- see bug 19614 -->
Silvia Pfeiffer,
&#x160;ime Vidas,
Simon Fraser,
Simon Montagu,
Simon Sapin,
Simon Spiegel,
Expand Down Expand Up @@ -120674,6 +120796,7 @@ INSERT INTERFACES HERE
Victor Costan,
Vipul Snehadeep Chawathe,
Vitya Muhachev,
Vlad Levin,
Vladimir Katardjiev,
Vladimir Vuki&#x0107;evi&#x0107;,
Vyacheslav Aristov,
Expand Down

0 comments on commit 0d4c6d6

Please sign in to comment.