Backing out changes for 39054, which caused several template regressions.

This commit is contained in:
waterson%netscape.com 2001-02-13 19:22:56 +00:00
Родитель b1a810b0aa
Коммит 5cc33330bf
18 изменённых файлов: 570 добавлений и 588 удалений

Просмотреть файл

@ -89,9 +89,6 @@ public:
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 0;
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList) = 0;
// Encapsulates logic for handling both of above
NS_IMETHOD GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 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;

Просмотреть файл

@ -348,8 +348,6 @@ public:
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList);
NS_IMETHOD GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints);
@ -782,28 +780,6 @@ nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* a
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
PRUint32 length;
// Retrieve the anonymous content that we should build.
GetAnonymousNodesFor(aContent, aResult);
if (*aResult) {
(*aResult)->GetLength(&length);
if (length == 0)
*aResult = 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 (! *aResult)
GetContentListFor(aContent, aResult);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{

Просмотреть файл

@ -41,7 +41,6 @@
#include "nsIDocument.h"
#include "nsIXMLContent.h"
#include "nsIXULContent.h"
#include "nsIXULDocument.h"
#include "nsIXMLContentSink.h"
#include "nsLayoutCID.h"
#include "nsXMLDocument.h"
@ -362,9 +361,7 @@ nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
mBoundElement->GetDocument(*getter_AddRefs(doc));
mContent->SetDocument(doc, PR_TRUE, AllowScripts());
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(doc));
// (2) The children's parent back pointer should not be to this synthetic root
// but should instead point to the bound element.
PRInt32 childCount;
@ -374,12 +371,6 @@ nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
mContent->ChildAt(i, *getter_AddRefs(child));
child->SetParent(mBoundElement);
child->SetBindingParent(mBoundElement);
// To make XUL templates work (and other goodies that happen when
// an element is added to a XUL document), we need to notify the
// XUL document using its special API.
if (xuldoc)
xuldoc->AddSubtreeToDocument(child);
}
return NS_OK;
@ -1298,25 +1289,9 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
nsCOMPtr<nsIContent> anonymous;
GetAnonymousContent(getter_AddRefs(anonymous));
if (anonymous) {
// To make XUL templates work (and other XUL-specific stuff),
// we'll need to notify it using its add & remove APIs. Grab the
// interface now...
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(aOldDocument));
if (mIsStyleBinding) {
if (mIsStyleBinding)
anonymous->SetDocument(nsnull, PR_TRUE, PR_TRUE); // Kill it.
if (xuldoc)
xuldoc->RemoveSubtreeFromDocument(anonymous);
}
else {
anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around.
if (xuldoc)
xuldoc->RemoveSubtreeFromDocument(anonymous);
xuldoc = do_QueryInterface(aNewDocument);
if (xuldoc)
xuldoc->AddSubtreeToDocument(anonymous);
}
else anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around.
}
}

Просмотреть файл

@ -126,16 +126,6 @@ public:
* Load inline and attribute style sheets
*/
NS_IMETHOD PrepareStyleSheets(nsIURI* aURI) = 0;
/**
* Notify the XUL document that a subtree has been added
*/
NS_IMETHOD AddSubtreeToDocument(nsIContent* aElement) = 0;
/**
* Notify the XUL document that a subtree has been removed
*/
NS_IMETHOD RemoveSubtreeFromDocument(nsIContent* aElement) = 0;
};
// factory functions

Просмотреть файл

