Bug 1166138 - Make img srcset react to resize/viewport changes, r=jdm

This commit is contained in:
Michael Layzell
2015-08-31 15:29:40 -04:00
parent f071e84266
commit 2bf048f526
8 changed files with 215 additions and 47 deletions

View File

@@ -80,8 +80,9 @@ namespace dom {
class ImageLoadTask : public nsRunnable
{
public:
explicit ImageLoadTask(HTMLImageElement *aElement) :
mElement(aElement)
ImageLoadTask(HTMLImageElement *aElement, bool aAlwaysLoad)
: mElement(aElement)
, mAlwaysLoad(aAlwaysLoad)
{
mDocument = aElement->OwnerDoc();
mDocument->BlockOnload();
@@ -91,7 +92,7 @@ public:
{
if (mElement->mPendingImageLoadTask == this) {
mElement->mPendingImageLoadTask = nullptr;
mElement->LoadSelectedImage(true, true);
mElement->LoadSelectedImage(true, true, mAlwaysLoad);
}
mDocument->UnblockOnload(false);
return NS_OK;
@@ -101,11 +102,13 @@ private:
~ImageLoadTask() {}
RefPtr<HTMLImageElement> mElement;
nsCOMPtr<nsIDocument> mDocument;
bool mAlwaysLoad;
};
HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
, mForm(nullptr)
, mInDocResponsiveContent(false)
{
// We start out broken
AddStatesSilently(NS_EVENT_STATE_BROKEN);
@@ -427,7 +430,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
mResponsiveSelector->Content() == this) {
mResponsiveSelector->SetDefaultSource(NullString());
}
QueueImageLoadTask();
QueueImageLoadTask(true);
} else {
// Bug 1076583 - We still behave synchronously in the non-responsive case
CancelImageRequests(aNotify);
@@ -447,7 +450,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
if (InResponsiveMode()) {
// per spec, full selection runs when this changes, even though
// it doesn't directly affect the source selection
QueueImageLoadTask();
QueueImageLoadTask(true);
} else {
// Bug 1076583 - We still use the older synchronous algorithm in
// non-responsive mode. Force a new load of the image with the
@@ -543,7 +546,7 @@ HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
mResponsiveSelector->Content() == this) {
mResponsiveSelector->SetDefaultSource(aValue);
}
QueueImageLoadTask();
QueueImageLoadTask(true);
} else if (aNotify) {
// If aNotify is false, we are coming from the parser or some such place;
// we'll get bound after all the attributes have been set, so we'll do the
@@ -586,13 +589,15 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
UpdateFormOwner();
}
bool addedToPicture = aParent && aParent->IsHTMLElement(nsGkAtoms::picture) &&
HTMLPictureElement::IsPictureEnabled();
if (addedToPicture) {
if (aDocument) {
if (HaveSrcsetOrInPicture()) {
if (aDocument && !mInDocResponsiveContent) {
aDocument->AddResponsiveContent(this);
mInDocResponsiveContent = true;
}
QueueImageLoadTask();
bool forceLoadEvent = HTMLPictureElement::IsPictureEnabled() &&
aParent && aParent->IsHTMLElement(nsGkAtoms::picture);
QueueImageLoadTask(forceLoadEvent);
} else if (!InResponsiveMode() &&
HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
// We skip loading when our attributes were set from parser land,
@@ -633,17 +638,22 @@ HTMLImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
}
}
if (mInDocResponsiveContent) {
nsIDocument* doc = GetOurOwnerDoc();
MOZ_ASSERT(doc);
if (doc) {
doc->RemoveResponsiveContent(this);
mInDocResponsiveContent = false;
}
}
if (GetParent() &&
GetParent()->IsHTMLElement(nsGkAtoms::picture) &&
HTMLPictureElement::IsPictureEnabled()) {
nsIDocument* doc = GetOurOwnerDoc();
if (doc) {
doc->RemoveResponsiveContent(this);
}
// Being removed from picture re-triggers selection, even if we
// weren't using a <source> peer
if (aNullParent) {
QueueImageLoadTask();
QueueImageLoadTask(true);
}
}
@@ -687,7 +697,7 @@ HTMLImageElement::MaybeLoadImage()
// Note, check LoadingEnabled() after LoadImage call.
LoadSelectedImage(false, true);
LoadSelectedImage(false, true, false);
if (!LoadingEnabled()) {
CancelImageRequests(true);
@@ -887,7 +897,7 @@ HTMLImageElement::ClearForm(bool aRemoveFromForm)
}
void
HTMLImageElement::QueueImageLoadTask()
HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad)
{
// If loading is temporarily disabled, we don't want to queue tasks
// that may then run when loading is re-enabled.
@@ -895,7 +905,7 @@ HTMLImageElement::QueueImageLoadTask()
return;
}
nsCOMPtr<nsIRunnable> task = new ImageLoadTask(this);
nsCOMPtr<nsIRunnable> task = new ImageLoadTask(this, aAlwaysLoad);
// The task checks this to determine if it was the last
// queued event, and so earlier tasks are implicitly canceled.
mPendingImageLoadTask = task;
@@ -929,7 +939,7 @@ HTMLImageElement::InResponsiveMode()
}
nsresult
HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify)
HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad)
{
nsresult rv = NS_ERROR_FAILURE;
@@ -937,7 +947,9 @@ HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify)
// In responsive mode we generally want to re-run the full
// selection algorithm whenever starting a new load, per
// spec. This also causes us to re-resolve the URI as appropriate.
UpdateResponsiveSource();
if (!UpdateResponsiveSource() && !aAlwaysLoad) {
return NS_OK;
}
}
if (mResponsiveSelector) {
@@ -990,9 +1002,17 @@ HTMLImageElement::PictureSourceSrcsetChanged(nsIContent *aSourceNode,
mResponsiveSelector->SetCandidatesFromSourceSet(aNewValue);
}
if (!mInDocResponsiveContent) {
nsIDocument* doc = GetOurOwnerDoc();
if (doc) {
doc->AddResponsiveContent(this);
mInDocResponsiveContent = true;
}
}
// This always triggers the image update steps per the spec, even if
// we are not using this source.
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@@ -1019,7 +1039,7 @@ HTMLImageElement::PictureSourceSizesChanged(nsIContent *aSourceNode,
// This always triggers the image update steps per the spec, even if
// we are not using this source.
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@@ -1035,7 +1055,7 @@ HTMLImageElement::PictureSourceMediaOrTypeChanged(nsIContent *aSourceNode,
// This always triggers the image update steps per the spec, even if
// we are not switching to/from this source
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@@ -1045,7 +1065,7 @@ HTMLImageElement::PictureSourceAdded(nsIContent *aSourceNode)
return;
}
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
@@ -1055,15 +1075,17 @@ HTMLImageElement::PictureSourceRemoved(nsIContent *aSourceNode)
return;
}
QueueImageLoadTask();
QueueImageLoadTask(true);
}
void
bool
HTMLImageElement::UpdateResponsiveSource()
{
bool hadSelector = !!mResponsiveSelector;
if (!IsSrcsetEnabled()) {
mResponsiveSelector = nullptr;
return;
return hadSelector;
}
nsIContent *currentSource =
@@ -1083,7 +1105,7 @@ HTMLImageElement::UpdateResponsiveSource()
if (candidateSource == currentSource) {
// found no better source before current, re-run selection on
// that and keep it if it's still usable.
mResponsiveSelector->SelectImage(true);
bool changed = mResponsiveSelector->SelectImage(true);
if (mResponsiveSelector->NumCandidates()) {
bool isUsableCandidate = true;
@@ -1095,7 +1117,7 @@ HTMLImageElement::UpdateResponsiveSource()
}
if (isUsableCandidate) {
break;
return changed;
}
}
@@ -1124,6 +1146,8 @@ HTMLImageElement::UpdateResponsiveSource()
// Ran out of siblings without finding ourself, e.g. XBL magic.
mResponsiveSelector = nullptr;
}
return !hadSelector || mResponsiveSelector;
}
/*static */ bool
@@ -1296,7 +1320,7 @@ HTMLImageElement::DestroyContent()
void
HTMLImageElement::MediaFeatureValuesChanged()
{
QueueImageLoadTask();
QueueImageLoadTask(false);
}
void