Fix for 55292, r=ben, sr=brendan

This commit is contained in:
hyatt%netscape.com 2001-02-02 00:54:47 +00:00
parent 32417b285f
commit 45c08e6635
44 changed files with 1678 additions and 1002 deletions

View File

@ -545,57 +545,6 @@ nsDocumentChildNodes::DropReference()
// =
// ==================================================================
MOZ_DECL_CTOR_COUNTER(nsAnonymousContentList)
nsAnonymousContentList::nsAnonymousContentList(nsISupportsArray* aElements)
{
MOZ_COUNT_CTOR(nsAnonymousContentList);
// We don't reference count our Anonymous reference (to avoid circular
// references). We'll be told when the Anonymous goes away.
mElements = aElements;
NS_IF_ADDREF(mElements);
}
nsAnonymousContentList::~nsAnonymousContentList()
{
MOZ_COUNT_DTOR(nsAnonymousContentList);
NS_IF_RELEASE(mElements);
}
NS_IMETHODIMP
nsAnonymousContentList::GetLength(PRUint32* aLength)
{
NS_ASSERTION(aLength != nsnull, "null ptr");
if (! aLength)
return NS_ERROR_NULL_POINTER;
PRUint32 cnt;
nsresult rv = mElements->Count(&cnt);
if (NS_FAILED(rv)) return rv;
*aLength = cnt;
return NS_OK;
}
NS_IMETHODIMP
nsAnonymousContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
{
PRUint32 cnt;
nsresult rv = mElements->Count(&cnt);
if (NS_FAILED(rv)) return rv;
if (aIndex >= (PRUint32) cnt)
return NS_ERROR_INVALID_ARG;
// Cast is okay because we're in a closed system.
*aReturn = (nsIDOMNode*) mElements->ElementAt(aIndex);
return NS_OK;
}
// ==================================================================
// =
// ==================================================================
nsDocument::nsDocument()
{
NS_INIT_REFCNT();
@ -2211,17 +2160,12 @@ NS_IMETHODIMP
nsDocument::GetAnonymousNodes(nsIDOMElement* aElement,
nsIDOMNodeList** aResult)
{
nsresult rv;
// Use the XBL service to get the anonymous node list.
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
PRBool dummy;
nsCOMPtr<nsIContent> dummyElt;
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return xblService->GetContentList(content, aResult, getter_AddRefs(dummyElt), &dummy);
*aResult = nsnull;
if (mBindingManager) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return mBindingManager->GetAnonymousNodesFor(content, aResult);
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -115,19 +115,6 @@ protected:
nsIDocument* mDocument;
};
class nsAnonymousContentList : public nsGenericDOMNodeList
{
public:
nsAnonymousContentList(nsISupportsArray* aElements);
virtual ~nsAnonymousContentList();
// nsIDOMNodeList interface
NS_DECL_IDOMNODELIST
private:
nsISupportsArray* mElements;
};
// Base class for our document implementations
class nsDocument : public nsIDocument,
public nsIDOMDocument,

View File

@ -33,6 +33,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLInsertionPoint.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \

View File

@ -2,6 +2,7 @@ nsIBindingManager.h
nsIXBLBinding.h
nsIXBLBindingAttachedHandler.h
nsIXBLDocumentInfo.h
nsIXBLInsertionPoint.h
nsIXBLPrototypeBinding.h
nsIXBLPrototypeHandler.h
nsIXBLService.h

View File

@ -26,6 +26,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLInsertionPoint.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \

View File

@ -55,6 +55,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult) = 0;
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding) = 0;
NS_IMETHOD GetInsertionParent(nsIContent* aContent, nsIContent** aResult)=0;
NS_IMETHOD SetInsertionParent(nsIContent* aContent, nsIContent* aResult)=0;
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult) = 0;
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult) = 0;
@ -79,8 +82,15 @@ public:
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult) = 0;
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult,
// For a given element with an insertion point child, returns a flat list of all the real children.
NS_IMETHOD GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 0;
NS_IMETHOD SetContentListFor(nsIContent* aContent, nsISupportsArray* aList)=0;
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 0;
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList) = 0;
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints) = 0;
NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsAReadableString& aURL) = 0;

View File

@ -85,8 +85,10 @@ public:
NS_IMETHOD GetDocURI(nsCString& aResult) = 0;
NS_IMETHOD GetID(nsCString& aResult) = 0;
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0;
NS_IMETHOD GetInsertionPointsFor(nsIContent* aParent, nsISupportsArray** aResult)=0;
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints) = 0;
NS_IMETHOD IsStyleBinding(PRBool* aResult) = 0;
NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) = 0;
@ -102,8 +104,7 @@ public:
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult)=0;
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult,
nsIContent** aParent, PRBool* aMultipleInsertionPoints)=0;
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult)=0;
};

View File

@ -32,6 +32,7 @@ class nsIDocument;
class nsIDOMEventReceiver;
class nsIXBLDocumentInfo;
class nsIXBLPrototypeHandler;
class nsIXBLBinding;
// {34D700F5-C1A2-4408-A0B1-DD8F891DD1FE}
#define NS_IXBLPROTOTYPEBINDING_IID \
@ -76,11 +77,13 @@ public:
NS_IMETHOD HasInsertionPoints(PRBool* aResult)=0;
NS_IMETHOD InstantiateInsertionPoints(nsIXBLBinding* aBinding)=0;
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent* aChild, nsIContent** aResult)=0;
nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)=0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent** aResult, PRBool* aMultipleInsertionPoints)=0;
nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints)=0;
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag)=0;
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)=0;

View File

@ -64,11 +64,6 @@ public:
// Indicates whether or not a binding is fully loaded.
NS_IMETHOD BindingReady(nsIContent* aBoundElement, const nsCString& aURLStr, PRBool* aIsReady) = 0;
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHOD GetContentList(nsIContent* aContent, nsIDOMNodeList** 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, PRInt32* aNameSpaceID, nsIAtom** aResult) = 0;

View File

@ -50,6 +50,7 @@ CPPSRCS = \
nsXBLScrollHandler.cpp \
nsXBLService.cpp \
nsBindingManager.cpp \
nsXBLInsertionPoint \
$(NULL)
include $(topsrcdir)/config/config.mk

View File

@ -46,6 +46,7 @@ CPPSRCS= \
nsXBLLoadHandler.cpp \
nsXBLPrototypeHandler.cpp \
nsBindingManager.cpp \
nsXBLInsertionPoint.cpp \
$(NULL)
CPP_OBJS= \
@ -68,6 +69,7 @@ CPP_OBJS= \
.\$(OBJDIR)\nsXBLPrototypeHandler.obj \
.\$(OBJDIR)\nsXBLService.obj \
.\$(OBJDIR)\nsBindingManager.obj \
.\$(OBJDIR)\nsXBLInsertionPoint.obj \
$(NULL)
EXPORTS = \

View File

@ -51,6 +51,7 @@
#include "nsIXBLBinding.h"
#include "nsIXBLDocumentInfo.h"
#include "nsIXBLBindingAttachedHandler.h"
#include "nsIXBLInsertionPoint.h"
#include "nsIStyleSheet.h"
#include "nsIHTMLStyleSheet.h"
@ -191,6 +192,89 @@ nsresult NS_NewXBLDocumentInfo(nsIDocument* aDocument, nsIXBLDocumentInfo** aRes
return NS_OK;
}
// ==================================================================
// = nsAnonymousContentList
// ==================================================================
class nsAnonymousContentList : public nsGenericDOMNodeList
{
public:
nsAnonymousContentList(nsISupportsArray* aElements);
virtual ~nsAnonymousContentList();
// nsIDOMNodeList interface
NS_DECL_IDOMNODELIST
private:
nsISupportsArray* mElements;
};
MOZ_DECL_CTOR_COUNTER(nsAnonymousContentList);
nsAnonymousContentList::nsAnonymousContentList(nsISupportsArray* aElements)
{
MOZ_COUNT_CTOR(nsAnonymousContentList);
// We don't reference count our Anonymous reference (to avoid circular
// references). We'll be told when the Anonymous goes away.
mElements = aElements;
NS_IF_ADDREF(mElements);
}
nsAnonymousContentList::~nsAnonymousContentList()
{
MOZ_COUNT_DTOR(nsAnonymousContentList);
NS_IF_RELEASE(mElements);
}
NS_IMETHODIMP
nsAnonymousContentList::GetLength(PRUint32* aLength)
{
NS_ASSERTION(aLength != nsnull, "null ptr");
if (! aLength)
return NS_ERROR_NULL_POINTER;
PRUint32 cnt;
mElements->Count(&cnt);
*aLength = 0;
nsCOMPtr<nsIXBLInsertionPoint> point;
PRUint32 l;
for (PRUint32 i = 0; i < cnt; i++) {
point = getter_AddRefs((nsIXBLInsertionPoint*)(mElements->ElementAt(i)));
point->ChildCount(&l);
*aLength += l;
}
return NS_OK;
}
NS_IMETHODIMP
nsAnonymousContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
{
PRUint32 cnt;
nsresult rv = mElements->Count(&cnt);
if (NS_FAILED(rv)) return rv;
PRUint32 pointCount = 0;
nsCOMPtr<nsIXBLInsertionPoint> point;
for (PRUint32 i = 0; i < cnt; i++) {
aIndex -= pointCount;
point = getter_AddRefs((nsIXBLInsertionPoint*)(mElements->ElementAt(i)));
point->ChildCount(&pointCount);
if (aIndex < pointCount) {
nsCOMPtr<nsIContent> result;
rv = point->ChildAt(aIndex, getter_AddRefs(result));
if (result && NS_SUCCEEDED(rv))
return result->QueryInterface(NS_GET_IID(nsIDOMNode), (void**)aReturn);
else return rv;
}
}
return NS_ERROR_FAILURE;
}
////////////////////////////////////////////////////////////////////////
@ -205,6 +289,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult);
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding);
NS_IMETHOD GetInsertionParent(nsIContent* aContent, nsIContent** aResult);
NS_IMETHOD SetInsertionParent(nsIContent* aContent, nsIContent* aResult);
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult);
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
@ -213,8 +300,14 @@ public:
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult,
NS_IMETHOD GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD SetContentListFor(nsIContent* aContent, nsISupportsArray* aList);
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList);
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints);
NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsAReadableString& aURL);
@ -258,11 +351,43 @@ protected:
// MEMBER VARIABLES
protected:
// A mapping from nsIContent* to the nsIXBLBinding* that is installed on that element.
nsSupportsHashtable* mBindingTable;
// A mapping from nsIContent* to an nsIDOMNodeList* (nsAnonymousContentList*).
// This list contains an accurate reflection of our *explicit* children (once intermingled with
// insertion points) in the altered DOM.
nsSupportsHashtable* mContentListTable;
// A mapping from nsIContent* to an nsIDOMNodeList* (nsAnonymousContentList*).
// This list contains an accurate reflection of our *anonymous* children (if and only if they are
// intermingled with insertion points) in the altered DOM. This table is not used
// if no insertion points were defined directly underneath a <content> tag in a
// binding. The NodeList from the <content> is used instead as a performance
// optimization.
nsSupportsHashtable* mAnonymousNodesTable;
// A mapping from nsIContent* to nsIContent*. The insertion parent is our one true
// parent in the transformed DOM. This gives us a more-or-less O(1) way of obtaining
// our transformed parent.
nsSupportsHashtable* mInsertionParentTable;
// A mapping from nsIContent* to nsIXPWrappedJS* (an XPConnect wrapper for JS objects).
// For XBL bindings that implement XPIDL interfaces, and that get referred to from C++,
// this table caches the XPConnect wrapper for the binding. By caching it, I control
// its lifetime, and I prevent a re-wrap of the same script object (in the case where
// multiple bindings in an XBL inheritance chain both implement an XPIDL interface).
nsSupportsHashtable* mWrapperTable;
// A mapping from nsIDocument* to nsIXBLDocumentInfo*. This table is the cache of
// all binding documents that have been loaded by a given bound document.
nsSupportsHashtable* mDocumentTable;
// The currently loading binding docs. If they're in this table, they have not yet
// finished loading.
nsSupportsHashtable* mLoadingDocTable;
// A queue of binding attached event handlers that are awaiting execution.
nsCOMPtr<nsISupportsArray> mAttachedQueue;
};
@ -279,6 +404,9 @@ nsBindingManager::nsBindingManager(void)
NS_INIT_REFCNT();
mBindingTable = nsnull;
mContentListTable = nsnull;
mAnonymousNodesTable = nsnull;
mInsertionParentTable = nsnull;
mWrapperTable = nsnull;
mDocumentTable = nsnull;
mLoadingDocTable = nsnull;
@ -289,6 +417,9 @@ nsBindingManager::nsBindingManager(void)
nsBindingManager::~nsBindingManager(void)
{
delete mBindingTable;
delete mContentListTable;
delete mAnonymousNodesTable;
delete mInsertionParentTable;
delete mWrapperTable;
delete mDocumentTable;
delete mLoadingDocTable;
@ -333,6 +464,36 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding )
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetInsertionParent(nsIContent* aContent, nsIContent** aResult)
{
if (mInsertionParentTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIContent*, mInsertionParentTable->Get(&key));
}
else {
*aResult = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetInsertionParent(nsIContent* aContent, nsIContent* aParent)
{
if (!mInsertionParentTable)
mInsertionParentTable = new nsSupportsHashtable;
nsISupportsKey key(aContent);
if (aParent) {
mInsertionParentTable->Put(&key, aParent);
}
else
mInsertionParentTable->Remove(&key);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult)
{
@ -383,6 +544,11 @@ nsBindingManager::ChangeDocumentFor(nsIContent* aContent, nsIDocument* aOldDocum
}
}
// Clear out insertion parents and content lists.
SetInsertionParent(aContent, nsnull);
SetContentListFor(aContent, nsnull);
SetAnonymousNodesFor(aContent, nsnull);
for (PRInt32 i = aOldDocument->GetNumberOfShells() - 1; i >= 0; --i) {
nsCOMPtr<nsIPresShell> shell = dont_AddRef( aOldDocument->GetShellAt(i) );
NS_ASSERTION(shell != nsnull, "Zoiks! nsIPresShell::ShellAt() broke");
@ -434,26 +600,105 @@ nsBindingManager::ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAto
}
NS_IMETHODIMP
nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult)
nsBindingManager::GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
// Locate the primary binding and get its node list of anonymous children.
*aResult = nsnull;
if (mContentListTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIDOMNodeList*, mContentListTable->Get(&key));
}
if (!*aResult) {
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
return node->GetChildNodes(aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetContentListFor(nsIContent* aContent, nsISupportsArray* aList)
{
if (!mContentListTable) {
if (!aList)
return NS_OK;
mContentListTable = new nsSupportsHashtable;
}
nsISupportsKey key(aContent);
if (aList) {
nsAnonymousContentList* contentList = new nsAnonymousContentList(aList);
mContentListTable->Put(&key, (nsIDOMNodeList*)contentList);
}
else
mContentListTable->Remove(&key);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
// Locate the primary binding and get its node list of anonymous children.
*aResult = nsnull;
if (mAnonymousNodesTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIDOMNodeList*, mAnonymousNodesTable->Get(&key));
}
if (!*aResult) {
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aContent, getter_AddRefs(binding));
if (binding)
return binding->GetAnonymousNodes(aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList)
{
if (!mAnonymousNodesTable) {
if (!aList)
return NS_OK;
mAnonymousNodesTable = new nsSupportsHashtable;
}
nsISupportsKey key(aContent);
if (aList) {
nsAnonymousContentList* contentList = new nsAnonymousContentList(aList);
mAnonymousNodesTable->Put(&key, (nsIDOMNodeList*)contentList);
}
else
mAnonymousNodesTable->Remove(&key);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aParent, getter_AddRefs(binding));
if (binding)
return binding->GetInsertionPoint(aChild, aResult);
return binding->GetInsertionPoint(aChild, aResult, aIndex);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult,
nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints)
{
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aParent, getter_AddRefs(binding));
if (binding)
return binding->GetSingleInsertionPoint( aResult, aMultipleInsertionPoints);
return binding->GetSingleInsertionPoint(aResult, aIndex, aMultipleInsertionPoints);
return NS_OK;
}

