Bug 737122 - Attr nodes shouldn't have children; r=sicking
authorMs2ger <ms2ger@gmail.com>
Tue, 03 Apr 2012 09:25:39 +0200
changeset 90888 af7362ead6e5
parent 90887 66101542ba09
child 90889 c0d3b3b6e2fb
push id22395
push userMs2ger@gmail.com
push date2012-04-03 07:28 +0000
Treeherderresults
reviewerssicking
bugs737122
milestone14.0a1
Bug 737122 - Attr nodes shouldn't have children; r=sicking
content/base/public/Makefile.in
content/base/public/nsIMutationObserver2.h
content/base/src/nsDOMAttribute.cpp
content/base/src/nsDOMAttribute.h
content/base/src/nsNodeIterator.cpp
content/base/src/nsNodeIterator.h
content/base/src/nsNodeUtils.cpp
content/base/src/nsNodeUtils.h
content/base/src/nsStubMutationObserver.cpp
content/base/src/nsStubMutationObserver.h
content/base/src/nsTextNode.cpp
content/base/src/nsTextNode.h
content/base/test/Makefile.in
content/base/test/test_bug590771.html
content/base/test/test_bug598877.html
content/base/test/test_bug600466.html
content/base/test/test_bug600468.html
content/base/test/test_bug600471.html
dom/tests/mochitest/dom-level1-core/exclusions.js
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -52,17 +52,16 @@ nsIAttribute.h \
 nsIContentIterator.h \
 nsContentErrors.h \
 nsContentPolicyUtils.h \
 nsContentUtils.h \
 nsIDocument.h \
 nsDeprecatedOperationList.h \
 nsIDocumentObserver.h \
 nsIMutationObserver.h \
-nsIMutationObserver2.h \
 nsINameSpaceManager.h \
 nsINode.h \
 nsINodeInfo.h \
 nsINodeList.h \
 nsIScriptElement.h \
 nsIStyleSheetLinkingElement.h \
 nsIContentSerializer.h \
 nsIXPathEvaluatorInternal.h \
deleted file mode 100644
--- a/content/base/public/nsIMutationObserver2.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- 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 <mounir.lamouri@mozilla.com> (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___ */
-
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -65,79 +65,51 @@
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 bool nsDOMAttribute::sInitialized;
 
 nsDOMAttribute::nsDOMAttribute(nsDOMAttributeMap *aAttrMap,
                                already_AddRefed<nsINodeInfo> aNodeInfo,
                                const nsAString   &aValue, bool aNsAware)
-  : nsIAttribute(aAttrMap, aNodeInfo, aNsAware), mValue(aValue), mChild(nsnull)
+  : nsIAttribute(aAttrMap, aNodeInfo, aNsAware), mValue(aValue)
 {
   NS_ABORT_IF_FALSE(mNodeInfo, "We must get a nodeinfo here!");
   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::ATTRIBUTE_NODE,
                     "Wrong nodeType");
 
   // We don't add a reference to our content. It will tell us
   // to drop our reference when it goes away.
-
-  EnsureChildState();
-
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    content->AddMutationObserver(this);
-  }
-}
-
-nsDOMAttribute::~nsDOMAttribute()
-{
-  if (mChild) {
-    static_cast<nsTextNode*>(mChild)->UnbindFromAttribute();
-    NS_RELEASE(mChild);
-    mFirstChild = nsnull;
-  }
-
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    content->RemoveMutationObserver(this);
-  }
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMAttribute)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttribute)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 
   if (!nsINode::Traverse(tmp, cb)) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
-
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mChild)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMAttribute)
   nsINode::Trace(tmp, aCallback, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttribute)
   nsINode::Unlink(tmp);
