if (aFirstGeneratedChild && !*aFirstGeneratedChild) { *aFirstGeneratedChild = realKid; NS_ADDREF(*aFirstGeneratedChild);
if (aContainer && !*aContainer) { *aContainer = aRealNode; NS_ADDREF(*aContainer);  PRInt32 indx; aRealNode->ChildCount(indx);    *aNewIndexInContainer = indx - 1;
RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,                                                nsIContent *trueParent,                                                nsIContent *aRealNode,                                                PRBool aIsUnique,                                                nsIRDFResource* aChild,                                                PRBool aNotify,                                                nsIContent** aFirstGeneratedChild){    nsresult rv;#ifdef PR_LOGGING    // Dump out the template node's tag, the template ID, and the RDF    // resource that is being used as the index into the graph.    if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {        nsCOMPtr<nsIAtom> tag;        rv = aTemplateNode->GetTag(*getter_AddRefs(tag));        if (NS_FAILED(rv)) return rv;        nsXPIDLCString resourceCStr;        rv = aChild->GetValue(getter_Copies(resourceCStr));        if (NS_FAILED(rv)) return rv;        nsAutoString tagstr;        tag->ToString(tagstr);        nsAutoString templatestr;        aTemplateNode->GetAttribute(kNameSpaceID_None, kIdAtom, templatestr);        PR_LOG(gLog, PR_LOG_DEBUG,               ("rdfgeneric[%p] build-content-from-template %s (template='%s') [%s]",                this,                (const char*) nsCAutoString(tagstr),                (const char*) nsCAutoString(templatestr),                (const char*) resourceCStr));    }#endif    // Iterate through all of the template children, constructing    // "real" content model nodes for each "template" child.    PRInt32    count;    rv = aTemplateNode->ChildCount(count);    if (NS_FAILED(rv)) return rv;    for (PRInt32 kid = 0; kid < count; kid++) {        nsCOMPtr<nsIContent> tmplKid;        rv = aTemplateNode->ChildAt(kid, *getter_AddRefs(tmplKid));        if (NS_FAILED(rv)) return rv;        PRInt32 nameSpaceID;        rv = tmplKid->GetNameSpaceID(nameSpaceID);        if (NS_FAILED(rv)) return rv;        // Check whether this element is the "resource" element. The        // "resource" element is the element that is cookie-cutter        // copied once for each different RDF resource specified by        // |aChild|.        //        // Nodes that appear -above- the resource element        // (that is, are ancestors of the resource element in the        // content model) are unique across all values of |aChild|,        // and are created only once.        //        // Nodes that appear -below- the resource element (that is,        // are descnendants of the resource element in the conte        // model), are cookie-cutter copied for each distinct value of        // |aChild|.        //        // For example, in a <tree> template:        //        //   <tree>        //     <template>        //       <treechildren> [1]        //         <treeitem uri="rdf:*"> [2]        //           <treerow> [3]        //             <treecell value="rdf:urn:foo" /> [4]        //             <treecell value="rdf:urn:bar" /> [5]        //           </treerow>        //         </treeitem>        //       </treechildren>        //     </template>        //   </tree>        //        // The <treeitem> element [2] is the "resource element". This        // element, and all of its descendants ([3], [4], and [5])        // will be duplicated for each different |aChild|        // resource. It's ancestor <treechildren> [1] is unique, and        // will only be created -once-, no matter how many <treeitem>s        // are created below it.        //        // Note that |isResourceElement| and |isUnique| are mutually        // exclusive.        PRBool isResourceElement = PR_FALSE;        PRBool isUnique = aIsUnique;        {            // We identify the resource element by presence of a            // "uri='rdf:*'" attribute. (We also support the older            // "uri='...'" syntax.)            PRUnichar buf[128];            nsAutoString idValue(CBufDescriptor(buf, PR_TRUE, sizeof(buf) / sizeof(PRUnichar), 0));            rv = tmplKid->GetAttribute(kNameSpaceID_None,                                       kURIAtom,                                       idValue);            if (NS_FAILED(rv)) return rv;            if ((rv == NS_CONTENT_ATTR_HAS_VALUE) &&                (idValue.Equals("...") || idValue.Equals("rdf:*"))) {                // If we -are- the resource element, then we are no                // matter unique.                isResourceElement = PR_TRUE;                isUnique = PR_FALSE;            }        }        nsCOMPtr<nsIAtom> tag;        rv = tmplKid->GetTag(*getter_AddRefs(tag));        if (NS_FAILED(rv)) return rv;#ifdef PR_LOGGING        if (PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {            nsAutoString tagname;            tag->ToString(tagname);            PR_LOG(gLog, PR_LOG_DEBUG,                   ("rdfgeneric[%p]     building %s %s %s",                    this, (const char*) nsCAutoString(tagname),                    (isResourceElement ? "[resource]" : ""),                    (isUnique ? "[unique]" : "")));        }#endif        // Set to PR_TRUE if the child we're trying to create now        // already existed in the content model.        PRBool realKidAlreadyExisted = PR_FALSE;        nsCOMPtr<nsIContent> realKid;        if (isUnique) {            // The content is "unique"; that is, we haven't descended            // far enough into the tempalte to hit the "resource"            // element yet. |EnsureElementHasGenericChild()| will            // conditionally create the element iff it isn't there            // already.            rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));            if (NS_FAILED(rv)) return rv;            if (rv == NS_RDF_ELEMENT_WAS_THERE) {                realKidAlreadyExisted = PR_TRUE;            }            else {                // Mark the element's contents as being generated so                // that any re-entrant calls don't trigger an infinite                // recursion.                nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(realKid);                if (xulcontent) {                    rv = xulcontent->SetLazyState(nsIXULContent::eTemplateContentsBuilt);                    if (NS_FAILED(rv)) return rv;                }                // Potentially remember this element as the first                // element that we've generated. Note that we remember                // this -before- we recurse!                if (aFirstGeneratedChild && !*aFirstGeneratedChild) {                    *aFirstGeneratedChild = realKid;                    NS_ADDREF(*aFirstGeneratedChild);                }            }            // Recurse until we get to the resource element. Since            // -we're- unique, assume that our child will be            // unique. The check for the "resource" element at the top            // of the function will trip this to |false| as soon as we            // encounter it.            rv = BuildContentFromTemplate(tmplKid, trueParent, realKid, PR_TRUE, aChild, aNotify, aFirstGeneratedChild);            if (NS_FAILED(rv)) return rv;        }        else if (isResourceElement) {            // It's the "resource" element. Create a new element using            // the namespace ID and tag from the template element.            rv = CreateElement(nameSpaceID, tag, getter_AddRefs(realKid));            if (NS_FAILED(rv)) return rv;            // Assign the element an 'id' attribute using the URI of            // the |aChild| resource.            const char *uri;            rv = aChild->GetValueConst(&uri);            NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource URI");            if (NS_FAILED(rv)) return rv;            nsAutoString id(uri);            rv = realKid->SetAttribute(kNameSpaceID_None, kIdAtom, id, PR_FALSE);            NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set id attribute");            if (NS_FAILED(rv)) return rv;            if (! aNotify) {                // XUL document will watch us, and take care of making                // sure that we get added to or removed from the                // element map if aNotify is true. If not, we gotta do                // it ourselves. Yay.                rv = mDocument->AddElementForID(id, realKid);                if (NS_FAILED(rv)) return rv;            }            // XXX Hackery to ensure that mailnews works. Force the            // element to hold a reference to the            // resource. Unfortunately, this'll break for HTML            // elements.            {                nsCOMPtr<nsIXULContent> xulele = do_QueryInterface(realKid);                if (xulele) {                    xulele->ForceElementToOwnResource(PR_TRUE);                }            }            // Set up the element's 'container' and 'empty'            // attributes.            if (IsContainer(tmplKid, aChild)) {                rv = realKid->SetAttribute(kNameSpaceID_None, kContainerAtom, trueStr, PR_FALSE);                if (NS_FAILED(rv)) return rv;                // test to see if the container has contents                nsAutoString isEmpty = IsEmpty(tmplKid, aChild) ? trueStr : falseStr;                rv = realKid->SetAttribute(kNameSpaceID_None, kEmptyAtom, isEmpty, PR_FALSE);                if (NS_FAILED(rv)) return rv;            }        }        else if ((tag.get() == kTextAtom) && (nameSpaceID == kNameSpaceID_XUL)) {            // <xul:text value="..."> is replaced by text of the            // actual value of the 'rdf:resource' attribute for the            // given node.            PRUnichar attrbuf[128];            nsAutoString attrValue(CBufDescriptor(attrbuf, PR_TRUE, sizeof(attrbuf) / sizeof(PRUnichar), 0));            rv = tmplKid->GetAttribute(kNameSpaceID_None, kValueAtom, attrValue);            if (NS_FAILED(rv)) return rv;            if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (attrValue.Length() > 0)) {                rv = SubstituteText(aChild, attrValue);                if (NS_FAILED(rv)) return rv;                nsCOMPtr<nsITextContent> content;                rv = nsComponentManager::CreateInstance(kTextNodeCID,                                                        nsnull,                                                        NS_GET_IID(nsITextContent),                                                        getter_AddRefs(content));                if (NS_FAILED(rv)) return rv;                rv = content->SetText(attrValue.GetUnicode(), attrValue.Length(), PR_FALSE);                if (NS_FAILED(rv)) return rv;                rv = aRealNode->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(content) ), aNotify);                if (NS_FAILED(rv)) return rv;                // XXX Don't bother remembering text nodes as the                // first element we've generated?            }        }        else {            // It's just a generic element. Create it!            rv = CreateElement(nameSpaceID, tag, getter_AddRefs(realKid));            if (NS_FAILED(rv)) return rv;        }        if (realKid && !realKidAlreadyExisted) {            // Potentially remember this element as the first            // element that we've generated.            if (aFirstGeneratedChild && !*aFirstGeneratedChild) {                *aFirstGeneratedChild = realKid;                NS_ADDREF(*aFirstGeneratedChild);            }            // 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, kIdAtom, templateID);            if (NS_FAILED(rv)) return rv;            rv = realKid->SetAttribute(kNameSpaceID_None, kTemplateAtom, templateID, PR_FALSE);            if (NS_FAILED(rv)) return rv;            // Copy all attributes from the template to the new            // element.            PRInt32    numAttribs;            rv = tmplKid->GetAttributeCount(numAttribs);            if (NS_FAILED(rv)) return rv;            for (PRInt32 attr = 0; attr < numAttribs; attr++) {                PRInt32 attribNameSpaceID;                nsCOMPtr<nsIAtom> attribName;                rv = tmplKid->GetAttributeNameAt(attr, attribNameSpaceID, *getter_AddRefs(attribName));                if (NS_FAILED(rv)) return rv;                if (! IsIgnoreableAttribute(attribNameSpaceID, attribName)) {                    // Create a buffer here, because there's a good                    // chance that an attribute in the template is                    // going to be an RDF URI, which is usually                    // longish.                    PRUnichar attrbuf[128];                    nsAutoString attribValue(CBufDescriptor(attrbuf, PR_TRUE, sizeof(attrbuf) / sizeof(PRUnichar), 0));                    rv = tmplKid->GetAttribute(attribNameSpaceID, attribName, attribValue);                    if (NS_FAILED(rv)) return rv;                    if (rv == NS_CONTENT_ATTR_HAS_VALUE) {                        rv = SubstituteText(aChild, attribValue);                        if (NS_FAILED(rv)) return rv;                        rv = realKid->SetAttribute(attribNameSpaceID, attribName, attribValue, PR_FALSE);                        if (NS_FAILED(rv)) return rv;                    }                }            }            // Add any persistent attributes            if (isResourceElement) {                rv = AddPersistentAttributes(tmplKid, aChild, realKid);                if (NS_FAILED(rv)) return rv;            }                        if (nameSpaceID == kNameSpaceID_HTML) {                // If we just built HTML, then we have to recurse "by                // hand" because HTML won't build itself up                // lazily. Note that we _don't_ need to notify: we'll                // add the entire subtree in a single whack.                //                // Note that we don't bother passing                // aFirstGeneratedChild down: since we're HTML, we                // -know- that we -must- have just been created.                rv = BuildContentFromTemplate(tmplKid, trueParent, realKid, isUnique,                                              aChild, PR_FALSE, nsnull /* don't care */);                if (NS_FAILED(rv)) return rv;                if (isResourceElement) {                    rv = CreateContainerContents(realKid, aChild, PR_FALSE, nsnull /* don't care */);                    if (NS_FAILED(rv)) return rv;                }            }            else {                // Otherwise, just mark the XUL element as requiring                // more work to be done. We'll get around to it when                // somebody asks for it.                nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(realKid);                if (! xulcontent)                    return NS_ERROR_UNEXPECTED;                rv = xulcontent->SetLazyState(nsIXULContent::eChildrenMustBeRebuilt);                if (NS_FAILED(rv)) return rv;            }            // We'll _already_ have added the unique elements; but if            // it's -not- unique, then use the XUL sort service now to            // append the element to the content model.            if (! isUnique) {                rv = NS_ERROR_UNEXPECTED;                if (gXULSortService && isResourceElement)                {			rv = gXULSortService->InsertContainerNode(mDB, &sortState,				mRoot, trueParent, aRealNode, realKid, aNotify);                }                if (NS_FAILED(rv)) {                    rv = aRealNode->AppendChildTo(realKid, aNotify);                    NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element");                }            }        }    }    return NS_OK;}