View File

@ -51,6 +51,7 @@
#include "nsJSUtils.h"
#include "nsIJSRuntimeService.h"
#include "nsXBLService.h"
#include "nsIXBLInsertionPoint.h"
// Event listeners
#include "nsIEventListenerManager.h"
@ -232,6 +233,7 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
// Constructors/Destructors
nsXBLBinding::nsXBLBinding(nsIXBLPrototypeBinding* aBinding)
: mFirstHandler(nsnull),
mInsertionPointTable(nsnull),
mIsStyleBinding(PR_TRUE),
mMarkedForDeath(PR_FALSE)
{
@ -277,6 +279,8 @@ nsXBLBinding::nsXBLBinding(nsIXBLPrototypeBinding* aBinding)
nsXBLBinding::~nsXBLBinding(void)
{
delete mInsertionPointTable;
gRefCnt--;
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
@ -437,6 +441,102 @@ nsXBLBinding::HasStyleSheets(PRBool* aResolveStyle)
return NS_OK;
}
struct ContentListData {
nsXBLBinding* mBinding;
nsIBindingManager* mBindingManager;
ContentListData(nsXBLBinding* aBinding, nsIBindingManager* aManager)
:mBinding(aBinding), mBindingManager(aManager)
{};
};
PRBool PR_CALLBACK BuildContentLists(nsHashKey* aKey, void* aData, void* aClosure)
{
ContentListData* data = (ContentListData*)aClosure;
nsIBindingManager* bm = data->mBindingManager;
nsXBLBinding* binding = data->mBinding;
nsCOMPtr<nsIContent> boundElement;
binding->GetBoundElement(getter_AddRefs(boundElement));
nsISupportsArray* arr = (nsISupportsArray*)aData;
PRUint32 count;
arr->Count(&count);
if (count == 0)
return NS_OK;
// XXX Could this array just be altered in place and passed directly to
// SetContentListFor? We'd save space if we could pull this off.
nsCOMPtr<nsISupportsArray> contentList;
NS_NewISupportsArray(getter_AddRefs(contentList));
// Figure out the relevant content node.
PRUint32 j = 0;
nsCOMPtr<nsIXBLInsertionPoint> currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
nsCOMPtr<nsIContent> parent;
PRUint32 currIndex;
currPoint->GetInsertionParent(getter_AddRefs(parent));
currPoint->GetInsertionIndex(&currIndex);
nsCOMPtr<nsIDOMNodeList> nodeList;
if (parent == boundElement) {
// We are altering anonymous nodes to accommodate insertion points.
binding->GetAnonymousNodes(getter_AddRefs(nodeList));
}
else {
// We are altering the explicit content list of a node to accommodate insertion points.
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(parent));
node->GetChildNodes(getter_AddRefs(nodeList));
}
nsCOMPtr<nsIXBLInsertionPoint> pseudoPoint;
PRUint32 childCount;
nodeList->GetLength(&childCount);
for (PRUint32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIDOMNode> node;
nodeList->Item(i, getter_AddRefs(node));
nsCOMPtr<nsIContent> child(do_QueryInterface(node));
if (i == currIndex) {
// Add the currPoint to the supports array.
contentList->AppendElement(currPoint);
// Get the next real insertion point and update our currIndex.
j++;
if (j < count) {
currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
currPoint->GetInsertionIndex(&currIndex);
}
// Null out our current pseudo-point.
pseudoPoint = nsnull;
}
if (!pseudoPoint) {
NS_NewXBLInsertionPoint(parent, 0, getter_AddRefs(pseudoPoint));
contentList->AppendElement(pseudoPoint);
}
pseudoPoint->AddChild(child);
}
// Add in all the remaining insertion points.
for ( ; j < count; j++) {
currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
contentList->AppendElement(currPoint);
}
// Now set the content list using the binding manager,
// If the bound element is the parent, then we alter the anonymous node list
// instead. This allows us to always maintain two distinct lists should
// insertion points be nested into an inner binding.
if (parent == boundElement)
bm->SetAnonymousNodesFor(parent, contentList);
else
bm->SetContentListFor(parent, contentList);
return PR_TRUE;
}
NS_IMETHODIMP
nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
{
@ -499,6 +599,103 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
clonedContent = do_QueryInterface(clonedNode);
SetAnonymousContent(clonedContent);
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
if (hasInsertionPoints) {
// Now check and see if we have a single insertion point
// or multiple insertion points.
nsCOMPtr<nsIDocument> doc;
mBoundElement->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIBindingManager> bindingManager;
doc->GetBindingManager(getter_AddRefs(bindingManager));
nsCOMPtr<nsIDOMNodeList> children;
bindingManager->GetContentListFor(mBoundElement, getter_AddRefs(children));
// Enumerate the prototype binding's insertion table to build
// our table of instantiated insertion points.
mPrototypeBinding->InstantiateInsertionPoints(this);
// We now have our insertion point table constructed. We
// enumerate this table. For each array of insertion points
// bundled under the same content node, we generate a content
// list. In the case of the bound element, we generate a new
// anonymous node list that will be used in place of the binding's
// cached anonymous node list.
ContentListData data(this, bindingManager);
mInsertionPointTable->Enumerate(BuildContentLists, &data);
// We need to place the children
// at their respective insertion points.
nsCOMPtr<nsIContent> singlePoint;
PRUint32 index = 0;
PRBool multiplePoints = PR_FALSE;
GetSingleInsertionPoint(getter_AddRefs(singlePoint), &index, &multiplePoints);
if (children) {
if (multiplePoints) {
// We must walk the entire content list in order to determine where
// each child belongs.
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
PRUint32 length;
children->GetLength(&length);
for (PRUint32 i = 0; i < length; i++) {
children->Item(i, getter_AddRefs(node));
content = do_QueryInterface(node);
// Now determine the insertion point in the prototype table.
nsCOMPtr<nsIContent> point;
PRUint32 index;
GetInsertionPoint(content, getter_AddRefs(point), &index);
bindingManager->SetInsertionParent(content, point);
// Find the correct nsIXBLInsertion point in our table.
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint;
nsCOMPtr<nsISupportsArray> arr;
GetInsertionPointsFor(point, getter_AddRefs(arr));
PRUint32 arrCount;
arr->Count(&arrCount);
for (PRUint32 j = 0; j < arrCount; j++) {
insertionPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
PRBool matches;
insertionPoint->Matches(point, index, &matches);
if (matches)
break;
insertionPoint = nsnull;
}
if (!insertionPoint) {
NS_ERROR("Filtered insertion point wasn't properly constructed.\n");
return NS_ERROR_FAILURE;
}
else
insertionPoint->AddChild(content);
}
}
else {
// All of our children are shunted to this single insertion point.
nsCOMPtr<nsISupportsArray> arr;
GetInsertionPointsFor(singlePoint, getter_AddRefs(arr));
PRUint32 arrCount;
arr->Count(&arrCount);
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(0));
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
PRUint32 length;
children->GetLength(&length);
for (PRUint32 i = 0; i < length; i++) {
children->Item(i, getter_AddRefs(node));
content = do_QueryInterface(node);
bindingManager->SetInsertionParent(content, singlePoint);
insertionPoint->AddChild(content);
}
}
}
}
}
// Always check the content element for potential attributes.
@ -529,9 +726,6 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
mContent->UnsetAttribute(namespaceID, name, PR_FALSE);
}
if (mContent)
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
return NS_OK;
}
@ -1407,25 +1601,42 @@ nsXBLBinding::AllowScripts()
}
NS_IMETHODIMP
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult)
nsXBLBinding::GetInsertionPointsFor(nsIContent* aParent, nsISupportsArray** aResult)
{
*aResult = nsnull;
if (mContent)
return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult);
else if (mNextBinding)
return mNextBinding->GetInsertionPoint(aChild, aResult);
if (!mInsertionPointTable)
mInsertionPointTable = new nsSupportsHashtable(4);
nsISupportsKey key(aParent);
*aResult = NS_STATIC_CAST(nsISupportsArray*, mInsertionPointTable->Get(&key));
if (!*aResult) {
NS_NewISupportsArray(aResult);
mInsertionPointTable->Put(&key, *aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints)
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{
*aResult = nsnull;
if (mContent)
return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult, aIndex);
else if (mNextBinding)
return mNextBinding->GetInsertionPoint(aChild, aResult, aIndex);
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints)
{
*aResult = nsnull;
*aMultipleInsertionPoints = PR_FALSE;
if (mContent)
return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aMultipleInsertionPoints);
return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aIndex, aMultipleInsertionPoints);
else if (mNextBinding)
return mNextBinding->GetSingleInsertionPoint(aResult, aMultipleInsertionPoints);
return mNextBinding->GetSingleInsertionPoint(aResult, aIndex, aMultipleInsertionPoints);
return NS_OK;
}
@ -1480,16 +1691,15 @@ nsXBLBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
}
NS_IMETHODIMP
nsXBLBinding::GetAnonymousNodes(nsIDOMNodeList** aResult, nsIContent** aParent, PRBool* aMultipleInsertionPoints)
nsXBLBinding::GetAnonymousNodes(nsIDOMNodeList** aResult)
{
*aResult = nsnull;
if (mContent) {
GetSingleInsertionPoint(aParent, aMultipleInsertionPoints);
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
return elt->GetChildNodes(aResult);
}
else if (mNextBinding)
return mNextBinding->GetAnonymousNodes(aResult, aParent, aMultipleInsertionPoints);
return mNextBinding->GetAnonymousNodes(aResult);
return NS_OK;
}

View File

@ -79,8 +79,10 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD GetDocURI(nsCString& aResult);
NS_IMETHOD GetID(nsCString& aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult);
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints);
NS_IMETHOD GetInsertionPointsFor(nsIContent* aParent, nsISupportsArray** aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints);
NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; };
NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; };
@ -96,7 +98,7 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult);
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult, nsIContent** aParent, PRBool* aMultipleInsertionPoints);
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult);
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult);
@ -172,6 +174,8 @@ protected:
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
nsSupportsHashtable* mInsertionPointTable; // A hash from nsIContent* -> (a sorted array of nsIXBLInsertionPoint*)
PRPackedBool mIsStyleBinding;
PRPackedBool mMarkedForDeath;
};

View File

