--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -113,17 +113,16 @@ private:
// True if we want to set nsIClassOfService::UrgentStart to the channel to
// get the response ASAP for better user responsiveness.
bool mUseUrgentStartForChannel;
};
HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
, mForm(nullptr)
- , mForceReload(false)
, mInDocResponsiveContent(false)
, mCurrentDensity(1.0)
{
// We start out broken
AddStatesSilently(NS_EVENT_STATE_BROKEN);
}
HTMLImageElement::~HTMLImageElement()
@@ -373,20 +372,16 @@ HTMLImageElement::GetAttributeMappingFun
return &MapAttributesIntoRule;
}
nsresult
HTMLImageElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify)
{
- if (aValue) {
- BeforeMaybeChangeAttr(aNameSpaceID, aName, *aValue, aNotify);
- }
-
if (aNameSpaceID == kNameSpaceID_None && mForm &&
(aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
// remove the image from the hashtable as needed
nsAutoString tmp;
GetAttr(kNameSpaceID_None, aName, tmp);
if (!tmp.IsEmpty()) {
mForm->RemoveImageElementFromTable(this, tmp);
@@ -397,36 +392,37 @@ HTMLImageElement::BeforeSetAttr(int32_t
aValue, aNotify);
}
nsresult
HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
const nsAttrValue* aOldValue, bool aNotify)
{
+ nsAttrValueOrString attrVal(aValue);
+
if (aValue) {
- AfterMaybeChangeAttr(aNameSpaceID, aName, aNotify);
+ AfterMaybeChangeAttr(aNameSpaceID, aName, attrVal, aOldValue, true,
+ aNotify);
}
if (aNameSpaceID == kNameSpaceID_None && mForm &&
(aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
aValue && !aValue->IsEmptyString()) {
// add the image to the hashtable as needed
MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom,
"Expected atom value for name/id");
mForm->AddImageElementToTable(this,
nsDependentAtomString(aValue->GetAtomValue()));
}
// Handle src/srcset updates. 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 image load from BindToTree.
- nsAttrValueOrString attrVal(aValue);
-
if (aName == nsGkAtoms::src &&
aNameSpaceID == kNameSpaceID_None &&
!aValue) {
// Mark channel as urgent-start before load image if the image load is
// initaiated by a user interaction.
mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
// SetAttr handles setting src since it needs to catch img.src =
@@ -461,41 +457,39 @@ HTMLImageElement::AfterSetAttr(int32_t a
aValue, aOldValue, aNotify);
}
nsresult
HTMLImageElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString& aValue,
bool aNotify)
{
- BeforeMaybeChangeAttr(aNamespaceID, aName, aValue, aNotify);
- AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
+ AfterMaybeChangeAttr(aNamespaceID, aName, aValue, nullptr, false, aNotify);
return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
aValue, aNotify);
}
void
-HTMLImageElement::BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValueOrString& aValue,
- bool aNotify)
+HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValueOrString& aValue,
+ const nsAttrValue* aOldValue,
+ bool aValueMaybeChanged, bool aNotify)
{
+ bool forceReload = false;
// We need to force our image to reload. This must be done here, not in
// AfterSetAttr or BeforeSetAttr, because we want to do it even if the attr is
// being set to its existing value, which is normally optimized away as a
// no-op.
//
// If we are in responsive mode, we drop the forced reload behavior,
// but still trigger a image load task for img.src = img.src per
// spec.
//
// Both cases handle unsetting src in AfterSetAttr
- //
- // Much of this should probably happen in AfterMaybeChangeAttr.
- // See Bug 1370705
if (aNamespaceID == kNameSpaceID_None &&
aName == nsGkAtoms::src) {
// Mark channel as urgent-start before load image if the image load is
// initaiated by a user interaction.
mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
if (InResponsiveMode()) {
@@ -510,78 +504,71 @@ HTMLImageElement::BeforeMaybeChangeAttr(
// sync image load from BindToTree. Skip the LoadImage call in that case.
// Note that this sync behavior is partially removed from the spec, bug 1076583
// A hack to get animations to reset. See bug 594771.
mNewRequestsWillNeedAnimationReset = true;
// Force image loading here, so that we'll try to load the image from
- // network if it's set to be not cacheable... If we change things so that
- // the state gets in Element's attr-setting happen around this
- // LoadImage call, we could start passing false instead of aNotify
- // here.
+ // network if it's set to be not cacheable.
+ // Potentially, false could be passed here rather than aNotify since
+ // UpdateState will be called by SetAttrAndNotify, but there are two
+ // obstacles to this: 1) LoadImage will end up calling
+ // UpdateState(aNotify), and we do not want it to call UpdateState(false)
+ // when aNotify is true, and 2) When this function is called by
+ // OnAttrSetButNotChanged, SetAttrAndNotify will not subsequently call
+ // UpdateState.
LoadImage(aValue.String(), true, aNotify, eImageLoadType_Normal);
mNewRequestsWillNeedAnimationReset = false;
}
} else if (aNamespaceID == kNameSpaceID_None &&
aName == nsGkAtoms::crossorigin &&
aNotify) {
- nsAttrValue attrValue;
- ParseCORSValue(aValue.String(), attrValue);
- if (GetCORSMode() != AttrValueToCORSMode(&attrValue)) {
+ if (aValueMaybeChanged && GetCORSMode() != AttrValueToCORSMode(aOldValue)) {
// Force a new load of the image with the new cross origin policy.
- mForceReload = true;
+ forceReload = true;
}
} else if (aName == nsGkAtoms::referrerpolicy &&
aNamespaceID == kNameSpaceID_None &&
aNotify) {
- ReferrerPolicy referrerPolicy = AttributeReferrerPolicyFromString(aValue.String());
+ ReferrerPolicy referrerPolicy = GetImageReferrerPolicy();
if (!InResponsiveMode() &&
referrerPolicy != RP_Unset &&
- referrerPolicy != GetImageReferrerPolicy()) {
+ aValueMaybeChanged &&
+ referrerPolicy != ReferrerPolicyFromAttr(aOldValue)) {
// XXX: Bug 1076583 - We still use the older synchronous algorithm
// Because referrerPolicy is not treated as relevant mutations, setting
// the attribute will neither trigger a reload nor update the referrer
// policy of the loading channel (whether it has previously completed or
// not). Force a new load of the image with the new referrerpolicy.
- mForceReload = true;
+ forceReload = true;
}
}
- return;
-}
-
-void
-HTMLImageElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
- bool aNotify)
-{
// Because we load image synchronously in non-responsive-mode, we need to do
// reload after the attribute has been set if the reload is triggerred by
// cross origin changing.
- if (mForceReload) {
- mForceReload = false;
+ if (forceReload) {
// Mark channel as urgent-start before load image if the image load is
// initaiated by a user interaction.
mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
if (InResponsiveMode()) {
// per spec, full selection runs when this changes, even though
// it doesn't directly affect the source selection
QueueImageLoadTask(true);
} else if (OwnerDoc()->IsCurrentActiveDocument()) {
// Bug 1076583 - We still use the older synchronous algorithm in
// non-responsive mode. Force a new load of the image with the
// new cross origin policy
ForceReload(aNotify);
}
}
-
- return;
}
nsresult
HTMLImageElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
// We handle image element with attribute ismap in its corresponding frame
// element. Set mMultipleActionsPrevented here to prevent the click event
// trigger the behaviors in Element::PostHandleEventForLinks
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -356,44 +356,35 @@ protected:
RefPtr<ResponsiveImageSelector> mResponsiveSelector;
private:
bool SourceElementMatches(nsIContent* aSourceNode);
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
GenericSpecifiedValues* aGenericData);
/**
- * This function is called by BeforeSetAttr and OnAttrSetButNotChanged.
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
* It will not be called if the value is being unset.
*
* @param aNamespaceID the namespace of the attr being set
* @param aName the localname of the attribute being set
* @param aValue the value it's being set to represented as either a string or
* a parsed nsAttrValue.
- * @param aNotify Whether we plan to notify document observers.
- */
- void BeforeMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValueOrString& aValue,
- bool aNotify);
- /**
- * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
- * It will not be called if the value is being unset.
- *
- * @param aNamespaceID the namespace of the attr being set
- * @param aName the localname of the attribute being set
+ * @param aOldValue the value previously set. Will be null if no value was
+ * previously set. This value should only be used when
+ * aValueMaybeChanged is true; when aValueMaybeChanged is false,
+ * aOldValue should be considered unreliable.
+ * @param aValueMaybeChanged will be false when this function is called from
+ * OnAttrSetButNotChanged to indicate that the value was not changed.
* @param aNotify Whether we plan to notify document observers.
*/
void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
- bool aNotify);
- /**
- * Used by BeforeMaybeChangeAttr and AfterMaybeChangeAttr to keep track of
- * whether a reload needs to be forced after an attribute change that is
- * currently in progress.
- */
- bool mForceReload;
+ const nsAttrValueOrString& aValue,
+ const nsAttrValue* aOldValue,
+ bool aValueMaybeChanged, bool aNotify);
bool mInDocResponsiveContent;
RefPtr<ImageLoadTask> mPendingImageLoadTask;
// Last URL that was attempted to load by this element.
nsCOMPtr<nsIURI> mLastSelectedSource;
// Last pixel density that was selected.
double mCurrentDensity;