-  if (tmp->mChild) {
-    static_cast<nsTextNode*>(tmp->mChild)->UnbindFromAttribute();
-    NS_RELEASE(tmp->mChild);
-    tmp->mFirstChild = nsnull;
-  }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 DOMCI_NODE_DATA(Attr, nsDOMAttribute)
 
 // QueryInterface implementation for nsDOMAttribute
 NS_INTERFACE_TABLE_HEAD(nsDOMAttribute)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_NODE_INTERFACE_TABLE5(nsDOMAttribute, nsIDOMAttr, nsIAttribute, nsIDOMNode,
-                           nsIDOMEventTarget, nsIMutationObserver)
+  NS_NODE_INTERFACE_TABLE4(nsDOMAttribute, nsIDOMAttr, nsIAttribute, nsIDOMNode,
+                           nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttribute)
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
                                  new nsNodeSupportsWeakRefTearoff(this))
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
                                  new nsNode3Tearoff(this))
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Attr)
 NS_INTERFACE_MAP_END
 
@@ -149,28 +121,17 @@ void
 nsDOMAttribute::SetMap(nsDOMAttributeMap *aMap)
 {
   if (mAttrMap && !aMap && sInitialized) {
     // We're breaking a relationship with content and not getting a new one,
     // need to locally cache value. GetValue() does that.
     GetValue(mValue);
   }
 
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    content->RemoveMutationObserver(this);
-  }
-
   mAttrMap = aMap;
-
-  // If we have a new content, we sholud start listening to it.
-  content = GetContentInternal();
-  if (content) {
-    content->AddMutationObserver(this);
-  }
 }
 
 nsIContent*
 nsDOMAttribute::GetContent() const
 {
   return GetContentInternal();
 }
 