@ -48,6 +48,7 @@
#include "nsINameSpace.h"
#include "nsXBLService.h"
#include "nsXBLBinding.h"
#include "nsIXBLInsertionPoint.h"
#include "nsXBLPrototypeBinding.h"
#include "nsFixedSizeAllocator.h"
#include "xptinfo.h"
@ -108,6 +109,59 @@ public:
NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
// nsIXBLInsertionPointEntry and helpers. This class stores all the necessary
// info to figure out the position of an insertion point.
// {76F238AE-5ACB-49e6-B2DE-FD1940637753}
#define NS_IXBLINS_IID \
{ 0x76f238ae, 0x5acb, 0x49e6, { 0xb2, 0xde, 0xfd, 0x19, 0x40, 0x63, 0x77, 0x53 } }
class nsIXBLInsertionPointEntry : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IXBLINS_IID; return iid; }
NS_IMETHOD GetInsertionParent(nsIContent** aResult)=0;
NS_IMETHOD GetInsertionIndex(PRUint32* aResult)=0;
NS_IMETHOD SetInsertionIndex(PRUint32 aIndex)=0;
};
class nsXBLInsertionPointEntry : public nsIXBLInsertionPointEntry {
public:
NS_IMETHOD GetInsertionParent(nsIContent** aResult)
{
*aResult = mInsertionParent;
NS_IF_ADDREF(*aResult);
return NS_OK;
};
NS_IMETHOD GetInsertionIndex(PRUint32* aResult) { *aResult = mInsertionIndex; return NS_OK; };
NS_IMETHOD SetInsertionIndex(PRUint32 aIndex) { mInsertionIndex = aIndex; return NS_OK; };
nsCOMPtr<nsIContent> mInsertionParent;
PRUint32 mInsertionIndex;
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
return aAllocator.Alloc(aSize);
}
static void operator delete(void* aPtr, size_t aSize) {
nsFixedSizeAllocator::Free(aPtr, aSize);
}
nsXBLInsertionPointEntry(nsIContent* aParent) {
NS_INIT_REFCNT();
mInsertionIndex = 0;
mInsertionParent = aParent;
};
virtual ~nsXBLInsertionPointEntry() {};
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS1(nsXBLInsertionPointEntry, nsIXBLInsertionPointEntry)
// =============================================================================
// Static initialization
@ -123,15 +177,24 @@ nsIAtom* nsXBLPrototypeBinding::kValueAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kXBLTextAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementationAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementsAtom = nsnull;
nsFixedSizeAllocator nsXBLPrototypeBinding::kPool;
nsFixedSizeAllocator nsXBLPrototypeBinding::kAttrPool;
nsFixedSizeAllocator nsXBLPrototypeBinding::kInsPool;
static const size_t kBucketSizes[] = {
static const PRInt32 kNumElements = 128;
static const size_t kAttrBucketSizes[] = {
sizeof(nsXBLAttributeEntry)
};
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
static const PRInt32 kNumElements = 128;
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
static const PRInt32 kAttrNumBuckets = sizeof(kAttrBucketSizes)/sizeof(size_t);
static const PRInt32 kAttrInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
static const size_t kInsBucketSizes[] = {
sizeof(nsXBLInsertionPointEntry)
};
static const PRInt32 kInsNumBuckets = sizeof(kInsBucketSizes)/sizeof(size_t);
static const PRInt32 kInsInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLInsertionPointEntry))) * kNumElements;
// Implementation /////////////////////////////////////////////////////////////////
@ -156,7 +219,8 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 1) {
kPool.Init("XBL Attribute Entries", kBucketSizes, kNumBuckets, kInitialSize);
kAttrPool.Init("XBL Attribute Entries", kAttrBucketSizes, kAttrNumBuckets, kAttrInitialSize);
kInsPool.Init("XBL Insertion Point Entries", kInsBucketSizes, kInsNumBuckets, kInsInitialSize);
kInheritStyleAtom = NS_NewAtom("inheritstyle");
kHandlersAtom = NS_NewAtom("handlers");
@ -466,31 +530,107 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceI
return NS_OK;
}
struct InsertionData {
nsIXBLBinding* mBinding;
nsXBLPrototypeBinding* mPrototype;
InsertionData(nsIXBLBinding* aBinding,
nsXBLPrototypeBinding* aPrototype)
:mBinding(aBinding), mPrototype(aPrototype) {};
};
PRBool PR_CALLBACK InstantiateInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
{
nsIXBLInsertionPointEntry* entry = (nsIXBLInsertionPointEntry*)aData;
InsertionData* data = (InsertionData*)aClosure;
nsIXBLBinding* binding = data->mBinding;
nsXBLPrototypeBinding* proto = data->mPrototype;
// Get the insertion parent.
nsCOMPtr<nsIContent> content;
entry->GetInsertionParent(getter_AddRefs(content));
PRUint32 index;
entry->GetInsertionIndex(&index);
// Locate the real content.
nsCOMPtr<nsIContent> realContent;
nsCOMPtr<nsIContent> instanceRoot;
binding->GetAnonymousContent(getter_AddRefs(instanceRoot));
nsCOMPtr<nsIContent> templRoot;
proto->GetImmediateChild(nsXBLPrototypeBinding::kContentAtom, getter_AddRefs(templRoot));
proto->LocateInstance(templRoot, instanceRoot, content, getter_AddRefs(realContent));
if (!realContent)
binding->GetBoundElement(getter_AddRefs(realContent));
// Now that we have the real content, look it up in our table.
nsCOMPtr<nsISupportsArray> points;
binding->GetInsertionPointsFor(realContent, getter_AddRefs(points));
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint;
PRUint32 count;
points->Count(&count);
PRUint32 i = 0, currIndex = 0;
for ( ; i < count; i++) {
nsCOMPtr<nsIXBLInsertionPoint> currPoint = getter_AddRefs((nsIXBLInsertionPoint*)points->ElementAt(i));
currPoint->GetInsertionIndex(&currIndex);
if (currIndex == index) {
// This is a match. Break out of the loop and set our variable.
insertionPoint = currPoint;
break;
}
if (currIndex > index)
// There was no match. Break.
break;
}
if (!insertionPoint) {
// We need to make a new insertion point.
NS_NewXBLInsertionPoint(realContent, index, getter_AddRefs(insertionPoint));
points->InsertElementAt(insertionPoint, i);
}
return PR_TRUE;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::InstantiateInsertionPoints(nsIXBLBinding* aBinding)
{
InsertionData data(aBinding, this);
if (mInsertionPointTable)
mInsertionPointTable->Enumerate(InstantiateInsertionPoint, &data);
return NS_OK;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent* aChild, nsIContent** aResult)
nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{
if (mInsertionPointTable) {
nsCOMPtr<nsIAtom> tag;
aChild->GetTag(*getter_AddRefs(tag));
nsISupportsKey key(tag);
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
mInsertionPointTable->Get(&key)));
if (!content) {
nsCOMPtr<nsIXBLInsertionPointEntry> entry = getter_AddRefs(NS_STATIC_CAST(nsIXBLInsertionPointEntry*,
mInsertionPointTable->Get(&key)));
if (!entry) {
nsISupportsKey key2(kChildrenAtom);
content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2)));
entry = getter_AddRefs(NS_STATIC_CAST(nsIXBLInsertionPointEntry*, mInsertionPointTable->Get(&key2)));
}
nsCOMPtr<nsIContent> realContent;
if (content) {
if (entry) {
nsCOMPtr<nsIContent> content;
entry->GetInsertionParent(getter_AddRefs(content));
entry->GetInsertionIndex(aIndex);
nsCOMPtr<nsIContent> templContent;
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
}
if (realContent)
*aResult = realContent;
else
*aResult = aBoundElement;
NS_IF_ADDREF(*aResult);
}
return NS_OK;
@ -499,15 +639,19 @@ nsXBLPrototypeBinding::GetInsertionPoint(nsIContent* aBoundElement, nsIContent*
NS_IMETHODIMP
nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
nsIContent* aCopyRoot,
nsIContent** aResult, PRBool* aMultipleInsertionPoints)
nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints)
{
if (mInsertionPointTable) {
if(mInsertionPointTable->Count() == 1) {
nsISupportsKey key(kChildrenAtom);
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
mInsertionPointTable->Get(&key)));
nsCOMPtr<nsIXBLInsertionPointEntry> entry = getter_AddRefs(NS_STATIC_CAST(nsIXBLInsertionPointEntry*,
mInsertionPointTable->Get(&key)));
nsCOMPtr<nsIContent> realContent;
if (content) {
if (entry) {
nsCOMPtr<nsIContent> content;
entry->GetInsertionParent(getter_AddRefs(content));
entry->GetInsertionIndex(aIndex);
nsCOMPtr<nsIContent> templContent;
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
@ -519,6 +663,7 @@ nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
// match the filter will just go right underneath the bound element).
*aMultipleInsertionPoints = PR_TRUE;
*aResult = nsnull;
*aIndex = 0;
return NS_OK;
}
@ -527,6 +672,7 @@ nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
*aResult = realContent;
else
*aResult = aBoundElement;
NS_IF_ADDREF(*aResult);
}
else
@ -774,7 +920,7 @@ nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
}
// Create an XBL attribute entry.
nsXBLAttributeEntry* xblAttr = new (kPool) nsXBLAttributeEntry(atom, attribute, aElement);
nsXBLAttributeEntry* xblAttr = new (kAttrPool) nsXBLAttributeEntry(atom, attribute, aElement);
// Now we should see if some element within our anonymous
// content is already observing this attribute.
@ -826,7 +972,7 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
if (!childrenElements)
return;
mInsertionPointTable = new nsSupportsHashtable;
mInsertionPointTable = new nsSupportsHashtable(4);
PRUint32 count;
childrenElements->Count(&count);
@ -838,11 +984,15 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
if (child) {
nsCOMPtr<nsIContent> parent;
child->GetParent(*getter_AddRefs(parent));
// Create an XBL insertion point entry.
nsXBLInsertionPointEntry* xblIns = new (kInsPool) nsXBLInsertionPointEntry(parent);
nsAutoString includes;
child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
if (includes.IsEmpty()) {
nsISupportsKey key(kChildrenAtom);
mInsertionPointTable->Put(&key, parent);
mInsertionPointTable->Put(&key, xblIns);
}
else {
// The user specified at least one attribute.
@ -860,26 +1010,28 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
nsISupportsKey key(atom);
mInsertionPointTable->Put(&key, parent);
mInsertionPointTable->Put(&key, xblIns);
token = nsCRT::strtok( newStr, ", ", &newStr );
}
nsMemory::Free(str);
}
}
}
// Now remove the <children> elements.
for (i = 0; i < count; i++) {
nsCOMPtr<nsISupports> supp;
childrenElements->GetElementAt(i, getter_AddRefs(supp));
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
if (child) {
nsCOMPtr<nsIContent> parent;
child->GetParent(*getter_AddRefs(parent));
// Compute the index of the <children> element. This index is
// equal to the index of the <children> in the template minus the #
// of previous insertion point siblings removed. Because our childrenElements
// array was built in a DFS that went from left-to-right through siblings,
// if we dynamically obtain our index each time, then the removals of previous
// siblings will cause the index to adjust (and we won't have to take that into
// account explicitly).
PRInt32 index;
parent->IndexOf(child, index);
xblIns->SetInsertionIndex((PRUint32)index);
// Now remove the <children> element from the template. This ensures that the
// binding instantiation will not contain a clone of the <children> element when
// it clones the binding template.
parent->RemoveChildAt(index, PR_FALSE);
}
}

View File

@ -75,11 +75,13 @@ class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding
NS_IMETHOD HasInsertionPoints(PRBool* aResult) { *aResult = (mInsertionPointTable != nsnull); return NS_OK; };
NS_IMETHOD InstantiateInsertionPoints(nsIXBLBinding* aBinding);
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent* aChild, nsIContent** aResult);
nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent** aResult, PRBool* aMultiple);
nsIContent** aResult, PRUint32* aIndex, PRBool* aMultiple);
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag);
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
@ -107,7 +109,8 @@ public:
static nsIAtom* kImplementationAtom;
static nsIAtom* kImplementsAtom;
static nsFixedSizeAllocator kPool;
static nsFixedSizeAllocator kAttrPool;
static nsFixedSizeAllocator kInsPool;
// Internal member functions
public:

View File

@ -710,31 +710,6 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsAReadableString& aURL,
return NS_OK;
}
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHODIMP
nsXBLService::GetContentList(nsIContent* aContent, nsIDOMNodeList** aResult, nsIContent** aParent,
PRBool* aMultipleInsertionPoints)
{
// Locate the primary binding and get the node list from its mContent parent.
*aResult = nsnull;
*aParent = nsnull;
*aMultipleInsertionPoints = PR_FALSE;
nsCOMPtr<nsIDocument> document;
aContent->GetDocument(*getter_AddRefs(document));
nsCOMPtr<nsIBindingManager> bindingManager;
NS_ASSERTION(document, "no document");
if (!document) return NS_ERROR_FAILURE;
document->GetBindingManager(getter_AddRefs(bindingManager));
nsCOMPtr<nsIXBLBinding> binding;
bindingManager->GetBinding(aContent, getter_AddRefs(binding));
binding->GetAnonymousNodes(getter_AddRefs(aResult), aParent, aMultipleInsertionPoints);
return NS_OK;
}
NS_IMETHODIMP
nsXBLService::FlushStyleBindings(nsIContent* aContent)
{

View File

@ -65,11 +65,6 @@ class nsXBLService : public nsIXBLService, public nsIObserver, public nsSupports
// This function clears out the bindings on a given content node.
NS_IMETHOD FlushStyleBindings(nsIContent* aContent);
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHOD GetContentList(nsIContent* aContent, nsIDOMNodeList** aResult, nsIContent** aChildElement,
PRBool* aMultipleInsertionPoints);
// Gets the object's base class type.
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);

View File

