--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2251,23 +2251,25 @@ Element::InternalGetAttrNameFromQName(co
bool
Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify,
nsAttrValue& aOldValue,
uint8_t* aModType,
- bool* aHasListeners)
+ bool* aHasListeners,
+ bool* aOldValueSet)
{
bool modification = false;
*aHasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
+ *aOldValueSet = false;
// If we have no listeners and aNotify is false, we are almost certainly
// coming from the content sink and will almost certainly have no previous
// value. Even if we do, setting the value is cheap when we have no
// listeners and don't plan to notify. The check for aNotify here is an
// optimization, the check for *aHasListeners is a correctness issue.
if (*aHasListeners || aNotify) {
BorrowedAttrInfo info(GetAttrInfo(aNamespaceID, aName));
@@ -2282,16 +2284,17 @@ Element::MaybeCheckSameAttrVal(int32_t a
// If the current attribute value contains a pointer to some other data
// structure that gets updated in the process of setting the attribute
// we'll no longer have the old value of the attribute. Therefore, we
// should serialize the attribute value now to keep a snapshot.
//
// We have to serialize the value anyway in order to create the
// mutation event so there's no cost in doing it now.
aOldValue.SetToSerialized(*info.mValue);
+ *aOldValueSet = true;
}
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
return true;
}
modification = true;
}
}
@@ -2301,20 +2304,22 @@ Element::MaybeCheckSameAttrVal(int32_t a
return false;
}
bool
Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
- uint8_t* aModType, bool* aHasListeners)
+ uint8_t* aModType, bool* aHasListeners,
+ bool* aOldValueSet)
{
if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
- aOldValue, aModType, aHasListeners)) {
+ aOldValue, aModType, aHasListeners,
+ aOldValueSet)) {
return false;
}
nsAutoScriptBlocker scriptBlocker;
nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
return true;
}
@@ -2335,19 +2340,20 @@ Element::SetAttr(int32_t aNamespaceID, n
uint8_t modType;
bool hasListeners;
// We don't want to spend time preparsing class attributes if the value is not
// changing, so just init our nsAttrValueOrString with aValue for the
// OnlyNotifySameValueSet call.
nsAttrValueOrString value(aValue);
nsAttrValue oldValue;
+ bool oldValueSet;
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
- oldValue, &modType, &hasListeners)) {
+ oldValue, &modType, &hasListeners, &oldValueSet)) {
return NS_OK;
}
nsAttrValue attrValue;
nsAttrValue* preparsedAttrValue;
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::_class) {
attrValue.ParseAtomArray(aValue);
value.ResetToAttrValue(attrValue);
@@ -2370,17 +2376,18 @@ Element::SetAttr(int32_t aNamespaceID, n
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
// Even the value was pre-parsed, we still need to call ParseAttribute because
// it can have side effects.
if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
attrValue.SetTo(aValue);
}
- return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
+ return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
+ oldValueSet ? &oldValue : nullptr,
attrValue, modType, hasListeners, aNotify,
kCallAfterSetAttr, document, updateBatch);
}
nsresult
Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
bool aNotify)
@@ -2395,42 +2402,44 @@ Element::SetParsedAttr(int32_t aNamespac
return NS_ERROR_FAILURE;
}
uint8_t modType;
bool hasListeners;
nsAttrValueOrString value(aParsedValue);
nsAttrValue oldValue;
+ bool oldValueSet;
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
- oldValue, &modType, &hasListeners)) {
+ oldValue, &modType, &hasListeners, &oldValueSet)) {
return NS_OK;
}
if (aNotify) {
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
&aParsedValue);
}
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
- return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
+ return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
+ oldValueSet ? &oldValue : nullptr,
aParsedValue, modType, hasListeners, aNotify,
kCallAfterSetAttr, document, updateBatch);
}
nsresult
Element::SetAttrAndNotify(int32_t aNamespaceID,
nsIAtom* aName,
nsIAtom* aPrefix,
- const nsAttrValue& aOldValue,
+ const nsAttrValue* aOldValue,
nsAttrValue& aParsedValue,
uint8_t aModType,
bool aFireMutation,
bool aNotify,
bool aCallAfterSetAttr,
nsIDocument* aComposedDocument,
const mozAutoDocUpdate&)
{
@@ -2441,85 +2450,104 @@ Element::SetAttrAndNotify(int32_t aNames
// SetAndSwapMappedAttr below
nsAttrValue valueForAfterSetAttr;
if (aCallAfterSetAttr) {
valueForAfterSetAttr.SetTo(aParsedValue);
}
bool hadValidDir = false;
bool hadDirAuto = false;
+ bool oldValueSet;
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::dir) {
hadValidDir = HasValidDir() || IsHTMLElement(nsGkAtoms::bdi);
hadDirAuto = HasDirAuto(); // already takes bdi into account
}
// XXXbz Perhaps we should push up the attribute mapping function
// stuff to Element?
if (!IsAttributeMapped(aName) ||
- !SetMappedAttribute(aName, aParsedValue, &rv)) {
- rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
+ !SetAndSwapMappedAttribute(aName, aParsedValue, &oldValueSet, &rv)) {
+ rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
}
}
else {
RefPtr<mozilla::dom::NodeInfo> ni;
ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
aNamespaceID,
nsIDOMNode::ATTRIBUTE_NODE);
- rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
+ rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
}
+ NS_ENSURE_SUCCESS(rv, rv);
// If the old value owns its own data, we know it is OK to keep using it.
- const nsAttrValue* oldValue =
- aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
-
- NS_ENSURE_SUCCESS(rv, rv);
+ // oldValue will be null if there was no previously set value
+ const nsAttrValue* oldValue;
+ if (aParsedValue.StoresOwnData()) {
+ if (oldValueSet) {
+ oldValue = &aParsedValue;
+ } else {
+ oldValue = nullptr;
+ }
+ } else {
+ // No need to conditionally assign null here. If there was no previously
+ // set value for the attribute, aOldValue will already be null.
+ oldValue = aOldValue;
+ }
if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
RefPtr<nsXBLBinding> binding = GetXBLBinding();
if (binding) {
binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
}
}
nsIDocument* ownerDoc = OwnerDoc();
if (ownerDoc && GetCustomElementData()) {
- nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
+ nsCOMPtr<nsIAtom> oldValueAtom;
+ if (oldValue) {
+ oldValueAtom = oldValue->GetAsAtom();
+ } else {
+ // If there is no old value, get the value of the uninitialized attribute
+ // that was swapped with aParsedValue.
+ oldValueAtom = aParsedValue.GetAsAtom();
+ }
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
LifecycleCallbackArgs args = {
nsDependentAtomString(aName),
aModType == nsIDOMMutationEvent::ADDITION ?
NullString() : nsDependentAtomString(oldValueAtom),
nsDependentAtomString(newValueAtom)
};
nsContentUtils::EnqueueLifecycleCallback(
ownerDoc, nsIDocument::eAttributeChanged, this, &args);
}
if (aCallAfterSetAttr) {
- rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
+ rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
+ aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
OnSetDirAttr(this, &valueForAfterSetAttr,
hadValidDir, hadDirAuto, aNotify);
}
}
UpdateState(aNotify);
if (aNotify) {
// Don't pass aOldValue to AttributeChanged since it may not be reliable.
// Callers only compute aOldValue under certain conditions which may not
// be triggered by all nsIMutationObservers.
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
- oldValue == &aParsedValue ? &aParsedValue : nullptr);
+ aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
}
if (aFireMutation) {
InternalMutationEvent mutation(true, eLegacyAttrModified);
nsAutoString ns;
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
Attr* attrNode =
@@ -2527,17 +2555,17 @@ Element::SetAttrAndNotify(int32_t aNames
mutation.mRelatedNode = attrNode;
mutation.mAttrName = aName;
nsAutoString newValue;
GetAttr(aNamespaceID, aName, newValue);
if (!newValue.IsEmpty()) {
mutation.mNewAttrValue = NS_Atomize(newValue);
}
- if (!oldValue->IsEmptyString()) {
+ if (oldValue && !oldValue->IsEmptyString()) {
mutation.mPrevAttrValue = oldValue->GetAsAtom();
}
mutation.mAttrChange = aModType;
mozAutoSubtreeModified subtree(OwnerDoc(), this);
(new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
}
@@ -2570,19 +2598,20 @@ Element::ParseAttribute(int32_t aNamespa
return true;
}
}
return false;
}
bool
-Element::SetMappedAttribute(nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval)
+Element::SetAndSwapMappedAttribute(nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval)
{
*aRetval = NS_OK;
return false;
}
EventListenerManager*
Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
bool* aDefer)
@@ -2727,17 +2756,17 @@ Element::UnsetAttr(int32_t aNameSpaceID,
nsDependentAtomString(oldValueAtom),
NullString()
};
nsContentUtils::EnqueueLifecycleCallback(
ownerDoc, nsIDocument::eAttributeChanged, this, &args);
}
- rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
+ rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
UpdateState(aNotify);
if (aNotify) {
// We can always pass oldValue here since there is no new value which could
// have corrupted it.
nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -606,35 +606,59 @@ public:
/**
* Helper for SetAttr/SetParsedAttr. This method will return true if aNotify
* is true or there are mutation listeners that must be triggered, the
* attribute is currently set, and the new value that is about to be set is
* different to the current value. As a perf optimization the new and old
* values will not actually be compared if we aren't notifying and we don't
* have mutation listeners (in which case it's cheap to just return false
* and let the caller go ahead and set the value).
- * @param aOldValue Set to the old value of the attribute, but only if there
- * are event listeners. If set, the type of aOldValue will be either
+ * @param aOldValue [out] Set to the old value of the attribute, but only if
+ * there are event listeners. If set, the type of aOldValue will be either
* nsAttrValue::eString or nsAttrValue::eAtom.
- * @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to
+ * @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
- * @param aHasListeners Set to true if there are mutation event listeners
- * listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
+ * @param aHasListeners [out] Set to true if there are mutation event
+ * listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
+ * @param aOldValueSet [out] Indicates whether an old attribute value has been
+ * stored in aOldValue. The bool will be set to true if a value was stored.
*/
bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
- uint8_t* aModType, bool* aHasListeners);
+ uint8_t* aModType, bool* aHasListeners,
+ bool* aOldValueSet);
+ /**
+ * Notifies mutation listeners if aNotify is true, there are mutation
+ * listeners, and the attribute value is changing.
+ *
+ * @param aNamespaceID The namespace of the attribute
+ * @param aName The local name of the attribute
+ * @param aPrefix The prefix of the attribute
+ * @param aValue The value that the attribute is being changed to
+ * @param aNotify If true, mutation listeners will be notified if they exist
+ * and the attribute value is changing
+ * @param aOldValue [out] Set to the old value of the attribute, but only if
+ * there are event listeners. If set, the type of aOldValue will be either
+ * nsAttrValue::eString or nsAttrValue::eAtom.
+ * @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
+ * nsIDOMMutationEvent::ADDITION, but only if this helper returns true
+ * @param aHasListeners [out] Set to true if there are mutation event
+ * listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
+ * @param aOldValueSet [out] Indicates whether an old attribute value has been
+ * stored in aOldValue. The bool will be set to true if a value was stored.
+ */
bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
- uint8_t* aModType, bool* aHasListeners);
+ uint8_t* aModType, bool* aHasListeners,
+ bool* aOldValueSet);
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
const nsAString& aValue, bool aNotify) override;
// aParsedValue receives the old value of the attribute. That's useful if
// either the input or output value of aParsedValue is StoresOwnData.
nsresult SetParsedAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
nsAttrValue& aParsedValue, bool aNotify);
// GetAttr is not inlined on purpose, to keep down codesize from all
@@ -1327,31 +1351,34 @@ protected:
* @param aNamespaceID namespace of attribute
* @param aAttribute local-name of attribute
* @param aPrefix aPrefix of attribute
* @param aOldValue The old value of the attribute to use as a fallback
* in the cases where the actual old value (i.e.
* its current value) is !StoresOwnData() --- in which
* case the current value is probably already useless.
* If the current value is StoresOwnData() (or absent),
- * aOldValue will not be used.
+ * aOldValue will not be used. aOldValue will only be set
+ * in certain circumstances (there are mutation
+ * listeners, element is a custom element, attribute was
+ * not previously unset). Otherwise it will be null.
* @param aParsedValue parsed new value of attribute. Replaced by the
* old value of the attribute. This old value is only
* useful if either it or the new value is StoresOwnData.
* @param aModType nsIDOMMutationEvent::MODIFICATION or ADDITION. Only
* needed if aFireMutation or aNotify is true.
* @param aFireMutation should mutation-events be fired?
* @param aNotify should we notify document-observers?
* @param aCallAfterSetAttr should we call AfterSetAttr?
* @param aComposedDocument The current composed document of the element.
*/
nsresult SetAttrAndNotify(int32_t aNamespaceID,
nsIAtom* aName,
nsIAtom* aPrefix,
- const nsAttrValue& aOldValue,
+ const nsAttrValue* aOldValue,
nsAttrValue& aParsedValue,
uint8_t aModType,
bool aFireMutation,
bool aNotify,
bool aCallAfterSetAttr,
nsIDocument* aComposedDocument,
const mozAutoDocUpdate& aGuard);
@@ -1385,23 +1412,30 @@ protected:
/**
* Try to set the attribute as a mapped attribute, if applicable. This will
* only be called for attributes that are in the null namespace and only on
* attributes that returned true when passed to IsAttributeMapped. The
* caller will not try to set the attr in any other way if this method
* returns true (the value of aRetval does not matter for that purpose).
*
* @param aName the name of the attribute
- * @param aValue the nsAttrValue to set
+ * @param aValue the nsAttrValue to set. Will be swapped with the existing
+ * value of the attribute if the attribute already exists.
+ * @param [out] aValueWasSet If the attribute was not set previously,
+ * aValue will be swapped with an empty attribute
+ * and aValueWasSet will be set to false. Otherwise,
+ * aValueWasSet will be set to true and aValue will
+ * contain the previous value set.
* @param [out] aRetval the nsresult status of the operation, if any.
* @return true if the setting was attempted, false otherwise.
*/
- virtual bool SetMappedAttribute(nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval);
+ virtual bool SetAndSwapMappedAttribute(nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval);
/**
* Hook that is called by Element::SetAttr to allow subclasses to
* deal with attribute sets. This will only be called after we verify that
* we're actually doing an attr set and will be called before
* AttributeWillChange and before ParseAttribute and hence before we've set
* the new value.
*
@@ -1419,29 +1453,34 @@ protected:
bool aNotify)
{
return NS_OK;
}
/**
* Hook that is called by Element::SetAttr to allow subclasses to
* deal with attribute sets. This will only be called after we have called
- * SetAndTakeAttr and AttributeChanged (that is, after we have actually set
- * the attr). It will always be called under a scriptblocker.
+ * SetAndSwapAttr (that is, after we have actually set the attr). It will
+ * always be called under a scriptblocker.
*
* @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. If null, the attr is being
* removed.
+ * @param aOldValue the value that the attribute had previously. If null,
+ * the attr was not previously set. This argument may not have the
+ * correct value for SVG elements, or other cases in which the
+ * attribute value doesn't store its own data
* @param aNotify Whether we plan to notify document observers.
*/
// Note that this is inlined so that when subclasses call it it gets
// inlined. Those calls don't go through a vtable.
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
return NS_OK;
}
/**
* Hook to allow subclasses to produce a different EventListenerManager if
* needed for attachment of attribute-defined handlers
*/
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -384,22 +384,25 @@ nsAttrAndChildArray::AttrAt(uint32_t aPo
if (aPos < nonmapped) {
return &ATTRS(mImpl)[aPos].mValue;
}
return mImpl->mMappedAttrs->AttrAt(aPos - nonmapped);
}
nsresult
-nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
+nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
+ bool* aHadValue)
{
+ *aHadValue = false;
uint32_t i, slotCount = AttrSlotCount();
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
+ *aHadValue = true;
return NS_OK;
}
}
NS_ENSURE_TRUE(i < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
NS_ERROR_FAILURE);
if (i == slotCount && !AddAttrSlot()) {
@@ -409,31 +412,32 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIA
new (&ATTRS(mImpl)[i].mName) nsAttrName(aLocalName);
new (&ATTRS(mImpl)[i].mValue) nsAttrValue();
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
return NS_OK;
}
nsresult
-nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
+nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
+ nsAttrValue& aValue, bool* aHadValue)
{
int32_t namespaceID = aName->NamespaceID();
nsIAtom* localName = aName->NameAtom();
if (namespaceID == kNameSpaceID_None) {
- return SetAndSwapAttr(localName, aValue);
+ return SetAndSwapAttr(localName, aValue, aHadValue);
}
+ *aHadValue = false;
uint32_t i, slotCount = AttrSlotCount();
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
ATTRS(mImpl)[i].mName.SetTo(aName);
- ATTRS(mImpl)[i].mValue.Reset();
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
-
+ *aHadValue = true;
return NS_OK;
}
}
NS_ENSURE_TRUE(i < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
NS_ERROR_FAILURE);
if (i == slotCount && !AddAttrSlot()) {
@@ -578,30 +582,31 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom
}
}
}
return -1;
}
nsresult
-nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
+nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
- nsHTMLStyleSheet* aSheet)
+ nsHTMLStyleSheet* aSheet,
+ bool* aHadValue)
{
bool willAdd = true;
if (mImpl && mImpl->mMappedAttrs) {
willAdd = !mImpl->mMappedAttrs->GetAttr(aLocalName);
}
RefPtr<nsMappedAttributes> mapped =
GetModifiableMapped(aContent, aSheet, willAdd);
- mapped->SetAndTakeAttr(aLocalName, aValue);
+ mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
return MakeMappedUnique(mapped);
}
nsresult
nsAttrAndChildArray::DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet)
{
NS_PRECONDITION(mImpl && mImpl->mMappedAttrs,
--- a/dom/base/nsAttrAndChildArray.h
+++ b/dom/base/nsAttrAndChildArray.h
@@ -86,18 +86,23 @@ public:
// kNameSpaceID_None. This is always case-sensitive.
const nsAttrValue* GetAttr(const nsAString& aName) const;
// Get an nsAttrValue by qualified name. Can optionally do
// ASCII-case-insensitive name matching.
const nsAttrValue* GetAttr(const nsAString& aName,
nsCaseTreatment aCaseSensitive) const;
const nsAttrValue* AttrAt(uint32_t aPos) const;
// SetAndSwapAttr swaps the current attribute value with aValue.
- nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
- nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
+ // If the attribute was unset, an empty value will be swapped into aValue
+ // and aHadValue will be set to false. Otherwise, aHadValue will be set to
+ // true.
+ nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
+ bool* aHadValue);
+ nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
+ bool* aHadValue);
// Remove the attr at position aPos. The value of the attr is placed in
// aValue; any value that was already in aValue is destroyed.
nsresult RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue);
// Returns attribute name at given position, *not* out-of-bounds safe
const nsAttrName* AttrNameAt(uint32_t aPos) const;
@@ -105,19 +110,24 @@ public:
BorrowedAttrInfo AttrInfoAt(uint32_t aPos) const;
// Returns attribute name at given position or null if aPos is out-of-bounds
const nsAttrName* GetSafeAttrNameAt(uint32_t aPos) const;
const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
- nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
+ // SetAndSwapMappedAttr swaps the current attribute value with aValue.
+ // If the attribute was unset, an empty value will be swapped into aValue
+ // and aHadValue will be set to false. Otherwise, aHadValue will be set to
+ // true.
+ nsresult SetAndSwapMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
nsMappedAttributeElement* aContent,
- nsHTMLStyleSheet* aSheet);
+ nsHTMLStyleSheet* aSheet,
+ bool* aHadValue);
nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
if (!mImpl || !mImpl->mMappedAttrs) {
return NS_OK;
}
return DoSetMappedAttrStyleSheet(aSheet);
}
void WalkMappedAttributeStyleRules(nsRuleWalker* aRuleWalker);
--- a/dom/base/nsMappedAttributeElement.cpp
+++ b/dom/base/nsMappedAttributeElement.cpp
@@ -10,23 +10,24 @@
nsresult
nsMappedAttributeElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{
mAttrsAndChildren.WalkMappedAttributeStyleRules(aRuleWalker);
return NS_OK;
}
bool
-nsMappedAttributeElement::SetMappedAttribute(nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval)
+nsMappedAttributeElement::SetAndSwapMappedAttribute(nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval)
{
nsHTMLStyleSheet* sheet = OwnerDoc()->GetAttributeStyleSheet();
- *aRetval = mAttrsAndChildren.SetAndTakeMappedAttr(aName, aValue,
- this, sheet);
+ *aRetval = mAttrsAndChildren.SetAndSwapMappedAttr(aName, aValue,
+ this, sheet, aValueWasSet);
return true;
}
nsMapRuleToAttributesFunc
nsMappedAttributeElement::GetAttributeMappingFunction() const
{
return &MapNoAttributesInto;
}
--- a/dom/base/nsMappedAttributeElement.h
+++ b/dom/base/nsMappedAttributeElement.h
@@ -35,16 +35,17 @@ protected:
public:
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
static void MapNoAttributesInto(const nsMappedAttributes* aAttributes,
mozilla::GenericSpecifiedValues* aGenericData);
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
- virtual bool SetMappedAttribute(nsIAtom* aName,
- nsAttrValue& aValue,
- nsresult* aRetval) override;
+ virtual bool SetAndSwapMappedAttribute(nsIAtom* aName,
+ nsAttrValue& aValue,
+ bool* aValueWasSet,
+ nsresult* aRetval) override;
virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
};
#endif // NS_MAPPEDATTRIBUTEELEMENT_H_
--- a/dom/base/nsMappedAttributes.cpp
+++ b/dom/base/nsMappedAttributes.cpp
@@ -151,24 +151,26 @@ nsMappedAttributes::LastRelease()
NS_IMPL_ADDREF(nsMappedAttributes)
NS_IMPL_RELEASE_WITH_DESTROY(nsMappedAttributes, LastRelease())
NS_IMPL_QUERY_INTERFACE(nsMappedAttributes,
nsIStyleRule)
void
-nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue)
+nsMappedAttributes::SetAndSwapAttr(nsIAtom* aAttrName, nsAttrValue& aValue,
+ bool* aValueWasSet)
{
NS_PRECONDITION(aAttrName, "null name");
+ *aValueWasSet = false;
uint32_t i;
for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) {
if (Attrs()[i].mName.Equals(aAttrName)) {
- Attrs()[i].mValue.Reset();
Attrs()[i].mValue.SwapValueWith(aValue);
+ *aValueWasSet = true;
return;
}
}
NS_ASSERTION(mBufferSize >= mAttrCount + 1, "can't fit attributes");
if (mAttrCount != i) {
memmove(&Attrs()[i + 1], &Attrs()[i], (mAttrCount - i) * sizeof(InternalAttr));
--- a/dom/base/nsMappedAttributes.h
+++ b/dom/base/nsMappedAttributes.h
@@ -29,17 +29,18 @@ public:
nsMapRuleToAttributesFunc aMapRuleFunc);
// Do not return null.
void* operator new(size_t size, uint32_t aAttrCount = 1) CPP_THROW_NEW;
nsMappedAttributes* Clone(bool aWillAddAttr);
NS_DECL_ISUPPORTS
- void SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue);
+ void SetAndSwapAttr(nsIAtom* aAttrName, nsAttrValue& aValue,
+ bool* aValueWasSet);
const nsAttrValue* GetAttr(nsIAtom* aAttrName) const;
const nsAttrValue* GetAttr(const nsAString& aAttrName) const;
uint32_t Count() const
{
return mAttrCount;
}
--- a/dom/base/nsStyledElement.cpp
+++ b/dom/base/nsStyledElement.cpp
@@ -52,16 +52,17 @@ nsStyledElement::ParseAttribute(int32_t
nsresult
nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
const nsAString* aSerialized,
bool aNotify)
{
SetMayHaveStyle();
bool modification = false;
nsAttrValue oldValue;
+ bool oldValueSet = false;
bool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
// There's no point in comparing the stylerule pointers since we're always
// getting a new stylerule here. And we can't compare the stringvalues of
@@ -69,35 +70,36 @@ nsStyledElement::SetInlineStyleDeclarati
// and thus will be the same.
if (hasListeners) {
// save the old attribute so we can set up the mutation event properly
nsAutoString oldValueStr;
modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style,
oldValueStr);
if (modification) {
oldValue.SetTo(oldValueStr);
+ oldValueSet = true;
}
}
else if (aNotify && IsInUncomposedDoc()) {
modification = !!mAttrsAndChildren.GetAttr(nsGkAtoms::style);
}
nsAttrValue attrValue(do_AddRef(aDeclaration), aSerialized);
// XXXbz do we ever end up with ADDITION here? I doubt it.
uint8_t modType = modification ?
static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
- oldValue, attrValue, modType, hasListeners,
- aNotify, kDontCallAfterSetAttr, document,
- updateBatch);
+ oldValueSet ? &oldValue : nullptr, attrValue, modType,
+ hasListeners, aNotify, kDontCallAfterSetAttr,
+ document, updateBatch);
}
// ---------------------------------------------------------------
// Others and helpers
nsICSSDeclaration*
nsStyledElement::Style()
{
@@ -123,17 +125,19 @@ nsStyledElement::ReparseStyleAttribute(b
const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
if (oldVal && (aForceIfAlreadyParsed || oldVal->Type() != nsAttrValue::eCSSDeclaration)) {
nsAttrValue attrValue;
nsAutoString stringValue;
oldVal->ToString(stringValue);
ParseStyleAttribute(stringValue, attrValue, aForceInDataDoc);
// Don't bother going through SetInlineStyleDeclaration; we don't
// want to fire off mutation events or document notifications anyway
- nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue);
+ bool oldValueSet;
+ nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
+ &oldValueSet);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
void
nsStyledElement::NodeInfoChanged(nsIDocument* aOldDoc)
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -437,20 +437,21 @@ HTMLBodyElement::BindToTree(nsIDocument*
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
return mAttrsAndChildren.ForceMapped(this, OwnerDoc());
}
nsresult
HTMLBodyElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
- bool aNotify)
+ const nsAttrValue* aOldValue, bool aNotify)
{
nsresult rv = nsGenericHTMLElement::AfterSetAttr(aNameSpaceID,
- aName, aValue, aNotify);
+ aName, aValue, aOldValue,
+ aNotify);
NS_ENSURE_SUCCESS(rv, rv);
// if the last mapped attribute was removed, don't clear the
// nsMappedAttributes, our style can still depend on the containing frame element
if (!aValue && IsAttributeMapped(aName)) {
nsresult rv = mAttrsAndChildren.ForceMapped(this, OwnerDoc());
NS_ENSURE_SUCCESS(rv, rv);
}
--- a/dom/html/HTMLBodyElement.h
+++ b/dom/html/HTMLBodyElement.h
@@ -114,17 +114,19 @@ public:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
/**
* Called when an attribute has just been changed
*/
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
protected:
virtual ~HTMLBodyElement();
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
private:
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -423,34 +423,36 @@ HTMLButtonElement::BeforeSetAttr(int32_t
}
return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::type) {
if (aValue) {
mType = aValue->GetEnumValue();
} else {
mType = kButtonDefaultType->value;
}
}
if (aName == nsGkAtoms::type || aName == nsGkAtoms::disabled) {
UpdateBarredFromConstraintValidation();
}
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue,
+ aNotify);
}
NS_IMETHODIMP
HTMLButtonElement::SaveState()
{
if (!mDisabledChanged) {
return NS_OK;
}
--- a/dom/html/HTMLButtonElement.h
+++ b/dom/html/HTMLButtonElement.h
@@ -81,18 +81,20 @@ public:
* Called when an attribute is about to be changed
*/
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
/**
* Called when an attribute has just been changed
*/
- nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
// nsGenericHTMLElement
virtual bool IsHTMLFocusable(bool aWithMouse,
bool* aIsFocusable,
--- a/dom/html/HTMLFieldSetElement.cpp
+++ b/dom/html/HTMLFieldSetElement.cpp
@@ -78,34 +78,35 @@ HTMLFieldSetElement::GetEventTargetParen
return NS_OK;
}
return nsGenericHTMLFormElement::GetEventTargetParent(aVisitor);
}
nsresult
HTMLFieldSetElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled &&
nsINode::GetFirstChild()) {
if (!mElements) {
mElements = new nsContentList(this, MatchListedElements, nullptr, nullptr,
true);
}
uint32_t length = mElements->Length(true);
for (uint32_t i=0; i<length; ++i) {
static_cast<nsGenericHTMLFormElement*>(mElements->Item(i))
->FieldSetDisabledChanged(aNotify);
}
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
// nsIDOMHTMLFieldSetElement
NS_IMETHODIMP
HTMLFieldSetElement::GetForm(nsIDOMHTMLFormElement** aForm)
{
return nsGenericHTMLFormElement::GetForm(aForm);
--- a/dom/html/HTMLFieldSetElement.h
+++ b/dom/html/HTMLFieldSetElement.h
@@ -38,17 +38,19 @@ public:
// nsIDOMHTMLFieldSetElement
NS_DECL_NSIDOMHTMLFIELDSETELEMENT
// nsIContent
virtual nsresult GetEventTargetParent(
EventChainPreVisitor& aVisitor) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult InsertChildAt(nsIContent* aChild, uint32_t aIndex,
bool aNotify) override;
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
// nsIFormControl
NS_IMETHOD Reset() override;
NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -211,33 +211,35 @@ HTMLFormElement::SetAttr(int32_t aNameSp
mNotifiedObservers = notifiedObservers;
}
return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
aNotify);
}
nsresult
HTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) {
// Update all form elements states because they might be [no longer]
// affected by :-moz-ui-valid or :-moz-ui-invalid.
for (uint32_t i = 0, length = mControls->mElements.Length();
i < length; ++i) {
mControls->mElements[i]->UpdateState(true);
}
for (uint32_t i = 0, length = mControls->mNotInElements.Length();
i < length; ++i) {
mControls->mNotInElements[i]->UpdateState(true);
}
}
- return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify);
+ return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
+ aOldValue, aNotify);
}
NS_IMPL_STRING_ATTR(HTMLFormElement, AcceptCharset, acceptcharset)
NS_IMPL_ACTION_ATTR(HTMLFormElement, Action, action)
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Autocomplete, autocomplete,
kFormDefaultAutocomplete->tag)
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Enctype, enctype,
kFormDefaultEnctype->tag)
--- a/dom/html/HTMLFormElement.h
+++ b/dom/html/HTMLFormElement.h
@@ -109,17 +109,19 @@ public:
const nsAString& aValue, bool aNotify)
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
}
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* Forget all information about the current submission (and the fact that we
* are currently submitting at all).
*/
void ForgetCurrentSubmission();
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
--- a/dom/html/HTMLIFrameElement.cpp
+++ b/dom/html/HTMLIFrameElement.cpp
@@ -169,27 +169,27 @@ HTMLIFrameElement::SetAttr(int32_t aName
}
return NS_OK;
}
nsresult
HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
- bool aNotify)
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::sandbox &&
aNameSpaceID == kNameSpaceID_None && mFrameLoader) {
// If we have an nsFrameLoader, apply the new sandbox flags.
// Since this is called after the setter, the sandbox flags have
// alreay been updated.
mFrameLoader->ApplySandboxFlags(GetSandboxFlags());
}
return nsGenericHTMLFrameElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
HTMLIFrameElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify)
{
// Invoke on the superclass.
nsresult rv = nsGenericHTMLFrameElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -52,16 +52,17 @@ public:
{
return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
}
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify) override;
uint32_t GetSandboxFlags();
// Web IDL binding methods
// The XPCOM GetSrc is fine for our purposes
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -384,17 +384,18 @@ HTMLImageElement::BeforeSetAttr(int32_t
}
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool 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,
@@ -426,17 +427,17 @@ HTMLImageElement::AfterSetAttr(int32_t a
aNameSpaceID == kNameSpaceID_None) {
PictureSourceSrcsetChanged(this, attrVal.String(), aNotify);
} else if (aName == nsGkAtoms::sizes &&
aNameSpaceID == kNameSpaceID_None) {
PictureSourceSizesChanged(this, attrVal.String(), aNotify);
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
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
@@ -344,17 +344,19 @@ protected:
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
void UpdateFormOwner();
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
// Override for nsImageLoadingContent.
nsIContent* AsContent() override { return this; }
// This is a weak reference that this element and the HTMLFormElement
// cooperate in maintaining.
HTMLFormElement* mForm;
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1390,17 +1390,18 @@ HTMLInputElement::BeforeSetAttr(int32_t
}
return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
//
// When name or type changes, radio should be added to radio group.
// (type changes are handled in the form itself currently)
// If we are not done creating the radio, we also should not do it.
//
if ((aName == nsGkAtoms::name ||
@@ -1512,17 +1513,18 @@ HTMLInputElement::AfterSetAttr(int32_t a
}
} else if (aName == nsGkAtoms::autocomplete) {
// Clear the cached @autocomplete attribute state.
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
}
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue,
+ aNotify);
}
void
HTMLInputElement::BeforeSetForm(bool aBindToTree)
{
// No need to remove from radio group if we are just binding to tree.
if (mType == NS_FORM_INPUT_RADIO && !aBindToTree) {
WillRemoveFromRadioGroup();
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -977,17 +977,19 @@ protected:
*/
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
/**
* Called when an attribute has just been changed
*/
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual void BeforeSetForm(bool aBindToTree) override;
virtual void AfterClearForm(bool aUnbindOrDelete) override;
/**
* Dispatch a select event. Returns true if the event was not cancelled.
*/
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -341,17 +341,18 @@ HTMLLinkElement::BeforeSetAttr(int32_t a
}
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
// It's safe to call ResetLinkState here because our new attr value has
// already been set or unset. ResetLinkState needs the updated attribute
// value because notifying the document that content states have changed will
// call IntrinsicState, which will try to get updated information about the
// visitedness from Link.
if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
bool hasHref = aValue;
@@ -410,17 +411,17 @@ HTMLLinkElement::AfterSetAttr(int32_t aN
if (aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel) {
UpdateImport();
}
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
HTMLLinkElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
return GetEventTargetParentForAnchors(aVisitor);
}
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -62,16 +62,17 @@ public:
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
virtual bool IsLink(nsIURI** aURI) const override;
virtual already_AddRefed<nsIURI> GetHrefURI() const override;
// Element
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4199,17 +4199,18 @@ nsresult HTMLMediaElement::UnsetAttr(int
}
}
return rv;
}
nsresult
HTMLMediaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
mSrcMediaSource = nullptr;
if (aValue) {
nsString srcStr = aValue->GetStringValue();
nsCOMPtr<nsIURI> uri;
NewURIFromString(srcStr, getter_AddRefs(uri));
if (uri && IsMediaSourceURI(uri)) {
@@ -4221,17 +4222,17 @@ HTMLMediaElement::AfterSetAttr(int32_t a
const char16_t* params[] = { spec.get() };
ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
}
}
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
{
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument,
aParent,
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -133,16 +133,17 @@ public:
}
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify) override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
virtual void DoneCreatingElement() override;
--- a/dom/html/HTMLMenuElement.cpp
+++ b/dom/html/HTMLMenuElement.cpp
@@ -110,28 +110,29 @@ HTMLMenuElement::Build(nsIMenuBuilder* a
return;
}
BuildSubmenu(EmptyString(), this, aBuilder);
}
nsresult
HTMLMenuElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::type) {
if (aValue) {
mType = aValue->GetEnumValue();
} else {
mType = kMenuDefaultType->value;
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
bool
HTMLMenuElement::ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult)
{
--- a/dom/html/HTMLMenuElement.h
+++ b/dom/html/HTMLMenuElement.h
@@ -25,18 +25,20 @@ public:
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLMenuElement, menu)
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMHTMLMenuElement
NS_DECL_NSIDOMHTMLMENUELEMENT
- nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -369,17 +369,18 @@ HTMLMenuItemElement::GetText(nsAString&
nsContentUtils::GetNodeTextContent(this, false, text);
text.CompressWhitespace(true, true);
aText = text;
}
nsresult
HTMLMenuItemElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
// Handle type changes first, since some of the later conditions in this
// method look at mType and want to see the new value.
if (aName == nsGkAtoms::type) {
if (aValue) {
mType = aValue->GetEnumValue();
} else {
@@ -403,17 +404,17 @@ HTMLMenuItemElement::AfterSetAttr(int32_
mShouldInitChecked = true;
} else {
InitChecked();
}
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
void
HTMLMenuItemElement::WalkRadioGroup(Visitor* aVisitor)
{
nsIContent* parent = GetParent();
if (!parent) {
aVisitor->Visit(this);
--- a/dom/html/HTMLMenuItemElement.h
+++ b/dom/html/HTMLMenuItemElement.h
@@ -121,17 +121,19 @@ public:
protected:
virtual ~HTMLMenuItemElement();
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
protected:
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
void WalkRadioGroup(Visitor* aVisitor);
HTMLMenuItemElement* GetSelectedRadio();
void AddedToRadioGroup();
void InitChecked();
--- a/dom/html/HTMLMetaElement.cpp
+++ b/dom/html/HTMLMetaElement.cpp
@@ -55,17 +55,18 @@ HTMLMetaElement::SetMetaReferrer(nsIDocu
content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
aDocument->SetHeaderData(nsGkAtoms::referrer, content);
}
return NS_OK;
}
nsresult
HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
nsIDocument *document = GetUncomposedDoc();
if (aName == nsGkAtoms::content) {
if (document && AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
nsGkAtoms::viewport, eIgnoreCase)) {
nsAutoString content;
nsresult rv = GetContent(content);
@@ -77,17 +78,17 @@ HTMLMetaElement::AfterSetAttr(int32_t aN
// Update referrer policy when it got changed from JS
nsresult rv = SetMetaReferrer(document);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
{
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
--- a/dom/html/HTMLMetaElement.h
+++ b/dom/html/HTMLMetaElement.h
@@ -28,17 +28,19 @@ public:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName);
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
// XPCOM GetName is fine.
void SetName(const nsAString& aName, ErrorResult& aRv)
--- a/dom/html/HTMLOptGroupElement.cpp
+++ b/dom/html/HTMLOptGroupElement.cpp
@@ -97,32 +97,33 @@ HTMLOptGroupElement::RemoveChildAt(uint3
{
SafeOptionListMutation safeMutation(GetSelect(), this, nullptr, aIndex,
aNotify);
nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify);
}
nsresult
HTMLOptGroupElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled) {
// All our children <option> have their :disabled state depending on our
// disabled attribute. We should make sure their state is updated.
for (nsIContent* child = nsINode::GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->IsHTMLElement(nsGkAtoms::option)) {
// No need to call |IsElement()| because it's an HTML element.
child->AsElement()->UpdateState(true);
}
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
EventStates
HTMLOptGroupElement::IntrinsicState() const
{
EventStates state = nsGenericHTMLElement::IntrinsicState();
if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
--- a/dom/html/HTMLOptGroupElement.h
+++ b/dom/html/HTMLOptGroupElement.h
@@ -39,17 +39,19 @@ public:
EventChainPreVisitor& aVisitor) override;
virtual EventStates IntrinsicState() const override;
virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
bool aPreallocateChildren) const override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsIDOMNode* AsDOMNode() override { return this; }
virtual bool IsDisabled() const override {
return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
}
bool Disabled() const
--- a/dom/html/HTMLOptionElement.cpp
+++ b/dom/html/HTMLOptionElement.cpp
@@ -239,31 +239,32 @@ HTMLOptionElement::BeforeSetAttr(int32_t
// more than once; make sure our mSelectedChanged state is set correctly.
mSelectedChanged = mIsSelected != defaultSelected;
return NS_OK;
}
nsresult
HTMLOptionElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None &&
aName == nsGkAtoms::value && Selected()) {
// Since this option is selected, changing value
// may have changed missing validity state of the
// Select element
HTMLSelectElement* select = GetSelect();
if (select) {
select->UpdateValueMissingValidityState();
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
NS_IMETHODIMP
HTMLOptionElement::GetText(nsAString& aText)
{
nsAutoString text;
nsIContent* child = nsINode::GetFirstChild();
--- a/dom/html/HTMLOptionElement.h
+++ b/dom/html/HTMLOptionElement.h
@@ -45,17 +45,19 @@ public:
virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
int32_t aModType) const override;
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
void SetSelectedInternal(bool aValue, bool aNotify);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -229,23 +229,24 @@ HTMLScriptElement::NoModule()
void
HTMLScriptElement::SetNoModule(bool aValue, ErrorResult& aRv)
{
SetHTMLBoolAttr(nsGkAtoms::nomodule, aValue, aRv);
}
nsresult
HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
mForceAsync = false;
}
return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
NS_IMETHODIMP
HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML)
{
if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
--- a/dom/html/HTMLScriptElement.h
+++ b/dom/html/HTMLScriptElement.h
@@ -53,17 +53,19 @@ public:
const nsAString& aValue,
nsAttrValue& aResult) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
// Element
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
// WebIDL
void SetText(const nsAString& aValue, ErrorResult& rv);
void SetCharset(const nsAString& aCharset, ErrorResult& rv);
void SetDefer(bool aDefer, ErrorResult& rv);
bool Defer();
void SetSrc(const nsAString& aSrc, ErrorResult& rv);
void SetType(const nsAString& aType, ErrorResult& rv);
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1305,31 +1305,33 @@ HTMLSelectElement::BeforeSetAttr(int32_t
}
return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::disabled) {
UpdateBarredFromConstraintValidation();
} else if (aName == nsGkAtoms::required) {
UpdateValueMissingValidityState();
} else if (aName == nsGkAtoms::autocomplete) {
// Clear the cached @autocomplete attribute state
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
}
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue,
+ aNotify);
}
nsresult
HTMLSelectElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify)
{
if (aNotify && aNameSpaceID == kNameSpaceID_None &&
aAttribute == nsGkAtoms::multiple) {
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -379,17 +379,19 @@ public:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify) override;
virtual void DoneAddingChildren(bool aHaveNotified) override;
virtual bool IsDoneAddingChildren() override {
return mIsDoneAddingChildren;
}
--- a/dom/html/HTMLSourceElement.cpp
+++ b/dom/html/HTMLSourceElement.cpp
@@ -90,17 +90,18 @@ HTMLSourceElement::UpdateMediaList(const
}
nsCSSParser cssParser;
mMediaList = MediaList::Create(OwnerDoc()->GetStyleBackendType(), mediaStr);
}
nsresult
HTMLSourceElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
// If we are associated with a <picture> with a valid <img>, notify it of
// responsive parameter changes
Element *parent = nsINode::GetParentElement();
if (aNameSpaceID == kNameSpaceID_None &&
(aName == nsGkAtoms::srcset ||
aName == nsGkAtoms::sizes ||
aName == nsGkAtoms::media ||
@@ -135,17 +136,17 @@ HTMLSourceElement::AfterSetAttr(int32_t
NewURIFromString(srcStr, getter_AddRefs(uri));
if (uri && IsMediaSourceURI(uri)) {
NS_GetSourceForMediaSourceURI(uri, getter_AddRefs(mSrcMediaSource));
}
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
nsresult
HTMLSourceElement::BindToTree(nsIDocument *aDocument,
nsIContent *aParent,
nsIContent *aBindingParent,
bool aCompileEventHandlers)
{
--- a/dom/html/HTMLSourceElement.h
+++ b/dom/html/HTMLSourceElement.h
@@ -107,16 +107,17 @@ public:
protected:
virtual ~HTMLSourceElement();
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
protected:
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
private:
RefPtr<MediaList> mMediaList;
RefPtr<MediaSource> mSrcMediaSource;
// Generates a new MediaList using the given input
void UpdateMediaList(const nsAttrValue* aValue);
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -166,31 +166,32 @@ HTMLStyleElement::UnbindFromTree(bool aD
return;
}
UpdateStyleSheetInternal(oldDoc, oldShadow);
}
nsresult
HTMLStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
} else if (aName == nsGkAtoms::scoped) {
bool isScoped = aValue;
UpdateStyleSheetScopedness(isScoped);
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
NS_IMETHODIMP
HTMLStyleElement::GetInnerHTML(nsAString& aInnerHTML)
{
if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
--- a/dom/html/HTMLStyleElement.h
+++ b/dom/html/HTMLStyleElement.h
@@ -43,16 +43,17 @@ public:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep = true,
bool aNullParent = true) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -879,17 +879,19 @@ HTMLTableElement::BuildInheritedAttribut
if (sheet) {
const nsAttrValue* value = mAttrsAndChildren.GetAttr(nsGkAtoms::cellpadding);
if (value) {
RefPtr<nsMappedAttributes> modifiableMapped = new
nsMappedAttributes(sheet, MapInheritedTableAttributesIntoRule);
if (modifiableMapped) {
nsAttrValue val(*value);
- modifiableMapped->SetAndTakeAttr(nsGkAtoms::cellpadding, val);
+ bool oldValueSet;
+ modifiableMapped->SetAndSwapAttr(nsGkAtoms::cellpadding, val,
+ &oldValueSet);
}
newAttrs = sheet->UniqueMappedAttributes(modifiableMapped);
NS_ASSERTION(newAttrs, "out of memory, but handling gracefully");
if (newAttrs != modifiableMapped) {
// Reset the stylesheet of modifiableMapped so that it doesn't
// spend time trying to remove itself from the hash. There is no
// risk that modifiableMapped is in the hash since we created
@@ -940,19 +942,19 @@ HTMLTableElement::BeforeSetAttr(int32_t
}
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
aNotify);
}
nsresult
HTMLTableElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
- bool aNotify)
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
BuildInheritedAttributes();
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
} // namespace dom
} // namespace mozilla
--- a/dom/html/HTMLTableElement.h
+++ b/dom/html/HTMLTableElement.h
@@ -202,17 +202,19 @@ public:
*/
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
/**
* Called when an attribute has just been changed
*/
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTableElement,
nsGenericHTMLElement)
nsMappedAttributes* GetAttributesMappedForCell();
protected:
virtual ~HTMLTableElement();
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -1094,17 +1094,18 @@ HTMLTextAreaElement::ContentChanged(nsIC
// further auditing.
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
Reset();
}
}
nsresult
HTMLTextAreaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
aName == nsGkAtoms::readonly) {
UpdateValueMissingValidityState();
// This *has* to be called *after* validity has changed.
if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
@@ -1113,17 +1114,17 @@ HTMLTextAreaElement::AfterSetAttr(int32_
} else if (aName == nsGkAtoms::maxlength) {
UpdateTooLongValidityState();
} else if (aName == nsGkAtoms::minlength) {
UpdateTooShortValidityState();
}
}
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
nsresult
HTMLTextAreaElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
{
nsresult rv = nsGenericHTMLFormElementWithState::CopyInnerTo(aDest,
aPreallocateChildren);
NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/html/HTMLTextAreaElement.h
+++ b/dom/html/HTMLTextAreaElement.h
@@ -360,17 +360,19 @@ protected:
/**
* Common method to call from the various mutation observer methods.
* aContent is a content node that's either the one that changed or its
* parent; we should only respond to the change if aContent is non-anonymous.
*/
void ContentChanged(nsIContent* aContent);
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom *aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* Return if an element should have a specific validity UI
* (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes).
*
* @return Whether the element should have a validity UI.
*/
bool ShouldShowValidityUI() const {
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -640,17 +640,18 @@ nsGenericHTMLElement::GetHrefURIForAncho
nsCOMPtr<nsIURI> uri;
GetURIAttr(nsGkAtoms::href, nullptr, getter_AddRefs(uri));
return uri.forget();
}
nsresult
nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None) {
if (IsEventAttributeName(aName) && aValue) {
MOZ_ASSERT(aValue->Type() == nsAttrValue::eString,
"Expected string value for script body");
nsresult rv = SetEventHandler(aName, aValue->GetStringValue());
NS_ENSURE_SUCCESS(rv, rv);
}
@@ -681,17 +682,17 @@ nsGenericHTMLElement::AfterSetAttr(int32
dir = RecomputeDirectionality(this, aNotify);
}
}
SetDirectionalityOnDescendants(this, dir, aNotify);
}
}
return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
EventListenerManager*
nsGenericHTMLElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
bool* aDefer)
{
// Attributes on the body and frameset tags get set on the global object
if ((mNodeInfo->Equals(nsGkAtoms::body) ||
@@ -1964,17 +1965,18 @@ nsGenericHTMLFormElement::BeforeSetAttr(
}
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
// add the control to the hashtable as needed
if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
aValue && !aValue->IsEmptyString()) {
MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom,
"Expected atom value for name/id");
@@ -2013,17 +2015,17 @@ nsGenericHTMLFormElement::AfterSetAttr(i
// Because we have a new @form value (or no more @form), we have to
// update our form owner.
UpdateFormOwner(false, formIdElement);
}
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
nsresult
nsGenericHTMLFormElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
{
if (aVisitor.mEvent->IsTrusted() && (aVisitor.mEvent->mMessage == eFocus ||
aVisitor.mEvent->mMessage == eBlur)) {
// We have to handle focus/blur event to change focus states in
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -938,17 +938,19 @@ protected:
}
}
private:
void RegUnRegAccessKey(bool aDoReg);
protected:
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual mozilla::EventListenerManager*
GetEventListenerManagerForAttr(nsIAtom* aAttrName,
bool* aDefer) override;
/**
* Dispatch a simulated mouse click by keyboard to the given element.
*/
@@ -1296,17 +1298,19 @@ public:
protected:
virtual ~nsGenericHTMLFormElement();
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual void BeforeSetForm(bool aBindToTree) {}
virtual void AfterClearForm(bool aUnbindOrDelete) {}
void SetForm(mozilla::dom::HTMLFormElement* aForm, bool aBindToTree);
/**
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -381,17 +381,17 @@ PrincipalAllowsBrowserFrame(nsIPrincipal
nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, "browser", &permission);
NS_ENSURE_SUCCESS(rv, false);
return permission == nsIPermissionManager::ALLOW_ACTION;
}
/* virtual */ nsresult
nsGenericHTMLFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
- bool aNotify)
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::scrolling && aNameSpaceID == kNameSpaceID_None) {
if (mFrameLoader) {
nsIDocShell* docshell = mFrameLoader->GetExistingDocShell();
nsCOMPtr<nsIScrollable> scrollable = do_QueryInterface(docshell);
if (scrollable) {
int32_t cur;
scrollable->GetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, &cur);
@@ -413,17 +413,17 @@ nsGenericHTMLFrameElement::AfterSetAttr(
}
if (aName == nsGkAtoms::mozbrowser && aNameSpaceID == kNameSpaceID_None) {
mReallyIsBrowser = !!aValue && BrowserFramesEnabled() &&
PrincipalAllowsBrowserFrame(NodePrincipal());
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
}
void
nsGenericHTMLFrameElement::DestroyContent()
{
if (mFrameLoader) {
mFrameLoader->Destroy();
mFrameLoader = nullptr;
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -60,16 +60,17 @@ public:
}
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify) override;
virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
bool aNotify) override;
virtual void DestroyContent() override;
nsresult CopyInnerTo(mozilla::dom::Element* aDest, bool aPreallocateChildren);
virtual int32_t TabIndexDefault() override;
virtual nsIMozBrowserFrame* GetAsMozBrowserFrame() override { return this; }
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -278,21 +278,22 @@ SVGAnimationElement::ParseAttribute(int3
}
return SVGAnimationElementBase::ParseAttribute(aNamespaceID, aAttribute,
aValue, aResult);
}
nsresult
SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
nsresult rv =
SVGAnimationElementBase::AfterSetAttr(aNamespaceID, aName, aValue,
- aNotify);
+ aOldValue, aNotify);
if (SVGTests::IsConditionalProcessingAttribute(aName)) {
bool isDisabled = !SVGTests::PassesConditionalProcessingTests();
if (mTimedElement.SetIsDisabled(isDisabled)) {
AnimationNeedsResample();
}
}
--- a/dom/svg/SVGAnimationElement.h
+++ b/dom/svg/SVGAnimationElement.h
@@ -54,17 +54,19 @@ public:
virtual bool IsNodeOfType(uint32_t aFlags) const override;
// Element specializations
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
const nsAttrValue* GetAnimAttr(nsIAtom* aName) const;
bool GetAnimAttr(nsIAtom* aAttName, nsAString& aResult) const;
bool HasAnimAttr(nsIAtom* aAttName) const;
Element* GetTargetElementContent();
virtual bool GetTargetAttributeName(int32_t* aNamespaceID,
nsIAtom** aLocalName) const;
nsSMILTimedElement& TimedElement();
--- a/dom/svg/SVGFEImageElement.cpp
+++ b/dom/svg/SVGFEImageElement.cpp
@@ -114,31 +114,32 @@ SVGFEImageElement::IsAttributeMapped(con
};
return FindAttributeDependence(name, map) ||
SVGFEImageElementBase::IsAttributeMapped(name);
}
nsresult
SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::href &&
(aNamespaceID == kNameSpaceID_XLink ||
aNamespaceID == kNameSpaceID_None)) {
if (aValue) {
LoadSVGImage(true, aNotify);
} else {
CancelImageRequests(aNotify);
}
}
return SVGFEImageElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
void
SVGFEImageElement::MaybeLoadSVGImage()
{
if ((mStringAttributes[HREF].IsExplicitlySet() ||
mStringAttributes[XLINK_HREF].IsExplicitlySet() ) &&
(NS_FAILED(LoadSVGImage(false, true)) ||
--- a/dom/svg/SVGFEImageElement.h
+++ b/dom/svg/SVGFEImageElement.h
@@ -54,17 +54,19 @@ public:
// nsIContent
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual EventStates IntrinsicState() const override;
NS_IMETHOD Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData) override;
--- a/dom/svg/SVGGeometryElement.cpp
+++ b/dom/svg/SVGGeometryElement.cpp
@@ -31,25 +31,26 @@ SVGGeometryElement::SVGGeometryElement(a
nsSVGElement::NumberAttributesInfo
SVGGeometryElement::GetNumberInfo()
{
return NumberAttributesInfo(&mPathLength, &sNumberInfo, 1);
}
nsresult
SVGGeometryElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (mCachedPath &&
aNamespaceID == kNameSpaceID_None &&
AttributeDefinesGeometry(aName)) {
mCachedPath = nullptr;
}
return SVGGeometryElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
bool
SVGGeometryElement::AttributeDefinesGeometry(const nsIAtom *aName)
{
if (aName == nsGkAtoms::pathLength) {
return true;
}
--- a/dom/svg/SVGGeometryElement.h
+++ b/dom/svg/SVGGeometryElement.h
@@ -47,17 +47,19 @@ protected:
typedef mozilla::gfx::PathBuilder PathBuilder;
typedef mozilla::gfx::Rect Rect;
typedef mozilla::gfx::StrokeOptions StrokeOptions;
public:
explicit SVGGeometryElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
/**
* Causes this element to discard any Path object that GetOrBuildPath may
* have cached.
*/
virtual void ClearAnyCachedPath() override final {
mCachedPath = nullptr;
}
--- a/dom/svg/SVGImageElement.cpp
+++ b/dom/svg/SVGImageElement.cpp
@@ -145,30 +145,31 @@ SVGImageElement::AsyncEventRunning(Async
nsImageLoadingContent::AsyncEventRunning(aEvent);
}
//----------------------------------------------------------------------
// nsIContent methods:
nsresult
SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aName == nsGkAtoms::href &&
(aNamespaceID == kNameSpaceID_None ||
aNamespaceID == kNameSpaceID_XLink)) {
if (aValue) {
LoadSVGImage(true, aNotify);
} else {
CancelImageRequests(aNotify);
}
}
return SVGImageElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
void
SVGImageElement::MaybeLoadSVGImage()
{
if ((mStringAttributes[HREF].IsExplicitlySet() ||
mStringAttributes[XLINK_HREF].IsExplicitlySet()) &&
(NS_FAILED(LoadSVGImage(false, true)) ||
--- a/dom/svg/SVGImageElement.h
+++ b/dom/svg/SVGImageElement.h
@@ -41,17 +41,19 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// EventTarget
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
// nsIContent interface
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
virtual EventStates IntrinsicState() const override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;
--- a/dom/svg/SVGScriptElement.cpp
+++ b/dom/svg/SVGScriptElement.cpp
@@ -228,25 +228,26 @@ SVGScriptElement::BindToTree(nsIDocument
MaybeProcessScript();
}
return NS_OK;
}
nsresult
SVGScriptElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if ((aNamespaceID == kNameSpaceID_XLink ||
aNamespaceID == kNameSpaceID_None) &&
aName == nsGkAtoms::href) {
MaybeProcessScript();
}
return SVGScriptElementBase::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
bool
SVGScriptElement::ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult)
{
--- a/dom/svg/SVGScriptElement.h
+++ b/dom/svg/SVGScriptElement.h
@@ -50,17 +50,19 @@ public:
// ScriptElement
virtual bool HasScriptContent() override;
// nsIContent specializations:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers) override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
bool aPreallocateChildren) const override;
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -273,26 +273,29 @@ nsSVGElement::BindToTree(nsIDocument* aD
// ownerDocument on XBL anonymous content, this can all go away.
nsAttrValue attrValue;
nsAutoString stringValue;
oldVal->ToString(stringValue);
// Force in data doc, since we already have a style rule
ParseStyleAttribute(stringValue, attrValue, true);
// Don't bother going through SetInlineStyleDeclaration; we don't
// want to fire off mutation events or document notifications anyway
- rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue);
+ bool oldValueSet;
+ rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
+ &oldValueSet);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult
nsSVGElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
// We don't currently use nsMappedAttributes within SVG. If this changes, we
// need to be very careful because some nsAttrValues used by SVG point to
// member data of SVG elements and if an nsAttrValue outlives the SVG element
// whose data it points to (by virtue of being stored in
// mAttrsAndChildren->mMappedAttributes, meaning it's shared between
// elements), the pointer will dangle. See bug 724680.
MOZ_ASSERT(!mAttrsAndChildren.HasMappedAttrs(),
@@ -312,17 +315,18 @@ nsSVGElement::AfterSetAttr(int32_t aName
if (IsEventAttributeName(aName) && aValue) {
MOZ_ASSERT(aValue->Type() == nsAttrValue::eString,
"Expected string value for script body");
nsresult rv = SetEventHandler(GetEventNameForAttr(aName),
aValue->GetStringValue());
NS_ENSURE_SUCCESS(rv, rv);
}
- return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aNotify);
+ return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aOldValue,
+ aNotify);
}
bool
nsSVGElement::ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult)
{
@@ -1470,17 +1474,21 @@ nsSVGElement::DidChangeValue(nsIAtom* aN
this);
uint8_t modType = HasAttr(kNameSpaceID_None, aName)
? static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION)
: static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL,
kNotifyDocumentObservers);
- SetAttrAndNotify(kNameSpaceID_None, aName, nullptr, aEmptyOrOldValue,
+ // XXX Really, the fourth argument to SetAttrAndNotify should be null if
+ // aEmptyOrOldValue does not represent the actual previous value of the
+ // attribute, but currently SVG elements do not even use the old attribute
+ // value in |AfterSetAttr|, so this should be ok.
+ SetAttrAndNotify(kNameSpaceID_None, aName, nullptr, &aEmptyOrOldValue,
aNewValue, modType, hasListeners, kNotifyDocumentObservers,
kCallAfterSetAttr, document, updateBatch);
}
void
nsSVGElement::MaybeSerializeAttrBeforeRemoval(nsIAtom* aName, bool aNotify)
{
if (!aNotify ||
@@ -1492,17 +1500,18 @@ nsSVGElement::MaybeSerializeAttrBeforeRe
const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(aName);
if (!attrValue)
return;
nsAutoString serializedValue;
attrValue->ToString(serializedValue);
nsAttrValue oldAttrValue(serializedValue);
- mAttrsAndChildren.SetAndSwapAttr(aName, oldAttrValue);
+ bool oldValueSet;
+ mAttrsAndChildren.SetAndSwapAttr(aName, oldAttrValue, &oldValueSet);
}
/* static */
nsIAtom* nsSVGElement::GetEventNameForAttr(nsIAtom* aAttr)
{
if (aAttr == nsGkAtoms::onload)
return nsGkAtoms::onSVGLoad;
if (aAttr == nsGkAtoms::onunload)
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -347,17 +347,19 @@ protected:
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override final
{
return nsSVGElementBase::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify);
}
#endif // DEBUG
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID, nsIAtom* aAttribute,
const nsAString& aValue, nsAttrValue& aResult) override;
static nsresult ReportAttributeParseFailure(nsIDocument* aDocument,
nsIAtom* aAttribute,
const nsAString& aValue);
nsAttrValue WillChangeValue(nsIAtom* aName);
// aNewValue is set to the old value. This value may be invalid if
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -391,22 +391,25 @@ nsXULElement::Clone(mozilla::dom::NodeIn
nsString stringValue;
originalValue->ToString(stringValue);
attrValue.SetTo(declClone.forget(), &stringValue);
} else {
attrValue.SetTo(*originalValue);
}
+ bool oldValueSet;
if (originalName->IsAtom()) {
rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->Atom(),
- attrValue);
+ attrValue,
+ &oldValueSet);
} else {
rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->NodeInfo(),
- attrValue);
+ attrValue,
+ &oldValueSet);
}
NS_ENSURE_SUCCESS(rv, rv);
element->AddListenerFor(*originalName, true);
if (originalName->Equals(nsGkAtoms::id) &&
!originalValue->IsEmptyString()) {
element->SetHasID();
}
if (originalName->Equals(nsGkAtoms::_class)) {
@@ -1064,17 +1067,18 @@ nsXULElement::BeforeSetAttr(int32_t aNam
}
return nsStyledElement::BeforeSetAttr(aNamespaceID, aName,
aValue, aNotify);
}
nsresult
nsXULElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify)
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, bool aNotify)
{
if (aNamespaceID == kNameSpaceID_None) {
if (aValue) {
// Add popup and event listeners. We can't call AddListenerFor since
// the attribute isn't set yet.
MaybeAddPopupListener(aName);
if (nsContentUtils::IsEventAttributeName(aName, EventNameType_XUL)) {
if (aValue->Type() == nsAttrValue::eString) {
@@ -1185,17 +1189,17 @@ nsXULElement::AfterSetAttr(int32_t aName
}
}
// XXX need to check if they're changing an event handler: if
// so, then we need to unhook the old one. Or something.
}
return nsStyledElement::AfterSetAttr(aNamespaceID, aName,
- aValue, aNotify);
+ aValue, aOldValue, aNotify);
}
bool
nsXULElement::ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult)
{
@@ -1787,22 +1791,24 @@ nsXULElement::MakeHeavyweight(nsXULProto
nsString stringValue;
protoattr->mValue.ToString(stringValue);
attrValue.SetTo(declClone.forget(), &stringValue);
} else {
attrValue.SetTo(protoattr->mValue);
}
+ bool oldValueSet;
// XXX we might wanna have a SetAndTakeAttr that takes an nsAttrName
if (protoattr->mName.IsAtom()) {
- rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.Atom(), attrValue);
+ rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.Atom(),
+ attrValue, &oldValueSet);
} else {
rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.NodeInfo(),
- attrValue);
+ attrValue, &oldValueSet);
}
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult
nsXULElement::HideWindowChrome(bool aShouldHide)
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -750,17 +750,19 @@ protected:
* Abandon our prototype linkage, and copy all attributes locally
*/
nsresult MakeHeavyweight(nsXULPrototypeElement* aPrototype);
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue, bool aNotify) override;
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ bool aNotify) override;
virtual void UpdateEditableState(bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;