Closed
Bug 1037643
Opened 10 years ago
Closed 10 years ago
<img srcset> and <picture> load ordering not in line with spec
Categories
(Core :: DOM: Core & HTML, defect)
Core
DOM: Core & HTML
Tracking
()
RESOLVED
FIXED
mozilla36
People
(Reporter: johns, Assigned: johns)
References
(Depends on 1 open bug, Blocks 1 open bug, )
Details
Attachments
(7 files, 6 obsolete files)
10.76 KB,
patch
|
bzbarsky
:
review+
|
Details | Diff | Splinter Review |
12.44 KB,
patch
|
bzbarsky
:
review+
|
Details | Diff | Splinter Review |
3.44 KB,
patch
|
johns
:
review+
|
Details | Diff | Splinter Review |
7.31 KB,
patch
|
johns
:
review+
|
Details | Diff | Splinter Review |
4.62 KB,
patch
|
johns
:
review+
|
Details | Diff | Splinter Review |
2.01 KB,
patch
|
johns
:
review+
|
Details | Diff | Splinter Review |
35.58 KB,
patch
|
johns
:
review+
|
Details | Diff | Splinter Review |
Currently the responsive modes of <img> take most actions synchronously, whereas some should queue a task.
We also don't track responsive state at all before BindToTree for this reason
Updated•10 years ago
|
Depends on: shadowcurrentdoc
Assignee | ||
Comment 1•10 years ago
|
||
Adds a call to explicitly force image image selection to happen, optionally blowing away cached selection
Attachment #8498610 -
Flags: review?(jst)
Assignee | ||
Comment 2•10 years ago
|
||
Pegging :bz for this, since he's probably most familiar with <img> spec things, but let me know if you think someone else should be on the hook.
This attempts to make us match the new "update the image data" algorithm for all "relevant mutations" in the spec, at least as they pertain to responsive mode -- srcset and <picture>. It doesn't give us full last/pending/next load symantics, which I'm going to work on in bug 1076583.
https://www.w3.org/Bugs/Public/show_bug.cgi?id=24711
https://html.spec.whatwg.org/multipage/embedded-content.html#update-the-image-data
https://html.spec.whatwg.org/multipage/embedded-content.html#relevant-mutations
This also leaves us doing the older synchronous behavior for basic img.src, only using the new algorithm when we have srcset or <picture> in most cases, since the new "update the image data" steps 3 through 5.3 still replace some of the synchronous behavior. Using both behaviors adds a minor edge case in that setting img.src followed by img.srcset via script on an empty <img> may trigger two loads where the spec would have us only do one, but otherwise mostly works for making picture/srcset behavior sane without significant change on basic img content. I opened Bug 1076583 for the remaining non-picture work.
This also rips out a good deal of logic landed with picture originally, since the old algorithm it was written against only updated the necessary state, whereas the new algorithm essentially re-runs all of the selection steps whenever any mutation event occurs. This is much simpler, and also much saner from the web author's point of view, in that mutating a <picture> will cause it to re-select its ideal image source, full stop.
We also can now move on to the next <source> if the current one doesn't parse correctly, so ideally we would keep ResponsiveImageSelectors around for all sources we're aware of to avoid re-parsing previous ones to see if they are now valid when mutations occur. I'm going to open a follow-up to do that, but let me know if you think it should land with this.
(These patches are rebased on the ones in bug 1076587, which are probably needed to apply cleanly)
Attachment #8498617 -
Flags: review?(bzbarsky)
Assignee | ||
Comment 3•10 years ago
|
||
Attachment #8498618 -
Flags: review?(bzbarsky)
Assignee | ||
Comment 4•10 years ago
|
||
Attachment #8498619 -
Flags: review?(bzbarsky)
Comment 5•10 years ago
|
||
Comment on attachment 8498610 [details] [diff] [review]
Part 1 - Add ResponsiveImageSelector::SelectImage
- In ResponsiveImageSelector.h
+ // Get the url and density for the selected best candidate. That
+ // these implicitly cause an image to be selected if necessary.
Fix the comment, i.e. remove 'That'.
r=jst
Attachment #8498610 -
Flags: review?(jst) → review+
Comment 6•10 years ago
|
||
Sorry for the lag here; I need to read through the spec bits a bit. :(
Assignee | ||
Comment 7•10 years ago
|
||
Split to part 3 to not complicate reviewing, but this could be folded into part 2 --
Working on mixed content blocking for <picture> i found a few cases where our behavior was confused because we were only checking if (mResponsiveSelector) without considering a image task might be queued. This just makes the interim behavior paths more explicit behind InResponsiveMode()
HaveSrcsetOrInPicture is split out because it is used in the mixed content blocking patches, which explicitly have "if the image has a srcset attribute or a parent element of <picture>" condition (Bug 1055750)
Attachment #8501357 -
Flags: review?(bzbarsky)
Assignee | ||
Updated•10 years ago
|
Blocks: srcset-mixed-content
Comment 8•10 years ago
|
||
Sorry for the lag here.... I'll try to get to this tomorrow; need to sort through the spec bits.
Comment 9•10 years ago
|
||
Comment on attachment 8498617 [details] [diff] [review]
Part 2 - Line up with new spec for <img srcset> and <picture> mutations
>+++ b/content/html/content/src/HTMLImageElement.cpp
> HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
>+ if (nsContentUtils::IsImageSrcSetDisabled()) {
>+ return NS_OK;
That can't be right. With this change, if I do:
var img = new Image();
img.setAttribute("foo", "bar");
alert(img.getAttribute("foo"));
I won't get "bar", will I? Please fix, and add a test that would have caught this.
> HTMLImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
Posting these events when tearing down a document seems a bit annoying. Could we skip doing the QueueImageLoadTask in that case? Followup might be ok here as long as it gets uplifted to whatever branches this lands on.
>+HTMLImageElement::QueueImageLoadTask()
>+ if (!LoadingEnabled() || !doc || !doc->IsActive()) {
I thought the documentation on nsIDocument::IsActive is pretty clear:
this does NOT match the "active document" concept in the WHATWG spec.
Though neither does what it suggests using; the closest thing is nsPIDOMWindow::HasActiveDocument, but with our document instead of mDoc.
We should add a better way of doing this test and use it here.
Also, no need to null-check "doc". It can't ever be null.
Please document that this is not used in the cases when we just have an src, so the fact that those cases need to pick a selected source synchronously is ok.
> HTMLImageElement::PictureSourceSrcsetChanged(nsIContent *aSourceNode,
>+ MOZ_ASSERT(isSelf || IsPreviousSibling(aSourceNode, AsContent()),
Why AsContent() instead of "this"?
Same for all the other places where AsContent() is used here.
>+ nsIContent *currentSrc = \
Why the backslash? Shouldn't be needed. This also happens several times.
>+HTMLImageElement::UpdateResponsiveSource()
>+ candidateSource = thisContent;
That's a confusing way to write:
candidateSource = this;
>+ MOZ_ASSERT(candidateSource,
>+ "Did not hit ourselves before reaching end of siblings?");
I don't think this assert (an some other asserts here) is necessarily valid when XBL is involved.... (e.g. consider when "this" is an anon subtree root in the binding, so our parent is the bound element).
>+++ b/content/html/content/src/HTMLPictureElement.cpp
>+ if (nextSibling->Tag() == nsGkAtoms::img) {
>+ HTMLImageElement *img = static_cast<HTMLImageElement*>
(nextSibling.get());
how about using NS_IMPL_FROMCONTENT_HTML_WITH_TAG in the header and then here:
if (HTMLImageElement* img = HTMLImageElement::FromContent(nextSibling)) {
....
r+, but please do fix the above issues.
Attachment #8498617 -
Flags: review?(bzbarsky) → review+
Comment 10•10 years ago
|
||
Comment on attachment 8498618 [details] [diff] [review]
img src/srcset mutation tests
r=me
Attachment #8498618 -
Flags: review?(bzbarsky) → review+
Comment 11•10 years ago
|
||
Comment on attachment 8498619 [details] [diff] [review]
<picture> mutation tests
A very skimmy r+.
Attachment #8498619 -
Flags: review?(bzbarsky) → review+
Comment 12•10 years ago
|
||
Comment on attachment 8501357 [details] [diff] [review]
Part 3 - Be more explicit about when we're falling back to synchronous behavior
r=me
Attachment #8501357 -
Flags: review?(bzbarsky) → review+
Assignee | ||
Comment 13•10 years ago
|
||
Addressed review comment, carrying over r=jst
Attachment #8498610 -
Attachment is obsolete: true
Attachment #8504373 -
Flags: review+
Assignee | ||
Comment 14•10 years ago
|
||
So it turns out not nulling out mResponsiveSelector in UnbindFromTree creates a cycle, and HTMLImageElement is CC'd (inherited) but not explicitly CC'd
Attachment #8504991 -
Flags: review?(continuation)
Comment 15•10 years ago
|
||
Comment on attachment 8504991 [details] [diff] [review]
Part 4 - Cycle collect HTMLImageElement/ResponsiveImageSelector
Review of attachment 8504991 [details] [diff] [review]:
-----------------------------------------------------------------
::: content/base/src/ResponsiveImageSelector.cpp
@@ +15,5 @@
> #include "nsIMediaList.h"
> #include "nsRuleNode.h"
> #include "nsRuleData.h"
>
> +#include "nsCycleCollectionParticipant.h"
nit: you don't really need this, as you are including it via the header of this file, IMO.
@@ +23,5 @@
>
> namespace mozilla {
> namespace dom {
>
> +// Cycle collection
nit: don't really need this comment
::: content/html/content/src/HTMLImageElement.cpp
@@ +27,5 @@
> #include "nsIDOMWindow.h"
> #include "nsFocusManager.h"
> #include "mozilla/dom/HTMLFormElement.h"
> #include "nsAttrValueOrString.h"
> +#include "nsCycleCollectionParticipant.h"
nit: you don't really need this, as you are including it via the header of this file, IMO.
@@ +116,5 @@
>
> NS_IMPL_ADDREF_INHERITED(HTMLImageElement, Element)
> NS_IMPL_RELEASE_INHERITED(HTMLImageElement, Element)
>
> +// Cycle collection
nit: you don't really need the comment here.
::: content/html/content/src/HTMLImageElement.h
@@ +37,5 @@
> const Optional<uint32_t>& aWidth,
> const Optional<uint32_t>& aHeight,
> ErrorResult& aError);
>
> + // CC
nit: you don't need this comment
Attachment #8504991 -
Flags: review?(continuation) → review+
Assignee | ||
Comment 16•10 years ago
|
||
From addressing the review comments for part 2 -- this bit should probably be re-reviewed by bz. Also, should we rev the IID for this class when adding a non-virtual?
Attachment #8505013 -
Flags: review?(bzbarsky)
Assignee | ||
Comment 17•10 years ago
|
||
Updated comment in QueueImageLoadTask to document that it is not used yet in the img.src case (from part 2 review comments)
Attachment #8505050 -
Flags: review+
Assignee | ||
Comment 18•10 years ago
|
||
Addressed comments as noted below, carrying over r+ but let me know if you'd like further changes
(In reply to Boris Zbarsky [:bz] from comment #9)
> Comment on attachment 8498617 [details] [diff] [review]
> Part 2 - Line up with new spec for <img srcset> and <picture> mutations
>
> >+++ b/content/html/content/src/HTMLImageElement.cpp
> > HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
>
> >+ if (nsContentUtils::IsImageSrcSetDisabled()) {
> >+ return NS_OK;
>
> That can't be right. With this change, if I do:
>
> var img = new Image();
> img.setAttribute("foo", "bar");
> alert(img.getAttribute("foo"));
>
> I won't get "bar", will I? Please fix, and add a test that would have
> caught this.
.. if you have | dom.disable_image_src_set | set, which is unused (except maybe in seamonkey?) and being removed in Bug 773429!
I moved the bailout to the right spot, but I don't think we should be adding tests for dom.disable_image_src_set if it's waiting for someone to remove it
> > HTMLImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
>
> Posting these events when tearing down a document seems a bit annoying.
> Could we skip doing the QueueImageLoadTask in that case? Followup might be
> ok here as long as it gets uplifted to whatever branches this lands on.
I filed Bug 1082828 for this, and put it on my list for picture followups
> >+HTMLImageElement::QueueImageLoadTask()
> >+ if (!LoadingEnabled() || !doc || !doc->IsActive()) {
>
> I thought the documentation on nsIDocument::IsActive is pretty clear:
>
> this does NOT match the "active document" concept in the WHATWG spec.
>
> Though neither does what it suggests using; the closest thing is
> nsPIDOMWindow::HasActiveDocument, but with our document instead of mDoc.
>
> We should add a better way of doing this test and use it here.
I added part 1.99 for this and asked for separate review since its adding new nsIDocument fun. Changed this patch to use IsCurrentActiveDocument from that patch
> Also, no need to null-check "doc". It can't ever be null.
Dropped
> Please document that this is not used in the cases when we just have an src,
> so the fact that those cases need to pick a selected source synchronously is
> ok.
Part 3 adds more comments about the img.src case, updated it with a better description for QueueImageLoadTask
> > HTMLImageElement::PictureSourceSrcsetChanged(nsIContent *aSourceNode,
> >+ MOZ_ASSERT(isSelf || IsPreviousSibling(aSourceNode, AsContent()),
>
> Why AsContent() instead of "this"?
>
> Same for all the other places where AsContent() is used here.
I had assumed, for some reason, we couldn't simply downcast to nsIContent. I'm not sure why. I removed some of the superfluousness here.
> >+ nsIContent *currentSrc = \
>
> Why the backslash? Shouldn't be needed. This also happens several times.
Delimiting uncommon linebreak points, just a style thing for readability (but removed since its not in line with mozilla style either way)
> >+HTMLImageElement::UpdateResponsiveSource()
> >+ candidateSource = thisContent;
>
> That's a confusing way to write:
>
> candidateSource = this;
Also fixed
> >+ MOZ_ASSERT(candidateSource,
> >+ "Did not hit ourselves before reaching end of siblings?");
>
> I don't think this assert (an some other asserts here) is necessarily valid
> when XBL is involved.... (e.g. consider when "this" is an anon subtree root
> in the binding, so our parent is the bound element).
Removed assert and just null out mResponsiveSelector here (like we would have if we hit <img> with still no candidate). If we run into other asserts with odd XBL usage on <picture>, it would probably be worth the bug to make sure whatever something is doing with XBL is what we actually expect...
> >+++ b/content/html/content/src/HTMLPictureElement.cpp
> >+ if (nextSibling->Tag() == nsGkAtoms::img) {
> >+ HTMLImageElement *img = static_cast<HTMLImageElement*>
> (nextSibling.get());
>
> how about using NS_IMPL_FROMCONTENT_HTML_WITH_TAG in the header and then
> here:
>
> if (HTMLImageElement* img = HTMLImageElement::FromContent(nextSibling)) {
> ....
That is much cleaner, done
Attachment #8505069 -
Flags: review+
Assignee | ||
Comment 19•10 years ago
|
||
Comment on attachment 8498617 [details] [diff] [review]
Part 2 - Line up with new spec for <img srcset> and <picture> mutations
[ obsolete w/ comment 18 ]
Attachment #8498617 -
Attachment is obsolete: true
Assignee | ||
Comment 20•10 years ago
|
||
Comment on attachment 8501357 [details] [diff] [review]
Part 3 - Be more explicit about when we're falling back to synchronous behavior
[ obsolete w/ comment 17 ]
Attachment #8501357 -
Attachment is obsolete: true
Assignee | ||
Comment 21•10 years ago
|
||
Addressed review comments
Attachment #8504991 -
Attachment is obsolete: true
Attachment #8505076 -
Flags: review+
Comment 22•10 years ago
|
||
Comment on attachment 8505013 [details] [diff] [review]
Part 1.99 - Add nsIDocument::IsCurrentActiveDocument
>+ * differentiate the *current* activate document from any active
s/Activate/Active/
>+ (inner->IsCurrentInnerWindow() ||
No, this isn't right. We could have inner->IsCurrentInnerWindow(), but inner->GetDoc() != this, in which case this is not the active document.
>+ outer->GetCurrentInnerWindow()->GetDoc() == this));
On the other hand, this bit is, I think, not needed. If our inner window is not current we can't be the active doc. The case when a window is non-current but has an active document is when the document has gotten a new inner window, so the old inner still has an active doc but isn't current anymore.
So I think this test should just be:
inner && inner->IsCurrentInnerWindow() && inner->GetDoc() == this
r=me with that
Attachment #8505013 -
Flags: review?(bzbarsky) → review+
Comment 23•10 years ago
|
||
> Also, should we rev the IID for this class when adding a non-virtual?
No. The vtable is no changing, so no need.
> .. if you have | dom.disable_image_src_set | set
Ah, fair. OK.
The rest of comment 18 sounds great.
Assignee | ||
Comment 24•10 years ago
|
||
Addressed review comments
Attachment #8505013 -
Attachment is obsolete: true
Attachment #8510590 -
Flags: review+
Assignee | ||
Comment 25•10 years ago
|
||
Minor fix found by try: the QueueImageLoadTask() in UnbindFromTree() was missing a IsPictureEnabled check, causing unexpected pass on some platform tests
Attachment #8505069 -
Attachment is obsolete: true
Attachment #8511217 -
Flags: review+
Assignee | ||
Comment 26•10 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/987133583ef3
https://hg.mozilla.org/integration/mozilla-inbound/rev/4c739aa459fb
https://hg.mozilla.org/integration/mozilla-inbound/rev/f43030eb22a4
https://hg.mozilla.org/integration/mozilla-inbound/rev/73a28e6fbe84
https://hg.mozilla.org/integration/mozilla-inbound/rev/7e0376b11638
https://hg.mozilla.org/integration/mozilla-inbound/rev/f81dc8f11838
https://hg.mozilla.org/integration/mozilla-inbound/rev/56cee6c6cd5c
Try:
https://treeherder.mozilla.org/ui/#/jobs?repo=try&revision=8af04bb0dc51
https://hg.mozilla.org/mozilla-central/rev/987133583ef3
https://hg.mozilla.org/mozilla-central/rev/4c739aa459fb
https://hg.mozilla.org/mozilla-central/rev/f43030eb22a4
https://hg.mozilla.org/mozilla-central/rev/73a28e6fbe84
https://hg.mozilla.org/mozilla-central/rev/7e0376b11638
https://hg.mozilla.org/mozilla-central/rev/f81dc8f11838
https://hg.mozilla.org/mozilla-central/rev/56cee6c6cd5c
Status: ASSIGNED → RESOLVED
Closed: 10 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla36
Updated•6 years ago
|
Component: DOM → DOM: Core & HTML
You need to log in
before you can comment on or make changes to this bug.
Description
•