From 5352b69a9286223272c0ed072900b4c78ba2ed7c Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Tue, 14 Apr 2020 21:24:51 -0400 Subject: Bug 1305458 - Changing -moz-appearence on hover breaks change event * Rename nsIDOMEventTarget::PreHandleEvent to nsIDOMEventTarget::GetEventTargetParent * Add nsIDOMEventTarget::PreHandleEvent * Add EventTargetChainItem::GetFirstEventTarget * Call EventTargetChainItem::PreHandleEvent even it sets mCanHandle=false * Move form control frame focus/blur from nsGenericHTMLFormElement::GetEventTargetParent to PreHandleEvent * Move fire change event from HTMLTextAreaElement::GetEventTargetParent to PreHandleEvent * Refine nsXULElement::GetEventTargetParent * Move dispatch XUL command from nsXULElement::GetEventTargetParent to PreHandleEvent * Move fire events and set value from HTMLInputElement::GetEventTargetParent to PreHandleEvent * Add test case * Let HTMLInputElement delegate event handling to it's parent class * Refine EventTargetChain flags to reduce overheads * Refine event target chain creation * Refine assertion in EventTargetChainItem::Create Tag #1375 --- dom/archivereader/ArchiveRequest.cpp | 2 +- dom/archivereader/ArchiveRequest.h | 3 +- dom/base/Attr.cpp | 2 +- dom/base/Attr.h | 2 +- dom/base/Element.cpp | 7 +- dom/base/Element.h | 2 +- dom/base/FragmentOrElement.cpp | 2 +- dom/base/nsDocument.cpp | 2 +- dom/base/nsDocument.h | 2 +- dom/base/nsGenConImageContent.cpp | 4 +- dom/base/nsGlobalWindow.cpp | 7 +- dom/base/nsIContent.h | 2 +- dom/base/nsINode.cpp | 2 +- dom/base/nsInProcessTabChildGlobal.cpp | 4 +- dom/base/nsInProcessTabChildGlobal.h | 4 +- dom/base/nsWindowRoot.cpp | 2 +- dom/events/DOMEventTargetHelper.cpp | 2 +- dom/events/DOMEventTargetHelper.h | 4 +- dom/events/EventDispatcher.cpp | 256 ++++++++++++++++++++-------- dom/events/EventDispatcher.h | 24 ++- dom/events/test/mochitest.ini | 1 + dom/events/test/test_bug1305458.html | 50 ++++++ dom/html/HTMLAnchorElement.cpp | 4 +- dom/html/HTMLAnchorElement.h | 3 +- dom/html/HTMLAreaElement.cpp | 4 +- dom/html/HTMLAreaElement.h | 3 +- dom/html/HTMLButtonElement.cpp | 4 +- dom/html/HTMLButtonElement.h | 3 +- dom/html/HTMLCanvasElement.cpp | 4 +- dom/html/HTMLCanvasElement.h | 3 +- dom/html/HTMLFieldSetElement.cpp | 4 +- dom/html/HTMLFieldSetElement.h | 3 +- dom/html/HTMLFormElement.cpp | 4 +- dom/html/HTMLFormElement.h | 3 +- dom/html/HTMLImageElement.cpp | 4 +- dom/html/HTMLImageElement.h | 3 +- dom/html/HTMLInputElement.cpp | 90 ++++++---- dom/html/HTMLInputElement.h | 4 +- dom/html/HTMLLinkElement.cpp | 4 +- dom/html/HTMLLinkElement.h | 3 +- dom/html/HTMLMenuItemElement.cpp | 4 +- dom/html/HTMLMenuItemElement.h | 3 +- dom/html/HTMLOptGroupElement.cpp | 4 +- dom/html/HTMLOptGroupElement.h | 3 +- dom/html/HTMLSelectElement.cpp | 4 +- dom/html/HTMLSelectElement.h | 3 +- dom/html/HTMLTextAreaElement.cpp | 17 +- dom/html/HTMLTextAreaElement.h | 4 +- dom/html/nsGenericHTMLElement.cpp | 21 ++- dom/html/nsGenericHTMLElement.h | 9 +- dom/indexedDB/IDBFileHandle.cpp | 2 +- dom/indexedDB/IDBFileHandle.h | 2 +- dom/indexedDB/IDBFileRequest.cpp | 2 +- dom/indexedDB/IDBFileRequest.h | 2 +- dom/indexedDB/IDBRequest.cpp | 2 +- dom/indexedDB/IDBRequest.h | 2 +- dom/indexedDB/IDBTransaction.cpp | 2 +- dom/indexedDB/IDBTransaction.h | 2 +- dom/interfaces/events/nsIDOMEventTarget.idl | 15 +- dom/ipc/TabChild.h | 2 +- dom/mathml/nsMathMLElement.cpp | 6 +- dom/mathml/nsMathMLElement.h | 2 +- dom/svg/SVGAElement.cpp | 6 +- dom/svg/SVGAElement.h | 3 +- dom/svg/SVGSVGElement.cpp | 4 +- dom/svg/SVGSVGElement.h | 3 +- dom/workers/SharedWorker.cpp | 4 +- dom/workers/SharedWorker.h | 2 +- dom/xul/nsXULElement.cpp | 124 ++++++++------ dom/xul/nsXULElement.h | 10 +- 70 files changed, 547 insertions(+), 258 deletions(-) create mode 100644 dom/events/test/test_bug1305458.html (limited to 'dom') diff --git a/dom/archivereader/ArchiveRequest.cpp b/dom/archivereader/ArchiveRequest.cpp index ec1686804..c4b19f56b 100644 --- a/dom/archivereader/ArchiveRequest.cpp +++ b/dom/archivereader/ArchiveRequest.cpp @@ -69,7 +69,7 @@ ArchiveRequest::~ArchiveRequest() } nsresult -ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor) +ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = true; aVisitor.mParentTarget = nullptr; diff --git a/dom/archivereader/ArchiveRequest.h b/dom/archivereader/ArchiveRequest.h index 3988f1aa1..3081a3e42 100644 --- a/dom/archivereader/ArchiveRequest.h +++ b/dom/archivereader/ArchiveRequest.h @@ -38,7 +38,8 @@ public: ArchiveReader* aReader); // nsIDOMEventTarget - virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override; + virtual nsresult GetEventTargetParent( + EventChainPreVisitor& aVisitor) override; public: // This is called by the DOMArchiveRequestEvent diff --git a/dom/base/Attr.cpp b/dom/base/Attr.cpp index 71b559392..df05ef5cb 100644 --- a/dom/base/Attr.cpp +++ b/dom/base/Attr.cpp @@ -344,7 +344,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify) } nsresult -Attr::PreHandleEvent(EventChainPreVisitor& aVisitor) +Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = true; return NS_OK; diff --git a/dom/base/Attr.h b/dom/base/Attr.h index 3f80030d2..39ac8b195 100644 --- a/dom/base/Attr.h +++ b/dom/base/Attr.h @@ -54,7 +54,7 @@ public: // nsIDOMAttr interface NS_DECL_NSIDOMATTR - virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override; + virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override; // nsIAttribute interface void SetMap(nsDOMAttributeMap *aMap) override; diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index c8467e036..5a92853ae 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -3129,7 +3129,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor, } nsresult -Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor) +Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor) { // Optimisation: return early if this event doesn't interest us. // IMPORTANT: this switch and the switch below it must be kept in sync! @@ -3151,8 +3151,9 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor) nsresult rv = NS_OK; - // We do the status bar updates in PreHandleEvent so that the status bar gets - // updated even if the event is consumed before we have a chance to set it. + // We do the status bar updates in GetEventTargetParent so that the status bar + // gets updated even if the event is consumed before we have a chance to set + // it. switch (aVisitor.mEvent->mMessage) { // Set the status bar similarly for mouseover and focus case eMouseOver: diff --git a/dom/base/Element.h b/dom/base/Element.h index 782004703..0104d795c 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -1400,7 +1400,7 @@ protected: /** * Handle status bar updates before they can be cancelled. */ - nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor); + nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor); /** * Handle default actions for link event if the event isn't consumed yet. diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index 526c3c9d4..ca00a49a5 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -718,7 +718,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent) } nsresult -nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor) +nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor) { //FIXME! Document how this event retargeting works, Bug 329124. aVisitor.mCanHandle = true; diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index b05bf827b..45c80ca7f 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -7712,7 +7712,7 @@ nsDocument::GetExistingListenerManager() const } nsresult -nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor) +nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor) { aVisitor.mCanHandle = true; // FIXME! This is a hack to make middle mouse paste working also in Editor. diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 90e511dcb..79b7f18f4 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -810,7 +810,7 @@ public: NS_DECL_NSIDOMDOCUMENTXBL // nsIDOMEventTarget - virtual nsresult PreHandleEvent( + virtual nsresult GetEventTargetParent( mozilla::EventChainPreVisitor& aVisitor) override; virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override; diff --git a/dom/base/nsGenConImageContent.cpp b/dom/base/nsGenConImageContent.cpp index e1b1f5a17..af3b186bd 100644 --- a/dom/base/nsGenConImageContent.cpp +++ b/dom/base/nsGenConImageContent.cpp @@ -46,7 +46,7 @@ public: virtual void UnbindFromTree(bool aDeep, bool aNullParent) override; virtual EventStates IntrinsicState() const override; - virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override + virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override { MOZ_ASSERT(IsInNativeAnonymousSubtree()); if (aVisitor.mEvent->mMessage == eLoad || @@ -54,7 +54,7 @@ public: // Don't propagate the events to the parent. return NS_OK; } - return nsXMLElement::PreHandleEvent(aVisitor); + return nsXMLElement::GetEventTargetParent(aVisitor); } private: diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index c965d5b97..802b44f38 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -3577,9 +3577,10 @@ nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor) } nsresult -nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor) +nsGlobalWindow::GetEventTargetParent(EventChainPreVisitor& aVisitor) { - NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?"); + NS_PRECONDITION(IsInnerWindow(), + "GetEventTargetParent is used on outer window!?"); EventMessage msg = aVisitor.mEvent->mMessage; aVisitor.mCanHandle = true; @@ -3812,7 +3813,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor) } else if (aVisitor.mEvent->mMessage == eLoad && aVisitor.mEvent->IsTrusted()) { // This is page load event since load events don't propagate to |window|. - // @see nsDocument::PreHandleEvent. + // @see nsDocument::GetEventTargetParent. mIsDocumentLoaded = true; nsCOMPtr element = GetOuterWindow()->GetFrameElementInternal(); diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h index dcdc632b4..e179d6ebc 100644 --- a/dom/base/nsIContent.h +++ b/dom/base/nsIContent.h @@ -947,7 +947,7 @@ public: // Overloaded from nsINode virtual already_AddRefed GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override; - virtual nsresult PreHandleEvent( + virtual nsresult GetEventTargetParent( mozilla::EventChainPreVisitor& aVisitor) override; virtual bool IsPurple() = 0; diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 212110b72..0b56f519d 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1243,7 +1243,7 @@ nsINode::RemoveEventListener(const nsAString& aType, NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode) nsresult -nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor) +nsINode::GetEventTargetParent(EventChainPreVisitor& aVisitor) { // This is only here so that we can use the NS_DECL_NSIDOMTARGET macro NS_ABORT(); diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp index 10ccf4aec..547bb8d36 100644 --- a/dom/base/nsInProcessTabChildGlobal.cpp +++ b/dom/base/nsInProcessTabChildGlobal.cpp @@ -97,7 +97,7 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell, mozilla::HoldJSObjects(this); // If owner corresponds to an + + \ No newline at end of file diff --git a/dom/html/reftests/body-frame-margin-remove-other-pres-hint.html b/dom/html/reftests/body-frame-margin-remove-other-pres-hint.html new file mode 100644 index 000000000..6f4953637 --- /dev/null +++ b/dom/html/reftests/body-frame-margin-remove-other-pres-hint.html @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/dom/html/reftests/body-topmargin-dynamic.html b/dom/html/reftests/body-topmargin-dynamic.html new file mode 100644 index 000000000..e6c8c505e --- /dev/null +++ b/dom/html/reftests/body-topmargin-dynamic.html @@ -0,0 +1,12 @@ + + + +this text should have a margin of 100px on the top and left +