@ -228,6 +228,8 @@ protected:
nsresult GetTopNode(nsXULPrototypeNode** aNode);
nsresult GetTopChildren(nsVoidArray** aChildren);
PRBool IsInsideXULTemplate();
};
friend class ContextStack;
@ -328,6 +330,31 @@ XULContentSinkImpl::ContextStack::GetTopChildren(nsVoidArray** aChildren)
}
PRBool
XULContentSinkImpl::ContextStack::IsInsideXULTemplate()
{
if (mDepth) {
Entry* entry = mTop;
while (entry) {
nsXULPrototypeNode* node = entry->mNode;
if (node->mType == nsXULPrototypeNode::eType_Element) {
nsXULPrototypeElement* element =
NS_REINTERPRET_CAST(nsXULPrototypeElement*, node);
if (element->mNodeInfo->Equals(kTemplateAtom,
kNameSpaceID_XUL)) {
return PR_TRUE;
}
}
entry = entry->mNext;
}
}
return PR_FALSE;
}
//----------------------------------------------------------------------
@ -1197,16 +1224,50 @@ XULContentSinkImpl::AddAttributes(const nsIParserNode& aNode, nsXULPrototypeElem
nsresult rv;
PRInt32 count = aNode.GetAttributeCount();
PRBool generateIDAttr = PR_FALSE;
if (mContextStack.IsInsideXULTemplate()) {
// Check for an 'id' attribute. If we're inside a XUL
// template, then _everything_ needs to have an ID for the
// 'template' attribute hookup.
generateIDAttr = PR_TRUE;
for (PRInt32 i = 0; i < count; i++) {
if (aNode.GetKeyAt(i).Equals(NS_LITERAL_STRING("id"))) {
generateIDAttr = PR_FALSE;
break;
}
}
}
// Create storage for the attributes
PRInt32 numattrs = count;
if (generateIDAttr)
++numattrs;
nsXULPrototypeAttribute* attrs = nsnull;
if (count > 0) {
attrs = new nsXULPrototypeAttribute[count];
if (numattrs > 0) {
attrs = new nsXULPrototypeAttribute[numattrs];
if (! attrs)
return NS_ERROR_OUT_OF_MEMORY;
}
aElement->mAttributes = attrs;
aElement->mNumAttributes = count;
aElement->mNumAttributes = numattrs;
if (generateIDAttr) {
// Deal with generating an ID attribute for stuff inside a XUL
// template
nsAutoString id; id.AssignWithConversion("$");
id.AppendInt(PRInt32(aElement), 16);
mNodeInfoManager->GetNodeInfo(kIdAtom, nsnull, kNameSpaceID_None,
*getter_AddRefs(attrs->mNodeInfo));
NS_ENSURE_TRUE(attrs->mNodeInfo, NS_ERROR_FAILURE);
attrs->mValue.SetValue( id );
++attrs;
}
// Copy the attributes into the prototype
for (PRInt32 i = 0; i < count; i++) {

Просмотреть файл

@ -3141,7 +3141,7 @@ nsXULDocument::GetElementsByTagNameNS(const nsAReadableString& aNamespaceURI,
return NS_OK;
}
NS_IMETHODIMP
nsresult
nsXULDocument::AddSubtreeToDocument(nsIContent* aElement)
{
// Do a bunch of work that's necessary when an element gets added
@ -3194,13 +3194,10 @@ nsXULDocument::AddSubtreeToDocument(nsIContent* aElement)
if (NS_FAILED(rv)) return rv;
}
// 5. See if we need to attach a XUL template to this node
CheckTemplateBuilder(aElement);
return NS_OK;
}
NS_IMETHODIMP
nsresult
nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aElement)
{
// Do a bunch of cleanup to remove an element from the XUL
@ -5048,12 +5045,26 @@ nsXULDocument::ResumeWalk()
if (NS_FAILED(rv)) return rv;
if (indx >= proto->mNumChildren) {
// We've processed all of the prototype's children. If
// we're in the master prototype, do document-level
// hookup. (An overlay will get its document hookup
// done when it's successfully resolved.)
if (element && (mState == eState_Master))
AddSubtreeToDocument(element);
if (element && ((mState == eState_Master) || (mContextStack.Depth() > 2))) {
// We've processed all of the prototype's children.
// Check the element for a 'datasources' attribute, in
// which case we'll need to create a template builder
// and construct the first 'ply' of elements beneath
// it.
//
// N.B. that we do this -after- all other XUL children
// have been created: this ensures that there'll be a
// <template> tag available when we try to build that
// first ply of generated elements.
//
// N.B. that we do -not- do this if we are dealing
// with an 'overlay element'; that is, an element
// in the first ply of an overlay
// document. OverlayForwardReference::Merge() will
// handle that case.
rv = CheckTemplateBuilder(element);
if (NS_FAILED(rv)) return rv;
}
// Now pop the context stack back up to the parent
// element and continue the prototype walk.
@ -5087,6 +5098,15 @@ nsXULDocument::ResumeWalk()
// ...and append it to the content model.
rv = element->AppendChildTo(child, PR_FALSE);
if (NS_FAILED(rv)) return rv;
// ...but only do document-level hookup if we're
// in the master document. For an overlay, this
// will happend when the overlay is successfully
// resolved.
if (mState == eState_Master) {
rv = AddSubtreeToDocument(child);
if (NS_FAILED(rv)) return rv;
}
}
else {
// We're in the "first ply" of an overlay: the
@ -5586,19 +5606,6 @@ nsXULDocument::CheckTemplateBuilder(nsIContent* aElement)
// one, create and initialize a template builder.
nsresult rv;
// See if the element already has a `database' attribute. If it
// does, then the template builder has already been created.
//
// XXX this approach will crash and burn (well, maybe not _that_
// bad) if aElement is not a XUL element.
nsCOMPtr<nsIDOMXULElement> xulele = do_QueryInterface(aElement);
if (xulele) {
nsCOMPtr<nsIRDFCompositeDataSource> ds;
xulele->GetDatabase(getter_AddRefs(ds));
if (ds)
return NS_OK;
}
nsAutoString datasources;
rv = aElement->GetAttribute(kNameSpaceID_None, kDataSourcesAtom, datasources);
if (NS_FAILED(rv)) return rv;
@ -5868,11 +5875,6 @@ nsXULDocument::OverlayForwardReference::Resolve()
rv = Merge(target, mOverlay);
if (NS_FAILED(rv)) return eResolve_Error;
// Add child and any descendants to the element map
rv = mDocument->AddSubtreeToDocument(target);
if (NS_FAILED(rv)) return eResolve_Error;
nsCAutoString idC;
idC.AssignWithConversion(id);
PR_LOG(gXULLog, PR_LOG_ALWAYS,
@ -5901,6 +5903,12 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
nsresult rv;
// XXX - ??? - waterson says this should be moved elsewhere.
// This'll get set to PR_TRUE if a new 'datasources' attribute is
// set on the element. In which case, we need to add a template
// builder.
PRBool datasources = PR_FALSE;
// Merge attributes from the overlay content node to that of the
// actual document.
PRInt32 attrCount, i;
@ -5951,6 +5959,11 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
rv = aTargetNode->SetAttribute(ni, value, PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX - ???
if (/* ignore namespace && */ attr.get() == kDataSourcesAtom) {
datasources = PR_TRUE;
}
}
@ -6029,6 +6042,18 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
if (NS_FAILED(rv)) return rv;
}
// Add child and any descendants to the element map
rv = mDocument->AddSubtreeToDocument(aTargetNode);
if (NS_FAILED(rv)) return rv;
if (datasources) {
// If a new 'datasources' attribute was added via the
// overlay, then initialize the <template> builder on the
// element.
rv = CheckTemplateBuilder(aTargetNode);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}

Просмотреть файл

@ -299,9 +299,6 @@ public:
NS_IMETHOD SetCurrentPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD SetDocumentURL(nsIURI* anURL);
NS_IMETHOD PrepareStyleSheets(nsIURI* anURL);
NS_IMETHOD AddSubtreeToDocument(nsIContent* aElement);
NS_IMETHOD RemoveSubtreeFromDocument(nsIContent* aElement);
// nsIStreamLoadableDocument interface
NS_IMETHOD LoadFromStream(nsIInputStream& xulStream,
@ -390,6 +387,12 @@ protected:
nsresult CloseWidgetItem(nsIContent* aElement);
nsresult RebuildWidgetItem(nsIContent* aElement);
nsresult
AddSubtreeToDocument(nsIContent* aElement);
nsresult
RemoveSubtreeFromDocument(nsIContent* aElement);
nsresult
AddElementToMap(nsIContent* aElement);

Просмотреть файл

@ -63,8 +63,6 @@
#include "nsIDOMXULDocument.h"
#include "nsIDOMXULElement.h"
#include "nsIDocument.h"
#include "nsIBindingManager.h"
#include "nsIDOMNodeList.h"
#include "nsIHTMLContent.h"
#include "nsIElementFactory.h"
#include "nsINameSpace.h"
@ -81,7 +79,6 @@
#include "nsIScriptObjectOwner.h"
#include "nsIScriptGlobalObject.h"
#include "nsIServiceManager.h"
#include "nsISecurityCheckedComponent.h"
#include "nsISupportsArray.h"
#include "nsITextContent.h"
#include "nsITimer.h"
@ -109,8 +106,6 @@
#include "rdfutil.h"
#include "nsIFormControl.h"
#include "nsIDOMHTMLFormElement.h"
#include "pldhash.h"
#include "plhash.h"
// Return values for EnsureElementHasGenericChild()
#define NS_RDF_ELEMENT_GOT_CREATED NS_RDF_NO_VALUE
@ -2514,7 +2509,6 @@ ContentSupportMap::Get(nsIContent* aElement, Match** aMatch)
class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
public nsIRDFContentModelBuilder,
public nsISecurityCheckedComponent,
public nsIRDFObserver
{
public:
@ -2529,9 +2523,6 @@ public:
// nsIXULTemplateBuilder interface
NS_DECL_NSIXULTEMPLATEBUILDER
// nsISecurityCheckedComponent
NS_DECL_NSISECURITYCHECKEDCOMPONENT
// nsIRDFContentModelBuilder interface
NS_IMETHOD SetDocument(nsIXULDocument* aDocument);
NS_IMETHOD SetDataBase(nsIRDFCompositeDataSource* aDataBase);
@ -2559,9 +2550,6 @@ public:
nsresult
GetFlags();
static PRBool
IsTemplateElement(nsIContent* aContent);
nsresult
CompileRules();
@ -2697,7 +2685,7 @@ public:
nsresult
CreateTemplateContents(nsIContent* aElement,
nsIContent* aTemplateElement,
const nsString& aTemplateID,
nsIContent** aContainer,
PRInt32* aNewIndexInContainer);
@ -2892,82 +2880,6 @@ protected:
};
friend class ContentTestNode;
class TemplateMap {
protected:
struct Entry {
PLDHashEntryHdr mHdr;
nsIContent* mContent;
nsIContent* mTemplate;
};
PLDHashTable mTable;
void
Init() { PL_DHashTableInit(&mTable, PL_DHashGetStubOps(), nsnull, sizeof(Entry), PL_DHASH_MIN_SIZE); }
void
Finish() { PL_DHashTableFinish(&mTable); }
public:
TemplateMap() { Init(); }
~TemplateMap() { Finish(); }
void
Put(nsIContent* aContent, nsIContent* aTemplate) {
NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP)),
"aContent already in map");
Entry* entry =
NS_REINTERPRET_CAST(Entry*, PL_DHashTableOperate(&mTable, aContent, PL_DHASH_ADD));
if (entry) {
entry->mContent = aContent;
entry->mTemplate = aTemplate;
} }
void
Remove(nsIContent* aContent) {
NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP)),
"aContent not in map");
PL_DHashTableOperate(&mTable, aContent, PL_DHASH_REMOVE);
PRInt32 count;
// If possible, use the special nsIXULContent interface to
// "peek" at the child count without accidentally creating
// children as a side effect, since we're about to rip 'em
// outta the map anyway.
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aContent);
if (xulcontent) {
xulcontent->PeekChildCount(count);
}
else {
aContent->ChildCount(count);
}
for (PRInt32 i = 0; i < count; ++i) {
nsCOMPtr<nsIContent> child;
aContent->ChildAt(i, *getter_AddRefs(child));
Remove(child);
} }
void
GetTemplateFor(nsIContent* aContent, nsIContent** aResult) {
Entry* entry =
NS_REINTERPRET_CAST(Entry*, PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP));
NS_IF_ADDREF(*aResult = entry->mTemplate); }
void
Clear() { Finish(); Init(); }
};
TemplateMap mTemplateMap;
};
//----------------------------------------------------------------------
@ -4285,10 +4197,9 @@ nsXULTemplateBuilder::Init()
return NS_OK;
}
NS_IMPL_ISUPPORTS4(nsXULTemplateBuilder,
NS_IMPL_ISUPPORTS3(nsXULTemplateBuilder,
nsIXULTemplateBuilder,
nsIRDFContentModelBuilder,
nsISecurityCheckedComponent,
nsIRDFObserver);
//----------------------------------------------------------------------
@ -4566,7 +4477,6 @@ nsXULTemplateBuilder::RebuildContainerInternal(nsIContent* aElement, PRBool aRec
if (aElement == mRoot.get()) {
// Nuke the content support map and conflict set completely.
mContentSupportMap.Clear();
mTemplateMap.Clear();
mConflictSet.Clear();
if (aRecompileRules) {
@ -5633,10 +5543,15 @@ nsXULTemplateBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
*aNewIndexInContainer = indx;
}
// Remember the template kid from which we created the
// real kid. This allows us to sync back up with the
// template to incrementally build content.
mTemplateMap.Put(realKid, tmplKid);
// Mark the node with the ID of the template node used to
// create this element. This allows us to sync back up
// with the template to incrementally build content.
nsAutoString templateID;
rv = tmplKid->GetAttribute(kNameSpaceID_None, nsXULAtoms::id, templateID);
if (NS_FAILED(rv)) return rv;
rv = realKid->SetAttribute(kNameSpaceID_None, nsXULAtoms::Template, templateID, PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Copy all attributes from the template to the new
// element.
@ -5925,8 +5840,26 @@ nsXULTemplateBuilder::SynchronizeAll(nsIRDFResource* aSource,
if (! IsElementContainedBy(element, parent))
continue;
nsCOMPtr<nsIContent> templateNode;
mTemplateMap.GetTemplateFor(element, getter_AddRefs(templateNode));
nsAutoString templateID;
rv = element->GetAttribute(kNameSpaceID_None,
nsXULAtoms::Template,
templateID);
if (NS_FAILED(rv)) return rv;
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
continue;
nsCOMPtr<nsIDOMXULDocument> xulDoc;
xulDoc = do_QueryInterface(mDocument);
if (! xulDoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMElement> domElement;
rv = xulDoc->GetElementById(templateID, getter_AddRefs(domElement));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to find template node");
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIContent> templateNode = do_QueryInterface(domElement);
if (! templateNode)
return NS_ERROR_UNEXPECTED;
@ -6056,10 +5989,30 @@ nsXULTemplateBuilder::IsDirectlyContainedBy(nsIContent* aChild, nsIContent* aPar
if (! aChild)
return PR_FALSE;
nsresult rv;
// Every generated element has a "template" attribute that gives
// us the ID of the template node that it was created from.
nsCOMPtr<nsIContent> tmpl;
mTemplateMap.GetTemplateFor(aChild, getter_AddRefs(tmpl));
nsAutoString tmplID;
rv = aChild->GetAttribute(kNameSpaceID_None, nsXULAtoms::Template, tmplID);
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
return PR_FALSE;
// We've got the template ID; find the element in the content
// model.
nsCOMPtr<nsIDOMXULDocument> xuldoc( do_QueryInterface(mDocument) );
NS_ASSERTION(xuldoc != nsnull, "not an nsIDOMXULDocument");
if (! xuldoc)
return PR_FALSE;
nsCOMPtr<nsIDOMElement> tmplele;
xuldoc->GetElementById(tmplID, getter_AddRefs(tmplele));
NS_ASSERTION(tmplele != nsnull, "couldn't find template element");
if (! tmplele)
return PR_FALSE;
nsCOMPtr<nsIContent> tmpl( do_QueryInterface(tmplele) );
NS_ASSERTION(tmpl != nsnull, "not an nsIContent");
if (! tmpl)
return PR_FALSE;
@ -6149,9 +6102,6 @@ nsXULTemplateBuilder::RemoveMember(nsIContent* aContainerElement,
// Remove from the content support map.
mContentSupportMap.Remove(child);
// Remove from the template map
mTemplateMap.Remove(child);
#ifdef PR_LOGGING
if (PR_LOG_TEST(gLog, PR_LOG_ALWAYS)) {
nsCOMPtr<nsIAtom> parentTag;
@ -6199,6 +6149,7 @@ nsXULTemplateBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
// Generate both 1) the template content for the current element,
// and 2) recursive subcontent (if the current element refers to a
// container resource in the RDF graph).
nsresult rv;
// If we're asked to return the first generated child, then
// initialize to "none".
@ -6209,19 +6160,23 @@ nsXULTemplateBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
// Create the current resource's contents from the template, if
// appropriate
nsCOMPtr<nsIContent> tmpl;
mTemplateMap.GetTemplateFor(aElement, getter_AddRefs(tmpl));
nsAutoString templateID;
rv = aElement->GetAttribute(kNameSpaceID_None, nsXULAtoms::Template, templateID);
if (NS_FAILED(rv)) return rv;
if (tmpl)
CreateTemplateContents(aElement, tmpl, aContainer, aNewIndexInContainer);
if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
rv = CreateTemplateContents(aElement, templateID, aContainer, aNewIndexInContainer);
if (NS_FAILED(rv)) return rv;
}
nsCOMPtr<nsIRDFResource> resource;
gXULUtils->GetElementRefResource(aElement, getter_AddRefs(resource));
if (resource) {
rv = gXULUtils->GetElementRefResource(aElement, getter_AddRefs(resource));
if (NS_SUCCEEDED(rv)) {
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
CreateContainerContents(aElement, resource, PR_FALSE, aContainer, aNewIndexInContainer);
rv = CreateContainerContents(aElement, resource, PR_FALSE, aContainer, aNewIndexInContainer);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
@ -6336,7 +6291,7 @@ nsXULTemplateBuilder::CreateContainerContents(nsIContent* aElement,
nsresult
nsXULTemplateBuilder::CreateTemplateContents(nsIContent* aElement,
nsIContent* aTemplateElement,
const nsString& aTemplateID,
nsIContent** aContainer,
PRInt32* aNewIndexInContainer)
{
@ -6370,6 +6325,14 @@ nsXULTemplateBuilder::CreateTemplateContents(nsIContent* aElement,
if (! xulDoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMElement> tmplNode;
rv = xulDoc->GetElementById(aTemplateID, getter_AddRefs(tmplNode));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIContent> tmpl = do_QueryInterface(tmplNode);
if (! tmpl)
return NS_ERROR_UNEXPECTED;
// Crawl up the content model until we find the "resource" element
// that spawned this template.
nsCOMPtr<nsIRDFResource> resource;
@ -6389,7 +6352,7 @@ nsXULTemplateBuilder::CreateTemplateContents(nsIContent* aElement,
Match* match;
mContentSupportMap.Get(element, &match);
rv = BuildContentFromTemplate(aTemplateElement, aElement, aElement, PR_FALSE, resource, PR_FALSE,
rv = BuildContentFromTemplate(tmpl, aElement, aElement, PR_FALSE, resource, PR_FALSE,
match, aContainer, aNewIndexInContainer);
if (NS_FAILED(rv)) return rv;
@ -6531,6 +6494,22 @@ nsXULTemplateBuilder::IsElementInWidget(nsIContent* aElement)
nsresult
nsXULTemplateBuilder::RemoveGeneratedContent(nsIContent* aElement)
{
// Remove and re-insert the element into the document. This'll
// minimize the number of notifications that the layout engine has
// to deal with.
nsCOMPtr<nsIContent> parent;
aElement->GetParent(*getter_AddRefs(parent));
NS_ASSERTION(parent != nsnull, "huh? no parent!");
if (! parent)
return NS_ERROR_UNEXPECTED;
PRInt32 pos;
parent->IndexOf(aElement, pos);
parent->RemoveChildAt(pos, PR_TRUE);
#define FAST_REMOVE_GENERATED_CONTENT
#ifdef FAST_REMOVE_GENERATED_CONTENT
// Keep a queue of "ungenerated" elements that we have to probe
// for generated content.
nsAutoVoidArray ungenerated;
@ -6561,19 +6540,23 @@ nsXULTemplateBuilder::RemoveGeneratedContent(nsIContent* aElement)
if (tag.get() == nsXULAtoms::Template)
continue;
// If the element is in the template map, then we
// If the element has a 'template' attribute, then we
// assume it's been generated and nuke it.
nsCOMPtr<nsIContent> tmpl;
mTemplateMap.GetTemplateFor(child, getter_AddRefs(tmpl));
nsAutoString tmplID;
child->GetAttribute(kNameSpaceID_None, nsXULAtoms::Template, tmplID);
if (! tmpl) {
// Not in the template map, so this must not have been
if (tmplID.Length() == 0) {
// No 'template' attribute, so this must not have been
// generated. We'll need to examine its kids.
ungenerated.AppendElement(child);
continue;
}
// If we get here, it's "generated". Bye bye!
element->RemoveChildAt(i, PR_TRUE);
// If we get here, it's "generated". Bye bye! Remove it
// from the content model "quietly", because we'll remove
// and re-insert the top-level element into the document
// to minimze reflow.
element->RemoveChildAt(i, PR_FALSE);
child->SetDocument(nsnull, PR_TRUE, PR_TRUE);
// Remove element from the conflict set.
@ -6583,12 +6566,31 @@ nsXULTemplateBuilder::RemoveGeneratedContent(nsIContent* aElement)
// Remove this and any children from the content support map.
mContentSupportMap.Remove(child);
// Remove from the template map
mTemplateMap.Remove(child);
}
}
#else
// Compute the retractions that'll occur when we remove the
// element from the conflict set.
MatchSet firings, retractions;
mConflictSet.Remove(ContentTestNode::Element(aElement), firings, retractions);
// Removing the generated content, quietly.
MatchSet::Iterator last = retractions.Last();
for (MatchSet::Iterator match = retractions.First(); match != last; ++match) {
Value memberval;
match->mAssignments.GetAssignmentFor(match->mRule->GetMemberVariable(), &memberval);
RemoveMember(aElement, VALUE_TO_IRDFRESOURCE(memberval), PR_FALSE);
}
#endif
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
aElement->SetDocument(doc, PR_TRUE, PR_TRUE);
parent->InsertChildAt(aElement, pos, PR_TRUE);
return NS_OK;
}
@ -7169,23 +7171,6 @@ nsXULTemplateBuilder::GetFlags()
}
PRBool
nsXULTemplateBuilder::IsTemplateElement(nsIContent* aContent)
{
PRInt32 nameSpaceID;
aContent->GetNameSpaceID(nameSpaceID);
if (nameSpaceID == nsXULTemplateBuilder::kNameSpaceID_XUL) {
nsCOMPtr<nsIAtom> tag;
aContent->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsXULAtoms::Template)
return PR_TRUE;
}
return PR_FALSE;
}
nsresult
nsXULTemplateBuilder::CompileRules()
@ -7235,32 +7220,31 @@ nsXULTemplateBuilder::CompileRules()
// If root node has no template attribute, then look for a child
// node which is a template tag
if (! tmpl) {
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
nsCOMPtr<nsIBindingManager> bindingManager;
doc->GetBindingManager(getter_AddRefs(bindingManager));
PRInt32 count;
rv = mRoot->ChildCount(count);
if (NS_FAILED(rv)) return rv;
if (bindingManager) {
nsCOMPtr<nsIDOMNodeList> kids;
bindingManager->GetXBLChildNodesFor(mRoot, getter_AddRefs(kids));
for (PRInt32 i = 0; i < count; i++) {
nsCOMPtr<nsIContent> child;
rv = mRoot->ChildAt(i, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
if (kids) {
PRUint32 length;
kids->GetLength(&length);
PRInt32 nameSpaceID;
rv = child->GetNameSpaceID(nameSpaceID);
if (NS_FAILED(rv)) return rv;
for (PRUint32 i = 0; i < length; ++i) {
nsCOMPtr<nsIDOMNode> node;
kids->Item(i, getter_AddRefs(node));
if (! node)
continue;
if (nameSpaceID != kNameSpaceID_XUL)
continue;
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
nsCOMPtr<nsIAtom> tag;
rv = child->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
if (IsTemplateElement(child)) {
tmpl = child;
break;
}
}
}
if (tag.get() != nsXULAtoms::Template)
continue;
tmpl = child;
break;
}
}
@ -8131,35 +8115,3 @@ nsXULTemplateBuilder::CompileBinding(Rule* aRule,
return aRule->AddBinding(svar, pres, ovar);
}
/* string canCreateWrapper (in nsIIDPtr iid); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanCreateWrapper(const nsIID * iid, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}
/* string canCallMethod (in nsIIDPtr iid, in wstring methodName); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}
/* string canGetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}
/* string canSetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanSetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}

Просмотреть файл

@ -805,9 +805,21 @@ struct ChildIterator
doc->GetBindingManager(getter_AddRefs(mBindingManager));
// Retrieve the anonymous content that we should build.
mBindingManager->GetXBLChildNodesFor(mContent, getter_AddRefs(mNodes));
if (mNodes)
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() {

Просмотреть файл

@ -805,9 +805,21 @@ struct ChildIterator
doc->GetBindingManager(getter_AddRefs(mBindingManager));
// Retrieve the anonymous content that we should build.
mBindingManager->GetXBLChildNodesFor(mContent, getter_AddRefs(mNodes));
if (mNodes)
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() {

Просмотреть файл

@ -89,9 +89,6 @@ public:
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 0;
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList) = 0;
// Encapsulates logic for handling both of above
NS_IMETHOD GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult) = 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;

Просмотреть файл

@ -348,8 +348,6 @@ public:
NS_IMETHOD GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* aList);
NS_IMETHOD GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex);
NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRUint32* aIndex,
PRBool* aMultipleInsertionPoints);
@ -782,28 +780,6 @@ nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent, nsISupportsArray* a
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
{
PRUint32 length;
// Retrieve the anonymous content that we should build.
GetAnonymousNodesFor(aContent, aResult);
if (*aResult) {
(*aResult)->GetLength(&length);
if (length == 0)
*aResult = 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 (! *aResult)
GetContentListFor(aContent, aResult);
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
{

Просмотреть файл

@ -41,7 +41,6 @@
#include "nsIDocument.h"
#include "nsIXMLContent.h"
#include "nsIXULContent.h"
#include "nsIXULDocument.h"
#include "nsIXMLContentSink.h"
#include "nsLayoutCID.h"
#include "nsXMLDocument.h"
@ -362,9 +361,7 @@ nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
mBoundElement->GetDocument(*getter_AddRefs(doc));
mContent->SetDocument(doc, PR_TRUE, AllowScripts());
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(doc));
// (2) The children's parent back pointer should not be to this synthetic root
// but should instead point to the bound element.
PRInt32 childCount;
@ -374,12 +371,6 @@ nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
mContent->ChildAt(i, *getter_AddRefs(child));
child->SetParent(mBoundElement);
child->SetBindingParent(mBoundElement);
// To make XUL templates work (and other goodies that happen when
// an element is added to a XUL document), we need to notify the
// XUL document using its special API.
if (xuldoc)
xuldoc->AddSubtreeToDocument(child);
}
return NS_OK;
@ -1298,25 +1289,9 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
nsCOMPtr<nsIContent> anonymous;
GetAnonymousContent(getter_AddRefs(anonymous));
if (anonymous) {
// To make XUL templates work (and other XUL-specific stuff),
// we'll need to notify it using its add & remove APIs. Grab the
// interface now...
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(aOldDocument));
if (mIsStyleBinding) {
if (mIsStyleBinding)
anonymous->SetDocument(nsnull, PR_TRUE, PR_TRUE); // Kill it.
if (xuldoc)
xuldoc->RemoveSubtreeFromDocument(anonymous);
}
else {
anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around.
if (xuldoc)
xuldoc->RemoveSubtreeFromDocument(anonymous);
xuldoc = do_QueryInterface(aNewDocument);
if (xuldoc)
xuldoc->AddSubtreeToDocument(anonymous);
}
else anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around.
}
}

Просмотреть файл

@ -126,16 +126,6 @@ public:
* Load inline and attribute style sheets
*/
NS_IMETHOD PrepareStyleSheets(nsIURI* aURI) = 0;
/**
* Notify the XUL document that a subtree has been added
*/
NS_IMETHOD AddSubtreeToDocument(nsIContent* aElement) = 0;
/**
* Notify the XUL document that a subtree has been removed
*/
NS_IMETHOD RemoveSubtreeFromDocument(nsIContent* aElement) = 0;
};
// factory functions

Просмотреть файл

@ -228,6 +228,8 @@ protected:
nsresult GetTopNode(nsXULPrototypeNode** aNode);
nsresult GetTopChildren(nsVoidArray** aChildren);
PRBool IsInsideXULTemplate();
};
friend class ContextStack;
@ -328,6 +330,31 @@ XULContentSinkImpl::ContextStack::GetTopChildren(nsVoidArray** aChildren)
}
PRBool
XULContentSinkImpl::ContextStack::IsInsideXULTemplate()
{
if (mDepth) {
Entry* entry = mTop;
while (entry) {
nsXULPrototypeNode* node = entry->mNode;
if (node->mType == nsXULPrototypeNode::eType_Element) {
nsXULPrototypeElement* element =
NS_REINTERPRET_CAST(nsXULPrototypeElement*, node);
if (element->mNodeInfo->Equals(kTemplateAtom,
kNameSpaceID_XUL)) {
return PR_TRUE;
}
}
entry = entry->mNext;
}
}
return PR_FALSE;
}
//----------------------------------------------------------------------
@ -1197,16 +1224,50 @@ XULContentSinkImpl::AddAttributes(const nsIParserNode& aNode, nsXULPrototypeElem
nsresult rv;
PRInt32 count = aNode.GetAttributeCount();
PRBool generateIDAttr = PR_FALSE;
if (mContextStack.IsInsideXULTemplate()) {
// Check for an 'id' attribute. If we're inside a XUL
// template, then _everything_ needs to have an ID for the
// 'template' attribute hookup.
generateIDAttr = PR_TRUE;
for (PRInt32 i = 0; i < count; i++) {
if (aNode.GetKeyAt(i).Equals(NS_LITERAL_STRING("id"))) {
generateIDAttr = PR_FALSE;
break;
}
}
}
// Create storage for the attributes
PRInt32 numattrs = count;
if (generateIDAttr)
++numattrs;
nsXULPrototypeAttribute* attrs = nsnull;
if (count > 0) {
attrs = new nsXULPrototypeAttribute[count];
if (numattrs > 0) {
attrs = new nsXULPrototypeAttribute[numattrs];
if (! attrs)
return NS_ERROR_OUT_OF_MEMORY;
}
aElement->mAttributes = attrs;
aElement->mNumAttributes = count;
aElement->mNumAttributes = numattrs;
if (generateIDAttr) {
// Deal with generating an ID attribute for stuff inside a XUL
// template
nsAutoString id; id.AssignWithConversion("$");
id.AppendInt(PRInt32(aElement), 16);
mNodeInfoManager->GetNodeInfo(kIdAtom, nsnull, kNameSpaceID_None,
*getter_AddRefs(attrs->mNodeInfo));
NS_ENSURE_TRUE(attrs->mNodeInfo, NS_ERROR_FAILURE);
attrs->mValue.SetValue( id );
++attrs;
}
// Copy the attributes into the prototype
for (PRInt32 i = 0; i < count; i++) {

Просмотреть файл

@ -3141,7 +3141,7 @@ nsXULDocument::GetElementsByTagNameNS(const nsAReadableString& aNamespaceURI,
return NS_OK;
}
NS_IMETHODIMP
nsresult
nsXULDocument::AddSubtreeToDocument(nsIContent* aElement)
{
// Do a bunch of work that's necessary when an element gets added
@ -3194,13 +3194,10 @@ nsXULDocument::AddSubtreeToDocument(nsIContent* aElement)
if (NS_FAILED(rv)) return rv;
}
// 5. See if we need to attach a XUL template to this node
CheckTemplateBuilder(aElement);
return NS_OK;
}
NS_IMETHODIMP
nsresult
nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aElement)
{
// Do a bunch of cleanup to remove an element from the XUL
@ -5048,12 +5045,26 @@ nsXULDocument::ResumeWalk()
if (NS_FAILED(rv)) return rv;
if (indx >= proto->mNumChildren) {
// We've processed all of the prototype's children. If
// we're in the master prototype, do document-level
// hookup. (An overlay will get its document hookup
// done when it's successfully resolved.)
if (element && (mState == eState_Master))
AddSubtreeToDocument(element);
if (element && ((mState == eState_Master) || (mContextStack.Depth() > 2))) {
// We've processed all of the prototype's children.
// Check the element for a 'datasources' attribute, in
// which case we'll need to create a template builder
// and construct the first 'ply' of elements beneath
// it.
//
// N.B. that we do this -after- all other XUL children
// have been created: this ensures that there'll be a
// <template> tag available when we try to build that
// first ply of generated elements.
//
// N.B. that we do -not- do this if we are dealing
// with an 'overlay element'; that is, an element
// in the first ply of an overlay
// document. OverlayForwardReference::Merge() will
// handle that case.
rv = CheckTemplateBuilder(element);
if (NS_FAILED(rv)) return rv;
}
// Now pop the context stack back up to the parent
// element and continue the prototype walk.
@ -5087,6 +5098,15 @@ nsXULDocument::ResumeWalk()
// ...and append it to the content model.
rv = element->AppendChildTo(child, PR_FALSE);
if (NS_FAILED(rv)) return rv;
// ...but only do document-level hookup if we're
// in the master document. For an overlay, this
// will happend when the overlay is successfully
// resolved.
if (mState == eState_Master) {
rv = AddSubtreeToDocument(child);
if (NS_FAILED(rv)) return rv;
}
}
else {
// We're in the "first ply" of an overlay: the
@ -5586,19 +5606,6 @@ nsXULDocument::CheckTemplateBuilder(nsIContent* aElement)
// one, create and initialize a template builder.
nsresult rv;
// See if the element already has a `database' attribute. If it
// does, then the template builder has already been created.
//
// XXX this approach will crash and burn (well, maybe not _that_
// bad) if aElement is not a XUL element.
nsCOMPtr<nsIDOMXULElement> xulele = do_QueryInterface(aElement);
if (xulele) {
nsCOMPtr<nsIRDFCompositeDataSource> ds;
xulele->GetDatabase(getter_AddRefs(ds));
if (ds)
return NS_OK;
}
nsAutoString datasources;
rv = aElement->GetAttribute(kNameSpaceID_None, kDataSourcesAtom, datasources);
if (NS_FAILED(rv)) return rv;
@ -5868,11 +5875,6 @@ nsXULDocument::OverlayForwardReference::Resolve()
rv = Merge(target, mOverlay);
if (NS_FAILED(rv)) return eResolve_Error;
// Add child and any descendants to the element map
rv = mDocument->AddSubtreeToDocument(target);
if (NS_FAILED(rv)) return eResolve_Error;
nsCAutoString idC;
idC.AssignWithConversion(id);
PR_LOG(gXULLog, PR_LOG_ALWAYS,
@ -5901,6 +5903,12 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
nsresult rv;
// XXX - ??? - waterson says this should be moved elsewhere.
// This'll get set to PR_TRUE if a new 'datasources' attribute is
// set on the element. In which case, we need to add a template
// builder.
PRBool datasources = PR_FALSE;
// Merge attributes from the overlay content node to that of the
// actual document.
PRInt32 attrCount, i;
@ -5951,6 +5959,11 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
rv = aTargetNode->SetAttribute(ni, value, PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX - ???
if (/* ignore namespace && */ attr.get() == kDataSourcesAtom) {
datasources = PR_TRUE;
}
}
@ -6029,6 +6042,18 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
if (NS_FAILED(rv)) return rv;
}
// Add child and any descendants to the element map
rv = mDocument->AddSubtreeToDocument(aTargetNode);
if (NS_FAILED(rv)) return rv;
if (datasources) {
// If a new 'datasources' attribute was added via the
// overlay, then initialize the <template> builder on the
// element.
rv = CheckTemplateBuilder(aTargetNode);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}

Просмотреть файл

@ -299,9 +299,6 @@ public:
NS_IMETHOD SetCurrentPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD SetDocumentURL(nsIURI* anURL);
NS_IMETHOD PrepareStyleSheets(nsIURI* anURL);
NS_IMETHOD AddSubtreeToDocument(nsIContent* aElement);
NS_IMETHOD RemoveSubtreeFromDocument(nsIContent* aElement);
// nsIStreamLoadableDocument interface
NS_IMETHOD LoadFromStream(nsIInputStream& xulStream,
@ -390,6 +387,12 @@ protected:
nsresult CloseWidgetItem(nsIContent* aElement);
nsresult RebuildWidgetItem(nsIContent* aElement);
nsresult
AddSubtreeToDocument(nsIContent* aElement);
nsresult
RemoveSubtreeFromDocument(nsIContent* aElement);
nsresult
AddElementToMap(nsIContent* aElement);

Просмотреть файл

@ -63,8 +63,6 @@
#include "nsIDOMXULDocument.h"
#include "nsIDOMXULElement.h"
#include "nsIDocument.h"
#include "nsIBindingManager.h"
#include "nsIDOMNodeList.h"
#include "nsIHTMLContent.h"
#include "nsIElementFactory.h"
#include "nsINameSpace.h"
@ -81,7 +79,6 @@
#include "nsIScriptObjectOwner.h"
#include "nsIScriptGlobalObject.h"
#include "nsIServiceManager.h"
#include "nsISecurityCheckedComponent.h"
#include "nsISupportsArray.h"
#include "nsITextContent.h"
#include "nsITimer.h"
@ -109,8 +106,6 @@
#include "rdfutil.h"
#include "nsIFormControl.h"
#include "nsIDOMHTMLFormElement.h"
#include "pldhash.h"
#include "plhash.h"
// Return values for EnsureElementHasGenericChild()
#define NS_RDF_ELEMENT_GOT_CREATED NS_RDF_NO_VALUE
@ -2514,7 +2509,6 @@ ContentSupportMap::Get(nsIContent* aElement, Match** aMatch)
class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
public nsIRDFContentModelBuilder,
public nsISecurityCheckedComponent,
public nsIRDFObserver
{
public:
@ -2529,9 +2523,6 @@ public:
// nsIXULTemplateBuilder interface
NS_DECL_NSIXULTEMPLATEBUILDER
// nsISecurityCheckedComponent
NS_DECL_NSISECURITYCHECKEDCOMPONENT
// nsIRDFContentModelBuilder interface
NS_IMETHOD SetDocument(nsIXULDocument* aDocument);
NS_IMETHOD SetDataBase(nsIRDFCompositeDataSource* aDataBase);
@ -2559,9 +2550,6 @@ public:
nsresult
GetFlags();
static PRBool
IsTemplateElement(nsIContent* aContent);
nsresult
CompileRules();
@ -2697,7 +2685,7 @@ public:
nsresult
CreateTemplateContents(nsIContent* aElement,
nsIContent* aTemplateElement,
const nsString& aTemplateID,
nsIContent** aContainer,
PRInt32* aNewIndexInContainer);
@ -2892,82 +2880,6 @@ protected:
};
friend class ContentTestNode;
class TemplateMap {
protected:
struct Entry {
PLDHashEntryHdr mHdr;
nsIContent* mContent;
nsIContent* mTemplate;
};
PLDHashTable mTable;
void
Init() { PL_DHashTableInit(&mTable, PL_DHashGetStubOps(), nsnull, sizeof(Entry), PL_DHASH_MIN_SIZE); }
void
Finish() { PL_DHashTableFinish(&mTable); }
public:
TemplateMap() { Init(); }
~TemplateMap() { Finish(); }
void
Put(nsIContent* aContent, nsIContent* aTemplate) {
NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP)),
"aContent already in map");
Entry* entry =
NS_REINTERPRET_CAST(Entry*, PL_DHashTableOperate(&mTable, aContent, PL_DHASH_ADD));
if (entry) {
entry->mContent = aContent;
entry->mTemplate = aTemplate;
} }
void
Remove(nsIContent* aContent) {
NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP)),
"aContent not in map");
PL_DHashTableOperate(&mTable, aContent, PL_DHASH_REMOVE);
PRInt32 count;
// If possible, use the special nsIXULContent interface to
// "peek" at the child count without accidentally creating
// children as a side effect, since we're about to rip 'em
// outta the map anyway.
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aContent);
if (xulcontent) {
xulcontent->PeekChildCount(count);
}
else {
aContent->ChildCount(count);
}
for (PRInt32 i = 0; i < count; ++i) {
nsCOMPtr<nsIContent> child;
aContent->ChildAt(i, *getter_AddRefs(child));
Remove(child);
} }
void
GetTemplateFor(nsIContent* aContent, nsIContent** aResult) {
Entry* entry =
NS_REINTERPRET_CAST(Entry*, PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP));
NS_IF_ADDREF(*aResult = entry->mTemplate); }
void
Clear() { Finish(); Init(); }
};
TemplateMap mTemplateMap;
};
//----------------------------------------------------------------------
@ -4285,10 +4197,9 @@ nsXULTemplateBuilder::Init()
return NS_OK;
}
NS_IMPL_ISUPPORTS4(nsXULTemplateBuilder,
NS_IMPL_ISUPPORTS3(nsXULTemplateBuilder,
nsIXULTemplateBuilder,
nsIRDFContentModelBuilder,
nsISecurityCheckedComponent,
nsIRDFObserver);
//----------------------------------------------------------------------
@ -4566,7 +4477,6 @@ nsXULTemplateBuilder::RebuildContainerInternal(nsIContent* aElement, PRBool aRec
if (aElement == mRoot.get()) {
// Nuke the content support map and conflict set completely.
mContentSupportMap.Clear();
mTemplateMap.Clear();
mConflictSet.Clear();
if (aRecompileRules) {
@ -5633,10 +5543,15 @@ nsXULTemplateBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
*aNewIndexInContainer = indx;
}
// Remember the template kid from which we created the
// real kid. This allows us to sync back up with the
// template to incrementally build content.
mTemplateMap.Put(realKid, tmplKid);
// Mark the node with the ID of the template node used to
// create this element. This allows us to sync back up
// with the template to incrementally build content.
nsAutoString templateID;
rv = tmplKid->GetAttribute(kNameSpaceID_None, nsXULAtoms::id, templateID);
if (NS_FAILED(rv)) return rv;
rv = realKid->SetAttribute(kNameSpaceID_None, nsXULAtoms::Template, templateID, PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Copy all attributes from the template to the new
// element.
@ -5925,8 +5840,26 @@ nsXULTemplateBuilder::SynchronizeAll(nsIRDFResource* aSource,
if (! IsElementContainedBy(element, parent))
continue;
nsCOMPtr<nsIContent> templateNode;
mTemplateMap.GetTemplateFor(element, getter_AddRefs(templateNode));
nsAutoString templateID;
rv = element->GetAttribute(kNameSpaceID_None,
nsXULAtoms::Template,
templateID);
if (NS_FAILED(rv)) return rv;
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
continue;
nsCOMPtr<nsIDOMXULDocument> xulDoc;
xulDoc = do_QueryInterface(mDocument);
if (! xulDoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMElement> domElement;
rv = xulDoc->GetElementById(templateID, getter_AddRefs(domElement));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to find template node");
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIContent> templateNode = do_QueryInterface(domElement);
if (! templateNode)
return NS_ERROR_UNEXPECTED;
@ -6056,10 +5989,30 @@ nsXULTemplateBuilder::IsDirectlyContainedBy(nsIContent* aChild, nsIContent* aPar
if (! aChild)
return PR_FALSE;
nsresult rv;
// Every generated element has a "template" attribute that gives
// us the ID of the template node that it was created from.
nsCOMPtr<nsIContent> tmpl;
mTemplateMap.GetTemplateFor(aChild, getter_AddRefs(tmpl));
nsAutoString tmplID;
rv = aChild->GetAttribute(kNameSpaceID_None, nsXULAtoms::Template, tmplID);
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
return PR_FALSE;
// We've got the template ID; find the element in the content
// model.
nsCOMPtr<nsIDOMXULDocument> xuldoc( do_QueryInterface(mDocument) );
NS_ASSERTION(xuldoc != nsnull, "not an nsIDOMXULDocument");
if (! xuldoc)
return PR_FALSE;
nsCOMPtr<nsIDOMElement> tmplele;
xuldoc->GetElementById(tmplID, getter_AddRefs(tmplele));
NS_ASSERTION(tmplele != nsnull, "couldn't find template element");
if (! tmplele)
return PR_FALSE;
nsCOMPtr<nsIContent> tmpl( do_QueryInterface(tmplele) );
NS_ASSERTION(tmpl != nsnull, "not an nsIContent");
if (! tmpl)
return PR_FALSE;
@ -6149,9 +6102,6 @@ nsXULTemplateBuilder::RemoveMember(nsIContent* aContainerElement,
// Remove from the content support map.
mContentSupportMap.Remove(child);
// Remove from the template map
mTemplateMap.Remove(child);
#ifdef PR_LOGGING
if (PR_LOG_TEST(gLog, PR_LOG_ALWAYS)) {
nsCOMPtr<nsIAtom> parentTag;
@ -6199,6 +6149,7 @@ nsXULTemplateBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
// Generate both 1) the template content for the current element,
// and 2) recursive subcontent (if the current element refers to a
// container resource in the RDF graph).
nsresult rv;
// If we're asked to return the first generated child, then
// initialize to "none".
@ -6209,19 +6160,23 @@ nsXULTemplateBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
// Create the current resource's contents from the template, if
// appropriate
nsCOMPtr<nsIContent> tmpl;
mTemplateMap.GetTemplateFor(aElement, getter_AddRefs(tmpl));
nsAutoString templateID;
rv = aElement->GetAttribute(kNameSpaceID_None, nsXULAtoms::Template, templateID);
if (NS_FAILED(rv)) return rv;
if (tmpl)
CreateTemplateContents(aElement, tmpl, aContainer, aNewIndexInContainer);
if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
rv = CreateTemplateContents(aElement, templateID, aContainer, aNewIndexInContainer);
if (NS_FAILED(rv)) return rv;
}
nsCOMPtr<nsIRDFResource> resource;
gXULUtils->GetElementRefResource(aElement, getter_AddRefs(resource));
if (resource) {
rv = gXULUtils->GetElementRefResource(aElement, getter_AddRefs(resource));
if (NS_SUCCEEDED(rv)) {
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
CreateContainerContents(aElement, resource, PR_FALSE, aContainer, aNewIndexInContainer);
rv = CreateContainerContents(aElement, resource, PR_FALSE, aContainer, aNewIndexInContainer);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
@ -6336,7 +6291,7 @@ nsXULTemplateBuilder::CreateContainerContents(nsIContent* aElement,
nsresult
nsXULTemplateBuilder::CreateTemplateContents(nsIContent* aElement,
nsIContent* aTemplateElement,
const nsString& aTemplateID,
nsIContent** aContainer,
PRInt32* aNewIndexInContainer)
{
@ -6370,6 +6325,14 @@ nsXULTemplateBuilder::CreateTemplateContents(nsIContent* aElement,
if (! xulDoc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMElement> tmplNode;
rv = xulDoc->GetElementById(aTemplateID, getter_AddRefs(tmplNode));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIContent> tmpl = do_QueryInterface(tmplNode);
if (! tmpl)
return NS_ERROR_UNEXPECTED;
// Crawl up the content model until we find the "resource" element
// that spawned this template.
nsCOMPtr<nsIRDFResource> resource;
@ -6389,7 +6352,7 @@ nsXULTemplateBuilder::CreateTemplateContents(nsIContent* aElement,
Match* match;
mContentSupportMap.Get(element, &match);
rv = BuildContentFromTemplate(aTemplateElement, aElement, aElement, PR_FALSE, resource, PR_FALSE,
rv = BuildContentFromTemplate(tmpl, aElement, aElement, PR_FALSE, resource, PR_FALSE,
match, aContainer, aNewIndexInContainer);
if (NS_FAILED(rv)) return rv;
@ -6531,6 +6494,22 @@ nsXULTemplateBuilder::IsElementInWidget(nsIContent* aElement)
nsresult
nsXULTemplateBuilder::RemoveGeneratedContent(nsIContent* aElement)
{
// Remove and re-insert the element into the document. This'll
// minimize the number of notifications that the layout engine has
// to deal with.
nsCOMPtr<nsIContent> parent;
aElement->GetParent(*getter_AddRefs(parent));
NS_ASSERTION(parent != nsnull, "huh? no parent!");
if (! parent)
return NS_ERROR_UNEXPECTED;
PRInt32 pos;
parent->IndexOf(aElement, pos);
parent->RemoveChildAt(pos, PR_TRUE);
#define FAST_REMOVE_GENERATED_CONTENT
#ifdef FAST_REMOVE_GENERATED_CONTENT
// Keep a queue of "ungenerated" elements that we have to probe
// for generated content.
nsAutoVoidArray ungenerated;
@ -6561,19 +6540,23 @@ nsXULTemplateBuilder::RemoveGeneratedContent(nsIContent* aElement)
if (tag.get() == nsXULAtoms::Template)
continue;
// If the element is in the template map, then we
// If the element has a 'template' attribute, then we
// assume it's been generated and nuke it.
nsCOMPtr<nsIContent> tmpl;
mTemplateMap.GetTemplateFor(child, getter_AddRefs(tmpl));
nsAutoString tmplID;
child->GetAttribute(kNameSpaceID_None, nsXULAtoms::Template, tmplID);
if (! tmpl) {
// Not in the template map, so this must not have been
if (tmplID.Length() == 0) {
// No 'template' attribute, so this must not have been
// generated. We'll need to examine its kids.
ungenerated.AppendElement(child);
continue;
}
// If we get here, it's "generated". Bye bye!
element->RemoveChildAt(i, PR_TRUE);
// If we get here, it's "generated". Bye bye! Remove it
// from the content model "quietly", because we'll remove
// and re-insert the top-level element into the document
// to minimze reflow.
element->RemoveChildAt(i, PR_FALSE);
child->SetDocument(nsnull, PR_TRUE, PR_TRUE);
// Remove element from the conflict set.
@ -6583,12 +6566,31 @@ nsXULTemplateBuilder::RemoveGeneratedContent(nsIContent* aElement)
// Remove this and any children from the content support map.
mContentSupportMap.Remove(child);
// Remove from the template map
mTemplateMap.Remove(child);
}
}
#else
// Compute the retractions that'll occur when we remove the
// element from the conflict set.
MatchSet firings, retractions;
mConflictSet.Remove(ContentTestNode::Element(aElement), firings, retractions);
// Removing the generated content, quietly.
MatchSet::Iterator last = retractions.Last();
for (MatchSet::Iterator match = retractions.First(); match != last; ++match) {
Value memberval;
match->mAssignments.GetAssignmentFor(match->mRule->GetMemberVariable(), &memberval);
RemoveMember(aElement, VALUE_TO_IRDFRESOURCE(memberval), PR_FALSE);
}
#endif
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
aElement->SetDocument(doc, PR_TRUE, PR_TRUE);
parent->InsertChildAt(aElement, pos, PR_TRUE);
return NS_OK;
}
@ -7169,23 +7171,6 @@ nsXULTemplateBuilder::GetFlags()
}
PRBool
nsXULTemplateBuilder::IsTemplateElement(nsIContent* aContent)
{
PRInt32 nameSpaceID;
aContent->GetNameSpaceID(nameSpaceID);
if (nameSpaceID == nsXULTemplateBuilder::kNameSpaceID_XUL) {
nsCOMPtr<nsIAtom> tag;
aContent->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsXULAtoms::Template)
return PR_TRUE;
}
return PR_FALSE;
}
nsresult
nsXULTemplateBuilder::CompileRules()
@ -7235,32 +7220,31 @@ nsXULTemplateBuilder::CompileRules()
// If root node has no template attribute, then look for a child
// node which is a template tag
if (! tmpl) {
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
nsCOMPtr<nsIBindingManager> bindingManager;
doc->GetBindingManager(getter_AddRefs(bindingManager));
PRInt32 count;
rv = mRoot->ChildCount(count);
if (NS_FAILED(rv)) return rv;
if (bindingManager) {
nsCOMPtr<nsIDOMNodeList> kids;
bindingManager->GetXBLChildNodesFor(mRoot, getter_AddRefs(kids));
for (PRInt32 i = 0; i < count; i++) {
nsCOMPtr<nsIContent> child;
rv = mRoot->ChildAt(i, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
if (kids) {
PRUint32 length;
kids->GetLength(&length);
PRInt32 nameSpaceID;
rv = child->GetNameSpaceID(nameSpaceID);
if (NS_FAILED(rv)) return rv;
for (PRUint32 i = 0; i < length; ++i) {
nsCOMPtr<nsIDOMNode> node;
kids->Item(i, getter_AddRefs(node));
if (! node)
continue;
if (nameSpaceID != kNameSpaceID_XUL)
continue;
nsCOMPtr<nsIContent> child = do_QueryInterface(node);
nsCOMPtr<nsIAtom> tag;
rv = child->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
if (IsTemplateElement(child)) {
tmpl = child;
break;
}
}
}
if (tag.get() != nsXULAtoms::Template)
continue;
tmpl = child;
break;
}
}
@ -8131,35 +8115,3 @@ nsXULTemplateBuilder::CompileBinding(Rule* aRule,
return aRule->AddBinding(svar, pres, ovar);
}
/* string canCreateWrapper (in nsIIDPtr iid); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanCreateWrapper(const nsIID * iid, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}
/* string canCallMethod (in nsIIDPtr iid, in wstring methodName); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}
/* string canGetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}
/* string canSetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP
nsXULTemplateBuilder::CanSetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
*_retval = PL_strdup("AllAccess");
return NS_OK;
}