@ -2899,17 +2899,12 @@ NS_IMETHODIMP
nsXULDocument::GetAnonymousNodes(nsIDOMElement* aElement,
nsIDOMNodeList** aResult)
{
nsresult rv;
// Use the XBL service to get the anonymous node list.
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
PRBool dummy;
nsCOMPtr<nsIContent> dummyElt;
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return xblService->GetContentList(content, aResult, getter_AddRefs(dummyElt), &dummy);
*aResult = nsnull;
if (mBindingManager) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return mBindingManager->GetAnonymousNodesFor(content, aResult);
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -786,6 +786,56 @@ nsMathMLmtableCreator::CreateTableCellInnerFrame(nsIFrame** aNewFrame)
}
#endif // MOZ_MATHML
// Helper class for iterating children during frame construction.
// This class should always be used in lieu of the straight content
// node APIs, since it handles XBL-generated anonymous content as well.
struct ChildIterator
{
nsCOMPtr<nsIContent> mContent;
nsCOMPtr<nsIBindingManager> mBindingManager;
PRUint32 mIndex;
PRUint32 mLength;
nsCOMPtr<nsIDOMNodeList> mNodes;
ChildIterator(nsIContent* aContent)
:mContent(aContent), mIndex(0), mLength(0), mNodes(nsnull)
{
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
doc->GetBindingManager(getter_AddRefs(mBindingManager));
// Retrieve the anonymous content that we should build.
mBindingManager->GetAnonymousNodesFor(mContent, getter_AddRefs(mNodes));
if (mNodes) {
mNodes->GetLength(&mLength);
if (mLength == 0)
mNodes = nsnull;
}
// We may have an altered list of children from XBL insertion points.
// If we don't have any anonymous kids, we next check to see if we have
// insertion points.
if (!mNodes) {
mBindingManager->GetContentListFor(mContent, getter_AddRefs(mNodes));
if (mNodes)
mNodes->GetLength(&mLength);
}
}
PRBool HasMoreChildren() {
return mIndex < mLength;
}
void NextChild(nsIContent** aChild) {
if (mNodes) {
nsCOMPtr<nsIDOMNode> node;
mNodes->Item(mIndex, getter_AddRefs(node));
node->QueryInterface(NS_GET_IID(nsIContent), (void**)aChild);
}
mIndex++;
}
};
// -----------------------------------------------------------
// return the child list that aFrame belongs on. does not ADDREF
@ -818,6 +868,7 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(void)
mGfxScrollFrame(nsnull)
{
NS_INIT_REFCNT();
#ifdef NS_DEBUG
mVerifyFastFindFrame = PR_FALSE;
// Get the pref for verifying the new fast find frame with hint code.
@ -2864,12 +2915,6 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShe
PR_TRUE, childItems, PR_TRUE, nsnull);
if (NS_FAILED(rv)) return rv;
// if there are any tree anonymous children create frames for them
nsCOMPtr<nsIAtom> tagName;
aContent->GetTag(*getter_AddRefs(tagName));
CreateAnonymousTableCellFrames(aPresShell, aPresContext, tagName, aState, aContent,
aNewCellInnerFrame, aNewCellOuterFrame, childItems);
aNewCellInnerFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList);
if (aState.mFloatedItems.childList) {
aNewCellInnerFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::floaterList,
@ -3019,13 +3064,11 @@ nsCSSFrameConstructor::TableProcessChildren(nsIPresShell* aPresShell,
nsCOMPtr<nsIStyleContext> parentStyleContext;
aParentFrame->GetStyleContext(getter_AddRefs(parentStyleContext));
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 childX = 0; childX < count; childX++) { // iterate the child content
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
rv = aContent->ChildAt(childX, *getter_AddRefs(childContent));
if (childContent.get() && NS_SUCCEEDED(rv)) {
iterator.NextChild(getter_AddRefs(childContent));
if (childContent.get()) {
rv = TableProcessChild(aPresShell, aPresContext, aState, *childContent.get(), aParentFrame,
parentFrameType.get(), parentStyleContext.get(),
aTableCreator, aChildItems, aCaption);
@ -4126,7 +4169,6 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsIPresShell* aPresShell,
InitializeSelectFrame(aPresShell, aPresContext, aState, listFrame, scrolledFrame, aContent, comboboxFrame,
listStyle, PR_FALSE, PR_FALSE, PR_TRUE);
newFrame = listFrame;
// XXX Temporary for Bug 19416
{
@ -5041,160 +5083,8 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
nsIFrame* aNewFrame,
nsFrameItems& aChildItems)
{
nsCOMPtr<nsIStyleContext> styleContext;
aNewFrame->GetStyleContext(getter_AddRefs(styleContext));
const nsStyleUserInterface* ui= (const nsStyleUserInterface*)
styleContext->GetStyleData(eStyleStruct_UserInterface);
if (!ui->mBehavior.IsEmpty()) {
// Get the XBL loader.
nsresult rv;
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsIDOMNodeList> anonymousItems;
nsCOMPtr<nsIContent> childElement;
PRBool multiple;
xblService->GetContentList(aParent, getter_AddRefs(anonymousItems), getter_AddRefs(childElement), &multiple);
if (anonymousItems)
{
// See if we have to move our explicit content.
nsFrameItems explicitItems;
if (childElement || multiple) {
// First, remove all of the kids from the frame list and put them
// in a new frame list.
explicitItems.childList = aChildItems.childList;
explicitItems.lastChild = aChildItems.lastChild;
aChildItems.childList = aChildItems.lastChild = nsnull;
}
// Build the frames for the anonymous content.
PRUint32 count = 0;
anonymousItems->GetLength(&count);
for (PRUint32 i=0; i < count; i++)
{
// get our child's content and set its parent to our content
nsCOMPtr<nsIDOMNode> elt;
if (NS_FAILED(anonymousItems->Item(i, getter_AddRefs(elt))))
continue;
// create the frame and attach it to our frame
nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
ConstructFrame(aPresShell, aPresContext, aState, content, aNewFrame, aChildItems);
}
if (childElement) {
// Now append the explicit frames
// All our explicit content that we built must be reparented.
nsIFrame* frame = nsnull;
nsIFrame* currFrame = aChildItems.childList;
while (currFrame) {
LocateAnonymousFrame(aPresContext,
currFrame,
childElement,
&frame);
if (frame)
break;
currFrame->GetNextSibling(&currFrame);
}
nsCOMPtr<nsIFrameManager> frameManager;
aPresShell->GetFrameManager(getter_AddRefs(frameManager));
if (frameManager && frame && explicitItems.childList) {
frameManager->AppendFrames(aPresContext, *aPresShell, frame,
nsnull, explicitItems.childList);
nsIFrame* insertionPoint = nsnull;
frameManager->GetInsertionPoint(aPresShell, frame, explicitItems.childList, &insertionPoint);
if (!insertionPoint) {
nsCOMPtr<nsIStyleContext> styleContextForFrame;
frame->GetStyleContext(getter_AddRefs(styleContextForFrame));
nsIFrame* walkit = explicitItems.childList;
while (walkit) {
nsIFrame* realFrame = GetRealFrame(walkit);
realFrame->SetParent(frame);
aPresContext->ReParentStyleContext(realFrame, styleContextForFrame);
walkit->GetNextSibling(&walkit);
}
}
}
}
else if (multiple) {
nsCOMPtr<nsIDocument> document;
nsCOMPtr<nsIBindingManager> bindingManager;
aParent->GetDocument(*getter_AddRefs(document));
document->GetBindingManager(getter_AddRefs(bindingManager));
nsCOMPtr<nsIContent> currContent;
nsCOMPtr<nsIContent> insertionElement;
nsIFrame* currFrame = explicitItems.childList;
explicitItems.childList = explicitItems.lastChild = nsnull;
nsCOMPtr<nsIFrameManager> frameManager;
aPresShell->GetFrameManager(getter_AddRefs(frameManager));
while (currFrame) {
nsIFrame* nextFrame;
currFrame->GetNextSibling(&nextFrame);
currFrame->SetNextSibling(nsnull);
currFrame->GetContent(getter_AddRefs(currContent));
bindingManager->GetInsertionPoint(aParent, currContent, getter_AddRefs(insertionElement));
nsIFrame* frame = nsnull;
if (insertionElement) {
nsIFrame* childFrame = aChildItems.childList;
while (childFrame) {
LocateAnonymousFrame(aPresContext,
childFrame,
insertionElement,
&frame);
if (frame)
break;
childFrame->GetNextSibling(&childFrame);
}
}
if (!frame) {
if (!explicitItems.childList)
explicitItems.childList = explicitItems.lastChild = currFrame;
else {
explicitItems.lastChild->SetNextSibling(currFrame);
explicitItems.lastChild = currFrame;
}
}
if (frameManager && frame) {
frameManager->AppendFrames(aPresContext, *aPresShell, frame,
nsnull, currFrame);
nsIFrame* insertionPoint = nsnull;
frameManager->GetInsertionPoint(aPresShell, frame, explicitItems.childList, &insertionPoint);
if (!insertionPoint) {
frame->GetStyleContext(getter_AddRefs(styleContext));
nsIFrame* realFrame = GetRealFrame(currFrame);
realFrame->SetParent(frame);
aPresContext->ReParentStyleContext(realFrame, styleContext);
}
}
currFrame = nextFrame;
}
if (explicitItems.lastChild) {
explicitItems.lastChild->SetNextSibling(aChildItems.childList);
aChildItems.childList = explicitItems.childList;
}
}
return NS_OK;
}
}
// If we have no anonymous content from XBL see if we might have
// some by looking at the tag rather than doing a QueryInterface on
// See if we might have anonymous content
// by looking at the tag rather than doing a QueryInterface on
// the frame. Only these tags' frames can have anonymous content
// through nsIAnonymousContentCreator. We do this check for
// performance reasons. If we did a QueryInterface on every tag it
@ -5278,61 +5168,6 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
return NS_OK;
}
// after the node has been constructed and initialized create any
// anonymous content a node needs.
nsresult
nsCSSFrameConstructor::CreateAnonymousTableCellFrames(nsIPresShell* aPresShell,
nsIPresContext* aPresContext,
nsIAtom* aTag,
nsFrameConstructorState& aState,
nsIContent* aParent,
nsIFrame* aNewFrame,
nsIFrame* aNewCellFrame,
nsFrameItems& aChildItems)
{
nsCOMPtr<nsIStyleContext> styleContext;
aNewCellFrame->GetStyleContext(getter_AddRefs(styleContext));
const nsStyleUserInterface* ui= (const nsStyleUserInterface*)
styleContext->GetStyleData(eStyleStruct_UserInterface);
if (!ui->mBehavior.IsEmpty()) {
// Get the XBL loader.
nsresult rv;
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsIContent> childElement;
nsCOMPtr<nsIDOMNodeList> anonymousItems;
PRBool multiple;
xblService->GetContentList(aParent, getter_AddRefs(anonymousItems), getter_AddRefs(childElement), &multiple);
if (!anonymousItems)
return NS_OK;
// Build the frames for the anonymous content.
PRUint32 count = 0;
anonymousItems->GetLength(&count);
for (PRUint32 i=0; i < count; i++)
{
// get our child's content and set its parent to our content
nsCOMPtr<nsIDOMNode> elt;
if (NS_FAILED(anonymousItems->Item(i, getter_AddRefs(elt))))
continue;
// create the frame and attach it to our frame
nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
ConstructFrame(aPresShell, aPresContext, aState, content, aNewFrame, aChildItems);
}
return NS_OK;
}
return NS_OK;
}
#ifdef INCLUDE_XUL
nsresult
nsCSSFrameConstructor::ConstructXULFrame(nsIPresShell* aPresShell,
@ -7175,29 +7010,19 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell,
rv = ResolveStyleContext(aPresContext, aParentFrame, aContent, tag, getter_AddRefs(styleContext));
if (NS_SUCCEEDED(rv)) {
// Pre-check for display "none" - if we find that, don't create
// any frame at all
const nsStyleDisplay* display = (const nsStyleDisplay*)
styleContext->GetStyleData(eStyleStruct_Display);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
aState.mFrameManager->SetUndisplayedContent(aContent, styleContext);
}
else
{
PRInt32 nameSpaceID;
aContent->GetNameSpaceID(nameSpaceID);
rv = ConstructFrameInternal(aPresShell,
aPresContext,
aState,
aContent,
aParentFrame,
tag,
nameSpaceID,
styleContext,
aFrameItems,
PR_FALSE);
}
PRInt32 nameSpaceID;
aContent->GetNameSpaceID(nameSpaceID);
rv = ConstructFrameInternal(aPresShell,
aPresContext,
aState,
aContent,
aParentFrame,
tag,
nameSpaceID,
styleContext,
aFrameItems,
PR_FALSE);
}
return rv;
@ -7216,13 +7041,8 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsIPresShell* aPresShe
nsFrameItems& aFrameItems,
PRBool aXBLBaseTag)
{
#ifdef DEBUG_hyatt
if (aTag == nsXULAtoms::menulist) {
printf("moo!");
}
#endif /* DEBUG_hyatt */
// The following code allows the user to specify the base tag
// of a XUL object using XBL. XUL objects (like boxes, menus, etc.)
// of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
// can then be extended arbitrarily.
nsCOMPtr<nsIStyleContext> styleContext(do_QueryInterface(aStyleContext));
nsCOMPtr<nsIXBLBinding> binding;
@ -7278,6 +7098,15 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsIPresShell* aPresShe
}
}
// Pre-check for display "none" - if we find that, don't create
// any frame at all
const nsStyleDisplay* display = (const nsStyleDisplay*)
styleContext->GetStyleData(eStyleStruct_Display);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
aState.mFrameManager->SetUndisplayedContent(aContent, styleContext);
return NS_OK;
}
nsIFrame* lastChild = aFrameItems.lastChild;
@ -11286,11 +11115,11 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresShell* aPresShell,
{
nsresult rv = NS_OK;
nsCOMPtr<nsIStyleContext> styleContext;
aFrame->GetStyleContext(getter_AddRefs(styleContext));
if (aCanHaveGeneratedContent) {
// Probe for generated content before
nsIFrame* generatedFrame;
aFrame->GetStyleContext(getter_AddRefs(styleContext));
if (CreateGeneratedContentFrame(aPresShell, aPresContext, aState, aFrame, aContent,
styleContext, nsCSSAtoms::beforePseudo,
aParentIsBlock, &generatedFrame)) {
@ -11310,19 +11139,15 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresShell* aPresShell,
nsPseudoFrames priorPseudoFrames;
aState.mPseudoFrames.Reset(&priorPseudoFrames);
// Iterate the child content objects and construct frames
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 i = 0; i < count; i++) {
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) {
// Construct a child frame
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
}
iterator.NextChild(getter_AddRefs(childContent));
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv))
return rv;
}
// process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aFrameItems);
@ -12471,17 +12296,14 @@ nsCSSFrameConstructor::ProcessBlockChildren(nsIPresShell* aPresShell,
}
// Iterate the child content objects and construct frames
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 i = 0; i < count; i++) {
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) {
// Construct a child frame
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
}
iterator.NextChild(getter_AddRefs(childContent));
// Construct a child frame
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv))
return rv;
}
// process pseudo frames if necessary
@ -12763,36 +12585,34 @@ nsCSSFrameConstructor::ProcessInlineChildren(nsIPresShell* aPresShell,
// Iterate the child content objects and construct frames
PRBool allKidsInline = PR_TRUE;
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 i = 0; i < count; i++) {
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) {
// Construct a child frame
nsIFrame* oldLastChild = aFrameItems.lastChild;
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
iterator.NextChild(getter_AddRefs(childContent));
// Construct a child frame
nsIFrame* oldLastChild = aFrameItems.lastChild;
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
// Examine newly added children (we may have added more than one
// child if the child was another inline frame that ends up
// being carved in 3 pieces) to maintain the allKidsInline flag.
if (allKidsInline) {
nsIFrame* kid;
if (oldLastChild) {
oldLastChild->GetNextSibling(&kid);
}
else {
kid = aFrameItems.childList;
}
while (kid) {
if (!IsInlineFrame(kid)) {
allKidsInline = PR_FALSE;
break;
}
kid->GetNextSibling(&kid);
// Examine newly added children (we may have added more than one
// child if the child was another inline frame that ends up
// being carved in 3 pieces) to maintain the allKidsInline flag.
if (allKidsInline) {
nsIFrame* kid;
if (oldLastChild) {
oldLastChild->GetNextSibling(&kid);
}
else {
kid = aFrameItems.childList;
}
while (kid) {
if (!IsInlineFrame(kid)) {
allKidsInline = PR_FALSE;
break;
}
kid->GetNextSibling(&kid);
}
}
}

View File

@ -40,9 +40,9 @@ struct nsStyleDisplay;
class nsIPresShell;
class nsVoidArray;
class nsIFrameManager;
class nsFrameConstructorState;
class nsIDOMHTMLSelectElement;
class nsIXBLService;
class nsCSSFrameConstructor : public nsIStyleFrameConstruction {
public:
@ -524,15 +524,6 @@ protected:
nsIFrame* aNewFrame,
nsFrameItems& aChildItems);
nsresult CreateAnonymousTableCellFrames(nsIPresShell* aPresShell,
nsIPresContext* aPresContext,
nsIAtom* aTag,
nsFrameConstructorState& aState,
nsIContent* aParent,
nsIFrame* aNewCellBodyFrame,
nsIFrame* aNewCellFrame,
nsFrameItems& aChildItems);
//MathML Mod - RBS
#ifdef MOZ_MATHML
nsresult ConstructMathMLFrame(nsIPresShell* aPresShell,
@ -954,12 +945,12 @@ protected:
PRBool mGotGfxPrefs;
PRBool mHasGfxScrollbars;
nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
#ifdef NS_DEBUG
PRBool mVerifyFastFindFrame; // if true, run both the old and new find frame code
// to validate that both ways get the same answer
#endif
nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
};
#endif /* nsCSSFrameConstructor_h___ */

View File

@ -2396,7 +2396,8 @@ FrameManager::GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aParent, nsIFram
return NS_OK; // It is anonymous. Don't use the insertion point, since that's only
// for the explicit kids.
bindingManager->GetInsertionPoint(content, currContent, getter_AddRefs(insertionElement));
PRUint32 index;
bindingManager->GetInsertionPoint(content, currContent, getter_AddRefs(insertionElement), &index);
if (insertionElement) {
aShell->GetPrimaryFrameFor(insertionElement, &frame);
if (frame) {
@ -2414,7 +2415,8 @@ FrameManager::GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aParent, nsIFram
}
else {
PRBool dummy;
bindingManager->GetSingleInsertionPoint(content, getter_AddRefs(insertionElement), &dummy);
PRUint32 index;
bindingManager->GetSingleInsertionPoint(content, getter_AddRefs(insertionElement), &index, &dummy);
if (insertionElement) {
aShell->GetPrimaryFrameFor(insertionElement, &frame);
if (frame) {

View File

@ -545,57 +545,6 @@ nsDocumentChildNodes::DropReference()
// =
// ==================================================================
MOZ_DECL_CTOR_COUNTER(nsAnonymousContentList)
nsAnonymousContentList::nsAnonymousContentList(nsISupportsArray* aElements)
{
MOZ_COUNT_CTOR(nsAnonymousContentList);
// We don't reference count our Anonymous reference (to avoid circular
// references). We'll be told when the Anonymous goes away.
mElements = aElements;
NS_IF_ADDREF(mElements);
}
nsAnonymousContentList::~nsAnonymousContentList()
{
MOZ_COUNT_DTOR(nsAnonymousContentList);
NS_IF_RELEASE(mElements);
}
NS_IMETHODIMP
nsAnonymousContentList::GetLength(PRUint32* aLength)
{
NS_ASSERTION(aLength != nsnull, "null ptr");
if (! aLength)
return NS_ERROR_NULL_POINTER;
PRUint32 cnt;
nsresult rv = mElements->Count(&cnt);
if (NS_FAILED(rv)) return rv;
*aLength = cnt;
return NS_OK;
}
NS_IMETHODIMP
nsAnonymousContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
{
PRUint32 cnt;
nsresult rv = mElements->Count(&cnt);
if (NS_FAILED(rv)) return rv;
if (aIndex >= (PRUint32) cnt)
return NS_ERROR_INVALID_ARG;
// Cast is okay because we're in a closed system.
*aReturn = (nsIDOMNode*) mElements->ElementAt(aIndex);
return NS_OK;
}
// ==================================================================
// =
// ==================================================================
nsDocument::nsDocument()
{
NS_INIT_REFCNT();
@ -2211,17 +2160,12 @@ NS_IMETHODIMP
nsDocument::GetAnonymousNodes(nsIDOMElement* aElement,
nsIDOMNodeList** aResult)
{
nsresult rv;
// Use the XBL service to get the anonymous node list.
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
PRBool dummy;
nsCOMPtr<nsIContent> dummyElt;
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return xblService->GetContentList(content, aResult, getter_AddRefs(dummyElt), &dummy);
*aResult = nsnull;
if (mBindingManager) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return mBindingManager->GetAnonymousNodesFor(content, aResult);
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -115,19 +115,6 @@ protected:
nsIDocument* mDocument;
};
class nsAnonymousContentList : public nsGenericDOMNodeList
{
public:
nsAnonymousContentList(nsISupportsArray* aElements);
virtual ~nsAnonymousContentList();
// nsIDOMNodeList interface
NS_DECL_IDOMNODELIST
private:
nsISupportsArray* mElements;
};
// Base class for our document implementations
class nsDocument : public nsIDocument,
public nsIDOMDocument,

View File

@ -2396,7 +2396,8 @@ FrameManager::GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aParent, nsIFram
return NS_OK; // It is anonymous. Don't use the insertion point, since that's only
// for the explicit kids.
bindingManager->GetInsertionPoint(content, currContent, getter_AddRefs(insertionElement));
PRUint32 index;
bindingManager->GetInsertionPoint(content, currContent, getter_AddRefs(insertionElement), &index);
if (insertionElement) {
aShell->GetPrimaryFrameFor(insertionElement, &frame);
if (frame) {
@ -2414,7 +2415,8 @@ FrameManager::GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aParent, nsIFram
}
else {
PRBool dummy;
bindingManager->GetSingleInsertionPoint(content, getter_AddRefs(insertionElement), &dummy);
PRUint32 index;
bindingManager->GetSingleInsertionPoint(content, getter_AddRefs(insertionElement), &index, &dummy);
if (insertionElement) {
aShell->GetPrimaryFrameFor(insertionElement, &frame);
if (frame) {

View File

@ -786,6 +786,56 @@ nsMathMLmtableCreator::CreateTableCellInnerFrame(nsIFrame** aNewFrame)
}
#endif // MOZ_MATHML
// Helper class for iterating children during frame construction.
// This class should always be used in lieu of the straight content
// node APIs, since it handles XBL-generated anonymous content as well.
struct ChildIterator
{
nsCOMPtr<nsIContent> mContent;
nsCOMPtr<nsIBindingManager> mBindingManager;
PRUint32 mIndex;
PRUint32 mLength;
nsCOMPtr<nsIDOMNodeList> mNodes;
ChildIterator(nsIContent* aContent)
:mContent(aContent), mIndex(0), mLength(0), mNodes(nsnull)
{
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
doc->GetBindingManager(getter_AddRefs(mBindingManager));
// Retrieve the anonymous content that we should build.
mBindingManager->GetAnonymousNodesFor(mContent, getter_AddRefs(mNodes));
if (mNodes) {
mNodes->GetLength(&mLength);
if (mLength == 0)
mNodes = nsnull;
}
// We may have an altered list of children from XBL insertion points.
// If we don't have any anonymous kids, we next check to see if we have
// insertion points.
if (!mNodes) {
mBindingManager->GetContentListFor(mContent, getter_AddRefs(mNodes));
if (mNodes)
mNodes->GetLength(&mLength);
}
}
PRBool HasMoreChildren() {
return mIndex < mLength;
}
void NextChild(nsIContent** aChild) {
if (mNodes) {
nsCOMPtr<nsIDOMNode> node;
mNodes->Item(mIndex, getter_AddRefs(node));
node->QueryInterface(NS_GET_IID(nsIContent), (void**)aChild);
}
mIndex++;
}
};
// -----------------------------------------------------------
// return the child list that aFrame belongs on. does not ADDREF
@ -818,6 +868,7 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(void)
mGfxScrollFrame(nsnull)
{
NS_INIT_REFCNT();
#ifdef NS_DEBUG
mVerifyFastFindFrame = PR_FALSE;
// Get the pref for verifying the new fast find frame with hint code.
@ -2864,12 +2915,6 @@ nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell* aPresShe
PR_TRUE, childItems, PR_TRUE, nsnull);
if (NS_FAILED(rv)) return rv;
// if there are any tree anonymous children create frames for them
nsCOMPtr<nsIAtom> tagName;
aContent->GetTag(*getter_AddRefs(tagName));
CreateAnonymousTableCellFrames(aPresShell, aPresContext, tagName, aState, aContent,
aNewCellInnerFrame, aNewCellOuterFrame, childItems);
aNewCellInnerFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList);
if (aState.mFloatedItems.childList) {
aNewCellInnerFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::floaterList,
@ -3019,13 +3064,11 @@ nsCSSFrameConstructor::TableProcessChildren(nsIPresShell* aPresShell,
nsCOMPtr<nsIStyleContext> parentStyleContext;
aParentFrame->GetStyleContext(getter_AddRefs(parentStyleContext));
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 childX = 0; childX < count; childX++) { // iterate the child content
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
rv = aContent->ChildAt(childX, *getter_AddRefs(childContent));
if (childContent.get() && NS_SUCCEEDED(rv)) {
iterator.NextChild(getter_AddRefs(childContent));
if (childContent.get()) {
rv = TableProcessChild(aPresShell, aPresContext, aState, *childContent.get(), aParentFrame,
parentFrameType.get(), parentStyleContext.get(),
aTableCreator, aChildItems, aCaption);
@ -4126,7 +4169,6 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsIPresShell* aPresShell,
InitializeSelectFrame(aPresShell, aPresContext, aState, listFrame, scrolledFrame, aContent, comboboxFrame,
listStyle, PR_FALSE, PR_FALSE, PR_TRUE);
newFrame = listFrame;
// XXX Temporary for Bug 19416
{
@ -5041,160 +5083,8 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
nsIFrame* aNewFrame,
nsFrameItems& aChildItems)
{
nsCOMPtr<nsIStyleContext> styleContext;
aNewFrame->GetStyleContext(getter_AddRefs(styleContext));
const nsStyleUserInterface* ui= (const nsStyleUserInterface*)
styleContext->GetStyleData(eStyleStruct_UserInterface);
if (!ui->mBehavior.IsEmpty()) {
// Get the XBL loader.
nsresult rv;
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsIDOMNodeList> anonymousItems;
nsCOMPtr<nsIContent> childElement;
PRBool multiple;
xblService->GetContentList(aParent, getter_AddRefs(anonymousItems), getter_AddRefs(childElement), &multiple);
if (anonymousItems)
{
// See if we have to move our explicit content.
nsFrameItems explicitItems;
if (childElement || multiple) {
// First, remove all of the kids from the frame list and put them
// in a new frame list.
explicitItems.childList = aChildItems.childList;
explicitItems.lastChild = aChildItems.lastChild;
aChildItems.childList = aChildItems.lastChild = nsnull;
}
// Build the frames for the anonymous content.
PRUint32 count = 0;
anonymousItems->GetLength(&count);
for (PRUint32 i=0; i < count; i++)
{
// get our child's content and set its parent to our content
nsCOMPtr<nsIDOMNode> elt;
if (NS_FAILED(anonymousItems->Item(i, getter_AddRefs(elt))))
continue;
// create the frame and attach it to our frame
nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
ConstructFrame(aPresShell, aPresContext, aState, content, aNewFrame, aChildItems);
}
if (childElement) {
// Now append the explicit frames
// All our explicit content that we built must be reparented.
nsIFrame* frame = nsnull;
nsIFrame* currFrame = aChildItems.childList;
while (currFrame) {
LocateAnonymousFrame(aPresContext,
currFrame,
childElement,
&frame);
if (frame)
break;
currFrame->GetNextSibling(&currFrame);
}
nsCOMPtr<nsIFrameManager> frameManager;
aPresShell->GetFrameManager(getter_AddRefs(frameManager));
if (frameManager && frame && explicitItems.childList) {
frameManager->AppendFrames(aPresContext, *aPresShell, frame,
nsnull, explicitItems.childList);
nsIFrame* insertionPoint = nsnull;
frameManager->GetInsertionPoint(aPresShell, frame, explicitItems.childList, &insertionPoint);
if (!insertionPoint) {
nsCOMPtr<nsIStyleContext> styleContextForFrame;
frame->GetStyleContext(getter_AddRefs(styleContextForFrame));
nsIFrame* walkit = explicitItems.childList;
while (walkit) {
nsIFrame* realFrame = GetRealFrame(walkit);
realFrame->SetParent(frame);
aPresContext->ReParentStyleContext(realFrame, styleContextForFrame);
walkit->GetNextSibling(&walkit);
}
}
}
}
else if (multiple) {
nsCOMPtr<nsIDocument> document;
nsCOMPtr<nsIBindingManager> bindingManager;
aParent->GetDocument(*getter_AddRefs(document));
document->GetBindingManager(getter_AddRefs(bindingManager));
nsCOMPtr<nsIContent> currContent;
nsCOMPtr<nsIContent> insertionElement;
nsIFrame* currFrame = explicitItems.childList;
explicitItems.childList = explicitItems.lastChild = nsnull;
nsCOMPtr<nsIFrameManager> frameManager;
aPresShell->GetFrameManager(getter_AddRefs(frameManager));
while (currFrame) {
nsIFrame* nextFrame;
currFrame->GetNextSibling(&nextFrame);
currFrame->SetNextSibling(nsnull);
currFrame->GetContent(getter_AddRefs(currContent));
bindingManager->GetInsertionPoint(aParent, currContent, getter_AddRefs(insertionElement));
nsIFrame* frame = nsnull;
if (insertionElement) {
nsIFrame* childFrame = aChildItems.childList;
while (childFrame) {
LocateAnonymousFrame(aPresContext,
childFrame,
insertionElement,
&frame);
if (frame)
break;
childFrame->GetNextSibling(&childFrame);
}
}
if (!frame) {
if (!explicitItems.childList)
explicitItems.childList = explicitItems.lastChild = currFrame;
else {
explicitItems.lastChild->SetNextSibling(currFrame);
explicitItems.lastChild = currFrame;
}
}
if (frameManager && frame) {
frameManager->AppendFrames(aPresContext, *aPresShell, frame,
nsnull, currFrame);
nsIFrame* insertionPoint = nsnull;
frameManager->GetInsertionPoint(aPresShell, frame, explicitItems.childList, &insertionPoint);
if (!insertionPoint) {
frame->GetStyleContext(getter_AddRefs(styleContext));
nsIFrame* realFrame = GetRealFrame(currFrame);
realFrame->SetParent(frame);
aPresContext->ReParentStyleContext(realFrame, styleContext);
}
}
currFrame = nextFrame;
}
if (explicitItems.lastChild) {
explicitItems.lastChild->SetNextSibling(aChildItems.childList);
aChildItems.childList = explicitItems.childList;
}
}
return NS_OK;
}
}
// If we have no anonymous content from XBL see if we might have
// some by looking at the tag rather than doing a QueryInterface on
// See if we might have anonymous content
// by looking at the tag rather than doing a QueryInterface on
// the frame. Only these tags' frames can have anonymous content
// through nsIAnonymousContentCreator. We do this check for
// performance reasons. If we did a QueryInterface on every tag it
@ -5278,61 +5168,6 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell,
return NS_OK;
}
// after the node has been constructed and initialized create any
// anonymous content a node needs.
nsresult
nsCSSFrameConstructor::CreateAnonymousTableCellFrames(nsIPresShell* aPresShell,
nsIPresContext* aPresContext,
nsIAtom* aTag,
nsFrameConstructorState& aState,
nsIContent* aParent,
nsIFrame* aNewFrame,
nsIFrame* aNewCellFrame,
nsFrameItems& aChildItems)
{
nsCOMPtr<nsIStyleContext> styleContext;
aNewCellFrame->GetStyleContext(getter_AddRefs(styleContext));
const nsStyleUserInterface* ui= (const nsStyleUserInterface*)
styleContext->GetStyleData(eStyleStruct_UserInterface);
if (!ui->mBehavior.IsEmpty()) {
// Get the XBL loader.
nsresult rv;
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsIContent> childElement;
nsCOMPtr<nsIDOMNodeList> anonymousItems;
PRBool multiple;
xblService->GetContentList(aParent, getter_AddRefs(anonymousItems), getter_AddRefs(childElement), &multiple);
if (!anonymousItems)
return NS_OK;
// Build the frames for the anonymous content.
PRUint32 count = 0;
anonymousItems->GetLength(&count);
for (PRUint32 i=0; i < count; i++)
{
// get our child's content and set its parent to our content
nsCOMPtr<nsIDOMNode> elt;
if (NS_FAILED(anonymousItems->Item(i, getter_AddRefs(elt))))
continue;
// create the frame and attach it to our frame
nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
ConstructFrame(aPresShell, aPresContext, aState, content, aNewFrame, aChildItems);
}
return NS_OK;
}
return NS_OK;
}
#ifdef INCLUDE_XUL
nsresult
nsCSSFrameConstructor::ConstructXULFrame(nsIPresShell* aPresShell,
@ -7175,29 +7010,19 @@ nsCSSFrameConstructor::ConstructFrame(nsIPresShell* aPresShell,
rv = ResolveStyleContext(aPresContext, aParentFrame, aContent, tag, getter_AddRefs(styleContext));
if (NS_SUCCEEDED(rv)) {
// Pre-check for display "none" - if we find that, don't create
// any frame at all
const nsStyleDisplay* display = (const nsStyleDisplay*)
styleContext->GetStyleData(eStyleStruct_Display);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
aState.mFrameManager->SetUndisplayedContent(aContent, styleContext);
}
else
{
PRInt32 nameSpaceID;
aContent->GetNameSpaceID(nameSpaceID);
rv = ConstructFrameInternal(aPresShell,
aPresContext,
aState,
aContent,
aParentFrame,
tag,
nameSpaceID,
styleContext,
aFrameItems,
PR_FALSE);
}
PRInt32 nameSpaceID;
aContent->GetNameSpaceID(nameSpaceID);
rv = ConstructFrameInternal(aPresShell,
aPresContext,
aState,
aContent,
aParentFrame,
tag,
nameSpaceID,
styleContext,
aFrameItems,
PR_FALSE);
}
return rv;
@ -7216,13 +7041,8 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsIPresShell* aPresShe
nsFrameItems& aFrameItems,
PRBool aXBLBaseTag)
{
#ifdef DEBUG_hyatt
if (aTag == nsXULAtoms::menulist) {
printf("moo!");
}
#endif /* DEBUG_hyatt */
// The following code allows the user to specify the base tag
// of a XUL object using XBL. XUL objects (like boxes, menus, etc.)
// of an element using XBL. XUL and HTML objects (like boxes, menus, etc.)
// can then be extended arbitrarily.
nsCOMPtr<nsIStyleContext> styleContext(do_QueryInterface(aStyleContext));
nsCOMPtr<nsIXBLBinding> binding;
@ -7278,6 +7098,15 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsIPresShell* aPresShe
}
}
// Pre-check for display "none" - if we find that, don't create
// any frame at all
const nsStyleDisplay* display = (const nsStyleDisplay*)
styleContext->GetStyleData(eStyleStruct_Display);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
aState.mFrameManager->SetUndisplayedContent(aContent, styleContext);
return NS_OK;
}
nsIFrame* lastChild = aFrameItems.lastChild;
@ -11286,11 +11115,11 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresShell* aPresShell,
{
nsresult rv = NS_OK;
nsCOMPtr<nsIStyleContext> styleContext;
aFrame->GetStyleContext(getter_AddRefs(styleContext));
if (aCanHaveGeneratedContent) {
// Probe for generated content before
nsIFrame* generatedFrame;
aFrame->GetStyleContext(getter_AddRefs(styleContext));
if (CreateGeneratedContentFrame(aPresShell, aPresContext, aState, aFrame, aContent,
styleContext, nsCSSAtoms::beforePseudo,
aParentIsBlock, &generatedFrame)) {
@ -11310,19 +11139,15 @@ nsCSSFrameConstructor::ProcessChildren(nsIPresShell* aPresShell,
nsPseudoFrames priorPseudoFrames;
aState.mPseudoFrames.Reset(&priorPseudoFrames);
// Iterate the child content objects and construct frames
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 i = 0; i < count; i++) {
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) {
// Construct a child frame
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
}
iterator.NextChild(getter_AddRefs(childContent));
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv))
return rv;
}
// process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aFrameItems);
@ -12471,17 +12296,14 @@ nsCSSFrameConstructor::ProcessBlockChildren(nsIPresShell* aPresShell,
}
// Iterate the child content objects and construct frames
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 i = 0; i < count; i++) {
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) {
// Construct a child frame
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
}
iterator.NextChild(getter_AddRefs(childContent));
// Construct a child frame
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv))
return rv;
}
// process pseudo frames if necessary
@ -12763,36 +12585,34 @@ nsCSSFrameConstructor::ProcessInlineChildren(nsIPresShell* aPresShell,
// Iterate the child content objects and construct frames
PRBool allKidsInline = PR_TRUE;
PRInt32 count;
aContent->ChildCount(count);
for (PRInt32 i = 0; i < count; i++) {
ChildIterator iterator(aContent);
while (iterator.HasMoreChildren()) {
nsCOMPtr<nsIContent> childContent;
if (NS_SUCCEEDED(aContent->ChildAt(i, *getter_AddRefs(childContent)))) {
// Construct a child frame
nsIFrame* oldLastChild = aFrameItems.lastChild;
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
iterator.NextChild(getter_AddRefs(childContent));
// Construct a child frame
nsIFrame* oldLastChild = aFrameItems.lastChild;
rv = ConstructFrame(aPresShell, aPresContext, aState, childContent, aFrame, aFrameItems);
if (NS_FAILED(rv)) {
return rv;
}
// Examine newly added children (we may have added more than one
// child if the child was another inline frame that ends up
// being carved in 3 pieces) to maintain the allKidsInline flag.
if (allKidsInline) {
nsIFrame* kid;
if (oldLastChild) {
oldLastChild->GetNextSibling(&kid);
}
else {
kid = aFrameItems.childList;
}
while (kid) {
if (!IsInlineFrame(kid)) {
allKidsInline = PR_FALSE;
break;
}
kid->GetNextSibling(&kid);
// Examine newly added children (we may have added more than one
// child if the child was another inline frame that ends up
// being carved in 3 pieces) to maintain the allKidsInline flag.
if (allKidsInline) {
nsIFrame* kid;
if (oldLastChild) {
oldLastChild->GetNextSibling(&kid);
}
else {
kid = aFrameItems.childList;
}
while (kid) {
if (!IsInlineFrame(kid)) {
allKidsInline = PR_FALSE;
break;
}
kid->GetNextSibling(&kid);
}
}
}

View File

@ -40,9 +40,9 @@ struct nsStyleDisplay;
class nsIPresShell;
class nsVoidArray;
class nsIFrameManager;
class nsFrameConstructorState;
class nsIDOMHTMLSelectElement;
class nsIXBLService;
class nsCSSFrameConstructor : public nsIStyleFrameConstruction {
public:
@ -524,15 +524,6 @@ protected:
nsIFrame* aNewFrame,
nsFrameItems& aChildItems);
nsresult CreateAnonymousTableCellFrames(nsIPresShell* aPresShell,
nsIPresContext* aPresContext,
nsIAtom* aTag,
nsFrameConstructorState& aState,
nsIContent* aParent,
nsIFrame* aNewCellBodyFrame,
nsIFrame* aNewCellFrame,
nsFrameItems& aChildItems);
//MathML Mod - RBS
#ifdef MOZ_MATHML
nsresult ConstructMathMLFrame(nsIPresShell* aPresShell,
@ -954,12 +945,12 @@ protected:
PRBool mGotGfxPrefs;
PRBool mHasGfxScrollbars;
nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
#ifdef NS_DEBUG
PRBool mVerifyFastFindFrame; // if true, run both the old and new find frame code
// to validate that both ways get the same answer
#endif
nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
};
#endif /* nsCSSFrameConstructor_h___ */

View File

@ -33,6 +33,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLInsertionPoint.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \

View File

@ -2,6 +2,7 @@ nsIBindingManager.h
nsIXBLBinding.h
nsIXBLBindingAttachedHandler.h
nsIXBLDocumentInfo.h
nsIXBLInsertionPoint.h
nsIXBLPrototypeBinding.h
nsIXBLPrototypeHandler.h
nsIXBLService.h

View File

@ -26,6 +26,7 @@ EXPORTS = \
nsIXBLBinding.h \
nsIXBLBindingAttachedHandler.h \
nsIXBLDocumentInfo.h \
nsIXBLInsertionPoint.h \
nsIXBLPrototypeBinding.h \
nsIXBLPrototypeHandler.h \
nsIXBLService.h \

View File

@ -55,6 +55,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult) = 0;
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding) = 0;
NS_IMETHOD GetInsertionParent(nsIContent* aContent, nsIContent** aResult)=0;
NS_IMETHOD SetInsertionParent(nsIContent* aContent, nsIContent* aResult)=0;
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult) = 0;
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult) = 0;
@ -79,8 +82,15 @@ public:
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult) = 0;
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult,
// For a given element with an insertion point child, returns a flat list of all the real children.
NS_IMETHOD GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 0;
NS_IMETHOD SetContentListFor(nsIContent* aContent, nsISupportsArray* aList)=0;
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 0;
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList) = 0;
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints) = 0;
NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsAReadableString& aURL) = 0;

View File

@ -85,8 +85,10 @@ public:
NS_IMETHOD GetDocURI(nsCString& aResult) = 0;
NS_IMETHOD GetID(nsCString& aResult) = 0;
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0;
NS_IMETHOD GetInsertionPointsFor(nsIContent* aParent, nsISupportsArray** aResult)=0;
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex) = 0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints) = 0;
NS_IMETHOD IsStyleBinding(PRBool* aResult) = 0;
NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) = 0;
@ -102,8 +104,7 @@ public:
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult)=0;
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult,
nsIContent** aParent, PRBool* aMultipleInsertionPoints)=0;
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult)=0;
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult)=0;
};

