Bug 380872: Call BindToTree on anonymous children too when BindToTree is called on an element. r/sr=bz
authorjonas@sicking.cc
Mon, 21 May 2007 15:26:48 -0700
changeset 1685 068e9d520eb8e927ae033c58c6b378d60e98053c
parent 1684 a98fe4a428a9a0ee4d1b23c1043aea2f6f9a5796
child 1686 df4efdc3619f53143c9f7a45f53ade359e7ee46b
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs380872
milestone1.9a5pre
Bug 380872: Call BindToTree on anonymous children too when BindToTree is called on an element. r/sr=bz
content/base/src/nsGenericElement.cpp
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLBinding.h
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -109,16 +109,17 @@
 #include "nsICategoryManager.h"
 #include "nsIDOMNSFeatureFactory.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsEventDispatcher.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIFocusController.h"
 #include "nsIControllers.h"
+#include "nsXBLInsertionPoint.h"
 
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsCCUncollectableMarker.h"
 
 #ifdef MOZ_SVG
 PRBool NS_SVG_TestFeature(const nsAString &fstr);
 #endif /* MOZ_SVG */
@@ -1687,16 +1688,30 @@ nsGenericElement::Normalize()
           break;
       }
     }
   }
 
   return result;
 }
 
+static nsXBLBinding*
+GetFirstBindingWithContent(nsBindingManager* aBmgr, nsIContent* aBoundElem)
+{
+  nsXBLBinding* binding = aBmgr->GetBinding(aBoundElem);
+  while (binding) {
+    if (binding->GetAnonymousContent()) {
+      return binding;
+    }
+    binding = binding->GetBaseBinding();
+  }
+  
+  return nsnull;
+}
+
 nsresult
 nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                              nsIContent* aBindingParent,
                              PRBool aCompileEventHandlers)
 {
   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
   NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
                   "Must have the same owner document");
@@ -1707,16 +1722,19 @@ nsGenericElement::BindToTree(nsIDocument
   // only assert if our parent is _changing_ while we have a parent.
   NS_PRECONDITION(!GetParent() || aParent == GetParent(),
                   "Already have a parent.  Unbind first!");
   NS_PRECONDITION(!GetBindingParent() ||
                   aBindingParent == GetBindingParent() ||
                   (!aBindingParent && aParent &&
                    aParent->GetBindingParent() == GetBindingParent()),
                   "Already have a binding parent.  Unbind first!");
+  NS_PRECONDITION(!aParent || !aDocument ||
+                  !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
+                  "Parent in document but flagged as forcing XBL");
   // XXXbz XUL's SetNativeAnonymous is all weird, so can't assert
   // anything here
   NS_PRECONDITION(IsNodeOfType(eXUL) ||
                   aBindingParent != this || IsNativeAnonymous(),
                   "Only native anonymous content should have itself as its "
                   "own binding parent");
   
   if (!aBindingParent && aParent) {
@@ -1735,16 +1753,18 @@ nsGenericElement::BindToTree(nsIDocument
       if (!slots) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
     }
   }
 
+  PRBool hadForceXBL = HasFlag(NODE_FORCE_XBL_BINDINGS);
+
   // Now set the parent and set the "Force attach xbl" flag if needed.
   if (aParent) {
     mParentPtrBits = NS_REINTERPRET_CAST(PtrBits, aParent) | PARENT_BIT_PARENT_IS_CONTENT;
 
     if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
       SetFlags(NODE_FORCE_XBL_BINDINGS);
     }
   }
@@ -1767,18 +1787,68 @@ nsGenericElement::BindToTree(nsIDocument
 
     // Being added to a document.
     mParentPtrBits |= PARENT_BIT_INDOCUMENT;
 
     // Unset this flag since we now really are in a document.
     UnsetFlags(NODE_FORCE_XBL_BINDINGS);
   }
 