@@ -236,41 +197,28 @@ nsDOMAttribute::GetValue(nsAString& aVal
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::SetValue(const nsAString& aValue)
 {
-  nsresult rv = NS_OK;
   nsIContent* content = GetContentInternal();
-  if (content) {
-    nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
-    rv = content->SetAttr(mNodeInfo->NamespaceID(),
+  if (!content) {
+    mValue = aValue;
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
+  return content->SetAttr(mNodeInfo->NamespaceID(),
                           nameAtom,
                           mNodeInfo->GetPrefixAtom(),
                           aValue,
                           true);
-  }
-  else {
-    mValue = aValue;
-
-    if (mChild) {
-      if (mValue.IsEmpty()) {
-        doRemoveChild(true);
-      } else {
-        mChild->SetText(mValue, false);
-      }
-    } else {
-      EnsureChildState();
-    }
-  }
-
-  return rv;
 }
 
 
 NS_IMETHODIMP
 nsDOMAttribute::GetSpecified(bool* aSpecified)
 {
   NS_ENSURE_ARG_POINTER(aSpecified);
   OwnerDoc()->WarnOnceAbout(nsIDocument::eSpecified);
@@ -354,17 +302,17 @@ nsDOMAttribute::GetChildNodes(nsIDOMNode
   return nsINode::GetChildNodes(aChildNodes);
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::HasChildNodes(bool* aHasChildNodes)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eHasChildNodes);
 
-  *aHasChildNodes = mFirstChild != nsnull;
+  *aHasChildNodes = false;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::HasAttributes(bool* aHasAttributes)
 {
   NS_ENSURE_ARG_POINTER(aHasAttributes);
@@ -377,20 +325,16 @@ nsDOMAttribute::HasAttributes(bool* aHas
 
 NS_IMETHODIMP
 nsDOMAttribute::GetFirstChild(nsIDOMNode** aFirstChild)
 {
   *aFirstChild = nsnull;
 
   OwnerDoc()->WarnOnceAbout(nsIDocument::eFirstChild);
 
-  if (mFirstChild) {
-    CallQueryInterface(mFirstChild, aFirstChild);
-  }
-  
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMAttribute::GetLastChild(nsIDOMNode** aLastChild)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eLastChild);
 
@@ -653,40 +597,36 @@ bool
 nsDOMAttribute::IsNodeOfType(PRUint32 aFlags) const
 {
     return !(aFlags & ~eATTRIBUTE);
 }
 
 PRUint32
 nsDOMAttribute::GetChildCount() const
 {
-  return mFirstChild ? 1 : 0;
+  return 0;
 }
 
 nsIContent *
 nsDOMAttribute::GetChildAt(PRUint32 aIndex) const
 {
-  return aIndex == 0 ? mFirstChild : nsnull;
+  return nsnull;
 }
 
 nsIContent * const *
 nsDOMAttribute::GetChildArray(PRUint32* aChildCount) const
 {
-  *aChildCount = GetChildCount();
-  return &mFirstChild;
+  *aChildCount = 0;
+  return NULL;
 }
 
 PRInt32
 nsDOMAttribute::IndexOf(nsINode* aPossibleChild) const
 {
-  if (!aPossibleChild || aPossibleChild != mFirstChild) {
-    return -1;
-  }
-
-  return 0;
+  return -1;
 }
 
 nsresult
 nsDOMAttribute::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                               bool aNotify)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
@@ -695,106 +635,28 @@ nsresult
 nsDOMAttribute::AppendChildTo(nsIContent* aKid, bool aNotify)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void
 nsDOMAttribute::RemoveChildAt(PRUint32 aIndex, bool aNotify)
 {
-  if (aIndex != 0 || !mChild) {
-    return;
-  }
-
-  doRemoveChild(aNotify);
-
-  nsString nullString;
-  SetDOMStringToNull(nullString);
-  SetValue(nullString);
 }
 
 nsresult
 nsDOMAttribute::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   return NS_OK;
 }
 
 void
-nsDOMAttribute::EnsureChildState()
-{
-  NS_PRECONDITION(!mChild, "Someone screwed up");
-
-  nsAutoString value;
-  GetValue(value);
-
-  if (!value.IsEmpty()) {
-    NS_NewTextNode(&mChild, mNodeInfo->NodeInfoManager());
-
-    static_cast<nsTextNode*>(mChild)->BindToAttribute(this);
-    mFirstChild = mChild;
-
-    mChild->SetText(value, false);
-  }
-}
-
-void
-nsDOMAttribute::AttributeChanged(nsIDocument* aDocument,
-                                 Element* aElement,
-                                 PRInt32 aNameSpaceID,
-                                 nsIAtom* aAttribute,
-                                 PRInt32 aModType)
-{
-  nsIContent* content = GetContentInternal();
-  if (aElement != content) {
-    return;
-  }
-
-  if (aNameSpaceID != mNodeInfo->NamespaceID()) {
-    return;
-  }
-
-  nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
-  if (nameAtom != aAttribute) {
-    return;
-  }
-
-  nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
-  
-  // Just blow away our mChild and recreate it if needed
-  if (mChild) {
-    doRemoveChild(true);
-  }
-  EnsureChildState();
-}
-
-void
 nsDOMAttribute::Initialize()
 {
   sInitialized = true;
 }
 
 void
 nsDOMAttribute::Shutdown()
 {
   sInitialized = false;
 }
-
-void
-nsDOMAttribute::doRemoveChild(bool aNotify)
-{
-  NS_ASSERTION(mChild && mFirstChild, "Why are we here?");
-  NS_ASSERTION(mChild == mFirstChild, "Something got out of sync!");
-
-  nsRefPtr<nsTextNode> child = static_cast<nsTextNode*>(mChild);
-  nsMutationGuard::DidMutate();
-  mozAutoDocUpdate updateBatch(OwnerDoc(), UPDATE_CONTENT_MODEL, aNotify);
-
-  NS_RELEASE(mChild);
-  mFirstChild = nsnull;
-
-  if (aNotify) {
-    nsNodeUtils::AttributeChildRemoved(this, child);
-  }
-
-  child->UnbindFromAttribute();
-}
-
--- a/content/base/src/nsDOMAttribute.h
+++ b/content/base/src/nsDOMAttribute.h
@@ -51,25 +51,24 @@
 #include "nsINodeInfo.h"
 #include "nsDOMAttributeMap.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsStubMutationObserver.h"
 
 // Attribute helper class used to wrap up an attribute with a dom
 // object that implements nsIDOMAttr and nsIDOMNode
 class nsDOMAttribute : public nsIAttribute,
-                       public nsIDOMAttr,
-                       public nsStubMutationObserver
+                       public nsIDOMAttr
 {
 public:
   nsDOMAttribute(nsDOMAttributeMap* aAttrMap,
                  already_AddRefed<nsINodeInfo> aNodeInfo,
                  const nsAString& aValue,
                  bool aNsAware);
-  virtual ~nsDOMAttribute();
+  virtual ~nsDOMAttribute() {}
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   // nsIDOMNode interface
   NS_DECL_NSIDOMNODE
 
   // nsIDOMAttr interface
   NS_DECL_NSIDOMATTR
@@ -95,43 +94,29 @@ public:
   virtual already_AddRefed<nsIURI> GetBaseURI() const;
 
   static void Initialize();
   static void Shutdown();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDOMAttribute,
                                                          nsIAttribute)
 
-  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
-
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   virtual mozilla::dom::Element* GetNameSpaceElement()
   {
     return GetContentInternal();
   }
 
   static bool sInitialized;
 
 private:
   already_AddRefed<nsIAtom> GetNameAtom(nsIContent* aContent);
-
-  void EnsureChildState();
-
-  /**
-   * Really removing the attribute child (unbind and release).
-   */
-  void doRemoveChild(bool aNotify);
-
-  nsString mValue;
-  // XXX For now, there's only a single child - a text element
-  // representing the value.  This is strong ref, but we use a raw
-  // pointer so we can implement GetChildArray().
-  nsIContent* mChild;
-
   mozilla::dom::Element *GetContentInternal() const
   {
     return mAttrMap ? mAttrMap->GetContent() : nsnull;
   }
+
+  nsString mValue;
 };
 
 
 #endif /* nsDOMAttribute_h___ */
--- a/content/base/src/nsNodeIterator.cpp
+++ b/content/base/src/nsNodeIterator.cpp
@@ -202,17 +202,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 DOMCI_DATA(NodeIterator, nsNodeIterator)
 
 // QueryInterface implementation for 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
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeIterator)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeIterator)
 
 /* readonly attribute nsIDOMNode root; */
@@ -340,16 +339,8 @@ void nsNodeIterator::ContentRemoved(nsID
                                     PRInt32 aIndexInContainer,
                                     nsIContent *aPreviousSibling)
 {
     nsINode *container = NODE_FROM(aContainer, 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);
-}
-
--- a/content/base/src/nsNodeIterator.h
+++ b/content/base/src/nsNodeIterator.h
@@ -50,29 +50,28 @@
 #include "nsStubMutationObserver.h"
 
 class nsINode;
 class nsIDOMNode;
 class nsIDOMNodeFilter;
 
 class nsNodeIterator : public nsIDOMNodeIterator,
                        public nsTraversal,
-                       public nsStubMutationObserver2
+                       public nsStubMutationObserver
 {
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDOMNODEITERATOR
 
     nsNodeIterator(nsINode *aRoot,
                    PRUint32 aWhatToShow,
                    nsIDOMNodeFilter *aFilter);
     virtual ~nsNodeIterator();
 
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
-    NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNodeIterator, nsIDOMNodeIterator)
 
 private:
     struct NodePointer {
         NodePointer() : mNode(nsnull) {};
         NodePointer(nsINode *aNode, bool aBeforeNode);
 
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -37,21 +37,19 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsNodeUtils.h"
 #include "nsContentUtils.h"
 #include "nsINode.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Element.h"
 #include "nsIMutationObserver.h"
-#include "nsIMutationObserver2.h"
 #include "nsIDocument.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsEventListenerManager.h"
-#include "nsIAttribute.h"
 #include "nsIXPConnect.h"
 #include "nsGenericElement.h"
 #include "pldhash.h"
 #include "nsIDOMAttr.h"
 #include "nsCOMArray.h"
 #include "nsPIDOMWindow.h"
 #include "nsDocument.h"
 #ifdef MOZ_XUL
@@ -67,18 +65,16 @@
 #include "nsWrapperCacheInlines.h"
 #include "nsObjectLoadingContent.h"
 #include "nsDOMMutationObserver.h"
 
 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                                                  \
   bool needsEnterLeave = doc->MayHaveDOMMutationObservers();      \
   if (needsEnterLeave) {                                          \
     nsDOMMutationObserver::EnterMutationHandling();               \
   }                                                               \
   nsINode* node = content_;                                       \
   NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document");        \
@@ -202,42 +198,16 @@ nsNodeUtils::ContentRemoved(nsINode* aCo
   }
 
   IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
                              (document, container, aChild, aIndexInContainer,
                               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<nsIMutationObserver*>::ForwardIterator iter_ =
-        slots->mMutationObservers;
-      nsCOMPtr<nsIMutationObserver2> obs_;
-      while (iter_.HasMore()) {
-        obs_ = do_QueryInterface(iter_.GetNext());
-        if (obs_) {
-          obs_->AttributeChildRemoved(aAttribute, aChild);
-        }
-      }
-    }
-    aAttribute = aAttribute->GetNodeParent();
-  } while (aAttribute);
-}
-
-void
 nsNodeUtils::LastRelease(nsINode* aNode)
 {
   nsINode::nsSlots* slots = aNode->GetExistingSlots();
   if (slots) {
     if (!slots->mMutationObservers.IsEmpty()) {
       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
                                          nsIMutationObserver,
                                          NodeWillBeDestroyed, (aNode));
@@ -605,42 +575,21 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
     }
   }
 
   // XXX If there are any attribute nodes on this element with UserDataHandlers
   // we should technically adopt/clone/import such attribute nodes and notify
   // those handlers. However we currently don't have code to do so without
   // also notifying when it's not safe so we're not doing that at this time.
 