View File

@ -32,6 +32,7 @@ class nsIDocument;
class nsIDOMEventReceiver;
class nsIXBLDocumentInfo;
class nsIXBLPrototypeHandler;
class nsIXBLBinding;
// {34D700F5-C1A2-4408-A0B1-DD8F891DD1FE}
#define NS_IXBLPROTOTYPEBINDING_IID \
@ -76,11 +77,13 @@ public:
NS_IMETHOD HasInsertionPoints(PRBool* aResult)=0;
NS_IMETHOD InstantiateInsertionPoints(nsIXBLBinding* aBinding)=0;
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent* aChild, nsIContent** aResult)=0;
nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)=0;
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent** aResult, PRBool* aMultipleInsertionPoints)=0;
nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints)=0;
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag)=0;
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag)=0;

View File

@ -64,11 +64,6 @@ public:
// Indicates whether or not a binding is fully loaded.
NS_IMETHOD BindingReady(nsIContent* aBoundElement, const nsCString& aURLStr, PRBool* aIsReady) = 0;
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHOD GetContentList(nsIContent* aContent, nsIDOMNodeList** 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, PRInt32* aNameSpaceID, nsIAtom** aResult) = 0;

View File

@ -50,6 +50,7 @@ CPPSRCS = \
nsXBLScrollHandler.cpp \
nsXBLService.cpp \
nsBindingManager.cpp \
nsXBLInsertionPoint \
$(NULL)
include $(topsrcdir)/config/config.mk