this text should have a margin of 100px on the right

+ + + diff --git a/dom/html/reftests/body-topmargin-ref.html b/dom/html/reftests/body-topmargin-ref.html new file mode 100644 index 000000000..6530a0ae4 --- /dev/null +++ b/dom/html/reftests/body-topmargin-ref.html @@ -0,0 +1,7 @@ + + + +this text should have a margin of 100px on the top and left +

this text should have a margin of 100px on the right

+ + diff --git a/dom/html/reftests/reftest-stylo.list b/dom/html/reftests/reftest-stylo.list index dd6339edf..570c07358 100644 --- a/dom/html/reftests/reftest-stylo.list +++ b/dom/html/reftests/reftest-stylo.list @@ -64,3 +64,10 @@ pref(permissions.default.image,2) HTTP == bug1196784-with-srcset.html bug1196784 # Test video with rotation information can be rotated. == bug1228601-video-rotation-90.html bug1228601-video-rotation-90.html + +# Test that dynamically setting body margin attributes updates style appropriately +== body-topmargin-dynamic.html body-topmargin-dynamic.html + +# Test that dynamically removing a nonmargin mapped attribute does not +# destroy margins inherited from the frame. +== body-frame-margin-remove-other-pres-hint.html body-frame-margin-remove-other-pres-hint.html diff --git a/dom/html/reftests/reftest.list b/dom/html/reftests/reftest.list index 27a13e7c9..82e773abb 100644 --- a/dom/html/reftests/reftest.list +++ b/dom/html/reftests/reftest.list @@ -62,3 +62,10 @@ pref(permissions.default.image,2) HTTP == bug1196784-with-srcset.html bug1196784 # Test video with rotation information can be rotated. == bug1228601-video-rotation-90.html bug1228601-video-rotated-ref.html + +# Test that dynamically setting body margin attributes updates style appropriately +== body-topmargin-dynamic.html body-topmargin-ref.html + +# Test that dynamically removing a nonmargin mapped attribute does not +# destroy margins inherited from the frame. +== body-frame-margin-remove-other-pres-hint.html body-frame-margin-remove-other-pres-hint-ref.html -- cgit v1.2.3 From 7614fdb51b177e6975fce5bf9a7facef170e61aa Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 17 Apr 2020 05:10:25 -0400 Subject: Bug 1355351 - Make pseudo-elements return the correct style via getComputedStyle * Add a node property to access the ::before and ::after pseudo-elements * Look for the frame for ::before and ::after pseudos * Clean up pseudo-element props * Simplify nsLayoutUtils callers, and make child iterators notice display: contents pseudos Tag #1375 --- dom/animation/EffectCompositor.cpp | 22 +++------- dom/animation/KeyframeEffectReadOnly.cpp | 12 +++--- dom/base/ChildIterator.cpp | 73 ++++++++++++-------------------- dom/base/nsDOMWindowUtils.cpp | 6 +-- dom/base/nsGkAtomList.h | 2 + dom/xml/nsXMLElement.cpp | 23 ++++++++++ dom/xml/nsXMLElement.h | 3 ++ 7 files changed, 69 insertions(+), 72 deletions(-) (limited to 'dom') diff --git a/dom/animation/EffectCompositor.cpp b/dom/animation/EffectCompositor.cpp index c88cabe90..49da3c033 100644 --- a/dom/animation/EffectCompositor.cpp +++ b/dom/animation/EffectCompositor.cpp @@ -356,24 +356,16 @@ EffectCompositor::GetElementToRestyle(dom::Element* aElement, return aElement; } - nsIFrame* primaryFrame = aElement->GetPrimaryFrame(); - if (!primaryFrame) { - return nullptr; - } - nsIFrame* pseudoFrame; if (aPseudoType == CSSPseudoElementType::before) { - pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame); - } else if (aPseudoType == CSSPseudoElementType::after) { - pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame); - } else { - NS_NOTREACHED("Should not try to get the element to restyle for a pseudo " - "other that :before or :after"); - return nullptr; + return nsLayoutUtils::GetBeforePseudo(aElement); } - if (!pseudoFrame) { - return nullptr; + if (aPseudoType == CSSPseudoElementType::after) { + return nsLayoutUtils::GetAfterPseudo(aElement); } - return pseudoFrame->GetContent()->AsElement(); + + NS_NOTREACHED("Should not try to get the element to restyle for a pseudo " + "other that :before or :after"); + return nullptr; } bool diff --git a/dom/animation/KeyframeEffectReadOnly.cpp b/dom/animation/KeyframeEffectReadOnly.cpp index 639e0b2b0..164ee0292 100644 --- a/dom/animation/KeyframeEffectReadOnly.cpp +++ b/dom/animation/KeyframeEffectReadOnly.cpp @@ -1105,19 +1105,17 @@ KeyframeEffectReadOnly::GetAnimationFrame() const return nullptr; } - nsIFrame* frame = mTarget->mElement->GetPrimaryFrame(); - if (!frame) { - return nullptr; - } - + nsIFrame* frame; if (mTarget->mPseudoType == CSSPseudoElementType::before) { - frame = nsLayoutUtils::GetBeforeFrame(frame); + frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement); } else if (mTarget->mPseudoType == CSSPseudoElementType::after) { - frame = nsLayoutUtils::GetAfterFrame(frame); + frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement); } else { + frame = mTarget->mElement->GetPrimaryFrame(); MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo, "unknown mTarget->mPseudoType"); } + if (!frame) { return nullptr; } diff --git a/dom/base/ChildIterator.cpp b/dom/base/ChildIterator.cpp index fb07e9a21..23b919516 100644 --- a/dom/base/ChildIterator.cpp +++ b/dom/base/ChildIterator.cpp @@ -317,11 +317,9 @@ AllChildrenIterator::Get() const { switch (mPhase) { case eAtBeforeKid: { - nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); - MOZ_ASSERT(frame, "No frame at eAtBeforeKid phase"); - nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame); - MOZ_ASSERT(beforeFrame, "No content before frame at eAtBeforeKid phase"); - return beforeFrame->GetContent(); + Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent); + MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase"); + return before; } case eAtExplicitKids: @@ -331,11 +329,9 @@ AllChildrenIterator::Get() const return mAnonKids[mAnonKidsIdx]; case eAtAfterKid: { - nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); - MOZ_ASSERT(frame, "No frame at eAtAfterKid phase"); - nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame); - MOZ_ASSERT(afterFrame, "No content before frame at eAtBeforeKid phase"); - return afterFrame->GetContent(); + Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent); + MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase"); + return after; } default: @@ -349,15 +345,10 @@ AllChildrenIterator::Seek(nsIContent* aChildToFind) { if (mPhase == eAtBegin || mPhase == eAtBeforeKid) { mPhase = eAtExplicitKids; - nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); - if (frame) { - nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame); - if (beforeFrame) { - if (beforeFrame->GetContent() == aChildToFind) { - mPhase = eAtBeforeKid; - return true; - } - } + Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent); + if (beforePseudo && beforePseudo == aChildToFind) { + mPhase = eAtBeforeKid; + return true; } } @@ -404,13 +395,10 @@ AllChildrenIterator::GetNextChild() { if (mPhase == eAtBegin) { mPhase = eAtExplicitKids; - nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); - if (frame) { - nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame); - if (beforeFrame) { - mPhase = eAtBeforeKid; - return beforeFrame->GetContent(); - } + Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent); + if (beforeContent) { + mPhase = eAtBeforeKid; + return beforeContent; } } @@ -446,13 +434,10 @@ AllChildrenIterator::GetNextChild() return mAnonKids[mAnonKidsIdx]; } - nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); - if (frame) { - nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame); - if (afterFrame) { - mPhase = eAtAfterKid; - return afterFrame->GetContent(); - } + Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent); + if (afterContent) { + mPhase = eAtAfterKid; + return afterContent; } } @@ -466,13 +451,10 @@ AllChildrenIterator::GetPreviousChild() if (mPhase == eAtEnd) { MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length()); mPhase = eAtAnonKids; - nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); - if (frame) { - nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame); - if (afterFrame) { - mPhase = eAtAfterKid; - return afterFrame->GetContent(); - } + Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent); + if (afterContent) { + mPhase = eAtAfterKid; + return afterContent; } } @@ -501,13 +483,10 @@ AllChildrenIterator::GetPreviousChild() return kid; } - nsIFrame* frame = mOriginalContent->GetPrimaryFrame(); - if (frame) { - nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame); - if (beforeFrame) { - mPhase = eAtBeforeKid; - return beforeFrame->GetContent(); - } + Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent); + if (beforeContent) { + mPhase = eAtBeforeKid; + return beforeContent; } } diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 2ab5937ac..3f5b54c94 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -3657,11 +3657,11 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement, RefPtr cssValue = nullptr; nsIFrame* frame = element->GetPrimaryFrame(); - if (frame && !aPseudoElement.IsEmpty()) { + if (!aPseudoElement.IsEmpty()) { if (aPseudoElement.EqualsLiteral("::before")) { - frame = nsLayoutUtils::GetBeforeFrame(frame); + frame = nsLayoutUtils::GetBeforeFrame(element); } else if (aPseudoElement.EqualsLiteral("::after")) { - frame = nsLayoutUtils::GetAfterFrame(frame); + frame = nsLayoutUtils::GetAfterFrame(element); } else { return NS_ERROR_INVALID_ARG; } diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index c7c1197b1..2f0e30387 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -2144,12 +2144,14 @@ GK_ATOM(ongamepaddisconnected, "ongamepaddisconnected") #endif // Content property names +GK_ATOM(afterPseudoProperty, "afterPseudoProperty") // nsXMLElement* GK_ATOM(animationsProperty, "AnimationsProperty") // FrameAnimations* GK_ATOM(animationsOfBeforeProperty, "AnimationsOfBeforeProperty") // FrameAnimations* GK_ATOM(animationsOfAfterProperty, "AnimationsOfAfterProperty") // FrameAnimations* GK_ATOM(animationEffectsProperty, "AnimationEffectsProperty") // EffectSet* GK_ATOM(animationEffectsForBeforeProperty, "AnimationsEffectsForBeforeProperty") // EffectSet* GK_ATOM(animationEffectsForAfterProperty, "AnimationsEffectsForAfterProperty") // EffectSet* +GK_ATOM(beforePseudoProperty, "beforePseudoProperty") // nsXMLElement* GK_ATOM(cssPseudoElementBeforeProperty, "CSSPseudoElementBeforeProperty") // CSSPseudoElement* GK_ATOM(cssPseudoElementAfterProperty, "CSSPseudoElementAfterProperty") // CSSPseudoElement* GK_ATOM(transitionsProperty, "TransitionsProperty") // FrameTransitions* diff --git a/dom/xml/nsXMLElement.cpp b/dom/xml/nsXMLElement.cpp index 45163a1c4..ad0314f4c 100644 --- a/dom/xml/nsXMLElement.cpp +++ b/dom/xml/nsXMLElement.cpp @@ -9,6 +9,7 @@ #include "mozilla/dom/ElementInlines.h" #include "nsContentUtils.h" // nsAutoScriptBlocker +using namespace mozilla; using namespace mozilla::dom; nsresult @@ -29,4 +30,26 @@ nsXMLElement::WrapNode(JSContext *aCx, JS::Handle aGivenProto) return ElementBinding::Wrap(aCx, this, aGivenProto); } +void +nsXMLElement::UnbindFromTree(bool aDeep, bool aNullParent) +{ + CSSPseudoElementType pseudoType = GetPseudoElementType(); + bool isBefore = pseudoType == CSSPseudoElementType::before; + nsIAtom* property = isBefore + ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty; + + switch (pseudoType) { + case CSSPseudoElementType::before: + case CSSPseudoElementType::after: { + MOZ_ASSERT(GetParent()); + MOZ_ASSERT(GetParent()->IsElement()); + GetParent()->DeleteProperty(property); + break; + } + default: + break; + } + Element::UnbindFromTree(aDeep, aNullParent); +} + NS_IMPL_ELEMENT_CLONE(nsXMLElement) diff --git a/dom/xml/nsXMLElement.h b/dom/xml/nsXMLElement.h index d16b82f39..85f79970c 100644 --- a/dom/xml/nsXMLElement.h +++ b/dom/xml/nsXMLElement.h @@ -35,6 +35,9 @@ public: virtual nsIDOMNode* AsDOMNode() override { return this; } + virtual void UnbindFromTree(bool aDeep = true, + bool aNullParent = true) override; + protected: virtual ~nsXMLElement() {} -- cgit v1.2.3 From 091d06b43b294390a96106e57a7462f6303107a3 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 17 Apr 2020 05:26:58 -0400 Subject: Bug 1363481 - Add the old attribute value as a parameter to Element::AfterSetAttr Tag #1375 --- dom/base/Element.cpp | 78 +++++++++++++++++++++++----------- dom/base/Element.h | 74 ++++++++++++++++++++++++-------- dom/base/nsAttrAndChildArray.cpp | 21 +++++---- dom/base/nsAttrAndChildArray.h | 18 ++++++-- dom/base/nsMappedAttributeElement.cpp | 14 +++--- dom/base/nsMappedAttributeElement.h | 9 ++-- dom/base/nsMappedAttributes.cpp | 7 +-- 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/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/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/svg/nsSVGPathGeometryElement.cpp | 5 ++- dom/svg/nsSVGPathGeometryElement.h | 4 +- dom/xul/nsXULElement.cpp | 18 +++++--- dom/xul/nsXULElement.h | 4 +- 65 files changed, 352 insertions(+), 161 deletions(-) (limited to 'dom') diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 7c5029e2e..11ad042a0 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -2382,7 +2382,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID, bool aNotify, nsAttrValue& aOldValue, uint8_t* aModType, - bool* aHasListeners) + bool* aHasListeners, + bool* aOldValueSet) { bool modification = false; *aHasListeners = aNotify && @@ -2390,6 +2391,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID, 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 @@ -2413,6 +2416,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()) { @@ -2432,10 +2436,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; } @@ -2466,9 +2472,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; } @@ -2501,7 +2508,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); } @@ -2526,9 +2534,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; } @@ -2542,7 +2551,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); } @@ -2551,7 +2561,7 @@ nsresult Element::SetAttrAndNotify(int32_t aNamespaceID, nsIAtom* aName, nsIAtom* aPrefix, - const nsAttrValue& aOldValue, + const nsAttrValue* aOldValue, nsAttrValue& aParsedValue, uint8_t aModType, bool aFireMutation, @@ -2573,6 +2583,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, bool hadValidDir = false; bool hadDirAuto = false; + bool oldValueSet; if (aNamespaceID == kNameSpaceID_None) { if (aName == nsGkAtoms::dir) { @@ -2583,8 +2594,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, // XXXbz Perhaps we should push up the attribute mapping function // stuff to Element? if (!IsAttributeMapped(aName) || - !SetMappedAttribute(aComposedDocument, aName, aParsedValue, &rv)) { - rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue); + !SetAndSwapMappedAttribute(aComposedDocument, aName, aParsedValue, &oldValueSet, &rv)) { + rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet); } } else { @@ -2593,14 +2604,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(); @@ -2618,7 +2639,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID, MOZ_ASSERT(data->mState == CustomElementData::State::eCustom, "AttributeChanged callback should fire only if " "custom element state is custom"); - 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(); nsAutoString ns; nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns); @@ -2638,7 +2666,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) { @@ -2654,7 +2683,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) { @@ -2672,7 +2701,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; @@ -2715,10 +2744,11 @@ Element::ParseAttribute(int32_t aNamespaceID, } bool -Element::SetMappedAttribute(nsIDocument* aDocument, - nsIAtom* aName, - nsAttrValue& aValue, - nsresult* aRetval) +Element::SetAndSwapMappedAttribute(nsIDocument* aDocument, + nsIAtom* aName, + nsAttrValue& aValue, + bool* aValueWasSet, + nsresult* aRetval) { *aRetval = NS_OK; return false; @@ -2886,7 +2916,7 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName, } } - 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 6b55cf8cd..6f60c9ad0 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -537,25 +537,50 @@ 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; @@ -1261,7 +1286,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. @@ -1275,7 +1303,7 @@ protected: nsresult SetAttrAndNotify(int32_t aNamespaceID, nsIAtom* aName, nsIAtom* aPrefix, - const nsAttrValue& aOldValue, + const nsAttrValue* aOldValue, nsAttrValue& aParsedValue, uint8_t aModType, bool aFireMutation, @@ -1320,14 +1348,21 @@ protected: * * @param aDocument the current document of this node (an optimization) * @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(nsIDocument* aDocument, - nsIAtom* aName, - nsAttrValue& aValue, - nsresult* aRetval); + virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument, + nsIAtom* aName, + nsAttrValue& aValue, + bool* aValueWasSet, + nsresult* aRetval); /** * Hook that is called by Element::SetAttr to allow subclasses to @@ -1355,19 +1390,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 4daac498b..f8e4c3f18 100644 --- a/dom/base/nsAttrAndChildArray.cpp +++ b/dom/base/nsAttrAndChildArray.cpp @@ -382,12 +382,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; } } @@ -407,21 +410,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; } } @@ -576,10 +580,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) { @@ -589,7 +594,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 ffbad196c..0ce51c52e 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 1c1f8838f..d06cbf2bc 100644 --- a/dom/base/nsMappedAttributeElement.cpp +++ b/dom/base/nsMappedAttributeElement.cpp @@ -15,17 +15,19 @@ nsMappedAttributeElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) } bool -nsMappedAttributeElement::SetMappedAttribute(nsIDocument* aDocument, - nsIAtom* aName, - nsAttrValue& aValue, - nsresult* aRetval) +nsMappedAttributeElement::SetAndSwapMappedAttribute(nsIDocument* aDocument, + nsIAtom* aName, + nsAttrValue& aValue, + bool* aValueWasSet, + nsresult* aRetval) + { NS_PRECONDITION(aDocument == GetComposedDoc(), "Unexpected document"); nsHTMLStyleSheet* sheet = aDocument ? aDocument->GetAttributeStyleSheet() : nullptr; - *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 4668b36a1..a37af85ca 100644 --- a/dom/base/nsMappedAttributeElement.h +++ b/dom/base/nsMappedAttributeElement.h @@ -39,10 +39,11 @@ public: nsRuleData* aRuleData); NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override; - virtual bool SetMappedAttribute(nsIDocument* aDocument, - nsIAtom* aName, - nsAttrValue& aValue, - nsresult* aRetval) override; + virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument, + nsIAtom* aName, + nsAttrValue& aValue, + bool* aValueWasSet, + nsresult* aRetval) override; }; #endif // NS_MAPPEDATTRIBUTEELEMENT_H_ diff --git a/dom/base/nsMappedAttributes.cpp b/dom/base/nsMappedAttributes.cpp index 9e80c94df..05ad42310 100644 --- a/dom/base/nsMappedAttributes.cpp +++ b/dom/base/nsMappedAttributes.cpp @@ -85,15 +85,16 @@ NS_IMPL_ISUPPORTS(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 f00b888b9..0c24fd973 100644 --- a/dom/base/nsMappedAttributes.h +++ b/dom/base/nsMappedAttributes.h @@ -33,7 +33,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 cdfa56461..e3d8dfe57 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, @@ -76,6 +77,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration, oldValueStr); if (modification) { oldValue.SetTo(oldValueStr); + oldValueSet = true; } } else if (aNotify && IsInUncomposedDoc()) { @@ -92,9 +94,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); } DeclarationBlock* @@ -145,7 +147,9 @@ nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc) 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 f70e20389..112d48dd1 100644 --- a/dom/html/HTMLBodyElement.cpp +++ b/dom/html/HTMLBodyElement.cpp @@ -307,10 +307,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 ad1f5d872..6a888c71b 100644 --- a/dom/html/HTMLBodyElement.h +++ b/dom/html/HTMLBodyElement.h @@ -117,7 +117,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 c26e60ed0..1a76aac10 100644 --- a/dom/html/HTMLButtonElement.cpp +++ b/dom/html/HTMLButtonElement.cpp @@ -437,7 +437,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) { @@ -452,7 +453,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 19c93e483..8bab9fd48 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 c008b9b6d..f546cad5b 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 1e9f0214f..2c0e9cc14 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 bdc05b053..1fdfb602e 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -214,7 +214,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] @@ -230,7 +231,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 e45d4c10d..6102ea61f 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 0d5a209c0..6ae4ec9dd 100644 --- a/dom/html/HTMLIFrameElement.cpp +++ b/dom/html/HTMLIFrameElement.cpp @@ -202,7 +202,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) { @@ -212,7 +212,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 5bfda2470..23afaaddd 100644 --- a/dom/html/HTMLIFrameElement.h +++ b/dom/html/HTMLIFrameElement.h @@ -56,6 +56,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 5d0cfd15e..dd43ac36a 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -391,7 +391,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) && @@ -433,7 +434,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 d92cd84b8..52480d0a0 100644 --- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -348,7 +348,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; // This is a weak reference that this element and the HTMLFormElement // cooperate in maintaining. diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 1d3db145a..7c2688b7e 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -1287,7 +1287,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) { // @@ -1437,7 +1438,8 @@ HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, } return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName, - aValue, aNotify); + aValue, aOldValue, + aNotify); } // nsIDOMHTMLInputElement diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index d6a078f0b..48807f733 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -964,7 +964,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; /** * Dispatch a select event. Returns true if the event was not cancelled. diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index 4c42d310a..b05b92d7a 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -348,7 +348,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 @@ -417,7 +418,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 9c69cfb13..acac955cb 100644 --- a/dom/html/HTMLLinkElement.h +++ b/dom/html/HTMLLinkElement.h @@ -66,6 +66,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 bc63eab51..4bcc188d3 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -3774,7 +3774,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; @@ -3796,7 +3797,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 44c666f95..d81e9f591 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -146,6 +146,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/HTMLMenuItemElement.cpp b/dom/html/HTMLMenuItemElement.cpp index 6a8ad8174..3245a16b1 100644 --- a/dom/html/HTMLMenuItemElement.cpp +++ b/dom/html/HTMLMenuItemElement.cpp @@ -380,7 +380,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) { if ((aName == nsGkAtoms::radiogroup || aName == nsGkAtoms::type) && @@ -404,7 +405,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 1da63edd0..cb824edcc 100644 --- a/dom/html/HTMLMenuItemElement.h +++ b/dom/html/HTMLMenuItemElement.h @@ -125,7 +125,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 47effa2bc..833c3177a 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 d3f05826d..0b9117e55 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 0424ccef3..63af4e39f 100644 --- a/dom/html/HTMLOptGroupElement.cpp +++ b/dom/html/HTMLOptGroupElement.cpp @@ -101,7 +101,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