-  // The DOM spec says to always adopt/clone/import the children of attribute
-  // nodes.
-  // XXX The following block is here because our implementation of attribute
-  //     nodes is broken when it comes to inserting children. Instead of cloning
-  //     their children we force creation of the only child by calling
-  //     GetChildAt(0). We can remove this when
-  //     https://bugzilla.mozilla.org/show_bug.cgi?id=56758 is fixed.
-  if (aClone && aNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
-    nsCOMPtr<nsINode> attrChildNode = aNode->GetChildAt(0);
-    // We only need to do this if the child node has properties (because we
-    // might need to call a userdata handler).
-    if (attrChildNode && attrChildNode->HasProperties()) {
-      nsCOMPtr<nsINode> clonedAttrChildNode = clone->GetChildAt(0);
-      if (clonedAttrChildNode) {
-        bool ok = aNodesWithProperties.AppendObject(attrChildNode) &&
-                    aNodesWithProperties.AppendObject(clonedAttrChildNode);
-        NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
-      }
-    }
-  }
-  // XXX End of workaround for broken attribute nodes.
-  else if (aDeep || aNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
+  if (aDeep && (!aClone || !aNode->IsNodeOfType(nsINode::eATTRIBUTE))) {
     // aNode's children.
     for (nsIContent* cloneChild = aNode->GetFirstChild();
          cloneChild;
-       cloneChild = cloneChild->GetNextSibling()) {
+         cloneChild = cloneChild->GetNextSibling()) {
       nsCOMPtr<nsINode> child;
       rv = CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager,
                          aCx, aNewScope, aNodesWithProperties, clone,
                          getter_AddRefs(child));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
--- a/content/base/src/nsNodeUtils.h
+++ b/content/base/src/nsNodeUtils.h
@@ -125,23 +125,16 @@ public:
    * @param aIndexInContainer Index of removed child
    * @see nsIMutationObserver::ContentRemoved
    */
   static void ContentRemoved(nsINode* aContainer,
                              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.
    * @see nsIMutationObserver::ParentChainChanged
    */
   static inline void ParentChainChanged(nsIContent *aContent)
   {
     nsINode::nsSlots* slots = aContent->GetExistingSlots();
     if (slots && !slots->mMutationObservers.IsEmpty()) {
--- a/content/base/src/nsStubMutationObserver.cpp
+++ b/content/base/src/nsStubMutationObserver.cpp
@@ -41,11 +41,8 @@
  * used as a base class within the content/layout library.  All methods do
  * nothing.
  */
 
 #include "nsStubMutationObserver.h"
 
 NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver)
 NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(nsStubMutationObserver)
-
-NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver2)
-NS_IMPL_NSIMUTATIONOBSERVER2_CONTENT(nsStubMutationObserver2)
--- a/content/base/src/nsStubMutationObserver.h
+++ b/content/base/src/nsStubMutationObserver.h
@@ -41,30 +41,25 @@
  * used as a base class within the content/layout library.  All methods do
  * nothing.
  */
 
 #ifndef nsStubMutationObserver_h_
 #define nsStubMutationObserver_h_
 
 #include "nsIMutationObserver.h"
-#include "nsIMutationObserver2.h"
 
 /**
  * There are two advantages to inheriting from nsStubMutationObserver
  * rather than directly from nsIMutationObserver:
  *  1. smaller compiled code size (since there's no need for the code
  *     for the empty virtual function implementations for every
  *     nsIMutationObserver implementation)
  *  2. the performance of document's loop over observers benefits from
  *     the fact that more of the functions called are the same (which
  *     can reduce instruction cache misses and perhaps improve branch
  *     prediction)
  */
 class nsStubMutationObserver : public nsIMutationObserver {
   NS_DECL_NSIMUTATIONOBSERVER
 };
 
-class nsStubMutationObserver2 : public nsIMutationObserver2 {
-  NS_DECL_NSIMUTATIONOBSERVER2
-};
-
 #endif /* !defined(nsStubMutationObserver_h_) */
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -38,17 +38,16 @@
 /*
  * Implementation of DOM Core's nsIDOMText node.
  */
 
 #include "nsTextNode.h"
 #include "nsContentUtils.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMMutationEvent.h"
-#include "nsIAttribute.h"
 #include "nsIDocument.h"
 #include "nsThreadUtils.h"
 #ifdef DEBUG
 #include "nsRange.h"
 #endif
 
 using namespace mozilla::dom;
 
@@ -179,39 +178,16 @@ nsTextNode::CloneDataNode(nsINodeInfo *a
   nsTextNode *it = new nsTextNode(ni.forget());
   if (it && aCloneText) {
     it->mText = mText;
   }
 
   return it;
 }
 
-void
-nsTextNode::BindToAttribute(nsIAttribute* aAttr)
-{
-  NS_ASSERTION(!IsInDoc(), "Unbind before binding!");
-  NS_ASSERTION(!GetNodeParent(), "Unbind before binding!");
-  NS_ASSERTION(HasSameOwnerDoc(aAttr), "Wrong owner document!");
-
-  mParent = aAttr;
-  SetParentIsContent(false);
-  ClearInDocument();
-  SetSubtreeRootPointer(aAttr->SubtreeRoot());
-}
-
-void
-nsTextNode::UnbindFromAttribute()
-{
-  NS_ASSERTION(GetNodeParent(), "Bind before unbinding!");
-  NS_ASSERTION(GetNodeParent()->IsNodeOfType(nsINode::eATTRIBUTE),
-               "Use this method only to unbind from an attribute!");
-  mParent = nsnull;
-  SetSubtreeRootPointer(this);
-}
-
 nsresult
 nsTextNode::AppendTextForNormalize(const PRUnichar* aBuffer, PRUint32 aLength,
                                    bool aNotify, nsIContent* aNextSibling)
 {
   CharacterDataChangeInfo::Details details = {
     CharacterDataChangeInfo::Details::eMerge, aNextSibling
   };
   return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify, &details);
--- a/content/base/src/nsTextNode.h
+++ b/content/base/src/nsTextNode.h
@@ -37,20 +37,16 @@
 
 /*
  * Implementation of DOM Core's nsIDOMText node.
  */
 
 #include "nsGenericDOMDataNode.h"
 #include "nsIDOMText.h"
 
-#include "nsIAttribute.h"
-#include "nsIDocument.h"
-#include "nsThreadUtils.h"
-
 /**
  * Class used to implement DOM text nodes
  */
 class nsTextNode : public nsGenericDOMDataNode,
                    public nsIDOMText
 {
 public:
   nsTextNode(already_AddRefed<nsINodeInfo> aNodeInfo);
@@ -69,19 +65,16 @@ public:
   NS_FORWARD_NSIDOMTEXT(nsGenericDOMDataNode::)
 
   // nsINode
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
 
   virtual nsGenericDOMDataNode* CloneDataNode(nsINodeInfo *aNodeInfo,
                                               bool aCloneText) const;
 
-  void BindToAttribute(nsIAttribute* aAttr);
-  void UnbindFromAttribute();
-
   virtual nsXPCClassInfo* GetClassInfo();
 
   nsresult AppendTextForNormalize(const PRUnichar* aBuffer, PRUint32 aLength,
                                   bool aNotify, nsIContent* aNextSibling);
 
 #ifdef DEBUG
   virtual void List(FILE* out, PRInt32 aIndent) const;
   virtual void DumpContent(FILE* out, PRInt32 aIndent, bool aDumpAll) const;
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -436,21 +436,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug564047.html \
 		test_bug567350.html \
 		test_bug578096.html \
 		test_bug585978.html \
 		test_bug592366.html \
 		test_bug597345.html \
 		script-1_bug597345.sjs \
 		script-2_bug597345.js \
-		test_bug598877.html \
 		test_bug599588.html \
-		test_bug600466.html \
-		test_bug600468.html \
-		test_bug600471.html \
 		test_bug601803.html \
 		file_bug601803a.html \
 		file_bug601803b.html \
 		test_bug602838.html \
 		script_bug602838.sjs \
 		test_bug614583.html \
 		test_bug604660.html \
 		file_bug604660-1.xml \
@@ -458,17 +454,16 @@ include $(topsrcdir)/config/rules.mk
 		file_bug604660-3.js \
 		file_bug604660-4.js \
 		file_bug604660-5.xml \
 		file_bug604660-6.xsl \
 		test_bug605982.html \
 		test_bug606729.html \
 		test_treewalker_nextsibling.xml \
 		test_bug614058.html \
-		test_bug590771.html \
 		test_bug622117.html \
 		test_base.xhtml \
 		file_base_xbl.xml \
 		test_bug622246.html \
 		test_bug484396.html \
 		test_bug466080.html \
 		bug466080.sjs \
 		test_bug625722.html \
deleted file mode 100644
--- a/content/base/test/test_bug590771.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=590771
--->
-<head>
-  <title>Test for Bug 590771</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=590771">Mozilla Bug 590771</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 590771 **/
-
-function test1()
-{
-  var attr = document.createAttribute("foo");
-  attr.value = "bar";
-  var ni = document.createNodeIterator(attr, -1, null, false);
-  ni.nextNode();
-  ni.nextNode();
-  is(ni.referenceNode, attr.firstChild,
-      "iterator should be on the first child attribute");
-
-  attr.removeChild(attr.firstChild);
-  is(ni.referenceNode, attr,
-     "iterator should be on the attribute now");
-}
-
-function test2()
-{
-  var attr = document.createAttribute("foo");
-  attr.value = "bar";
-  var ni = document.createNodeIterator(attr, -1, null, false);
-  ni.nextNode();
-  ni.nextNode();
-  is(ni.referenceNode, attr.firstChild,
-      "iterator should be on the first child attribute");
-
-  attr.value = "";
-  is(ni.referenceNode, attr,
-     "iterator should be on the attribute now");
-}
-
-function test3()
-{
-  var attr = document.createAttribute("foo");
-  attr.value = "bar";
-  var node = document.createElement("div");
-  node.setAttributeNode(attr);
-  var ni = document.createNodeIterator(attr, -1, null, false);
-  ni.nextNode();
-  ni.nextNode();
-  is(ni.referenceNode, attr.firstChild,
-      "iterator should be on the first child attribute");
-
-  node.setAttribute("foo", "");
-  is(ni.referenceNode, attr,
-     "iterator should be on the attribute now");
-}
-
-test1();
-test2();
-test3();
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug598877.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=598877
--->
-<head>
-  <title>Test for Bug 598877</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=598877">Mozilla Bug 598877</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 598877 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-ok(attr.firstChild, "attr.firstChild should be a text node");
-is(attr.firstChild.nodeValue, "bar", "the text node value should be 'bar'");
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug600466.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=600466
--->
-<head>
-  <title>Test for Bug 600466</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=600466">Mozilla Bug 600466</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 600466 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-ok(attr.firstChild, "attr should have a first child");
-
-attr.removeChild(attr.firstChild);
-ok(!attr.firstChild, "attr should not have a first child anymore");
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug600468.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=600468
--->
-<head>
-  <title>Test for Bug 600468</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=600468">Mozilla Bug 600468</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 600468 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-ok(attr.firstChild, "attr should have a first child");
-
-attr.value = "";
-ok(!attr.firstChild, "attr should not have a first child");
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug600471.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=600471
--->
-<head>
-  <title>Test for Bug 600471</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=600471">Mozilla Bug 600471</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 600471 **/
-
-var attr = document.createAttribute("foo");
-attr.value = "bar";
-var node = document.createElement("div");
-node.setAttributeNode(attr);
-
-node.setAttribute("foo", "newvalue");
-is(attr.firstChild.nodeValue, "newvalue", "the value should be updated");
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/tests/mochitest/dom-level1-core/exclusions.js
+++ b/dom/tests/mochitest/dom-level1-core/exclusions.js
@@ -74,17 +74,20 @@ var indexErrTests = ["characterdataindex
                      "characterdataindexsizeerrsubstringcountnegative", "hc_characterdataindexsizeerrdeletedatacountnegative",
                      "hc_characterdataindexsizeerrreplacedatacountnegative", "hc_characterdataindexsizeerrsubstringcountnegative"];
 
 var attributeModTests = ["hc_attrappendchild1", "hc_attrappendchild3", "hc_attrappendchild5",
                          "hc_attrappendchild6", "hc_attrchildnodes2", "hc_attrclonenode1", "hc_attrinsertbefore1",
                          "hc_attrinsertbefore2", "hc_attrinsertbefore3", "hc_attrinsertbefore4", "hc_attrinsertbefore6",
                          "hc_attrnormalize", "hc_attrreplacechild1", "hc_attrreplacechild2",
                          "hc_attrsetvalue2", "hc_elementnormalize2", "hc_elementnotfounderr", "hc_elementremoveattribute", "hc_elementnormalize2",
-                         "hc_elementnotfounderr", "hc_elementremoveattribute", ];
+                         "hc_elementnotfounderr", "hc_elementremoveattribute",
+                         "hc_attrchildnodes1", "hc_attrfirstchild",
+                         "hc_attrhaschildnodes", "hc_attrlastchild",
+                         "hc_attrremovechild1", "hc_attrsetvalue1"];
 var modTests = ["hc_elementwrongdocumenterr", "hc_namednodemapwrongdocumenterr", "hc_nodeappendchildnewchilddiffdocument", "hc_nodeinsertbeforenewchilddiffdocument",
                 "hc_nodereplacechildnewchilddiffdocument", "hc_elementwrongdocumenterr", "hc_namednodemapwrongdocumenterr", "hc_nodeappendchildnewchilddiffdocument",
                 "hc_nodeinsertbeforenewchilddiffdocument", "hc_nodereplacechildnewchilddiffdocument", "elementwrongdocumenterr", "namednodemapwrongdocumenterr",
                 "nodeappendchildnewchilddiffdocument", "nodeinsertbeforenewchilddiffdocument", "nodereplacechildnewchilddiffdocument"];
 // These tests rely on an implementation of document.createEntityReference.
 var createEntityRef = ["documentinvalidcharacterexceptioncreateentref",
                        "documentinvalidcharacterexceptioncreateentref1",
                        "hc_attrgetvalue2", "hc_nodevalue03"];