View File

@ -46,6 +46,7 @@ CPPSRCS= \
nsXBLLoadHandler.cpp \
nsXBLPrototypeHandler.cpp \
nsBindingManager.cpp \
nsXBLInsertionPoint.cpp \
$(NULL)
CPP_OBJS= \
@ -68,6 +69,7 @@ CPP_OBJS= \
.\$(OBJDIR)\nsXBLPrototypeHandler.obj \
.\$(OBJDIR)\nsXBLService.obj \
.\$(OBJDIR)\nsBindingManager.obj \
.\$(OBJDIR)\nsXBLInsertionPoint.obj \
$(NULL)
EXPORTS = \

View File

@ -51,6 +51,7 @@
#include "nsIXBLBinding.h"
#include "nsIXBLDocumentInfo.h"
#include "nsIXBLBindingAttachedHandler.h"
#include "nsIXBLInsertionPoint.h"
#include "nsIStyleSheet.h"
#include "nsIHTMLStyleSheet.h"
@ -191,6 +192,89 @@ nsresult NS_NewXBLDocumentInfo(nsIDocument* aDocument, nsIXBLDocumentInfo** aRes
return NS_OK;
}
// ==================================================================
// = nsAnonymousContentList
// ==================================================================
class nsAnonymousContentList : public nsGenericDOMNodeList
{
public:
nsAnonymousContentList(nsISupportsArray* aElements);
virtual ~nsAnonymousContentList();
// nsIDOMNodeList interface
NS_DECL_IDOMNODELIST
private:
nsISupportsArray* mElements;
};
MOZ_DECL_CTOR_COUNTER(nsAnonymousContentList);
nsAnonymousContentList::nsAnonymousContentList(nsISupportsArray* aElements)
{
MOZ_COUNT_CTOR(nsAnonymousContentList);
// We don't reference count our Anonymous reference (to avoid circular
// references). We'll be told when the Anonymous goes away.
mElements = aElements;
NS_IF_ADDREF(mElements);
}
nsAnonymousContentList::~nsAnonymousContentList()
{
MOZ_COUNT_DTOR(nsAnonymousContentList);
NS_IF_RELEASE(mElements);
}
NS_IMETHODIMP
nsAnonymousContentList::GetLength(PRUint32* aLength)
{
NS_ASSERTION(aLength != nsnull, "null ptr");
if (! aLength)
return NS_ERROR_NULL_POINTER;
PRUint32 cnt;
mElements->Count(&cnt);
*aLength = 0;
nsCOMPtr<nsIXBLInsertionPoint> point;
PRUint32 l;
for (PRUint32 i = 0; i < cnt; i++) {
point = getter_AddRefs((nsIXBLInsertionPoint*)(mElements->ElementAt(i)));
point->ChildCount(&l);
*aLength += l;
}
return NS_OK;
}
NS_IMETHODIMP
nsAnonymousContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
{
PRUint32 cnt;
nsresult rv = mElements->Count(&cnt);
if (NS_FAILED(rv)) return rv;
PRUint32 pointCount = 0;
nsCOMPtr<nsIXBLInsertionPoint> point;
for (PRUint32 i = 0; i < cnt; i++) {
aIndex -= pointCount;
point = getter_AddRefs((nsIXBLInsertionPoint*)(mElements->ElementAt(i)));
point->ChildCount(&pointCount);
if (aIndex < pointCount) {
nsCOMPtr<nsIContent> result;
rv = point->ChildAt(aIndex, getter_AddRefs(result));
if (result && NS_SUCCEEDED(rv))
return result->QueryInterface(NS_GET_IID(nsIDOMNode), (void**)aReturn);
else return rv;
}
}
return NS_ERROR_FAILURE;
}
////////////////////////////////////////////////////////////////////////
@ -205,6 +289,9 @@ public:
NS_IMETHOD GetBinding(nsIContent* aContent, nsIXBLBinding** aResult);
NS_IMETHOD SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding);
NS_IMETHOD GetInsertionParent(nsIContent* aContent, nsIContent** aResult);
NS_IMETHOD SetInsertionParent(nsIContent* aContent, nsIContent* aResult);
NS_IMETHOD GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult);
NS_IMETHOD SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
@ -213,8 +300,14 @@ public:
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult,
NS_IMETHOD GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD SetContentListFor(nsIContent* aContent, nsISupportsArray* aList);
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList);
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints);
NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsAReadableString& aURL);
@ -258,11 +351,43 @@ protected:
// MEMBER VARIABLES
protected:
// A mapping from nsIContent* to the nsIXBLBinding* that is installed on that element.
nsSupportsHashtable* mBindingTable;
// A mapping from nsIContent* to an nsIDOMNodeList* (nsAnonymousContentList*).
// This list contains an accurate reflection of our *explicit* children (once intermingled with
// insertion points) in the altered DOM.
nsSupportsHashtable* mContentListTable;
// A mapping from nsIContent* to an nsIDOMNodeList* (nsAnonymousContentList*).
// This list contains an accurate reflection of our *anonymous* children (if and only if they are
// intermingled with insertion points) in the altered DOM. This table is not used
// if no insertion points were defined directly underneath a <content> tag in a
// binding. The NodeList from the <content> is used instead as a performance
// optimization.
nsSupportsHashtable* mAnonymousNodesTable;
// A mapping from nsIContent* to nsIContent*. The insertion parent is our one true
// parent in the transformed DOM. This gives us a more-or-less O(1) way of obtaining
// our transformed parent.
nsSupportsHashtable* mInsertionParentTable;
// A mapping from nsIContent* to nsIXPWrappedJS* (an XPConnect wrapper for JS objects).
// For XBL bindings that implement XPIDL interfaces, and that get referred to from C++,
// this table caches the XPConnect wrapper for the binding. By caching it, I control
// its lifetime, and I prevent a re-wrap of the same script object (in the case where
// multiple bindings in an XBL inheritance chain both implement an XPIDL interface).
nsSupportsHashtable* mWrapperTable;
// A mapping from nsIDocument* to nsIXBLDocumentInfo*. This table is the cache of
// all binding documents that have been loaded by a given bound document.
nsSupportsHashtable* mDocumentTable;
// The currently loading binding docs. If they're in this table, they have not yet
// finished loading.
nsSupportsHashtable* mLoadingDocTable;
// A queue of binding attached event handlers that are awaiting execution.
nsCOMPtr<nsISupportsArray> mAttachedQueue;
};
@ -279,6 +404,9 @@ nsBindingManager::nsBindingManager(void)
NS_INIT_REFCNT();
mBindingTable = nsnull;
mContentListTable = nsnull;
mAnonymousNodesTable = nsnull;
mInsertionParentTable = nsnull;
mWrapperTable = nsnull;
mDocumentTable = nsnull;
mLoadingDocTable = nsnull;
@ -289,6 +417,9 @@ nsBindingManager::nsBindingManager(void)
nsBindingManager::~nsBindingManager(void)
{
delete mBindingTable;
delete mContentListTable;
delete mAnonymousNodesTable;
delete mInsertionParentTable;
delete mWrapperTable;
delete mDocumentTable;
delete mLoadingDocTable;
@ -333,6 +464,36 @@ nsBindingManager::SetBinding(nsIContent* aContent, nsIXBLBinding* aBinding )
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetInsertionParent(nsIContent* aContent, nsIContent** aResult)
{
if (mInsertionParentTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIContent*, mInsertionParentTable->Get(&key));
}
else {
*aResult = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetInsertionParent(nsIContent* aContent, nsIContent* aParent)
{
if (!mInsertionParentTable)
mInsertionParentTable = new nsSupportsHashtable;
nsISupportsKey key(aContent);
if (aParent) {
mInsertionParentTable->Put(&key, aParent);
}
else
mInsertionParentTable->Remove(&key);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS** aResult)
{
@ -383,6 +544,11 @@ nsBindingManager::ChangeDocumentFor(nsIContent* aContent, nsIDocument* aOldDocum
}
}
// Clear out insertion parents and content lists.
SetInsertionParent(aContent, nsnull);
SetContentListFor(aContent, nsnull);
SetAnonymousNodesFor(aContent, nsnull);
for (PRInt32 i = aOldDocument->GetNumberOfShells() - 1; i >= 0; --i) {
nsCOMPtr<nsIPresShell> shell = dont_AddRef( aOldDocument->GetShellAt(i) );
NS_ASSERTION(shell != nsnull, "Zoiks! nsIPresShell::ShellAt() broke");
@ -434,26 +600,105 @@ nsBindingManager::ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAto
}
NS_IMETHODIMP
nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult)
nsBindingManager::GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
// Locate the primary binding and get its node list of anonymous children.
*aResult = nsnull;
if (mContentListTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIDOMNodeList*, mContentListTable->Get(&key));
}
if (!*aResult) {
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
return node->GetChildNodes(aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetContentListFor(nsIContent* aContent, nsISupportsArray* aList)
{
if (!mContentListTable) {
if (!aList)
return NS_OK;
mContentListTable = new nsSupportsHashtable;
}
nsISupportsKey key(aContent);
if (aList) {
nsAnonymousContentList* contentList = new nsAnonymousContentList(aList);
mContentListTable->Put(&key, (nsIDOMNodeList*)contentList);
}
else
mContentListTable->Remove(&key);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
// Locate the primary binding and get its node list of anonymous children.
*aResult = nsnull;
if (mAnonymousNodesTable) {
nsISupportsKey key(aContent);
*aResult = NS_STATIC_CAST(nsIDOMNodeList*, mAnonymousNodesTable->Get(&key));
}
if (!*aResult) {
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aContent, getter_AddRefs(binding));
if (binding)
return binding->GetAnonymousNodes(aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList)
{
if (!mAnonymousNodesTable) {
if (!aList)
return NS_OK;
mAnonymousNodesTable = new nsSupportsHashtable;
}
nsISupportsKey key(aContent);
if (aList) {
nsAnonymousContentList* contentList = new nsAnonymousContentList(aList);
mAnonymousNodesTable->Put(&key, (nsIDOMNodeList*)contentList);
}
else
mAnonymousNodesTable->Remove(&key);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aParent, getter_AddRefs(binding));
if (binding)
return binding->GetInsertionPoint(aChild, aResult);
return binding->GetInsertionPoint(aChild, aResult, aIndex);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult,
nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints)
{
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aParent, getter_AddRefs(binding));
if (binding)
return binding->GetSingleInsertionPoint( aResult, aMultipleInsertionPoints);
return binding->GetSingleInsertionPoint(aResult, aIndex, aMultipleInsertionPoints);
return NS_OK;
}

View File

@ -51,6 +51,7 @@
#include "nsJSUtils.h"
#include "nsIJSRuntimeService.h"
#include "nsXBLService.h"
#include "nsIXBLInsertionPoint.h"
// Event listeners
#include "nsIEventListenerManager.h"
@ -232,6 +233,7 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
// Constructors/Destructors
nsXBLBinding::nsXBLBinding(nsIXBLPrototypeBinding* aBinding)
: mFirstHandler(nsnull),
mInsertionPointTable(nsnull),
mIsStyleBinding(PR_TRUE),
mMarkedForDeath(PR_FALSE)
{
@ -277,6 +279,8 @@ nsXBLBinding::nsXBLBinding(nsIXBLPrototypeBinding* aBinding)
nsXBLBinding::~nsXBLBinding(void)
{
delete mInsertionPointTable;
gRefCnt--;
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
@ -437,6 +441,102 @@ nsXBLBinding::HasStyleSheets(PRBool* aResolveStyle)
return NS_OK;
}
struct ContentListData {
nsXBLBinding* mBinding;
nsIBindingManager* mBindingManager;
ContentListData(nsXBLBinding* aBinding, nsIBindingManager* aManager)
:mBinding(aBinding), mBindingManager(aManager)
{};
};
PRBool PR_CALLBACK BuildContentLists(nsHashKey* aKey, void* aData, void* aClosure)
{
ContentListData* data = (ContentListData*)aClosure;
nsIBindingManager* bm = data->mBindingManager;
nsXBLBinding* binding = data->mBinding;
nsCOMPtr<nsIContent> boundElement;
binding->GetBoundElement(getter_AddRefs(boundElement));
nsISupportsArray* arr = (nsISupportsArray*)aData;
PRUint32 count;
arr->Count(&count);
if (count == 0)
return NS_OK;
// XXX Could this array just be altered in place and passed directly to
// SetContentListFor? We'd save space if we could pull this off.
nsCOMPtr<nsISupportsArray> contentList;
NS_NewISupportsArray(getter_AddRefs(contentList));
// Figure out the relevant content node.
PRUint32 j = 0;
nsCOMPtr<nsIXBLInsertionPoint> currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
nsCOMPtr<nsIContent> parent;
PRUint32 currIndex;
currPoint->GetInsertionParent(getter_AddRefs(parent));
currPoint->GetInsertionIndex(&currIndex);
nsCOMPtr<nsIDOMNodeList> nodeList;
if (parent == boundElement) {
// We are altering anonymous nodes to accommodate insertion points.
binding->GetAnonymousNodes(getter_AddRefs(nodeList));
}
else {
// We are altering the explicit content list of a node to accommodate insertion points.
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(parent));
node->GetChildNodes(getter_AddRefs(nodeList));
}
nsCOMPtr<nsIXBLInsertionPoint> pseudoPoint;
PRUint32 childCount;
nodeList->GetLength(&childCount);
for (PRUint32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIDOMNode> node;
nodeList->Item(i, getter_AddRefs(node));
nsCOMPtr<nsIContent> child(do_QueryInterface(node));
if (i == currIndex) {
// Add the currPoint to the supports array.
contentList->AppendElement(currPoint);
// Get the next real insertion point and update our currIndex.
j++;
if (j < count) {
currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
currPoint->GetInsertionIndex(&currIndex);
}
// Null out our current pseudo-point.
pseudoPoint = nsnull;
}
if (!pseudoPoint) {
NS_NewXBLInsertionPoint(parent, 0, getter_AddRefs(pseudoPoint));
contentList->AppendElement(pseudoPoint);
}
pseudoPoint->AddChild(child);
}
// Add in all the remaining insertion points.
for ( ; j < count; j++) {
currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
contentList->AppendElement(currPoint);
}
// Now set the content list using the binding manager,
// If the bound element is the parent, then we alter the anonymous node list
// instead. This allows us to always maintain two distinct lists should
// insertion points be nested into an inner binding.
if (parent == boundElement)
bm->SetAnonymousNodesFor(parent, contentList);
else
bm->SetContentListFor(parent, contentList);
return PR_TRUE;
}
NS_IMETHODIMP
nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
{
@ -499,6 +599,103 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
clonedContent = do_QueryInterface(clonedNode);
SetAnonymousContent(clonedContent);
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
if (hasInsertionPoints) {
// Now check and see if we have a single insertion point
// or multiple insertion points.
nsCOMPtr<nsIDocument> doc;
mBoundElement->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIBindingManager> bindingManager;
doc->GetBindingManager(getter_AddRefs(bindingManager));
nsCOMPtr<nsIDOMNodeList> children;
bindingManager->GetContentListFor(mBoundElement, getter_AddRefs(children));
// Enumerate the prototype binding's insertion table to build
// our table of instantiated insertion points.
mPrototypeBinding->InstantiateInsertionPoints(this);
// We now have our insertion point table constructed. We
// enumerate this table. For each array of insertion points
// bundled under the same content node, we generate a content
// list. In the case of the bound element, we generate a new
// anonymous node list that will be used in place of the binding's
// cached anonymous node list.
ContentListData data(this, bindingManager);
mInsertionPointTable->Enumerate(BuildContentLists, &data);
// We need to place the children
// at their respective insertion points.
nsCOMPtr<nsIContent> singlePoint;
PRUint32 index = 0;
PRBool multiplePoints = PR_FALSE;
GetSingleInsertionPoint(getter_AddRefs(singlePoint), &index, &multiplePoints);
if (children) {
if (multiplePoints) {
// We must walk the entire content list in order to determine where
// each child belongs.
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
PRUint32 length;
children->GetLength(&length);
for (PRUint32 i = 0; i < length; i++) {
children->Item(i, getter_AddRefs(node));
content = do_QueryInterface(node);
// Now determine the insertion point in the prototype table.
nsCOMPtr<nsIContent> point;
PRUint32 index;
GetInsertionPoint(content, getter_AddRefs(point), &index);
bindingManager->SetInsertionParent(content, point);
// Find the correct nsIXBLInsertion point in our table.
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint;
nsCOMPtr<nsISupportsArray> arr;
GetInsertionPointsFor(point, getter_AddRefs(arr));
PRUint32 arrCount;
arr->Count(&arrCount);
for (PRUint32 j = 0; j < arrCount; j++) {
insertionPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
PRBool matches;
insertionPoint->Matches(point, index, &matches);
if (matches)
break;
insertionPoint = nsnull;
}
if (!insertionPoint) {
NS_ERROR("Filtered insertion point wasn't properly constructed.\n");
return NS_ERROR_FAILURE;
}
else
insertionPoint->AddChild(content);
}
}
else {
// All of our children are shunted to this single insertion point.
nsCOMPtr<nsISupportsArray> arr;
GetInsertionPointsFor(singlePoint, getter_AddRefs(arr));
PRUint32 arrCount;
arr->Count(&arrCount);
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(0));
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIContent> content;
PRUint32 length;
children->GetLength(&length);
for (PRUint32 i = 0; i < length; i++) {
children->Item(i, getter_AddRefs(node));
content = do_QueryInterface(node);
bindingManager->SetInsertionParent(content, singlePoint);
insertionPoint->AddChild(content);
}
}
}
}
}
// Always check the content element for potential attributes.
@ -529,9 +726,6 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement)
mContent->UnsetAttribute(namespaceID, name, PR_FALSE);
}
if (mContent)
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
return NS_OK;
}
@ -1407,25 +1601,42 @@ nsXBLBinding::AllowScripts()
}
NS_IMETHODIMP
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult)
nsXBLBinding::GetInsertionPointsFor(nsIContent* aParent, nsISupportsArray** aResult)
{
*aResult = nsnull;
if (mContent)
return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult);
else if (mNextBinding)
return mNextBinding->GetInsertionPoint(aChild, aResult);
if (!mInsertionPointTable)
mInsertionPointTable = new nsSupportsHashtable(4);
nsISupportsKey key(aParent);
*aResult = NS_STATIC_CAST(nsISupportsArray*, mInsertionPointTable->Get(&key));
if (!*aResult) {
NS_NewISupportsArray(aResult);
mInsertionPointTable->Put(&key, *aResult);
}
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints)
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{
*aResult = nsnull;
if (mContent)
return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult, aIndex);
else if (mNextBinding)
return mNextBinding->GetInsertionPoint(aChild, aResult, aIndex);
return NS_OK;
}
NS_IMETHODIMP
nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints)
{
*aResult = nsnull;
*aMultipleInsertionPoints = PR_FALSE;
if (mContent)
return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aMultipleInsertionPoints);
return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aIndex, aMultipleInsertionPoints);
else if (mNextBinding)
return mNextBinding->GetSingleInsertionPoint(aResult, aMultipleInsertionPoints);
return mNextBinding->GetSingleInsertionPoint(aResult, aIndex, aMultipleInsertionPoints);
return NS_OK;
}
@ -1480,16 +1691,15 @@ nsXBLBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
}
NS_IMETHODIMP
nsXBLBinding::GetAnonymousNodes(nsIDOMNodeList** aResult, nsIContent** aParent, PRBool* aMultipleInsertionPoints)
nsXBLBinding::GetAnonymousNodes(nsIDOMNodeList** aResult)
{
*aResult = nsnull;
if (mContent) {
GetSingleInsertionPoint(aParent, aMultipleInsertionPoints);
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
return elt->GetChildNodes(aResult);
}
else if (mNextBinding)
return mNextBinding->GetAnonymousNodes(aResult, aParent, aMultipleInsertionPoints);
return mNextBinding->GetAnonymousNodes(aResult);
return NS_OK;
}

