This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 24711 - <img>: Refactor the image loading model
Summary: <img>: Refactor the image loading model
Status: RESOLVED FIXED
Alias: None
Product: WHATWG
Classification: Unclassified
Component: HTML (show other bugs)
Version: unspecified
Hardware: Other other
: P2 normal
Target Milestone: Unsorted
Assignee: Simon Pieters
QA Contact: contributor
URL: http://www.whatwg.org/specs/web-apps/...
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-02-18 12:36 UTC by contributor
Modified: 2014-06-16 18:41 UTC (History)
6 users (show)

See Also:


Attachments

Description contributor 2014-02-18 12:36:21 UTC
Specification: http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html
Multipage: http://www.whatwg.org/C#update-the-image-data
Complete: http://www.whatwg.org/c#update-the-image-data
Referrer: http://www.whatwg.org/specs/web-apps/current-work/multipage/

Comment:
Should probably only abort the fetch if the selected source is different from
the last selected source. (step 2)

Posted from: 90.230.218.37 by simonp@opera.com
User agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_5_8) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.90 Safari/537.1
Comment 1 Ian 'Hixie' Hickson 2014-02-24 23:13:39 UTC
This test says Safari/Chrome do what the spec says:
   http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=2840
...whereas Firefox does what you suggest.
Comment 2 Ian 'Hixie' Hickson 2014-02-24 23:22:31 UTC
Nevermind, that test is busted.

