diff --git a/content/base/public/Makefile.in b/content/base/public/Makefile.in index c0758b948615..3d662c3b7451 100644 --- a/content/base/public/Makefile.in +++ b/content/base/public/Makefile.in @@ -57,6 +57,7 @@ nsIContentUtils.h \ nsIDocument.h \ nsIDocumentObserver.h \ nsIMutationObserver.h \ +nsIMutationObserver2.h \ nsINameSpaceManager.h \ nsINode.h \ nsINodeInfo.h \ diff --git a/content/base/public/nsIMutationObserver2.h b/content/base/public/nsIMutationObserver2.h new file mode 100644 index 000000000000..d4f83c774e83 --- /dev/null +++ b/content/base/public/nsIMutationObserver2.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mounir Lamouri (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsIMutationObserver2_h___ +#define nsIMutationObserver2_h___ + +#include "nsIMutationObserver.h" + +class nsIContent; +class nsINode; + +#define NS_IMUTATION_OBSERVER_2_IID \ +{0x61ac1cfd, 0xf3ef, 0x4408, \ + {0x8a, 0x72, 0xee, 0xf0, 0x41, 0xbe, 0xc7, 0xe9 } } + +/** + * Mutation observer interface 2 is adding AttributeChildRemoved to + * nsIMutationObserver. + * + * @see nsIMutationObserver. + */ +class nsIMutationObserver2 : public nsIMutationObserver +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMUTATION_OBSERVER_2_IID) + + /** + * Notification that an attribute's child has been removed. + * + * @param aContainer The attribute that had its child removed. + * @param aChild The child that was removed. + * + * @note Attributes can't have more than one child so it will be always the + * first one being removed. + */ + virtual void AttributeChildRemoved(nsINode* aAttribute, + nsIContent* aChild) = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver2, NS_IMUTATION_OBSERVER_2_IID) + +#define NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED \ + virtual void AttributeChildRemoved(nsINode* aAttribute, \ + nsIContent* aChild); + +#define NS_DECL_NSIMUTATIONOBSERVER2 \ + NS_DECL_NSIMUTATIONOBSERVER \ + NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED + +#define NS_IMPL_NSIMUTATIONOBSERVER2_CONTENT(_class) \ +NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(_class) \ +void \ +_class::AttributeChildRemoved(nsINode* aAttribute, nsIContent *aChild) \ +{ \ +} + + +#endif /* nsIMutationObserver2_h___ */ + diff --git a/content/base/src/nsDOMAttribute.cpp b/content/base/src/nsDOMAttribute.cpp index cd362eeb18f8..627a7586956b 100644 --- a/content/base/src/nsDOMAttribute.cpp +++ b/content/base/src/nsDOMAttribute.cpp @@ -263,7 +263,7 @@ nsDOMAttribute::SetValue(const nsAString& aValue) if (mChild) { if (mValue.IsEmpty()) { - doRemoveChild(); + doRemoveChild(true); } else { mChild->SetText(mValue, PR_FALSE); } @@ -683,7 +683,7 @@ nsDOMAttribute::RemoveChildAt(PRUint32 aIndex, PRBool aNotify, PRBool aMutationE return NS_OK; } - doRemoveChild(); + doRemoveChild(aNotify); } nsString nullString; @@ -791,7 +791,7 @@ nsDOMAttribute::AttributeChanged(nsIDocument* aDocument, // Just blow away our mChild and recreate it if needed if (mChild) { - doRemoveChild(); + doRemoveChild(true); } EnsureChildState(); } @@ -809,8 +809,12 @@ nsDOMAttribute::Shutdown() } void -nsDOMAttribute::doRemoveChild() +nsDOMAttribute::doRemoveChild(bool aNotify) { + if (aNotify) { + nsNodeUtils::AttributeChildRemoved(this, mChild); + } + static_cast(mChild)->UnbindFromAttribute(); NS_RELEASE(mChild); mFirstChild = nsnull; diff --git a/content/base/src/nsDOMAttribute.h b/content/base/src/nsDOMAttribute.h index 6525e25eccac..19aa7f163fda 100644 --- a/content/base/src/nsDOMAttribute.h +++ b/content/base/src/nsDOMAttribute.h @@ -140,7 +140,7 @@ private: /** * Really removing the attribute child (unbind and release). */ - void doRemoveChild(); + void doRemoveChild(bool aNotify); nsString mValue; // XXX For now, there's only a single child - a text element diff --git a/content/base/src/nsNodeIterator.cpp b/content/base/src/nsNodeIterator.cpp index dfc016e32562..cf914c4d6c17 100644 --- a/content/base/src/nsNodeIterator.cpp +++ b/content/base/src/nsNodeIterator.cpp @@ -208,6 +208,7 @@ DOMCI_DATA(NodeIterator, nsNodeIterator) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeIterator) NS_INTERFACE_MAP_ENTRY(nsIDOMNodeIterator) NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) + NS_INTERFACE_MAP_ENTRY(nsIMutationObserver2) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNodeIterator) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeIterator) NS_INTERFACE_MAP_END @@ -345,3 +346,11 @@ void nsNodeIterator::ContentRemoved(nsIDocument *aDocument, mPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling); mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling); } + +void nsNodeIterator::AttributeChildRemoved(nsINode* aAttribute, + nsIContent* aChild) +{ + mPointer.AdjustAfterRemoval(mRoot, aAttribute, aChild, 0); + mWorkingPointer.AdjustAfterRemoval(mRoot, aAttribute, aChild, 0); +} + diff --git a/content/base/src/nsNodeIterator.h b/content/base/src/nsNodeIterator.h index c653ad5452c1..ae7ef812240a 100644 --- a/content/base/src/nsNodeIterator.h +++ b/content/base/src/nsNodeIterator.h @@ -55,7 +55,7 @@ class nsIDOMNodeFilter; class nsNodeIterator : public nsIDOMNodeIterator, public nsTraversal, - public nsStubMutationObserver + public nsStubMutationObserver2 { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -68,6 +68,7 @@ public: virtual ~nsNodeIterator(); NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNodeIterator, nsIDOMNodeIterator) diff --git a/content/base/src/nsNodeUtils.cpp b/content/base/src/nsNodeUtils.cpp index c7008ec36a98..d79ef3afddfe 100644 --- a/content/base/src/nsNodeUtils.cpp +++ b/content/base/src/nsNodeUtils.cpp @@ -41,6 +41,7 @@ #include "nsIContent.h" #include "mozilla/dom/Element.h" #include "nsIMutationObserver.h" +#include "nsIMutationObserver2.h" #include "nsIDocument.h" #include "nsIDOMUserDataHandler.h" #include "nsIEventListenerManager.h" @@ -66,6 +67,8 @@ using namespace mozilla::dom; // This macro expects the ownerDocument of content_ to be in scope as // |nsIDocument* doc| +// NOTE: AttributeChildRemoved doesn't use this macro but has a very similar use. +// If you change how this macro behave please update AttributeChildRemoved. #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_) \ PR_BEGIN_MACRO \ nsINode* node = content_; \ @@ -191,6 +194,32 @@ nsNodeUtils::ContentRemoved(nsINode* aContainer, aPreviousSibling)); } +void +nsNodeUtils::AttributeChildRemoved(nsINode* aAttribute, + nsIContent* aChild) +{ + NS_PRECONDITION(aAttribute->IsNodeOfType(nsINode::eATTRIBUTE), + "container must be a nsIAttribute"); + + // This is a variant of IMPL_MUTATION_NOTIFICATION. + do { + nsINode::nsSlots* slots = aAttribute->GetExistingSlots(); + if (slots && !slots->mMutationObservers.IsEmpty()) { + // This is a variant of NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS. + nsTObserverArray::ForwardIterator iter_ = + slots->mMutationObservers; + nsCOMPtr obs_; + while (iter_.HasMore()) { + obs_ = do_QueryInterface(iter_.GetNext()); + if (obs_) { + obs_->AttributeChildRemoved(aAttribute, aChild); + } + } + } + aAttribute = aAttribute->GetNodeParent(); + } while (aAttribute); +} + void nsNodeUtils::ParentChainChanged(nsIContent *aContent) { diff --git a/content/base/src/nsNodeUtils.h b/content/base/src/nsNodeUtils.h index 47eda55a6db5..426bf7a3071f 100644 --- a/content/base/src/nsNodeUtils.h +++ b/content/base/src/nsNodeUtils.h @@ -128,6 +128,13 @@ public: nsIContent* aChild, PRInt32 aIndexInContainer, nsIContent* aPreviousSibling); + /** + * Send AttributeChildRemoved notifications to nsIMutationObservers. + * @param aAttribute Attribute from which the child has been removed. + * @param aChild Removed child. + * @see nsIMutationObserver2::AttributeChildRemoved. + */ + static void AttributeChildRemoved(nsINode* aAttribute, nsIContent* aChild); /** * Send ParentChainChanged notifications to nsIMutationObservers * @param aContent The piece of content that had its parent changed. diff --git a/content/base/src/nsStubMutationObserver.cpp b/content/base/src/nsStubMutationObserver.cpp index 8942efe0b14a..1d52e3dad0a1 100644 --- a/content/base/src/nsStubMutationObserver.cpp +++ b/content/base/src/nsStubMutationObserver.cpp @@ -46,3 +46,6 @@ NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver) NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(nsStubMutationObserver) + +NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver2) +NS_IMPL_NSIMUTATIONOBSERVER2_CONTENT(nsStubMutationObserver2) diff --git a/content/base/src/nsStubMutationObserver.h b/content/base/src/nsStubMutationObserver.h index 963e885c26ac..4a95e25f7333 100644 --- a/content/base/src/nsStubMutationObserver.h +++ b/content/base/src/nsStubMutationObserver.h @@ -46,6 +46,7 @@ #define nsStubMutationObserver_h_ #include "nsIMutationObserver.h" +#include "nsIMutationObserver2.h" /** * There are two advantages to inheriting from nsStubMutationObserver @@ -62,4 +63,8 @@ class nsStubMutationObserver : public nsIMutationObserver { NS_DECL_NSIMUTATIONOBSERVER }; +class nsStubMutationObserver2 : public nsIMutationObserver2 { + NS_DECL_NSIMUTATIONOBSERVER2 +}; + #endif /* !defined(nsStubMutationObserver_h_) */