View File

@ -79,8 +79,10 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD GetDocURI(nsCString& aResult);
NS_IMETHOD GetID(nsCString& aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult);
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints);
NS_IMETHOD GetInsertionPointsFor(nsIContent* aParent, nsISupportsArray** aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints);
NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; };
NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; };
@ -96,7 +98,7 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD ImplementsInterface(REFNSIID aIID, PRBool* aResult);
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult, nsIContent** aParent, PRBool* aMultipleInsertionPoints);
NS_IMETHOD GetAnonymousNodes(nsIDOMNodeList** aResult);
NS_IMETHOD ShouldBuildChildFrames(PRBool* aResult);
@ -172,6 +174,8 @@ protected:
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
nsSupportsHashtable* mInsertionPointTable; // A hash from nsIContent* -> (a sorted array of nsIXBLInsertionPoint*)
PRPackedBool mIsStyleBinding;
PRPackedBool mMarkedForDeath;
};

View File

@ -48,6 +48,7 @@
#include "nsINameSpace.h"
#include "nsXBLService.h"
#include "nsXBLBinding.h"
#include "nsIXBLInsertionPoint.h"
#include "nsXBLPrototypeBinding.h"
#include "nsFixedSizeAllocator.h"
#include "xptinfo.h"
@ -108,6 +109,59 @@ public:
NS_IMPL_ISUPPORTS1(nsXBLAttributeEntry, nsIXBLAttributeEntry)
// nsIXBLInsertionPointEntry and helpers. This class stores all the necessary
// info to figure out the position of an insertion point.
// {76F238AE-5ACB-49e6-B2DE-FD1940637753}
#define NS_IXBLINS_IID \
{ 0x76f238ae, 0x5acb, 0x49e6, { 0xb2, 0xde, 0xfd, 0x19, 0x40, 0x63, 0x77, 0x53 } }
class nsIXBLInsertionPointEntry : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IXBLINS_IID; return iid; }
NS_IMETHOD GetInsertionParent(nsIContent** aResult)=0;
NS_IMETHOD GetInsertionIndex(PRUint32* aResult)=0;
NS_IMETHOD SetInsertionIndex(PRUint32 aIndex)=0;
};
class nsXBLInsertionPointEntry : public nsIXBLInsertionPointEntry {
public:
NS_IMETHOD GetInsertionParent(nsIContent** aResult)
{
*aResult = mInsertionParent;
NS_IF_ADDREF(*aResult);
return NS_OK;
};
NS_IMETHOD GetInsertionIndex(PRUint32* aResult) { *aResult = mInsertionIndex; return NS_OK; };
NS_IMETHOD SetInsertionIndex(PRUint32 aIndex) { mInsertionIndex = aIndex; return NS_OK; };
nsCOMPtr<nsIContent> mInsertionParent;
PRUint32 mInsertionIndex;
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
return aAllocator.Alloc(aSize);
}
static void operator delete(void* aPtr, size_t aSize) {
nsFixedSizeAllocator::Free(aPtr, aSize);
}
nsXBLInsertionPointEntry(nsIContent* aParent) {
NS_INIT_REFCNT();
mInsertionIndex = 0;
mInsertionParent = aParent;
};
virtual ~nsXBLInsertionPointEntry() {};
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS1(nsXBLInsertionPointEntry, nsIXBLInsertionPointEntry)
// =============================================================================
// Static initialization
@ -123,15 +177,24 @@ nsIAtom* nsXBLPrototypeBinding::kValueAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kXBLTextAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementationAtom = nsnull;
nsIAtom* nsXBLPrototypeBinding::kImplementsAtom = nsnull;
nsFixedSizeAllocator nsXBLPrototypeBinding::kPool;
nsFixedSizeAllocator nsXBLPrototypeBinding::kAttrPool;
nsFixedSizeAllocator nsXBLPrototypeBinding::kInsPool;
static const size_t kBucketSizes[] = {
static const PRInt32 kNumElements = 128;
static const size_t kAttrBucketSizes[] = {
sizeof(nsXBLAttributeEntry)
};
static const PRInt32 kNumBuckets = sizeof(kBucketSizes)/sizeof(size_t);
static const PRInt32 kNumElements = 128;
static const PRInt32 kInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
static const PRInt32 kAttrNumBuckets = sizeof(kAttrBucketSizes)/sizeof(size_t);
static const PRInt32 kAttrInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLAttributeEntry))) * kNumElements;
static const size_t kInsBucketSizes[] = {
sizeof(nsXBLInsertionPointEntry)
};
static const PRInt32 kInsNumBuckets = sizeof(kInsBucketSizes)/sizeof(size_t);
static const PRInt32 kInsInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLInsertionPointEntry))) * kNumElements;
// Implementation /////////////////////////////////////////////////////////////////
@ -156,7 +219,8 @@ nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsAReadableCString& aID, nsIC
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 1) {
kPool.Init("XBL Attribute Entries", kBucketSizes, kNumBuckets, kInitialSize);
kAttrPool.Init("XBL Attribute Entries", kAttrBucketSizes, kAttrNumBuckets, kAttrInitialSize);
kInsPool.Init("XBL Insertion Point Entries", kInsBucketSizes, kInsNumBuckets, kInsInitialSize);
kInheritStyleAtom = NS_NewAtom("inheritstyle");
kHandlersAtom = NS_NewAtom("handlers");
@ -466,31 +530,107 @@ nsXBLPrototypeBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceI
return NS_OK;
}
struct InsertionData {
nsIXBLBinding* mBinding;
nsXBLPrototypeBinding* mPrototype;
InsertionData(nsIXBLBinding* aBinding,
nsXBLPrototypeBinding* aPrototype)
:mBinding(aBinding), mPrototype(aPrototype) {};
};
PRBool PR_CALLBACK InstantiateInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
{
nsIXBLInsertionPointEntry* entry = (nsIXBLInsertionPointEntry*)aData;
InsertionData* data = (InsertionData*)aClosure;
nsIXBLBinding* binding = data->mBinding;
nsXBLPrototypeBinding* proto = data->mPrototype;
// Get the insertion parent.
nsCOMPtr<nsIContent> content;
entry->GetInsertionParent(getter_AddRefs(content));
PRUint32 index;
entry->GetInsertionIndex(&index);
// Locate the real content.
nsCOMPtr<nsIContent> realContent;
nsCOMPtr<nsIContent> instanceRoot;
binding->GetAnonymousContent(getter_AddRefs(instanceRoot));
nsCOMPtr<nsIContent> templRoot;
proto->GetImmediateChild(nsXBLPrototypeBinding::kContentAtom, getter_AddRefs(templRoot));
proto->LocateInstance(templRoot, instanceRoot, content, getter_AddRefs(realContent));
if (!realContent)
binding->GetBoundElement(getter_AddRefs(realContent));
// Now that we have the real content, look it up in our table.
nsCOMPtr<nsISupportsArray> points;
binding->GetInsertionPointsFor(realContent, getter_AddRefs(points));
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint;
PRUint32 count;
points->Count(&count);
PRUint32 i = 0, currIndex = 0;
for ( ; i < count; i++) {
nsCOMPtr<nsIXBLInsertionPoint> currPoint = getter_AddRefs((nsIXBLInsertionPoint*)points->ElementAt(i));
currPoint->GetInsertionIndex(&currIndex);
if (currIndex == index) {
// This is a match. Break out of the loop and set our variable.
insertionPoint = currPoint;
break;
}
if (currIndex > index)
// There was no match. Break.
break;
}
if (!insertionPoint) {
// We need to make a new insertion point.
NS_NewXBLInsertionPoint(realContent, index, getter_AddRefs(insertionPoint));
points->InsertElementAt(insertionPoint, i);
}
return PR_TRUE;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::InstantiateInsertionPoints(nsIXBLBinding* aBinding)
{
InsertionData data(aBinding, this);
if (mInsertionPointTable)
mInsertionPointTable->Enumerate(InstantiateInsertionPoint, &data);
return NS_OK;
}
NS_IMETHODIMP
nsXBLPrototypeBinding::GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent* aChild, nsIContent** aResult)
nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{
if (mInsertionPointTable) {
nsCOMPtr<nsIAtom> tag;
aChild->GetTag(*getter_AddRefs(tag));
nsISupportsKey key(tag);
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
mInsertionPointTable->Get(&key)));
if (!content) {
nsCOMPtr<nsIXBLInsertionPointEntry> entry = getter_AddRefs(NS_STATIC_CAST(nsIXBLInsertionPointEntry*,
mInsertionPointTable->Get(&key)));
if (!entry) {
nsISupportsKey key2(kChildrenAtom);
content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mInsertionPointTable->Get(&key2)));
entry = getter_AddRefs(NS_STATIC_CAST(nsIXBLInsertionPointEntry*, mInsertionPointTable->Get(&key2)));
}
nsCOMPtr<nsIContent> realContent;
if (content) {
if (entry) {
nsCOMPtr<nsIContent> content;
entry->GetInsertionParent(getter_AddRefs(content));
entry->GetInsertionIndex(aIndex);
nsCOMPtr<nsIContent> templContent;
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
}
if (realContent)
*aResult = realContent;
else
*aResult = aBoundElement;
NS_IF_ADDREF(*aResult);
}
return NS_OK;
@ -499,15 +639,19 @@ nsXBLPrototypeBinding::GetInsertionPoint(nsIContent* aBoundElement, nsIContent*
NS_IMETHODIMP
nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
nsIContent* aCopyRoot,
nsIContent** aResult, PRBool* aMultipleInsertionPoints)
nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints)
{
if (mInsertionPointTable) {
if(mInsertionPointTable->Count() == 1) {
nsISupportsKey key(kChildrenAtom);
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*,
mInsertionPointTable->Get(&key)));
nsCOMPtr<nsIXBLInsertionPointEntry> entry = getter_AddRefs(NS_STATIC_CAST(nsIXBLInsertionPointEntry*,
mInsertionPointTable->Get(&key)));
nsCOMPtr<nsIContent> realContent;
if (content) {
if (entry) {
nsCOMPtr<nsIContent> content;
entry->GetInsertionParent(getter_AddRefs(content));
entry->GetInsertionIndex(aIndex);
nsCOMPtr<nsIContent> templContent;
GetImmediateChild(kContentAtom, getter_AddRefs(templContent));
LocateInstance(templContent, aCopyRoot, content, getter_AddRefs(realContent));
@ -519,6 +663,7 @@ nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
// match the filter will just go right underneath the bound element).
*aMultipleInsertionPoints = PR_TRUE;
*aResult = nsnull;
*aIndex = 0;
return NS_OK;
}
@ -527,6 +672,7 @@ nsXBLPrototypeBinding::GetSingleInsertionPoint(nsIContent* aBoundElement,
*aResult = realContent;
else
*aResult = aBoundElement;
NS_IF_ADDREF(*aResult);
}
else
@ -774,7 +920,7 @@ nsXBLPrototypeBinding::ConstructAttributeTable(nsIContent* aElement)
}
// Create an XBL attribute entry.
nsXBLAttributeEntry* xblAttr = new (kPool) nsXBLAttributeEntry(atom, attribute, aElement);
nsXBLAttributeEntry* xblAttr = new (kAttrPool) nsXBLAttributeEntry(atom, attribute, aElement);
// Now we should see if some element within our anonymous
// content is already observing this attribute.
@ -826,7 +972,7 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
if (!childrenElements)
return;
mInsertionPointTable = new nsSupportsHashtable;
mInsertionPointTable = new nsSupportsHashtable(4);
PRUint32 count;
childrenElements->Count(&count);
@ -838,11 +984,15 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
if (child) {
nsCOMPtr<nsIContent> parent;
child->GetParent(*getter_AddRefs(parent));
// Create an XBL insertion point entry.
nsXBLInsertionPointEntry* xblIns = new (kInsPool) nsXBLInsertionPointEntry(parent);
nsAutoString includes;
child->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
if (includes.IsEmpty()) {
nsISupportsKey key(kChildrenAtom);
mInsertionPointTable->Put(&key, parent);
mInsertionPointTable->Put(&key, xblIns);
}
else {
// The user specified at least one attribute.
@ -860,26 +1010,28 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
atom = getter_AddRefs(NS_NewAtom(tok.GetUnicode()));
nsISupportsKey key(atom);
mInsertionPointTable->Put(&key, parent);
mInsertionPointTable->Put(&key, xblIns);
token = nsCRT::strtok( newStr, ", ", &newStr );
}
nsMemory::Free(str);
}
}
}
// Now remove the <children> elements.
for (i = 0; i < count; i++) {
nsCOMPtr<nsISupports> supp;
childrenElements->GetElementAt(i, getter_AddRefs(supp));
nsCOMPtr<nsIContent> child(do_QueryInterface(supp));
if (child) {
nsCOMPtr<nsIContent> parent;
child->GetParent(*getter_AddRefs(parent));
// Compute the index of the <children> element. This index is
// equal to the index of the <children> in the template minus the #
// of previous insertion point siblings removed. Because our childrenElements
// array was built in a DFS that went from left-to-right through siblings,
// if we dynamically obtain our index each time, then the removals of previous
// siblings will cause the index to adjust (and we won't have to take that into
// account explicitly).
PRInt32 index;
parent->IndexOf(child, index);
xblIns->SetInsertionIndex((PRUint32)index);
// Now remove the <children> element from the template. This ensures that the
// binding instantiation will not contain a clone of the <children> element when
// it clones the binding template.
parent->RemoveChildAt(index, PR_FALSE);
}
}