This shows that Safari/Chrome do what you suggest, but Firefox does what the spec says: http://software.hixie.ch/utilities/js/live-dom-viewer/saved/2845
Comment 3 Simon Pieters 2014-02-26 07:17:40 UTC
OK, good that there is impl precedent. :-)
Comment 4 Ian 'Hixie' Hickson 2014-02-26 15:39:37 UTC
Any Firefox people want to make a case for leaving the spec as is rather than changing to the arguably better behaviour of not aborting the load in the redundant case? (Note that this doesn't affect srcset changes based on environment changes, since those loads use a different algorithm.)
Comment 5 Boris Zbarsky 2014-02-26 15:53:23 UTC
> This shows that Safari/Chrome do what you suggest, but Firefox does what the
> spec says: http://software.hixie.ch/utilities/js/live-dom-viewer/saved/2845

How does this testcase show anything about the behavior?

The main hard web compat constraint here I'm aware of is that given a loaded image, setting its src to the same value should check whether it's expired (HTTP caching semantics) and if so reload the image.  Gecko implements this by just always forcing a load on src set; if there is an existing load (whether done or not), it's dropped to make way for the new one.
Comment 6 Ian 'Hixie' Hickson 2014-02-28 00:16:13 UTC
slow-second-dim.cgi is a script that takes 3 seconds and returns an image whose width equals the current time's seconds component. I should probably have mentioned that. :-)

This bug is just about whether to drop the existing load and trigger a new one, or defer to an already-in-flight load if there is one. I don't think it affects the compat need mentioned in comment 5, since either way we are doing a load.
Comment 7 Boris Zbarsky 2014-02-28 05:04:33 UTC
So what matters for the testcase is whether the two logged widths are identical?

> or defer to an already-in-flight load if there is one.

This involves some fun defining of what makes for an in-flight load.  If the load has the image metadata but but not all the image data, is it in-flight?  If it's an animated gif and it has the first frame but not the other frames yet, is it in-flight?  If the bits are off the wire and in the image library but the DOM doesn't know anything about that yet, is the image in-flight?

I'm probably OK trying to change Gecko's behavior here assuming there's a clear spec and a good reason to make the change, but it would be pretty low priority, I suspect.
Comment 8 Ian 'Hixie' Hickson 2014-02-28 22:00:01 UTC
bz: Well from a spec perspective I would just define it as an ongoing instance of the "fetch" algorithm. In practice the edge cases are a race condition that I don't think your could black-box text anyway, so it probably doesn't need to be super-precise.

zcorpan: Your call. Do you still want to make this change given bz's comments? The spec's current state (what Firefox does) has fewer potential races...
Comment 9 Boris Zbarsky 2014-02-28 22:05:46 UTC
You can black-box test things like "size available, data is not" to some extent, if you control the server...  Especially given animated gifs.  We've run into problems with that sort of timing issue for images in the past.  :(
Comment 10 Ian 'Hixie' Hickson 2014-02-28 23:49:23 UTC
Those would both fall under "an ongoing instance of the "fetch" algorithm".
Comment 11 Boris Zbarsky 2014-03-01 03:06:24 UTC
Yes, but is that compatible?

As in, if you do img.src = img.src on an image in that state, you're saying it should be a no-op.  Is that what UAs currently do in that situation and what sites expect?
Comment 12 Ian 'Hixie' Hickson 2014-03-03 19:44:36 UTC
I dunno about what sites expect. From what I can tell, it's not what Gecko does, it is what Safari/Chrome do; see the test in comment 2.
Comment 13 Boris Zbarsky 2014-03-03 20:21:05 UTC
The test in comment 2 is not testing a partially-downloaded animated gif.
Comment 14 Boris Zbarsky 2014-03-03 20:23:03 UTC
To make my concern clearer:  I'm willing to consider switching to another widely-implemented behavior.  I'm less willing to consider switching to a simplified version of another widely-implemented behavior; we've been bitten far too often recently by doing that and discovering that the differences in various edge cases meant the simplified version is not web-compatible.

A clear description from some WebKit/Blink folks about what their exact behavior is would be a good start in evaluating how happy I am with it...
Comment 15 Ian 'Hixie' Hickson 2014-03-04 23:56:58 UTC
Can you elaborate on your animated GIF concern? I guess I didn't understand what you meant by "that state" in comment 11.
Comment 16 Boris Zbarsky 2014-03-05 02:40:22 UTC
Say I have an animated gif.  The UA has some frames and has started showing them, but the rest of the data is coming in from the network so the fetch is still in progress.  Now the page does img.src = img.src on that gif.  What should happen?  Is a new network load started?  Does the animation get reset to the beginning?
Comment 17 Ian 'Hixie' Hickson 2014-03-05 23:14:24 UTC
Crazy. With animated GIFs, I get the opposite result.

   http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=2869

I'm very confused now.
Comment 18 Boris Zbarsky 2014-03-06 03:27:13 UTC
Is that test testing network requests, or just whether the animation is restarted?
Comment 19 Ian 'Hixie' Hickson 2014-03-06 19:35:44 UTC
Both, though detecting a new request is a bit subtle (as far as I can tell, if it's a new request, you'll get a bigger pause between "0" and "2" than if the UA already has the data).

In the results below, a comma indicates a one-second-or-so pause, Z indicates that the log just had "zapped" added to it.

Chrome and Safari restart the animation, but don't start a new load.
That is, they render:
 (blank space),,0,,12,3,4,5Z,0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F.,0,1,2....

Firefox doesn't restart the animation until the load is over, and then it does. It doesn't actually trigger a new network request (according to the Web console, anyway. Not sure how reliably that is. But it matches the results — if there was a new request here, you'd expect a stutter between the second "0" and "2").
That is, it renders:
 (placeholder),,0,,2,3,4,5Z,6,7,8,9,A0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F.,0,1,2...

I guess the difference between this test and the earlier one is that here we have already started decoding by the time the URL changes? If that's what Firefox is relying on, it seems like a very race-prone design (more so even than just relying on the network connection being open — at least the author has some visibility into that on the client and server side via events, even if it's not precise).
Comment 20 Boris Zbarsky 2014-03-06 19:55:39 UTC
Oh, I see part of the confusion here.

So what Gecko does is it can have up to two "image requests" per image element: a "current" one and a "pending" one.  An "image request" includes both the fetch and the resulting data.

When we go to do the equivalent of "update the image data", we check whether the current request is in a state where we know the size of the image.  If it is, we make the new request a "pending request" and keep showing the old thing until the new request's size is available.  Then we drop the old "current request" and make the pending request be current.

The intent of the setup is that if you have an <img> whose src you set to different things every so often (like a slideshow, say), but the loads are slow you don't keep bouncing between "showing an image" and "broken image, with different layout".  That's why the size-available check is important: that's when your layout is likely to stay stable.

I just tested Chrome, using a testcase like so:

<!DOCTYPE html>
<img height='10' src="http://software.hixie.ch/utilities/cgi/dynamic-images/second-dim.cgi">
<script>
  onload = function() {
    document.querySelector("img").src = "http://software.hixie.ch/utilities/cgi/dynamic-images/slow-second-dim.cgi";
  }
</script>

and they also seem to keep the current image showing while the new one loads, as far as I can tell.  I don't know how they decide when to do that or not.
Comment 21 Simon Pieters 2014-03-18 14:25:40 UTC
Comment 5 seems like a new spec bug. img.src = img.src is always a no-op per spec given the definition of "change" in http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#dom-trees

Comment 20 also seems like a new spec bug.
Comment 22 Ian 'Hixie' Hickson 2014-03-18 17:51:22 UTC
comment 5 is bug 24958.

comment 20 seems like a core part of this bug, or at least a prereq. Sounds like I'll have to move the <img> section to that model before we can really figure out what to do for comment 0.
Comment 23 Simon Pieters 2014-03-19 14:44:52 UTC
Yeah.
Comment 24 Simon Pieters 2014-05-19 08:36:06 UTC
(In reply to Boris Zbarsky from comment #5)
> The main hard web compat constraint here I'm aware of is that given a loaded
> image, setting its src to the same value should check whether it's expired
> (HTTP caching semantics) and if so reload the image.  Gecko implements this
> by just always forcing a load on src set; if there is an existing load
> (whether done or not), it's dropped to make way for the new one.

I can't get Firefox 26 to reload the image when setting src to the same value. Is the compat constraint just restarting the animation? As far as I can tell animations are restarted even if it's not expired.
Comment 25 Boris Zbarsky 2014-05-19 15:55:09 UTC
> I can't get Firefox 26 to reload the image when setting src to the same value.

How are you determining that?  Note that the "reload" will still follow HTTP cache semantics...

> Is the compat constraint just restarting the animation?

I don't believe so, given https://bugzilla.mozilla.org/show_bug.cgi?id=980243
Comment 26 Simon Pieters 2014-05-20 02:31:37 UTC
(In reply to Boris Zbarsky from comment #25)
> > I can't get Firefox 26 to reload the image when setting src to the same value.
> 
> How are you determining that?  Note that the "reload" will still follow HTTP
> cache semantics...

https://github.com/zcorpan/web-platform-tests/blob/img-bug-24711/html/semantics/embedded-content/the-img-element/update-the-image-data/set-src-idl-same-value-loaded-not-cacheable.html
https://github.com/zcorpan/web-platform-tests/blob/img-bug-24711/html/semantics/embedded-content/the-img-element/update-the-image-data/resources/common.js
https://github.com/zcorpan/web-platform-tests/blob/img-bug-24711/html/semantics/embedded-content/the-img-element/update-the-image-data/resources/stash-count-requests.py

Review for the tests at https://critic.hoppipolla.co.uk/r/1593

So what the test is doing is that it loads an image with the headers:

Cache-Control: no-store, no-cache, must-revalidate
Expires: Tue, 19 Nov 1985 21:00:00 GMT

Then, in img.onload, it does img.src = url_put; (which is the same value).

The test counts the number of requests on the server side and I only see 1 request in Firefox 26 for this test.

> I don't believe so, given https://bugzilla.mozilla.org/show_bug.cgi?id=980243

OK, thanks.

(I also found https://bugzilla.mozilla.org/show_bug.cgi?id=183470 which seems related.)
Comment 27 Boris Zbarsky 2014-05-20 03:36:27 UTC
> So what the test is doing is that it loads an image with the headers:

Is there a live version of the test somewhere I could take a look at?
Comment 28 Simon Pieters 2014-05-20 05:39:35 UTC
http://w3c-test.org/submissions/996/html/semantics/embedded-content/the-img-element/update-the-image-data/set-src-idl-same-value-loaded-not-cacheable.html

(When the PR gets merged in the future, remove "submissions/996/" from the URL.)
Comment 29 Boris Zbarsky 2014-05-21 06:25:26 UTC
Hmm.  Looks like there's some deal in Gecko now that basically assumes non-HTTP semantics are OK as long as the document is the same...  So maybe resetting animations (and perhaps firing load events; unclear) is all that's needed for compat.
Comment 30 Boris Zbarsky 2014-05-21 06:26:18 UTC
And thank you for the link, by the way!
Comment 31 Simon Pieters 2014-06-16 10:45:45 UTC
Specify how parallel image fetching works.
https://github.com/ResponsiveImagesCG/picture-element/commit/22efd4478d7714ac12fd128ca2c455d0f91f42a4

(Leaving open for comment 0.)
Comment 32 Simon Pieters 2014-06-16 18:41:44 UTC
Reuse ongoing fetches in 'update the image data'.
https://github.com/ResponsiveImagesCG/picture-element/commit/a67d019f75f95ec3552adc36376522059c582ccc