Bug 307394 part 1. Create a non-COM way to get at XBL child nodes, and put an IndexOf() method on nsINodeList. r+sr=peterv

This commit is contained in:
Boris Zbarsky 2009-01-29 14:46:18 -05:00
parent ff8ff59c94
commit f79bc67cfb
11 changed files with 138 additions and 87 deletions

View File

@ -51,6 +51,7 @@ class nsIDocument;
class nsIDOMEvent;
class nsIDOMNode;
class nsIDOMNodeList;
class nsINodeList;
class nsIPresShell;
class nsPresContext;
class nsEventChainVisitor;
@ -153,8 +154,8 @@ inline nsINode* NODE_FROM(C& aContent, D& aDocument)
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0x0dc8fad3, 0xcb3f, 0x4f14, \
{ 0x8e, 0x7e, 0x4f, 0x62, 0xab, 0x74, 0xb8, 0x1e } }
{ 0x355cc896, 0x2ed0, 0x4237, \
{ 0x85, 0xf7, 0x4d, 0xb0, 0xcf, 0x4d, 0xc4, 0x90 } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -690,7 +691,7 @@ public:
*/
nsIContent* GetSelectionRootContent(nsIPresShell* aPresShell);
virtual nsIDOMNodeList* GetChildNodesList();
virtual nsINodeList* GetChildNodesList();
nsIContent* GetSibling(PRInt32 aOffset)
{
nsINode *parent = GetNodeParent();

View File

@ -40,15 +40,16 @@
#include "nsIDOMNodeList.h"
class nsINode;
class nsIContent;
// IID for the nsINodeList interface
#define NS_INODELIST_IID \
{ 0x943420c4, 0x8774, 0x43ea, \
{ 0xb3, 0x53, 0x62, 0xa1, 0x26, 0x1c, 0x9b, 0x55 } }
{ 0x57ac9ea2, 0xe95f, 0x4856, \
{ 0xbb, 0xac, 0x82, 0x2d, 0x65, 0xb1, 0x92, 0x57 } }
/**
* An internal interface that allows QI-less getting of nodes from node lists
* An internal interface that allows QI-less getting of nodes from
* node lists and reasonably fast indexOf.
*/
class nsINodeList : public nsIDOMNodeList
{
@ -58,7 +59,13 @@ public:
/**
* Get the node at the index. Returns null if the index is out of bounds
*/
virtual nsINode* GetNodeAt(PRUint32 aIndex) = 0;
virtual nsIContent* GetNodeAt(PRUint32 aIndex) = 0;
/**
* Get the index of the given node in the list. Will return -1 if the node
* is not in the list.
*/
virtual PRInt32 IndexOf(nsIContent* aContent) = 0;
};
#define NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \

View File

@ -124,7 +124,7 @@ nsBaseContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
return CallQueryInterface(tmp, aReturn);
}
nsINode*
nsIContent*
nsBaseContentList::GetNodeAt(PRUint32 aIndex)
{
return mElements.SafeObjectAt(aIndex);
@ -148,6 +148,12 @@ nsBaseContentList::IndexOf(nsIContent *aContent, PRBool aDoFlush)
return mElements.IndexOf(aContent);
}
PRInt32
nsBaseContentList::IndexOf(nsIContent* aContent)
{
return IndexOf(aContent, PR_TRUE);
}
void
nsBaseContentList::Reset()
{
@ -444,6 +450,12 @@ nsContentList::IndexOf(nsIContent *aContent, PRBool aDoFlush)
return mElements.IndexOf(aContent);
}
PRInt32
nsContentList::IndexOf(nsIContent* aContent)
{
return IndexOf(aContent, PR_TRUE);
}
void
nsContentList::NodeWillBeDestroyed(const nsINode* aNode)
{
@ -508,7 +520,7 @@ nsContentList::NamedItem(const nsAString& aName, nsIDOMNode** aReturn)
return NS_OK;
}
nsINode*
nsIContent*
nsContentList::GetNodeAt(PRUint32 aIndex)
{
return Item(aIndex, PR_TRUE);

View File

@ -86,7 +86,8 @@ public:
NS_DECL_NSIDOMNODELIST
// nsINodeList
virtual nsINode* GetNodeAt(PRUint32 aIndex);
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
virtual PRInt32 IndexOf(nsIContent* aContent);
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsBaseContentList, nsINodeList)
@ -242,7 +243,8 @@ public:
// nsBaseContentList overrides
virtual PRInt32 IndexOf(nsIContent *aContent, PRBool aDoFlush);
virtual nsINode* GetNodeAt(PRUint32 aIndex);
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
virtual PRInt32 IndexOf(nsIContent* aContent);
// nsIHTMLCollection
virtual nsISupports* GetNodeAt(PRUint32 aIndex, nsresult* aResult);

View File

@ -424,7 +424,7 @@ nsINode::GetSelectionRootContent(nsIPresShell* aPresShell)
return doc->GetRootContent();
}
nsIDOMNodeList*
nsINodeList*
nsINode::GetChildNodesList()
{
nsSlots *slots = GetSlots();
@ -589,7 +589,7 @@ nsChildContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
return CallQueryInterface(node, aReturn);
}
nsINode*
nsIContent*
nsChildContentList::GetNodeAt(PRUint32 aIndex)
{
if (mNode) {
@ -599,6 +599,16 @@ nsChildContentList::GetNodeAt(PRUint32 aIndex)
return nsnull;
}
PRInt32
nsChildContentList::IndexOf(nsIContent* aContent)
{
if (mNode) {
return mNode->IndexOf(aContent);
}
return -1;
}
//----------------------------------------------------------------------
NS_IMPL_CYCLE_COLLECTION_1(nsNode3Tearoff, mContent)

View File

@ -108,7 +108,8 @@ public:
NS_DECL_NSIDOMNODELIST
// nsINodeList interface
virtual nsINode* GetNodeAt(PRUint32 aIndex);
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
virtual PRInt32 IndexOf(nsIContent* aContent);
void DropReference()
{

View File

@ -103,7 +103,8 @@ public:
NS_DECL_NSIDOMNODELIST
// nsINodeList interface
virtual nsINode* GetNodeAt(PRUint32 aIndex);
virtual nsIContent* GetNodeAt(PRUint32 aIndex);
virtual PRInt32 IndexOf(nsIContent* aContent);
PRInt32 GetInsertionPointCount() { return mElements->Length(); }
@ -185,7 +186,7 @@ nsAnonymousContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
return CallQueryInterface(item, aReturn);
}
nsINode*
nsIContent*
nsAnonymousContentList::GetNodeAt(PRUint32 aIndex)
{
PRInt32 cnt = mElements->Length();
@ -205,6 +206,27 @@ nsAnonymousContentList::GetNodeAt(PRUint32 aIndex)
return nsnull;
}
PRInt32
nsAnonymousContentList::IndexOf(nsIContent* aContent)
{
PRInt32 cnt = mElements->Length();
PRInt32 lengthSoFar = 0;
for (PRInt32 i = 0; i < cnt; ++i) {
nsXBLInsertionPoint* point =
static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i));
PRInt32 idx = point->IndexOf(aContent);
if (idx != -1) {
return idx + lengthSoFar;
}
lengthSoFar += point->ChildCount();
}
// Didn't find it anywhere
return -1;
}
//
// Generic pldhash table stuff for mapping one nsISupports to another
//
@ -663,11 +685,10 @@ nsBindingManager::ResolveTag(nsIContent* aContent, PRInt32* aNameSpaceID)
nsresult
nsBindingManager::GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
// Locate the primary binding and get its node list of anonymous children.
*aResult = nsnull;
if (mContentListTable.ops) {
*aResult = static_cast<nsIDOMNodeList*>
*aResult = static_cast<nsAnonymousContentList*>
(LookupObject(mContentListTable, aContent));
NS_IF_ADDREF(*aResult);
}
@ -688,7 +709,7 @@ nsBindingManager::SetContentListFor(nsIContent* aContent,
return NS_OK;
}
nsIDOMNodeList* contentList = nsnull;
nsAnonymousContentList* contentList = nsnull;
if (aList) {
contentList = new nsAnonymousContentList(aList);
if (!contentList) {
@ -706,30 +727,26 @@ nsBindingManager::HasContentListFor(nsIContent* aContent)
return mContentListTable.ops && LookupObject(mContentListTable, aContent);
}
nsresult
nsINodeList*
nsBindingManager::GetAnonymousNodesInternal(nsIContent* aContent,
nsIDOMNodeList** aResult,
PRBool* aIsAnonymousContentList)
{
// Locate the primary binding and get its node list of anonymous children.
*aResult = nsnull;
nsINodeList* result = nsnull;
if (mAnonymousNodesTable.ops) {
*aResult = static_cast<nsIDOMNodeList*>
(LookupObject(mAnonymousNodesTable, aContent));
NS_IF_ADDREF(*aResult);
result = static_cast<nsAnonymousContentList*>
(LookupObject(mAnonymousNodesTable, aContent));
}
if (!*aResult) {
if (!result) {
*aIsAnonymousContentList = PR_FALSE;
nsXBLBinding *binding = GetBinding(aContent);
if (binding) {
*aResult = binding->GetAnonymousNodes().get();
return NS_OK;
result = binding->GetAnonymousNodes();
}
} else
*aIsAnonymousContentList = PR_TRUE;
return NS_OK;
return result;
}
nsresult
@ -737,7 +754,8 @@ nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent,
nsIDOMNodeList** aResult)
{
PRBool dummy;
return GetAnonymousNodesInternal(aContent, aResult, &dummy);
NS_IF_ADDREF(*aResult = GetAnonymousNodesInternal(aContent, &dummy));
return NS_OK;
}
nsresult
@ -748,7 +766,7 @@ nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent,
return NS_OK;
}
nsIDOMNodeList* contentList = nsnull;
nsAnonymousContentList* contentList = nsnull;
if (aList) {
contentList = new nsAnonymousContentList(aList);
if (!contentList) {
@ -760,19 +778,15 @@ nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent,
return SetOrRemoveObject(mAnonymousNodesTable, aContent, contentList);
}
nsresult
nsINodeList*
nsBindingManager::GetXBLChildNodesInternal(nsIContent* aContent,
nsIDOMNodeList** aResult,
PRBool* aIsAnonymousContentList)
{
*aResult = nsnull;
PRUint32 length;
// Retrieve the anonymous content that we should build.
nsCOMPtr<nsIDOMNodeList> result;
GetAnonymousNodesInternal(aContent, getter_AddRefs(result),
aIsAnonymousContentList);
nsINodeList* result = GetAnonymousNodesInternal(aContent,
aIsAnonymousContentList);
if (result) {
result->GetLength(&length);
if (length == 0)
@ -784,22 +798,27 @@ nsBindingManager::GetXBLChildNodesInternal(nsIContent* aContent,
// insertion points.
if (!result) {
if (mContentListTable.ops) {
result = static_cast<nsIDOMNodeList*>
result = static_cast<nsAnonymousContentList*>
(LookupObject(mContentListTable, aContent));
*aIsAnonymousContentList = PR_TRUE;
}
}
result.swap(*aResult);
return NS_OK;
return result;
}
nsresult
nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
NS_IF_ADDREF(*aResult = GetXBLChildNodesFor(aContent));
return NS_OK;
}
nsINodeList*
nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent)
{
PRBool dummy;
return GetXBLChildNodesInternal(aContent, aResult, &dummy);
return GetXBLChildNodesInternal(aContent, &dummy);
}
nsIContent*
@ -1426,10 +1445,9 @@ nsBindingManager::ContentAppended(nsIDocument* aDocument,
}
}
else if (ins) {
nsCOMPtr<nsIDOMNodeList> nodeList;
PRBool isAnonymousContentList;
GetXBLChildNodesInternal(ins, getter_AddRefs(nodeList),
&isAnonymousContentList);
nsCOMPtr<nsIDOMNodeList> nodeList =
GetXBLChildNodesInternal(ins, &isAnonymousContentList);
if (nodeList && isAnonymousContentList) {
// Find the one non-pseudo-insertion point and just add ourselves.
@ -1503,10 +1521,9 @@ nsBindingManager::ContentRemoved(nsIDocument* aDocument,
nsCOMPtr<nsIContent> point = GetNestedInsertionPoint(aContainer, aChild);
if (point) {
nsCOMPtr<nsIDOMNodeList> nodeList;
PRBool isAnonymousContentList;
GetXBLChildNodesInternal(point, getter_AddRefs(nodeList),
&isAnonymousContentList);
nsCOMPtr<nsIDOMNodeList> nodeList =
GetXBLChildNodesInternal(point, &isAnonymousContentList);
if (nodeList && isAnonymousContentList) {
// Find a non-pseudo-insertion point and remove ourselves.
@ -1524,9 +1541,8 @@ nsBindingManager::ContentRemoved(nsIDocument* aDocument,
// aChild from the pseudo insertion point it's in.
if (mContentListTable.ops) {
nsAnonymousContentList* insertionPointList =
static_cast<nsAnonymousContentList*>(
static_cast<nsIDOMNodeList*>(LookupObject(mContentListTable,
aContainer)));
static_cast<nsAnonymousContentList*>(LookupObject(mContentListTable,
aContainer));
if (insertionPointList) {
RemoveChildFromInsertionPoint(insertionPointList, aChild, PR_TRUE);
}
@ -1622,10 +1638,9 @@ nsBindingManager::HandleChildInsertion(nsIContent* aContainer,
nsIContent* ins = GetNestedInsertionPoint(aContainer, aChild);
if (ins) {
nsCOMPtr<nsIDOMNodeList> nodeList;
PRBool isAnonymousContentList;
GetXBLChildNodesInternal(ins, getter_AddRefs(nodeList),
&isAnonymousContentList);
nsCOMPtr<nsIDOMNodeList> nodeList =
GetXBLChildNodesInternal(ins, &isAnonymousContentList);
if (nodeList && isAnonymousContentList) {
// Find a non-pseudo-insertion point and just jam ourselves in. This is

View File

@ -122,7 +122,10 @@ public:
PRBool HasContentListFor(nsIContent* aContent);
/**
* For a given element, retrieve the anonymous child content.
* Return the nodelist of "anonymous" kids for this node. This might
* actually include some of the nodes actual DOM kids, if there are
* <children> tags directly as kids of <content>. This will only end up
* returning a non-null list for nodes which have a binding attached.
*/
nsresult GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
@ -141,6 +144,11 @@ public:
*/
nsresult GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
/**
* Non-COMy version of GetXBLChildNodesFor
*/
nsINodeList* GetXBLChildNodesFor(nsIContent* aContent);
/**
* Given a parent element and a child content, determine where the
* child content should be inserted in the parent element's
@ -212,12 +220,10 @@ protected:
nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent);
nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
nsresult GetXBLChildNodesInternal(nsIContent* aContent,
nsIDOMNodeList** aResult,
PRBool* aIsAnonymousContentList);
nsresult GetAnonymousNodesInternal(nsIContent* aContent,
nsIDOMNodeList** aResult,
PRBool* aIsAnonymousContentList);
nsINodeList* GetXBLChildNodesInternal(nsIContent* aContent,
PRBool* aIsAnonymousContentList);
nsINodeList* GetAnonymousNodesInternal(nsIContent* aContent,
PRBool* aIsAnonymousContentList);
nsIContent* GetNestedInsertionPoint(nsIContent* aParent, nsIContent* aChild);
nsIContent* GetNestedSingleInsertionPoint(nsIContent* aParent,
@ -244,24 +250,22 @@ protected:
// installed on that element.
nsRefPtrHashtable<nsISupportsHashKey,nsXBLBinding> 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. There is an entry for a
// content node in this table only if that content node has some
// <children> kids.
// A mapping from nsIContent* to an nsAnonymousContentList*. This
// list contains an accurate reflection of our *explicit* children
// (once intermingled with insertion points) in the altered DOM.
// There is an entry for a content node in this table only if that
// content node has some <children> kids.
PLDHashTable 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. There
// is an entry for a content node in this table only if that content
// node has a binding with a <content> attached and this <content>
// contains <children> elements directly.
// A mapping from nsIContent* to an 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. There is an entry for a content node in this table
// only if that content node has a binding with a <content> attached
// and this <content> contains <children> elements directly.
PLDHashTable mAnonymousNodesTable;
// A mapping from nsIContent* to nsIContent*. The insertion parent

View File

@ -1570,14 +1570,11 @@ nsXBLBinding::ImplementsInterface(REFNSIID aIID) const
(mNextBinding && mNextBinding->ImplementsInterface(aIID));
}
already_AddRefed<nsIDOMNodeList>
nsINodeList*
nsXBLBinding::GetAnonymousNodes()
{
if (mContent) {
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
nsIDOMNodeList *nodeList = nsnull;
elt->GetChildNodes(&nodeList);
return nodeList;
return mContent->GetChildNodesList();
}
if (mNextBinding)

View File

@ -41,7 +41,7 @@
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIDOMNodeList.h"
#include "nsINodeList.h"
#include "nsIStyleRuleProcessor.h"
#include "nsClassHashtable.h"
#include "nsTArray.h"
@ -156,7 +156,7 @@ public:
void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
already_AddRefed<nsIDOMNodeList> GetAnonymousNodes();
nsINodeList* GetAnonymousNodes();
static nsresult DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
const nsAFlatCString& aClassName,

View File

@ -81,6 +81,8 @@ public:
nsIContent* ChildAt(PRUint32 aIndex);
PRInt32 IndexOf(nsIContent* aContent) { return mElements.IndexOf(aContent); }
PRBool Matches(nsIContent* aContent, PRUint32 aIndex);
// Unbind all the default content in this insertion point. Used