View File

@ -75,11 +75,13 @@ class nsXBLPrototypeBinding: public nsIXBLPrototypeBinding
NS_IMETHOD HasInsertionPoints(PRBool* aResult) { *aResult = (mInsertionPointTable != nsnull); return NS_OK; };
NS_IMETHOD InstantiateInsertionPoints(nsIXBLBinding* aBinding);
NS_IMETHOD GetInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent* aChild, nsIContent** aResult);
nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aBoundElement, nsIContent* aCopyRoot,
nsIContent** aResult, PRBool* aMultiple);
nsIContent** aResult, PRUint32* aIndex, PRBool* aMultiple);
NS_IMETHOD GetBaseTag(PRInt32* aNamespaceID, nsIAtom** aTag);
NS_IMETHOD SetBaseTag(PRInt32 aNamespaceID, nsIAtom* aTag);
@ -107,7 +109,8 @@ public:
static nsIAtom* kImplementationAtom;
static nsIAtom* kImplementsAtom;
static nsFixedSizeAllocator kPool;
static nsFixedSizeAllocator kAttrPool;
static nsFixedSizeAllocator kInsPool;
// Internal member functions
public:

View File

@ -710,31 +710,6 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsAReadableString& aURL,
return NS_OK;
}
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHODIMP
nsXBLService::GetContentList(nsIContent* aContent, nsIDOMNodeList** aResult, nsIContent** aParent,
PRBool* aMultipleInsertionPoints)
{
// Locate the primary binding and get the node list from its mContent parent.
*aResult = nsnull;
*aParent = nsnull;
*aMultipleInsertionPoints = PR_FALSE;
nsCOMPtr<nsIDocument> document;
aContent->GetDocument(*getter_AddRefs(document));
nsCOMPtr<nsIBindingManager> bindingManager;
NS_ASSERTION(document, "no document");
if (!document) return NS_ERROR_FAILURE;
document->GetBindingManager(getter_AddRefs(bindingManager));
nsCOMPtr<nsIXBLBinding> binding;
bindingManager->GetBinding(aContent, getter_AddRefs(binding));
binding->GetAnonymousNodes(getter_AddRefs(aResult), aParent, aMultipleInsertionPoints);
return NS_OK;
}
NS_IMETHODIMP
nsXBLService::FlushStyleBindings(nsIContent* aContent)
{

View File

@ -65,11 +65,6 @@ class nsXBLService : public nsIXBLService, public nsIObserver, public nsSupports
// This function clears out the bindings on a given content node.
NS_IMETHOD FlushStyleBindings(nsIContent* aContent);
// For a given element, returns a flat list of all the anonymous children that need
// frames built.
NS_IMETHOD GetContentList(nsIContent* aContent, nsIDOMNodeList** aResult, nsIContent** aChildElement,
PRBool* aMultipleInsertionPoints);
// Gets the object's base class type.
NS_IMETHOD ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID, nsIAtom** aResult);

View File

@ -2899,17 +2899,12 @@ NS_IMETHODIMP
nsXULDocument::GetAnonymousNodes(nsIDOMElement* aElement,
nsIDOMNodeList** aResult)
{
nsresult rv;
// Use the XBL service to get the anonymous node list.
NS_WITH_SERVICE(nsIXBLService, xblService, "@mozilla.org/xbl;1", &rv);
if (!xblService)
return rv;
PRBool dummy;
nsCOMPtr<nsIContent> dummyElt;
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return xblService->GetContentList(content, aResult, getter_AddRefs(dummyElt), &dummy);
*aResult = nsnull;
if (mBindingManager) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
return mBindingManager->GetAnonymousNodesFor(content, aResult);
}
return NS_OK;
}
NS_IMETHODIMP