+  // If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
+  // that also need to be told that they are moving.
+  nsresult rv;
+  if (hadForceXBL) {
+    nsIDocument* ownerDoc = GetOwnerDoc();
+    if (ownerDoc) {
+      nsBindingManager* bmgr = ownerDoc->BindingManager();
+
+      // First check if we have a binding...
+      nsXBLBinding* contBinding =
+        GetFirstBindingWithContent(bmgr, this);
+      if (contBinding) {
+        nsCOMPtr<nsIContent> anonRoot = contBinding->GetAnonymousContent();
+        PRBool allowScripts = contBinding->AllowScripts();
+        PRUint32 i;
+        for (i = 0; i < anonRoot->GetChildCount(); ++i) {
+          nsCOMPtr<nsIContent> child = anonRoot->GetChildAt(i);
+          rv = child->BindToTree(aDocument, this, this, allowScripts);
+          NS_ENSURE_SUCCESS(rv, rv);
+        }
+      }
+
+      // ...then check if we have content in insertion points
+      if (aBindingParent) {
+        nsXBLBinding* binding = bmgr->GetBinding(aBindingParent);
+        NS_ASSERTION(binding, "huh, no binding?");
+        if (binding) {
+          // These should be refcounted.
+          nsInsertionPointList* inserts =
+            binding->GetExistingInsertionPointsFor(this);
+          if (inserts) {
+            PRBool allowScripts = binding->AllowScripts();
+            PRUint32 i;
+            for (i = 0; i < inserts->Length(); ++i) {
+              nsCOMPtr<nsIContent> insertRoot =
+                inserts->ElementAt(i)->GetDefaultContent();
+              if (insertRoot) {
+                PRUint32 j;
+                for (j = 0; j < insertRoot->GetChildCount(); ++j) {
+                  nsCOMPtr<nsIContent> child = insertRoot->GetChildAt(j);
+                  rv = child->BindToTree(aDocument, this, aBindingParent, allowScripts);
+                  NS_ENSURE_SUCCESS(rv, rv);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
   // Now recurse into our kids
-  nsresult rv;
   PRUint32 i;
   // Don't call GetChildCount() here since that'll make XUL generate
   // template children, which we're not in a consistent enough state for.
   // Additionally, there's not really a need to generate the children here.
   for (i = 0; i < mAttrsAndChildren.ChildCount(); ++i) {
     // The child can remove itself from the parent in BindToTree.
     nsCOMPtr<nsIContent> child = mAttrsAndChildren.ChildAt(i);
     rv = child->BindToTree(aDocument, this, aBindingParent,
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -1247,16 +1247,28 @@ nsXBLBinding::GetInsertionPointsFor(nsIC
       *aResult = nsnull;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   return NS_OK;
 }
 
+nsInsertionPointList*
+nsXBLBinding::GetExistingInsertionPointsFor(nsIContent* aParent)
+{
+  if (!mInsertionPointTable) {
+    return nsnull;
+  }
+
+  nsInsertionPointList* result = nsnull;
+  mInsertionPointTable->Get(aParent, &result);
+  return result;
+}
+
 nsIContent*
 nsXBLBinding::GetInsertionPoint(nsIContent* aChild, PRUint32* aIndex)
 {
   if (mContent) {
     return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent,
                                                 aChild, aIndex);
   }
 
--- a/content/xbl/src/nsXBLBinding.h
+++ b/content/xbl/src/nsXBLBinding.h
@@ -129,16 +129,18 @@ public:
   nsXBLBinding* RootBinding();
   nsXBLBinding* GetFirstStyleBinding();
 
   // Get the list of insertion points for aParent. The nsInsertionPointList
   // is owned by the binding, you should not delete it.
   nsresult GetInsertionPointsFor(nsIContent* aParent,
                                  nsInsertionPointList** aResult);
 
+  nsInsertionPointList* GetExistingInsertionPointsFor(nsIContent* aParent);
+
   nsIContent* GetInsertionPoint(nsIContent* aChild, PRUint32* aIndex);
 
   nsIContent* GetSingleInsertionPoint(PRUint32* aIndex,
                                       PRBool* aMultipleInsertionPoints);
 
   void AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID,
                         PRBool aRemoveFlag, PRBool aNotify);
 
@@ -147,24 +149,24 @@ public:
   void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
 
   already_AddRefed<nsIDOMNodeList> GetAnonymousNodes();
 
   static nsresult DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
                                 const nsAFlatCString& aClassName,
                                 void **aClassObject);
 
+  PRBool AllowScripts();  // XXX make const
+
 // Internal member functions
 protected:
   nsresult InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
                      nsIDocument* aDocument, void** aScriptObject,
                      void** aClassObject);
 
-  PRBool AllowScripts();  // XXX make const
-  
 // MEMBER VARIABLES
 protected:
   nsAutoRefCnt mRefCnt;
   nsXBLPrototypeBinding* mPrototypeBinding; // Weak, but we're holding a ref to the docinfo
   nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
   nsRefPtr<nsXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.
   
   nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.