diff --git a/mozilla/content/xbl/public/nsIBindingManager.h b/mozilla/content/xbl/public/nsIBindingManager.h index 4c4b87fab30..17a045c657b 100644 --- a/mozilla/content/xbl/public/nsIBindingManager.h +++ b/mozilla/content/xbl/public/nsIBindingManager.h @@ -51,6 +51,10 @@ public: NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding) = 0; NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult) = 0; + + NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) = 0; + NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, + PRBool* aMultipleInsertionPoints) = 0; }; #endif // nsIBinding_Manager_h__ diff --git a/mozilla/content/xbl/public/nsIXBLBinding.h b/mozilla/content/xbl/public/nsIXBLBinding.h index 80c1f0e5ead..9ecbef025f1 100644 --- a/mozilla/content/xbl/public/nsIXBLBinding.h +++ b/mozilla/content/xbl/public/nsIXBLBinding.h @@ -57,8 +57,6 @@ public: NS_IMETHOD GetBindingElement(nsIContent** aResult) = 0; NS_IMETHOD SetBindingElement(nsIContent* aElement) = 0; - NS_IMETHOD GetInsertionPoint(nsIContent** aResult) = 0; - NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallProperties(nsIContent* aBoundElement) = 0; @@ -71,6 +69,9 @@ public: NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument) = 0; NS_IMETHOD GetBindingURI(nsString& aResult) = 0; + + NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) = 0; + NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0; }; extern nsresult diff --git a/mozilla/content/xbl/public/nsIXBLService.h b/mozilla/content/xbl/public/nsIXBLService.h index 1496b565a2a..d2977c4f8b8 100644 --- a/mozilla/content/xbl/public/nsIXBLService.h +++ b/mozilla/content/xbl/public/nsIXBLService.h @@ -58,7 +58,8 @@ public: // For a given element, returns a flat list of all the anonymous children that need // frames built. - NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement) = 0; + NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement, + PRBool* aMultipleInsertionPoints) = 0; // Retrieves our base class (e.g., tells us what type of frame and content node to build) NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult) = 0; diff --git a/mozilla/content/xbl/src/nsBindingManager.cpp b/mozilla/content/xbl/src/nsBindingManager.cpp index 8fe02aa661e..558ed0bf608 100644 --- a/mozilla/content/xbl/src/nsBindingManager.cpp +++ b/mozilla/content/xbl/src/nsBindingManager.cpp @@ -65,6 +65,10 @@ public: NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult); + NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult); + NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, + PRBool* aMultipleInsertionPoints); + // MEMBER VARIABLES protected: nsSupportsHashtable* mBindingTable; @@ -144,6 +148,31 @@ nsBindingManager::ResolveTag(nsIContent* aContent, nsIAtom** aResult) return aContent->GetTag(*aResult); } +NS_IMETHODIMP +nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) +{ + nsCOMPtr binding; + GetBinding(aParent, getter_AddRefs(binding)); + + if (binding) + return binding->GetInsertionPoint(aChild, aResult); + + return NS_OK; +} + +NS_IMETHODIMP +nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, + PRBool* aMultipleInsertionPoints) +{ + nsCOMPtr binding; + GetBinding(aParent, getter_AddRefs(binding)); + + if (binding) + return binding->GetSingleInsertionPoint( aResult, aMultipleInsertionPoints); + + return NS_OK; +} + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/mozilla/content/xbl/src/nsXBLBinding.cpp b/mozilla/content/xbl/src/nsXBLBinding.cpp index 22c33b3273f..a5be05e1fde 100644 --- a/mozilla/content/xbl/src/nsXBLBinding.cpp +++ b/mozilla/content/xbl/src/nsXBLBinding.cpp @@ -145,8 +145,6 @@ class nsXBLBinding: public nsIXBLBinding, public nsIScriptObjectOwner NS_IMETHOD GetBindingElement(nsIContent** aResult); NS_IMETHOD SetBindingElement(nsIContent* aElement); - NS_IMETHOD GetInsertionPoint(nsIContent** aResult); - NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); NS_IMETHOD InstallProperties(nsIContent* aBoundElement); @@ -158,6 +156,9 @@ class nsXBLBinding: public nsIXBLBinding, public nsIScriptObjectOwner NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument); NS_IMETHOD GetBindingURI(nsString& aResult); + + NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); + NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); // nsIScriptObjectOwner NS_IMETHOD GetScriptObject(nsIScriptContext* aContext, void** aScriptObject); @@ -180,6 +181,7 @@ public: static nsIAtom* kInterfaceAtom; static nsIAtom* kHandlersAtom; static nsIAtom* kExcludesAtom; + static nsIAtom* kIncludesAtom; static nsIAtom* kInheritsAtom; static nsIAtom* kTypeAtom; static nsIAtom* kCapturerAtom; @@ -214,6 +216,9 @@ protected: void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult); void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult); + void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList); + void BuildInsertionTable(); + void GetNestedChildren(); PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList); NS_IMETHOD ConstructAttributeTable(nsIContent* aElement); @@ -230,12 +235,12 @@ protected: nsCOMPtr mBinding; // Strong. As long as we're around, the binding can't go away. nsCOMPtr mContent; // Strong. Our anonymous content stays around with us. nsCOMPtr mNextBinding; // Strong. The derived binding owns the base class bindings. - nsCOMPtr mChildrenElement; // Strong. One of our anonymous content children. void* mScriptObject; // Strong nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it. nsSupportsHashtable* mAttributeTable; // A table for attribute entries. + nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. }; // Static initialization @@ -245,6 +250,7 @@ nsIAtom* nsXBLBinding::kContentAtom = nsnull; nsIAtom* nsXBLBinding::kInterfaceAtom = nsnull; nsIAtom* nsXBLBinding::kHandlersAtom = nsnull; nsIAtom* nsXBLBinding::kExcludesAtom = nsnull; +nsIAtom* nsXBLBinding::kIncludesAtom = nsnull; nsIAtom* nsXBLBinding::kInheritsAtom = nsnull; nsIAtom* nsXBLBinding::kTypeAtom = nsnull; nsIAtom* nsXBLBinding::kCapturerAtom = nsnull; @@ -319,7 +325,8 @@ NS_IMPL_ISUPPORTS2(nsXBLBinding, nsIXBLBinding, nsIScriptObjectOwner) // Constructors/Destructors nsXBLBinding::nsXBLBinding(void) : mScriptObject(nsnull), - mAttributeTable(nsnull) + mAttributeTable(nsnull), + mInsertionPointTable(nsnull) { NS_INIT_REFCNT(); gRefCnt++; @@ -328,6 +335,7 @@ nsXBLBinding::nsXBLBinding(void) kInterfaceAtom = NS_NewAtom("interface"); kHandlersAtom = NS_NewAtom("handlers"); kExcludesAtom = NS_NewAtom("excludes"); + kIncludesAtom = NS_NewAtom("includes"); kInheritsAtom = NS_NewAtom("inherits"); kTypeAtom = NS_NewAtom("type"); kCapturerAtom = NS_NewAtom("capturer"); @@ -362,6 +370,7 @@ nsXBLBinding::nsXBLBinding(void) nsXBLBinding::~nsXBLBinding(void) { delete mAttributeTable; + delete mInsertionPointTable; gRefCnt--; if (gRefCnt == 0) { @@ -369,6 +378,7 @@ nsXBLBinding::~nsXBLBinding(void) NS_RELEASE(kInterfaceAtom); NS_RELEASE(kHandlersAtom); NS_RELEASE(kExcludesAtom); + NS_RELEASE(kIncludesAtom); NS_RELEASE(kInheritsAtom); NS_RELEASE(kTypeAtom); NS_RELEASE(kCapturerAtom); @@ -468,14 +478,6 @@ nsXBLBinding::SetBindingElement(nsIContent* aElement) return NS_OK; } -NS_IMETHODIMP -nsXBLBinding::GetInsertionPoint(nsIContent** aResult) -{ - *aResult = mChildrenElement; - NS_IF_ADDREF(*aResult); - return NS_OK; -} - NS_IMETHODIMP nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) { @@ -569,9 +571,8 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) nsCOMPtr clonedContent = do_QueryInterface(clonedNode); SetAnonymousContent(clonedContent); - if (childrenElement) { - GetNestedChild(kChildrenAtom, clonedContent, getter_AddRefs(mChildrenElement)); - } + if (childrenElement) + BuildInsertionTable(); } if (mNextBinding) { @@ -1215,10 +1216,76 @@ nsXBLBinding::GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** a return; } } - - return; } +void +nsXBLBinding::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList) +{ + PRInt32 childCount; + aContent->ChildCount(childCount); + for (PRInt32 i = 0; i < childCount; i++) { + nsCOMPtr child; + aContent->ChildAt(i, *getter_AddRefs(child)); + nsCOMPtr tag; + child->GetTag(*getter_AddRefs(tag)); + if (aTag == tag.get()) + aList->AppendElement(child); + else + GetNestedChildren(aTag, child, aList); + } +} + +void +nsXBLBinding::BuildInsertionTable() +{ + if (!mInsertionPointTable) + mInsertionPointTable = new nsSupportsHashtable; + + nsCOMPtr childrenElements; + NS_NewISupportsArray(getter_AddRefs(childrenElements)); + GetNestedChildren(kChildrenAtom, mContent, childrenElements); + + PRUint32 count; + childrenElements->Count(&count); + for (PRUint32 i = 0; i < count; i++) { + nsCOMPtr supp; + childrenElements->GetElementAt(i, getter_AddRefs(supp)); + nsCOMPtr child(do_QueryInterface(supp)); + if (child) { + nsCOMPtr parent; + child->GetParent(*getter_AddRefs(parent)); + nsAutoString includes; + child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes); + if (includes.IsEmpty()) { + nsISupportsKey key(kChildrenAtom); + mInsertionPointTable->Put(&key, parent); + } + else { + // The user specified at least one attribute. + char* str = includes.ToNewCString(); + char* newStr; + // XXX We should use a strtok function that tokenizes PRUnichar's + // so that we don't have to convert from Unicode to ASCII and then back + + char* token = nsCRT::strtok( str, ", ", &newStr ); + while( token != NULL ) { + // Build an atom out of this string. + nsCOMPtr atom; + + nsAutoString tok; tok.AssignWithConversion(token); + atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode())); + + nsISupportsKey key(atom); + mInsertionPointTable->Put(&key, parent); + + token = nsCRT::strtok( newStr, ", ", &newStr ); + } + + nsAllocator::Free(str); + } + } + } +} PRBool nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList) @@ -1478,6 +1545,46 @@ nsXBLBinding::AllowScripts() return PR_FALSE; } +NS_IMETHODIMP +nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) +{ + *aResult = nsnull; + if (mInsertionPointTable) { + nsCOMPtr tag; + aChild->GetTag(*getter_AddRefs(tag)); + nsISupportsKey key(tag); + nsCOMPtr content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, + mInsertionPointTable->Get(&key))); + if (!content) { + nsISupportsKey key2(kChildrenAtom); + content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2))); + } + + *aResult = content; + NS_IF_ADDREF(*aResult); + } + return NS_OK; +} + +NS_IMETHODIMP +nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) +{ + *aResult = nsnull; + *aMultipleInsertionPoints = PR_FALSE; + if (mInsertionPointTable) { + if(mInsertionPointTable->Count() == 1) { + nsISupportsKey key(kChildrenAtom); + nsCOMPtr content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, + mInsertionPointTable->Get(&key))); + *aResult = content; + NS_IF_ADDREF(*aResult); + } + else + *aMultipleInsertionPoints = PR_TRUE; + } + return NS_OK; +} + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/mozilla/content/xbl/src/nsXBLService.cpp b/mozilla/content/xbl/src/nsXBLService.cpp index a4ee72e12db..18d9ee5daaa 100644 --- a/mozilla/content/xbl/src/nsXBLService.cpp +++ b/mozilla/content/xbl/src/nsXBLService.cpp @@ -127,7 +127,8 @@ class nsXBLService: public nsIXBLService // For a given element, returns a flat list of all the anonymous children that need // frames built. - NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement); + NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement, + PRBool* aMultipleInsertionPoints); // Gets the object's base class type. NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult); @@ -290,12 +291,14 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL) // For a given element, returns a flat list of all the anonymous children that need // frames built. NS_IMETHODIMP -nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aParent) +nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aParent, + PRBool* aMultipleInsertionPoints) { // Iterate over all of the bindings one by one and build up an array // of anonymous items. *aResult = nsnull; *aParent = nsnull; + *aMultipleInsertionPoints = PR_FALSE; nsCOMPtr document; aContent->GetDocument(*getter_AddRefs(document)); @@ -323,7 +326,7 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, n (*aResult)->AppendElement(anonymousChild); } - binding->GetInsertionPoint(aParent); + binding->GetSingleInsertionPoint(aParent, aMultipleInsertionPoints); return NS_OK; } diff --git a/mozilla/layout/xbl/public/nsIBindingManager.h b/mozilla/layout/xbl/public/nsIBindingManager.h index 4c4b87fab30..17a045c657b 100644 --- a/mozilla/layout/xbl/public/nsIBindingManager.h +++ b/mozilla/layout/xbl/public/nsIBindingManager.h @@ -51,6 +51,10 @@ public: NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding) = 0; NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult) = 0; + + NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) = 0; + NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, + PRBool* aMultipleInsertionPoints) = 0; }; #endif // nsIBinding_Manager_h__ diff --git a/mozilla/layout/xbl/public/nsIXBLBinding.h b/mozilla/layout/xbl/public/nsIXBLBinding.h index 80c1f0e5ead..9ecbef025f1 100644 --- a/mozilla/layout/xbl/public/nsIXBLBinding.h +++ b/mozilla/layout/xbl/public/nsIXBLBinding.h @@ -57,8 +57,6 @@ public: NS_IMETHOD GetBindingElement(nsIContent** aResult) = 0; NS_IMETHOD SetBindingElement(nsIContent* aElement) = 0; - NS_IMETHOD GetInsertionPoint(nsIContent** aResult) = 0; - NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallProperties(nsIContent* aBoundElement) = 0; @@ -71,6 +69,9 @@ public: NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument) = 0; NS_IMETHOD GetBindingURI(nsString& aResult) = 0; + + NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) = 0; + NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0; }; extern nsresult diff --git a/mozilla/layout/xbl/public/nsIXBLService.h b/mozilla/layout/xbl/public/nsIXBLService.h index 1496b565a2a..d2977c4f8b8 100644 --- a/mozilla/layout/xbl/public/nsIXBLService.h +++ b/mozilla/layout/xbl/public/nsIXBLService.h @@ -58,7 +58,8 @@ public: // For a given element, returns a flat list of all the anonymous children that need // frames built. - NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement) = 0; + NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement, + PRBool* aMultipleInsertionPoints) = 0; // Retrieves our base class (e.g., tells us what type of frame and content node to build) NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult) = 0; diff --git a/mozilla/layout/xbl/src/nsBindingManager.cpp b/mozilla/layout/xbl/src/nsBindingManager.cpp index 8fe02aa661e..558ed0bf608 100644 --- a/mozilla/layout/xbl/src/nsBindingManager.cpp +++ b/mozilla/layout/xbl/src/nsBindingManager.cpp @@ -65,6 +65,10 @@ public: NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult); + NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult); + NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, + PRBool* aMultipleInsertionPoints); + // MEMBER VARIABLES protected: nsSupportsHashtable* mBindingTable; @@ -144,6 +148,31 @@ nsBindingManager::ResolveTag(nsIContent* aContent, nsIAtom** aResult) return aContent->GetTag(*aResult); } +NS_IMETHODIMP +nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) +{ + nsCOMPtr binding; + GetBinding(aParent, getter_AddRefs(binding)); + + if (binding) + return binding->GetInsertionPoint(aChild, aResult); + + return NS_OK; +} + +NS_IMETHODIMP +nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, + PRBool* aMultipleInsertionPoints) +{ + nsCOMPtr binding; + GetBinding(aParent, getter_AddRefs(binding)); + + if (binding) + return binding->GetSingleInsertionPoint( aResult, aMultipleInsertionPoints); + + return NS_OK; +} + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/mozilla/layout/xbl/src/nsXBLBinding.cpp b/mozilla/layout/xbl/src/nsXBLBinding.cpp index 22c33b3273f..a5be05e1fde 100644 --- a/mozilla/layout/xbl/src/nsXBLBinding.cpp +++ b/mozilla/layout/xbl/src/nsXBLBinding.cpp @@ -145,8 +145,6 @@ class nsXBLBinding: public nsIXBLBinding, public nsIScriptObjectOwner NS_IMETHOD GetBindingElement(nsIContent** aResult); NS_IMETHOD SetBindingElement(nsIContent* aElement); - NS_IMETHOD GetInsertionPoint(nsIContent** aResult); - NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); NS_IMETHOD InstallProperties(nsIContent* aBoundElement); @@ -158,6 +156,9 @@ class nsXBLBinding: public nsIXBLBinding, public nsIScriptObjectOwner NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument); NS_IMETHOD GetBindingURI(nsString& aResult); + + NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); + NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); // nsIScriptObjectOwner NS_IMETHOD GetScriptObject(nsIScriptContext* aContext, void** aScriptObject); @@ -180,6 +181,7 @@ public: static nsIAtom* kInterfaceAtom; static nsIAtom* kHandlersAtom; static nsIAtom* kExcludesAtom; + static nsIAtom* kIncludesAtom; static nsIAtom* kInheritsAtom; static nsIAtom* kTypeAtom; static nsIAtom* kCapturerAtom; @@ -214,6 +216,9 @@ protected: void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult); void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult); + void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList); + void BuildInsertionTable(); + void GetNestedChildren(); PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList); NS_IMETHOD ConstructAttributeTable(nsIContent* aElement); @@ -230,12 +235,12 @@ protected: nsCOMPtr mBinding; // Strong. As long as we're around, the binding can't go away. nsCOMPtr mContent; // Strong. Our anonymous content stays around with us. nsCOMPtr mNextBinding; // Strong. The derived binding owns the base class bindings. - nsCOMPtr mChildrenElement; // Strong. One of our anonymous content children. void* mScriptObject; // Strong nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it. nsSupportsHashtable* mAttributeTable; // A table for attribute entries. + nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. }; // Static initialization @@ -245,6 +250,7 @@ nsIAtom* nsXBLBinding::kContentAtom = nsnull; nsIAtom* nsXBLBinding::kInterfaceAtom = nsnull; nsIAtom* nsXBLBinding::kHandlersAtom = nsnull; nsIAtom* nsXBLBinding::kExcludesAtom = nsnull; +nsIAtom* nsXBLBinding::kIncludesAtom = nsnull; nsIAtom* nsXBLBinding::kInheritsAtom = nsnull; nsIAtom* nsXBLBinding::kTypeAtom = nsnull; nsIAtom* nsXBLBinding::kCapturerAtom = nsnull; @@ -319,7 +325,8 @@ NS_IMPL_ISUPPORTS2(nsXBLBinding, nsIXBLBinding, nsIScriptObjectOwner) // Constructors/Destructors nsXBLBinding::nsXBLBinding(void) : mScriptObject(nsnull), - mAttributeTable(nsnull) + mAttributeTable(nsnull), + mInsertionPointTable(nsnull) { NS_INIT_REFCNT(); gRefCnt++; @@ -328,6 +335,7 @@ nsXBLBinding::nsXBLBinding(void) kInterfaceAtom = NS_NewAtom("interface"); kHandlersAtom = NS_NewAtom("handlers"); kExcludesAtom = NS_NewAtom("excludes"); + kIncludesAtom = NS_NewAtom("includes"); kInheritsAtom = NS_NewAtom("inherits"); kTypeAtom = NS_NewAtom("type"); kCapturerAtom = NS_NewAtom("capturer"); @@ -362,6 +370,7 @@ nsXBLBinding::nsXBLBinding(void) nsXBLBinding::~nsXBLBinding(void) { delete mAttributeTable; + delete mInsertionPointTable; gRefCnt--; if (gRefCnt == 0) { @@ -369,6 +378,7 @@ nsXBLBinding::~nsXBLBinding(void) NS_RELEASE(kInterfaceAtom); NS_RELEASE(kHandlersAtom); NS_RELEASE(kExcludesAtom); + NS_RELEASE(kIncludesAtom); NS_RELEASE(kInheritsAtom); NS_RELEASE(kTypeAtom); NS_RELEASE(kCapturerAtom); @@ -468,14 +478,6 @@ nsXBLBinding::SetBindingElement(nsIContent* aElement) return NS_OK; } -NS_IMETHODIMP -nsXBLBinding::GetInsertionPoint(nsIContent** aResult) -{ - *aResult = mChildrenElement; - NS_IF_ADDREF(*aResult); - return NS_OK; -} - NS_IMETHODIMP nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) { @@ -569,9 +571,8 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) nsCOMPtr clonedContent = do_QueryInterface(clonedNode); SetAnonymousContent(clonedContent); - if (childrenElement) { - GetNestedChild(kChildrenAtom, clonedContent, getter_AddRefs(mChildrenElement)); - } + if (childrenElement) + BuildInsertionTable(); } if (mNextBinding) { @@ -1215,10 +1216,76 @@ nsXBLBinding::GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** a return; } } - - return; } +void +nsXBLBinding::GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList) +{ + PRInt32 childCount; + aContent->ChildCount(childCount); + for (PRInt32 i = 0; i < childCount; i++) { + nsCOMPtr child; + aContent->ChildAt(i, *getter_AddRefs(child)); + nsCOMPtr tag; + child->GetTag(*getter_AddRefs(tag)); + if (aTag == tag.get()) + aList->AppendElement(child); + else + GetNestedChildren(aTag, child, aList); + } +} + +void +nsXBLBinding::BuildInsertionTable() +{ + if (!mInsertionPointTable) + mInsertionPointTable = new nsSupportsHashtable; + + nsCOMPtr childrenElements; + NS_NewISupportsArray(getter_AddRefs(childrenElements)); + GetNestedChildren(kChildrenAtom, mContent, childrenElements); + + PRUint32 count; + childrenElements->Count(&count); + for (PRUint32 i = 0; i < count; i++) { + nsCOMPtr supp; + childrenElements->GetElementAt(i, getter_AddRefs(supp)); + nsCOMPtr child(do_QueryInterface(supp)); + if (child) { + nsCOMPtr parent; + child->GetParent(*getter_AddRefs(parent)); + nsAutoString includes; + child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes); + if (includes.IsEmpty()) { + nsISupportsKey key(kChildrenAtom); + mInsertionPointTable->Put(&key, parent); + } + else { + // The user specified at least one attribute. + char* str = includes.ToNewCString(); + char* newStr; + // XXX We should use a strtok function that tokenizes PRUnichar's + // so that we don't have to convert from Unicode to ASCII and then back + + char* token = nsCRT::strtok( str, ", ", &newStr ); + while( token != NULL ) { + // Build an atom out of this string. + nsCOMPtr atom; + + nsAutoString tok; tok.AssignWithConversion(token); + atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode())); + + nsISupportsKey key(atom); + mInsertionPointTable->Put(&key, parent); + + token = nsCRT::strtok( newStr, ", ", &newStr ); + } + + nsAllocator::Free(str); + } + } + } +} PRBool nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList) @@ -1478,6 +1545,46 @@ nsXBLBinding::AllowScripts() return PR_FALSE; } +NS_IMETHODIMP +nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) +{ + *aResult = nsnull; + if (mInsertionPointTable) { + nsCOMPtr tag; + aChild->GetTag(*getter_AddRefs(tag)); + nsISupportsKey key(tag); + nsCOMPtr content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, + mInsertionPointTable->Get(&key))); + if (!content) { + nsISupportsKey key2(kChildrenAtom); + content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2))); + } + + *aResult = content; + NS_IF_ADDREF(*aResult); + } + return NS_OK; +} + +NS_IMETHODIMP +nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) +{ + *aResult = nsnull; + *aMultipleInsertionPoints = PR_FALSE; + if (mInsertionPointTable) { + if(mInsertionPointTable->Count() == 1) { + nsISupportsKey key(kChildrenAtom); + nsCOMPtr content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, + mInsertionPointTable->Get(&key))); + *aResult = content; + NS_IF_ADDREF(*aResult); + } + else + *aMultipleInsertionPoints = PR_TRUE; + } + return NS_OK; +} + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/mozilla/layout/xbl/src/nsXBLService.cpp b/mozilla/layout/xbl/src/nsXBLService.cpp index a4ee72e12db..18d9ee5daaa 100644 --- a/mozilla/layout/xbl/src/nsXBLService.cpp +++ b/mozilla/layout/xbl/src/nsXBLService.cpp @@ -127,7 +127,8 @@ class nsXBLService: public nsIXBLService // For a given element, returns a flat list of all the anonymous children that need // frames built. - NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement); + NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aChildElement, + PRBool* aMultipleInsertionPoints); // Gets the object's base class type. NS_IMETHOD ResolveTag(nsIContent* aContent, nsIAtom** aResult); @@ -290,12 +291,14 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL) // For a given element, returns a flat list of all the anonymous children that need // frames built. NS_IMETHODIMP -nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aParent) +nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, nsIContent** aParent, + PRBool* aMultipleInsertionPoints) { // Iterate over all of the bindings one by one and build up an array // of anonymous items. *aResult = nsnull; *aParent = nsnull; + *aMultipleInsertionPoints = PR_FALSE; nsCOMPtr document; aContent->GetDocument(*getter_AddRefs(document)); @@ -323,7 +326,7 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, n (*aResult)->AppendElement(anonymousChild); } - binding->GetInsertionPoint(aParent); + binding->GetSingleInsertionPoint(aParent, aMultipleInsertionPoints); return NS_OK; }