From e74f1cd51351a7d87acc786b788703c30bbc992d Mon Sep 17 00:00:00 2001 From: Kirk Steuber Date: Thu, 18 May 2017 14:09:01 -0700 Subject: [PATCH] Bug 1363481 - Add the old attribute value as a parameter to Element::AfterSetAttr r=bz In order to facilitate the movement of code with side-effects called by Element::SetAttr to Element::BeforeSetAttr and Element::AfterSetAttr, Element::AfterSetAttr should have access to the old value of the attribute. This includes information about whether there was previously a value set or not. Accomplishing this involved passing an additional argument through functions that find and change the old attribute value in order to ensure that we can differentiate between an empty old value and an absent old value (attribute was not set). Note that while I tried to ensure that accurate values (and their absence) are reported to Element::AfterSetAttr, I largely ignored SVG. While the old value reported for SVG values should be however accurate the value already being reported to SetAttrAndNotify was, SVG elements do not currently report unset values properly because they will never pass a null pointer to SetAttrAndNotify. MozReview-Commit-ID: K1mha8CNFZP --HG-- extra : rebase_source : 42776eb01451d371e4aebcc17fe3dd112c8d268b --- dom/base/Element.cpp | 75 ++++++++++++++++++-------- dom/base/Element.h | 71 ++++++++++++++++++------ dom/base/nsAttrAndChildArray.cpp | 21 +++++--- dom/base/nsAttrAndChildArray.h | 18 +++++-- dom/base/nsMappedAttributeElement.cpp | 11 ++-- dom/base/nsMappedAttributeElement.h | 7 +-- dom/base/nsMappedAttributes.cpp | 6 ++- dom/base/nsMappedAttributes.h | 3 +- dom/base/nsStyledElement.cpp | 12 +++-- dom/html/HTMLBodyElement.cpp | 5 +- dom/html/HTMLBodyElement.h | 4 +- dom/html/HTMLButtonElement.cpp | 6 ++- dom/html/HTMLButtonElement.h | 6 ++- dom/html/HTMLFieldSetElement.cpp | 5 +- dom/html/HTMLFieldSetElement.h | 4 +- dom/html/HTMLFormElement.cpp | 6 ++- dom/html/HTMLFormElement.h | 4 +- dom/html/HTMLIFrameElement.cpp | 4 +- dom/html/HTMLIFrameElement.h | 1 + dom/html/HTMLImageElement.cpp | 5 +- dom/html/HTMLImageElement.h | 4 +- dom/html/HTMLInputElement.cpp | 6 ++- dom/html/HTMLInputElement.h | 4 +- dom/html/HTMLLinkElement.cpp | 5 +- dom/html/HTMLLinkElement.h | 1 + dom/html/HTMLMediaElement.cpp | 5 +- dom/html/HTMLMediaElement.h | 1 + dom/html/HTMLMenuElement.cpp | 5 +- dom/html/HTMLMenuElement.h | 6 ++- dom/html/HTMLMenuItemElement.cpp | 5 +- dom/html/HTMLMenuItemElement.h | 4 +- dom/html/HTMLMetaElement.cpp | 5 +- dom/html/HTMLMetaElement.h | 4 +- dom/html/HTMLOptGroupElement.cpp | 5 +- dom/html/HTMLOptGroupElement.h | 4 +- dom/html/HTMLOptionElement.cpp | 5 +- dom/html/HTMLOptionElement.h | 4 +- dom/html/HTMLScriptElement.cpp | 5 +- dom/html/HTMLScriptElement.h | 4 +- dom/html/HTMLSelectElement.cpp | 6 ++- dom/html/HTMLSelectElement.h | 4 +- dom/html/HTMLSourceElement.cpp | 5 +- dom/html/HTMLSourceElement.h | 1 + dom/html/HTMLStyleElement.cpp | 5 +- dom/html/HTMLStyleElement.h | 1 + dom/html/HTMLTableElement.cpp | 8 +-- dom/html/HTMLTableElement.h | 4 +- dom/html/HTMLTextAreaElement.cpp | 5 +- dom/html/HTMLTextAreaElement.h | 4 +- dom/html/nsGenericHTMLElement.cpp | 10 ++-- dom/html/nsGenericHTMLElement.h | 8 ++- dom/html/nsGenericHTMLFrameElement.cpp | 4 +- dom/html/nsGenericHTMLFrameElement.h | 1 + dom/svg/SVGAnimationElement.cpp | 5 +- dom/svg/SVGAnimationElement.h | 4 +- dom/svg/SVGFEImageElement.cpp | 5 +- dom/svg/SVGFEImageElement.h | 4 +- dom/svg/SVGGeometryElement.cpp | 5 +- dom/svg/SVGGeometryElement.h | 4 +- dom/svg/SVGImageElement.cpp | 5 +- dom/svg/SVGImageElement.h | 4 +- dom/svg/SVGScriptElement.cpp | 5 +- dom/svg/SVGScriptElement.h | 4 +- dom/svg/nsSVGElement.cpp | 19 +++++-- dom/svg/nsSVGElement.h | 4 +- dom/xul/nsXULElement.cpp | 18 ++++--- dom/xul/nsXULElement.h | 4 +- 67 files changed, 352 insertions(+), 160 deletions(-) diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 50b347acb436..ad9bf503b926 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -2299,13 +2299,15 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID, 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 @@ -2330,6 +2332,7 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID, // 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()) { @@ -2349,10 +2352,12 @@ 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; } @@ -2383,9 +2388,10 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName, // 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; } @@ -2418,7 +2424,8 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName, attrValue.SetTo(aValue); } - return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue, + return SetAttrAndNotify(aNamespaceID, aName, aPrefix, + oldValueSet ? &oldValue : nullptr, attrValue, modType, hasListeners, aNotify, kCallAfterSetAttr, document, updateBatch); } @@ -2443,9 +2450,10 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName, 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; } @@ -2459,7 +2467,8 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName, 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); } @@ -2468,7 +2477,7 @@ nsresult Element::SetAttrAndNotify(int32_t aNamespaceID, nsIAtom* aName, nsIAtom* aPrefix, - const nsAttrValue& aOldValue, + const nsAttrValue* aOldValue, nsAttrValue& aParsedValue, uint8_t aModType, bool aFireMutation, @@ -2489,6 +2498,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, bool hadValidDir = false; bool hadDirAuto = false; + bool oldValueSet; if (aNamespaceID == kNameSpaceID_None) { if (aName == nsGkAtoms::dir) { @@ -2499,8 +2509,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, // 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 { @@ -2509,14 +2519,24 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, 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 binding = GetXBLBinding(); @@ -2527,7 +2547,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, nsIDocument* ownerDoc = OwnerDoc(); if (ownerDoc && GetCustomElementData()) { - nsCOMPtr oldValueAtom = oldValue->GetAsAtom(); + nsCOMPtr 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 newValueAtom = valueForAfterSetAttr.GetAsAtom(); LifecycleCallbackArgs args = { nsDependentAtomString(aName), @@ -2541,7 +2568,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, } 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) { @@ -2557,7 +2585,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, // 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) { @@ -2575,7 +2603,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, if (!newValue.IsEmpty()) { mutation.mNewAttrValue = NS_Atomize(newValue); } - if (!oldValue->IsEmptyString()) { + if (oldValue && !oldValue->IsEmptyString()) { mutation.mPrevAttrValue = oldValue->GetAsAtom(); } mutation.mAttrChange = aModType; @@ -2618,9 +2646,10 @@ Element::ParseAttribute(int32_t aNamespaceID, } bool -Element::SetMappedAttribute(nsIAtom* aName, - nsAttrValue& aValue, - nsresult* aRetval) +Element::SetAndSwapMappedAttribute(nsIAtom* aName, + nsAttrValue& aValue, + bool* aValueWasSet, + nsresult* aRetval) { *aRetval = NS_OK; return false; @@ -2775,7 +2804,7 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName, 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); diff --git a/dom/base/Element.h b/dom/base/Element.h index 79ee804f9346..3b76cdc223ea 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -631,25 +631,49 @@ public: * 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; @@ -1352,7 +1376,10 @@ protected: * 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. @@ -1366,7 +1393,7 @@ protected: nsresult SetAttrAndNotify(int32_t aNamespaceID, nsIAtom* aName, nsIAtom* aPrefix, - const nsAttrValue& aOldValue, + const nsAttrValue* aOldValue, nsAttrValue& aParsedValue, uint8_t aModType, bool aFireMutation, @@ -1410,13 +1437,20 @@ protected: * 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 @@ -1444,19 +1478,24 @@ protected: /** * 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; } diff --git a/dom/base/nsAttrAndChildArray.cpp b/dom/base/nsAttrAndChildArray.cpp index d229d1e88b33..40159373eabe 100644 --- a/dom/base/nsAttrAndChildArray.cpp +++ b/dom/base/nsAttrAndChildArray.cpp @@ -389,12 +389,15 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const } 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; } } @@ -414,21 +417,22 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue) } 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; } } @@ -583,10 +587,11 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) cons } 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) { @@ -596,7 +601,7 @@ nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName, RefPtr mapped = GetModifiableMapped(aContent, aSheet, willAdd); - mapped->SetAndTakeAttr(aLocalName, aValue); + mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue); return MakeMappedUnique(mapped); } diff --git a/dom/base/nsAttrAndChildArray.h b/dom/base/nsAttrAndChildArray.h index a1deab1f3854..2a5193fa5fbd 100644 --- a/dom/base/nsAttrAndChildArray.h +++ b/dom/base/nsAttrAndChildArray.h @@ -91,8 +91,13 @@ public: 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. @@ -110,9 +115,14 @@ public: 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; diff --git a/dom/base/nsMappedAttributeElement.cpp b/dom/base/nsMappedAttributeElement.cpp index 1408c1f4ba0a..bdbe553ff204 100644 --- a/dom/base/nsMappedAttributeElement.cpp +++ b/dom/base/nsMappedAttributeElement.cpp @@ -15,13 +15,14 @@ nsMappedAttributeElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) } 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; } diff --git a/dom/base/nsMappedAttributeElement.h b/dom/base/nsMappedAttributeElement.h index 0af7a652cc05..cec025dfc68d 100644 --- a/dom/base/nsMappedAttributeElement.h +++ b/dom/base/nsMappedAttributeElement.h @@ -40,9 +40,10 @@ public: 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; }; diff --git a/dom/base/nsMappedAttributes.cpp b/dom/base/nsMappedAttributes.cpp index e6e25337628d..0c5d6f0c615b 100644 --- a/dom/base/nsMappedAttributes.cpp +++ b/dom/base/nsMappedAttributes.cpp @@ -156,14 +156,16 @@ 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; } } diff --git a/dom/base/nsMappedAttributes.h b/dom/base/nsMappedAttributes.h index 2799895f9212..3c1d2707247c 100644 --- a/dom/base/nsMappedAttributes.h +++ b/dom/base/nsMappedAttributes.h @@ -34,7 +34,8 @@ public: 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; diff --git a/dom/base/nsStyledElement.cpp b/dom/base/nsStyledElement.cpp index f01af30bde33..228d3993d32a 100644 --- a/dom/base/nsStyledElement.cpp +++ b/dom/base/nsStyledElement.cpp @@ -57,6 +57,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration, SetMayHaveStyle(); bool modification = false; nsAttrValue oldValue; + bool oldValueSet = false; bool hasListeners = aNotify && nsContentUtils::HasMutationListeners(this, @@ -74,6 +75,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration, oldValueStr); if (modification) { oldValue.SetTo(oldValueStr); + oldValueSet = true; } } else if (aNotify && IsInUncomposedDoc()) { @@ -90,9 +92,9 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration, 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); } // --------------------------------------------------------------- @@ -128,7 +130,9 @@ nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc, bool aForceIfAlread 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); } diff --git a/dom/html/HTMLBodyElement.cpp b/dom/html/HTMLBodyElement.cpp index f0e6513735aa..424355e96c5c 100644 --- a/dom/html/HTMLBodyElement.cpp +++ b/dom/html/HTMLBodyElement.cpp @@ -442,10 +442,11 @@ HTMLBodyElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, 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 diff --git a/dom/html/HTMLBodyElement.h b/dom/html/HTMLBodyElement.h index 0f96b590d78d..cf24bcf2d0f0 100644 --- a/dom/html/HTMLBodyElement.h +++ b/dom/html/HTMLBodyElement.h @@ -119,7 +119,9 @@ public: * 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(); diff --git a/dom/html/HTMLButtonElement.cpp b/dom/html/HTMLButtonElement.cpp index eacaa05f5573..51d21ee51d88 100644 --- a/dom/html/HTMLButtonElement.cpp +++ b/dom/html/HTMLButtonElement.cpp @@ -428,7 +428,8 @@ HTMLButtonElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName, 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) { @@ -445,7 +446,8 @@ HTMLButtonElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, - aValue, aNotify); + aValue, aOldValue, + aNotify); } NS_IMETHODIMP diff --git a/dom/html/HTMLButtonElement.h b/dom/html/HTMLButtonElement.h index 3a05906ef126..0ef5ac27b33f 100644 --- a/dom/html/HTMLButtonElement.h +++ b/dom/html/HTMLButtonElement.h @@ -86,8 +86,10 @@ public: /** * 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, diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp index b6bfca950b47..723a7d55fc77 100644 --- a/dom/html/HTMLFieldSetElement.cpp +++ b/dom/html/HTMLFieldSetElement.cpp @@ -83,7 +83,8 @@ HTMLFieldSetElement::GetEventTargetParent(EventChainPreVisitor& 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()) { @@ -100,7 +101,7 @@ HTMLFieldSetElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, - aValue, aNotify); + aValue, aOldValue, aNotify); } // nsIDOMHTMLFieldSetElement diff --git a/dom/html/HTMLFieldSetElement.h b/dom/html/HTMLFieldSetElement.h index 66627d5062b0..5d64d192807a 100644 --- a/dom/html/HTMLFieldSetElement.h +++ b/dom/html/HTMLFieldSetElement.h @@ -43,7 +43,9 @@ public: 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; diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 84afd47205d6..5427b03a9d56 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -215,7 +215,8 @@ HTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, 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] @@ -231,7 +232,8 @@ HTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } } - return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify); + return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, + aOldValue, aNotify); } NS_IMPL_STRING_ATTR(HTMLFormElement, AcceptCharset, acceptcharset) diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index cabbf39d6b71..9fec37e69345 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -114,7 +114,9 @@ public: 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 diff --git a/dom/html/HTMLIFrameElement.cpp b/dom/html/HTMLIFrameElement.cpp index 772fadb2790f..6e4cd2b72e14 100644 --- a/dom/html/HTMLIFrameElement.cpp +++ b/dom/html/HTMLIFrameElement.cpp @@ -174,7 +174,7 @@ HTMLIFrameElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, 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) { @@ -184,7 +184,7 @@ HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, mFrameLoader->ApplySandboxFlags(GetSandboxFlags()); } return nsGenericHTMLFrameElement::AfterSetAttr(aNameSpaceID, aName, aValue, - aNotify); + aOldValue, aNotify); } nsresult diff --git a/dom/html/HTMLIFrameElement.h b/dom/html/HTMLIFrameElement.h index b662950dfc83..047f5f505844 100644 --- a/dom/html/HTMLIFrameElement.h +++ b/dom/html/HTMLIFrameElement.h @@ -57,6 +57,7 @@ public: 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; diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index f16af2511753..71b8f1ee9122 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -396,7 +396,8 @@ HTMLImageElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName, 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) && @@ -450,7 +451,7 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, - aValue, aNotify); + aValue, aOldValue, aNotify); } nsresult diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h index 379d07663ce4..5a34646745df 100644 --- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -349,7 +349,9 @@ protected: 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; } diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 970cf8bdd64c..aaa2d7b673d9 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -1398,7 +1398,8 @@ HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName, 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) { // @@ -1521,7 +1522,8 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, - aValue, aNotify); + aValue, aOldValue, + aNotify); } void diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index 86d7542e3ce8..2efda3208ddc 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -975,7 +975,9 @@ protected: * 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; diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index 611f5c90c778..788ded15ec47 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -346,7 +346,8 @@ HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName, 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 @@ -415,7 +416,7 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, - aNotify); + aOldValue, aNotify); } nsresult diff --git a/dom/html/HTMLLinkElement.h b/dom/html/HTMLLinkElement.h index a779ce156257..6ff2fff89a09 100644 --- a/dom/html/HTMLLinkElement.h +++ b/dom/html/HTMLLinkElement.h @@ -67,6 +67,7 @@ public: 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 GetHrefURI() const override; diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 4636fafa944c..e5f643152ab0 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -4235,7 +4235,8 @@ nsresult HTMLMediaElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr, 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; @@ -4257,7 +4258,7 @@ HTMLMediaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, - aValue, aNotify); + aValue, aOldValue, aNotify); } nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index e023d86543f8..70de2c0c6960 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -140,6 +140,7 @@ public: 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, diff --git a/dom/html/HTMLMenuElement.cpp b/dom/html/HTMLMenuElement.cpp index 8e47505c8729..7944e6a9c42c 100644 --- a/dom/html/HTMLMenuElement.cpp +++ b/dom/html/HTMLMenuElement.cpp @@ -115,7 +115,8 @@ HTMLMenuElement::Build(nsIMenuBuilder* 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) { @@ -126,7 +127,7 @@ HTMLMenuElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, - aNotify); + aOldValue, aNotify); } bool diff --git a/dom/html/HTMLMenuElement.h b/dom/html/HTMLMenuElement.h index a7d13f8a9424..df44db74a4db 100644 --- a/dom/html/HTMLMenuElement.h +++ b/dom/html/HTMLMenuElement.h @@ -30,8 +30,10 @@ public: // 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, diff --git a/dom/html/HTMLMenuItemElement.cpp b/dom/html/HTMLMenuItemElement.cpp index c6d976bad00e..e29f551fb184 100644 --- a/dom/html/HTMLMenuItemElement.cpp +++ b/dom/html/HTMLMenuItemElement.cpp @@ -374,7 +374,8 @@ HTMLMenuItemElement::GetText(nsAString& aText) 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 @@ -408,7 +409,7 @@ HTMLMenuItemElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, - aNotify); + aOldValue, aNotify); } void diff --git a/dom/html/HTMLMenuItemElement.h b/dom/html/HTMLMenuItemElement.h index 92130749868b..2f40369f368b 100644 --- a/dom/html/HTMLMenuItemElement.h +++ b/dom/html/HTMLMenuItemElement.h @@ -126,7 +126,9 @@ protected: 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); diff --git a/dom/html/HTMLMetaElement.cpp b/dom/html/HTMLMetaElement.cpp index 47effa2bc5fa..833c3177a763 100644 --- a/dom/html/HTMLMetaElement.cpp +++ b/dom/html/HTMLMetaElement.cpp @@ -60,7 +60,8 @@ HTMLMetaElement::SetMetaReferrer(nsIDocument* aDocument) 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(); @@ -82,7 +83,7 @@ HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, - aNotify); + aOldValue, aNotify); } nsresult diff --git a/dom/html/HTMLMetaElement.h b/dom/html/HTMLMetaElement.h index 0c92ad16ad09..d2edacfa850e 100644 --- a/dom/html/HTMLMetaElement.h +++ b/dom/html/HTMLMetaElement.h @@ -33,7 +33,9 @@ public: 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); diff --git a/dom/html/HTMLOptGroupElement.cpp b/dom/html/HTMLOptGroupElement.cpp index 73f51acf9730..7467c5da38b0 100644 --- a/dom/html/HTMLOptGroupElement.cpp +++ b/dom/html/HTMLOptGroupElement.cpp @@ -102,7 +102,8 @@ HTMLOptGroupElement::RemoveChildAt(uint32_t aIndex, bool 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