Bug 450990. Kill off EnsureContentsGenerated. r=peterv, sr=bzbarsky, sicking helped write the patch
authorNeil Deakin <enndeakin@gmail.com>
Fri, 10 Oct 2008 13:44:43 -0400
changeset 20269 eb627a89b7030840fa5955adfeecb0944f6fd614
parent 20268 56d8e1c0d95e5204b13d909e3ab02d610665fdd7
child 20270 94ee77d90fef1ec8bd088d264dc7d4c6504f1aeb
push id2759
push userbzbarsky@mozilla.com
push dateFri, 10 Oct 2008 17:45:08 +0000
treeherdermozilla-central@95e6729d8079 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, bzbarsky, sicking
bugs450990
milestone1.9.1b2pre
Bug 450990. Kill off EnsureContentsGenerated. r=peterv, sr=bzbarsky, sicking helped write the patch
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
content/xul/document/src/nsXULDocument.cpp
content/xul/templates/src/nsContentSupportMap.cpp
content/xul/templates/src/nsTemplateMap.h
content/xul/templates/src/nsXULContentBuilder.cpp
content/xul/templates/src/nsXULTemplateBuilder.cpp
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -151,28 +151,16 @@
 #include "nsXBLBinding.h"
 #include "nsEventDispatcher.h"
 #include "nsPresShellIterator.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIDOMXULCommandEvent.h"
 #include "nsIDOMNSEvent.h"
 #include "nsCCUncollectableMarker.h"
 
-/**
- * Three bits are used for XUL Element's lazy state.
- */
-#define XUL_ELEMENT_CHILDREN_MUST_BE_REBUILT \
-  (nsXULElement::eChildrenMustBeRebuilt << XUL_ELEMENT_LAZY_STATE_OFFSET)
-
-#define XUL_ELEMENT_TEMPLATE_CONTENTS_BUILT \
-  (nsXULElement::eTemplateContentsBuilt << XUL_ELEMENT_LAZY_STATE_OFFSET)
-
-#define XUL_ELEMENT_CONTAINER_CONTENTS_BUILT \
-  (nsXULElement::eContainerContentsBuilt << XUL_ELEMENT_LAZY_STATE_OFFSET)
-
 // Global object maintenance
 nsICSSParser* nsXULPrototypeElement::sCSSParser = nsnull;
 nsIXBLService * nsXULElement::gXBLService = nsnull;
 nsICSSOMFactory* nsXULElement::gCSSOMFactory = nsnull;
 
 /**
  * A tearoff class for nsXULElement to implement nsIScriptEventHandlerOwner.
  */
@@ -924,62 +912,20 @@ nsXULElement::UnbindFromTree(PRBool aDee
             slots->mFrameLoader->Destroy();
             slots->mFrameLoader = nsnull;
         }
     }
 
     nsGenericElement::UnbindFromTree(aDeep, aNullParent);
 }
 
-PRUint32
-nsXULElement::GetChildCount() const
-{
-    if (NS_FAILED(EnsureContentsGenerated())) {
-        return 0;
-    }
-
-    return PeekChildCount();
-}
-
-nsIContent *
-nsXULElement::GetChildAt(PRUint32 aIndex) const
-{
-    if (NS_FAILED(EnsureContentsGenerated())) {
-        return nsnull;
-    }
-
-    return mAttrsAndChildren.GetSafeChildAt(aIndex);
-}
-
-nsIContent * const *
-nsXULElement::GetChildArray() const
-{
-    if (NS_FAILED(EnsureContentsGenerated())) {
-        return nsnull;
-    }
-
-    return mAttrsAndChildren.GetChildArray();
-}
-
-PRInt32
-nsXULElement::IndexOf(nsINode* aPossibleChild) const
-{
-    if (NS_FAILED(EnsureContentsGenerated())) {
-        return -1;
-    }
-
-    return mAttrsAndChildren.IndexOfChild(aPossibleChild);
-}
-
 nsresult
 nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
 {
-    nsresult rv = EnsureContentsGenerated();
-    NS_ENSURE_SUCCESS(rv, rv);
-
+    nsresult rv;
     nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
     if (!oldKid) {
       return NS_OK;
     }
 
     // On the removal of a <treeitem>, <treechildren>, or <treecell> element,
     // the possibility exists that some of the items in the removed subtree
     // are selected (and therefore need to be deselected). We need to account for this.
@@ -1747,75 +1693,16 @@ nsXULElement::GetBuilder(nsIXULTemplateB
 
     return NS_OK;
 }
 
 
 //----------------------------------------------------------------------
 // Implementation methods
 
-nsresult
-nsXULElement::EnsureContentsGenerated(void) const
-{
-    if (GetFlags() & XUL_ELEMENT_CHILDREN_MUST_BE_REBUILT) {
-        // Ensure that the element is actually _in_ the document tree;
-        // otherwise, somebody is trying to generate children for a node
-        // that's not currently in the content model.
-        NS_PRECONDITION(IsInDoc(), "element not in tree");
-        if (!IsInDoc())
-            return NS_ERROR_NOT_INITIALIZED;
-
-        // XXX hack because we can't use "mutable"
-        nsXULElement* unconstThis = const_cast<nsXULElement*>(this);
-
-        // Clear this value *first*, so we can re-enter the nsIContent
-        // getters if needed.
-        unconstThis->ClearLazyState(eChildrenMustBeRebuilt);
-
-        // Walk up our ancestor chain, looking for an element with a
-        // XUL content model builder attached to it.
-        nsIContent* element = unconstThis;
-
-        do {
-            nsCOMPtr<nsIDOMXULElement> xulele = do_QueryInterface(element);
-            if (xulele) {
-                nsCOMPtr<nsIXULTemplateBuilder> builder;
-                xulele->GetBuilder(getter_AddRefs(builder));
-                if (builder) {
-                    if (HasAttr(kNameSpaceID_None, nsGkAtoms::xulcontentsgenerated)) {
-                        unconstThis->ClearLazyState(eChildrenMustBeRebuilt);
-                        return NS_OK;
-                    }
-
-                    return builder->CreateContents(unconstThis, PR_FALSE);
-                }
-            }
-
-            element = element->GetParent();
-        } while (element);
-
-        NS_ERROR("lazy state set with no XUL content builder in ancestor chain");
-        return NS_ERROR_UNEXPECTED;
-    }
-
-    return NS_OK;
-}
-
-// No need to implement AppendChildTo. The default implementation will call
-// GetChildCount which will call EnsureContentsGenerated
-nsresult
-nsXULElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify)
-{
-  nsresult rv = EnsureContentsGenerated();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return nsGenericElement::InsertChildAt(aKid, aIndex, aNotify);
-}
-
-
 /// XXX GetID must be defined here because we have proto attrs.
 nsIAtom*
 nsXULElement::GetID() const
 {
     if (!HasFlag(NODE_MAY_HAVE_ID)) {
         return nsnull;
     }
 
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -461,44 +461,23 @@ public:
 ////////////////////////////////////////////////////////////////////////
 
 /**
 
   The XUL element.
 
  */
 
-#define XUL_ELEMENT_LAZY_STATE_OFFSET NODE_TYPE_SPECIFIC_BITS_OFFSET
+#define XUL_ELEMENT_TEMPLATE_GENERATED 1 << NODE_TYPE_SPECIFIC_BITS_OFFSET
 
 class nsScriptEventHandlerOwnerTearoff;
 
 class nsXULElement : public nsGenericElement, public nsIDOMXULElement
 {
 public:
-    /**
-     * These flags are used to maintain bookkeeping information for partially-
-     * constructed content.
-     *
-     *   eChildrenMustBeRebuilt
-     *     The element's children are invalid or unconstructed, and should
-     *     be reconstructed.
-     *
-     *   eTemplateContentsBuilt
-     *     Child content that is built from a XUL template has been
-     *     constructed. 
-     *
-     *   eContainerContentsBuilt
-     *     Child content that is built by following the ``containment''
-     *     property in a XUL template has been built.
-     */
-    enum LazyState {
-        eChildrenMustBeRebuilt  = 0x1,
-        eTemplateContentsBuilt  = 0x2,
-        eContainerContentsBuilt = 0x4
-    };
 
     /** Typesafe, non-refcounting cast from nsIContent.  Cheaper than QI. **/
     static nsXULElement* FromContent(nsIContent *aContent)
     {
         if (aContent->IsNodeOfType(eXUL))
             return static_cast<nsXULElement*>(aContent);
         return nsnull;
     }
@@ -525,23 +504,17 @@ public:
            PRBool aIsScriptable, nsIContent** aResult);
 
     // nsISupports
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXULElement,
                                                        nsGenericElement)
 
     // nsINode
-    virtual PRUint32 GetChildCount() const;
-    virtual nsIContent *GetChildAt(PRUint32 aIndex) const;
-    virtual nsIContent * const * GetChildArray() const;
-    virtual PRInt32 IndexOf(nsINode* aPossibleChild) const;
     virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
-    virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
-                                   PRBool aNotify);
 
     // nsIContent
     virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                 nsIContent* aBindingParent,
                                 PRBool aCompileEventHandlers);
     virtual void UnbindFromTree(PRBool aDeep, PRBool aNullParent);
     virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify);
     virtual nsIAtom *GetIDAttributeName() const;
@@ -586,24 +559,23 @@ public:
     NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
     virtual nsICSSStyleRule* GetInlineStyleRule();
     NS_IMETHOD SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify);
     virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                                 PRInt32 aModType) const;
     NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
     // XUL element methods
-    PRUint32 PeekChildCount() const
-    { return mAttrsAndChildren.ChildCount(); }
-    void SetLazyState(LazyState aFlags)
-    { SetFlags(aFlags << XUL_ELEMENT_LAZY_STATE_OFFSET); }
-    void ClearLazyState(LazyState aFlags)
-    { UnsetFlags(aFlags << XUL_ELEMENT_LAZY_STATE_OFFSET); }
-    PRBool GetLazyState(LazyState aFlag)
-    { return !!(GetFlags() & (aFlag << XUL_ELEMENT_LAZY_STATE_OFFSET)); }
+    /**
+     * The template-generated flag is used to indicate that a
+     * template-generated element has already had its children generated.
+     */
+    void SetTemplateGenerated() { SetFlags(XUL_ELEMENT_TEMPLATE_GENERATED); }
+    void ClearTemplateGenerated() { UnsetFlags(XUL_ELEMENT_TEMPLATE_GENERATED); }
+    PRBool GetTemplateGenerated() { return !!(GetFlags() & XUL_ELEMENT_TEMPLATE_GENERATED); }
 
     // nsIDOMNode
     NS_FORWARD_NSIDOMNODE(nsGenericElement::)
 
     // nsIDOMElement
     NS_FORWARD_NSIDOMELEMENT(nsGenericElement::)
 
     // nsIDOMXULElement
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -1705,20 +1705,17 @@ nsXULDocument::AddSubtreeToDocument(nsIC
         return NS_OK;
     }
 
     // Do pre-order addition magic
     nsresult rv = AddElementToDocumentPre(aElement);
     if (NS_FAILED(rv)) return rv;
 
     // Recurse to children
-    nsXULElement *xulcontent = nsXULElement::FromContent(aElement);
-
-    PRUint32 count =
-        xulcontent ? xulcontent->PeekChildCount() : aElement->GetChildCount();
+    PRUint32 count = aElement->GetChildCount();
 
     while (count-- > 0) {
         rv = AddSubtreeToDocument(aElement->GetChildAt(count));
         if (NS_FAILED(rv))
             return rv;
     }
 
     // Do post-order addition magic
@@ -3752,27 +3749,17 @@ nsXULDocument::CreateTemplateBuilder(nsI
         // Create and initialize a content builder.
         nsCOMPtr<nsIXULTemplateBuilder> builder
             = do_CreateInstance("@mozilla.org/xul/xul-template-builder;1");
 
         if (! builder)
             return NS_ERROR_FAILURE;
 
         builder->Init(aElement);
-
-        nsXULElement *xulContent = nsXULElement::FromContent(aElement);
-        if (xulContent) {
-            // Mark the XUL element as being lazy, so the template builder
-            // will run when layout first asks for these nodes.
-            xulContent->SetLazyState(nsXULElement::eChildrenMustBeRebuilt);
-        }
-        else {
-            // Force construction of immediate template sub-content _now_.
-            builder->CreateContents(aElement, PR_FALSE);
-        }
+        builder->CreateContents(aElement, PR_FALSE);
     }
 
     return NS_OK;
 }
 
 
 nsresult
 nsXULDocument::AddPrototypeSheets()
--- a/content/xul/templates/src/nsContentSupportMap.cpp
+++ b/content/xul/templates/src/nsContentSupportMap.cpp
@@ -57,29 +57,17 @@ nsContentSupportMap::Finish()
 nsresult
 nsContentSupportMap::Remove(nsIContent* aElement)
 {
     if (!mMap.ops)
         return NS_ERROR_NOT_INITIALIZED;
 
     PL_DHashTableOperate(&mMap, aElement, PL_DHASH_REMOVE);
 
-    PRUint32 count;
-
-    // If possible, use the special nsXULElement 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.
-    nsXULElement *xulcontent = nsXULElement::FromContent(aElement);
-    if (xulcontent) {
-        count = xulcontent->PeekChildCount();
-    }
-    else {
-        count = aElement->GetChildCount();
-    }
-
+    PRUint32 count = aElement->GetChildCount();
     for (PRUint32 i = 0; i < count; ++i) {
         Remove(aElement->GetChildAt(i));
     }
 
     return NS_OK;
 }
 
 
--- a/content/xul/templates/src/nsTemplateMap.h
+++ b/content/xul/templates/src/nsTemplateMap.h
@@ -79,30 +79,17 @@ public:
 
     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);
 
-        PRUint32 count;
-
-        // If possible, use the special nsXULElement 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.
-        nsXULElement *xulcontent = nsXULElement::FromContent(aContent);
-        if (xulcontent) {
-            count = xulcontent->PeekChildCount();
-        }
-        else {
-            count = aContent->GetChildCount();
-        }
-
+        PRUint32 count = aContent->GetChildCount();
         for (PRUint32 i = 0; i < count; ++i) {
             Remove(aContent->GetChildAt(i));
         }
     }
 
 
     void
     GetTemplateFor(nsIContent* aContent, nsIContent** aResult) {
--- a/content/xul/templates/src/nsXULContentBuilder.cpp
+++ b/content/xul/templates/src/nsXULContentBuilder.cpp
@@ -80,55 +80,30 @@
 #define NS_ELEMENT_WAS_THERE   NS_OK
 
 //----------------------------------------------------------------------
 //
 // nsXULContentBuilder
 //
 
 /**
- * The content builder generates DOM nodes from a template. Generation is done
- * dynamically on demand when child nodes are asked for by some other part of
- * content or layout. This is done for a content node by calling
- * CreateContents which creates one and only one level of children deeper. The
- * next level of content is created by calling CreateContents on each child
- * node when requested.
- *
- * CreateTemplateAndContainerContents is used to determine where in a
- * hierarchy generation is currently, related to the current node being
- * processed. The actual content generation is done entirely inside
- * BuildContentFromTemplate.
+ * The content builder generates DOM nodes from a template. The actual content
+ * generation is done entirely inside BuildContentFromTemplate.
  *
  * Content generation is centered around the generation node (the node with
  * uri="?member" on it). Nodes above the generation node are unique and
  * generated only once. BuildContentFromTemplate will be passed the unique
  * flag as an argument for content at this point and will recurse until it
  * finds the generation node.
  *
  * Once the generation node has been found, the results for that content node
- * are added to the content map, stored in mContentSupportMap. When
- * CreateContents is later called for that node, the results are retrieved and
- * used to create a new child for each result, based on the template.
- *
- * Children below the generation node are created with CreateTemplateContents.
+ * are added to the content map, stored in mContentSupportMap.
  *
  * If recursion is allowed, generation continues, where the generation node
  * becomes the container to insert into.
- *
- * The XUL lazy state bits are used to control some aspects of generation:
- *
- * eChildrenMustBeRebuilt: set to true for a node that has its children
- *                         generated lazily. If this is set, the element will
- *                         need to call into the template builder to generate
- *                         its children. This state is cleared by the element
- *                         when this call is made.
- * eTemplateContentsBuilt: set to true for non-generation nodes if the
- *                         children have already been created.
- * eContainerContentsBuilt: set to true for generation nodes to indicate that
- *                          results have been determined.
  */
 class nsXULContentBuilder : public nsXULTemplateBuilder
 {
 public:
     // nsIXULTemplateBuilder interface
     NS_IMETHOD CreateContents(nsIContent* aElement, PRBool aForceCreation);
 
     NS_IMETHOD HasGeneratedContent(nsIRDFResource* aResource,
@@ -160,18 +135,17 @@ protected:
     OpenContainer(nsIContent* aElement);
 
     nsresult
     CloseContainer(nsIContent* aElement);
 
     /**
      * Build content from a template for a given result. This will be called
      * recursively or on demand and will be called for every node in the
-     * generated content tree. See the method defintion below for details
-     * of arguments.
+     * generated content tree.
      */
     nsresult
     BuildContentFromTemplate(nsIContent *aTemplateNode,
                              nsIContent *aResourceNode,
                              nsIContent *aRealNode,
                              PRBool aIsUnique,
                              PRBool aIsSelfReference,
                              nsIXULTemplateResult* aChild,
@@ -228,77 +202,41 @@ protected:
      * Remove the generated node aContent from the DOM and the hashtables
      * used by the content builder.
      */
     nsresult
     RemoveMember(nsIContent* aContent);
 
     /**
      * Create the appropriate generated content for aElement, by calling
-     * CreateTemplateContents and CreateContainerContents. Both of these
-     * functions will generate content but under different circumstances.
-     *
-     * Consider the following example:
-     *   <action>
-     *     <hbox uri="?node">
-     *       <button label="?name"/>
-     *     </hbox>
-     *   </action>
-     *
-     * At the top level, CreateTemplateContents will generate nothing, while
-     * CreateContainerContents will create an <hbox> for each result. When
-     * CreateTemplateAndContainerContents is called for each hbox,
-     * CreateTemplateContents will create the buttons, while
-     * CreateContainerContents will create the next set of hboxes recursively.
-     *
-     * Thus, CreateContainerContents creates the nodes with the uri attribute
-     * and above, while CreateTemplateContents creates the nodes below that.
-     *
-     * Note that all content is actually generated inside
-     * BuildContentFromTemplate, the various CreateX functions call this in
-     * different ways.
-     *
-     * aContainer will be set to the container in which content was generated.
-     * This will always be either aElement, or a descendant of it.
-     * aNewIndexInContainer will be the index in this container where content
-     * was generated.
+     * CreateContainerContents.
      *
      * @param aElement element to generate content inside
      * @param aForceCreation true to force creation for closed items such as menus
-     * @param aContainer container content was added inside. This is an in/out
-     *        parameter and must point to null or a valid object before calling
-     *        this function.
-     * @param aNewIndexInContainer index with container in which content was added
      */
     nsresult
     CreateTemplateAndContainerContents(nsIContent* aElement,
-                                       PRBool aForceCreation,
-                                       nsIContent** aContainer,
-                                       PRInt32* aNewIndexInContainer);
+                                       PRBool aForceCreation);
 
     /**
      * Generate the results for a template, by calling
      * CreateContainerContentsForQuerySet for each queryset.
      *
      * @param aElement element to generate content inside
      * @param aResult reference point for query
      * @param aForceCreation true to force creation for closed items such as menus
-     * @param aNotify true to notify of DOM changes
-     * @param aContainer container content was added inside. This is an in/out
-     *        parameter and must point to null or a valid object before calling
-     *        this function.
-     * @param aNewIndexInContainer index with container in which content was added
+     * @param aNotify true to notify of DOM changes as each element is inserted
+     * @param aNotifyAtEnd notify at the end of all DOM changes
      */
     nsresult
     CreateContainerContents(nsIContent* aElement,
                             nsIXULTemplateResult* aResult,
                             PRBool aForceCreation,
                             PRBool aNotify,
-                            nsIContent** aContainer,
-                            PRInt32* aNewIndexInContainer);
+                            PRBool aNotifyAtEnd);
 
     /**
      * Generate the results for a query.
      *
      * @param aElement element to generate content inside
      * @param aResult reference point for query
      * @param aNotify true to notify of DOM changes
      * @param aContainer container content was added inside
@@ -308,32 +246,16 @@ protected:
     CreateContainerContentsForQuerySet(nsIContent* aElement,
                                        nsIXULTemplateResult* aResult,
                                        PRBool aNotify,
                                        nsTemplateQuerySet* aQuerySet,
                                        nsIContent** aContainer,
                                        PRInt32* aNewIndexInContainer);
 
     /**
-     * Create the remaining content for a result. See the description of
-     * CreateTemplateAndContainerContents for details. aContainer will be
-     * either set to aElement if content was inserted or null otherwise.
-     *
-     * @param aElement element to generate content inside
-     * @param aTemplateElement element within template to generate from
-     * @param aContainer container content was added inside
-     * @param aNewIndexInContainer index with container in which content was added
-     */
-    nsresult
-    CreateTemplateContents(nsIContent* aElement,
-                           nsIContent* aTemplateElement,
-                           nsIContent** aContainer,
-                           PRInt32* aNewIndexInContainer);
-
-    /**
      * Check if an element with a particular tag exists with a container.
      * If it is not present, append a new element with that tag into the
      * container.
      *
      * @param aParent parent container
      * @param aNameSpaceID namespace of tag to locate or create
      * @param aTag tag to locate or create
      * @param aNotify true to notify of DOM changes
@@ -347,19 +269,16 @@ protected:
                                  nsIContent** aResult);
 
     PRBool
     IsOpen(nsIContent* aElement);
 
     nsresult
     RemoveGeneratedContent(nsIContent* aElement);
 
-    PRBool
-    IsLazyWidgetItem(nsIContent* aElement);
-
     nsresult
     GetElementsForResult(nsIXULTemplateResult* aResult,
                          nsCOMArray<nsIContent>& aElements);
 
     nsresult
     CreateElement(PRInt32 aNameSpaceID,
                   nsIAtom* aTag,
                   nsIContent** aResult);
@@ -668,24 +587,16 @@ nsXULContentBuilder::BuildContentFromTem
             rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));
             if (NS_FAILED(rv))
                 return rv;
 
             if (rv == NS_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.
-                nsXULElement *xulcontent = nsXULElement::FromContent(realKid);
-                if (xulcontent) {
-                    xulcontent->SetLazyState(nsXULElement::eTemplateContentsBuilt);
-                }
-
                 // Potentially remember the index of this element as the first
                 // element that we've generated. Note that we remember
                 // this -before- we recurse!
                 if (aContainer && !*aContainer) {
                     *aContainer = aRealNode;
                     NS_ADDREF(*aContainer);
 
                     PRUint32 indx = aRealNode->GetChildCount();
@@ -818,58 +729,36 @@ nsXULContentBuilder::BuildContentFromTem
             if (NS_FAILED(rv)) return rv;
 
             // Add any persistent attributes
             if (isGenerationElement) {
                 rv = AddPersistentAttributes(tmplKid, aChild, realKid);
                 if (NS_FAILED(rv)) return rv;
             }
 
-            // XUL elements inside a template rooted on a XUL element may have
-            // their children generated lazily.
-            nsXULElement *xulcontent = nsXULElement::FromContent(realKid);
-            if (xulcontent && mRoot->IsNodeOfType(nsINode::eXUL)) {
-                PRUint32 count2 = tmplKid->GetChildCount();
-
-                if (count2 == 0 && !isGenerationElement) {
-                    // If we're at a leaf node, then we'll eagerly
-                    // mark the content as having its template &
-                    // container contents built. This avoids a useless
-                    // trip back to the template builder only to find
-                    // that we've got no work to do!
-                    xulcontent->SetLazyState(nsXULElement::eTemplateContentsBuilt);
-                    xulcontent->SetLazyState(nsXULElement::eContainerContentsBuilt);
-                }
-                else if (!aIsSelfReference) {
-                    // Just mark the XUL element as requiring more work to
-                    // be done. We'll get around to it when somebody asks
-                    // for it.
-                    xulcontent->SetLazyState(nsXULElement::eChildrenMustBeRebuilt);
-                }
-            }
-            else {
-                // Otherwise, it doesn't support lazy instantiation,
-                // and we have to recurse "by hand". 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 aContainer and
-                // aNewIndexInContainer down: since we're HTML, we
-                // -know- that we -must- have just been created.
-                rv = BuildContentFromTemplate(tmplKid, aResourceNode, realKid, isUnique,
+            // the unique content recurses up above. Also, don't recurse if
+            // this is a self reference (a reference to the same resource)
+            // or we'll end up regenerating the same content.
+            if (!aIsSelfReference && !isUnique) {
+                // this call creates the content inside the generation node,
+                // for example the label below:
+                //  <vbox uri="?">
+                //    <label value="?title"/>
+                //  </vbox>
+                rv = BuildContentFromTemplate(tmplKid, aResourceNode, realKid, PR_FALSE,
                                               aIsSelfReference, aChild, PR_FALSE, aMatch,
                                               nsnull /* don't care */,
                                               nsnull /* don't care */);
-
                 if (NS_FAILED(rv)) return rv;
 
-                if (isGenerationElement) {
-                    rv = CreateContainerContents(realKid, aChild, PR_FALSE, PR_FALSE,
-                                                 nsnull /* don't care */,
-                                                 nsnull /* don't care */);
+                if (isGenerationElement && !(mFlags & eDontRecurse)) {
+                    // if recursion is allowed, continue by building the next
+                    // level of children
+                    rv = CreateContainerContents(realKid, aChild, PR_FALSE,
+                                                 PR_FALSE, PR_FALSE);
                     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) {
@@ -1029,59 +918,45 @@ nsXULContentBuilder::SynchronizeUsingTem
 {
     // check all attributes on the template node; if they reference a resource,
     // update the equivalent attribute on the content node
     nsresult rv;
     rv = CopyAttributesToElement(aTemplateNode, aRealElement, aResult, PR_TRUE);
     if (NS_FAILED(rv))
         return rv;
 
-    // See if we've generated kids for this node yet. If we have, then
-    // recursively sync up template kids with content kids
-    PRBool contentsGenerated = PR_TRUE;
-    nsXULElement *xulcontent = nsXULElement::FromContent(aRealElement);
-    if (xulcontent) {
-        contentsGenerated = xulcontent->GetLazyState(nsXULElement::eTemplateContentsBuilt);
-    }
-    else {
-        // HTML content will _always_ have been generated up-front
-    }
+    PRUint32 count = aTemplateNode->GetChildCount();
+
+    for (PRUint32 loop = 0; loop < count; ++loop) {
+        nsIContent *tmplKid = aTemplateNode->GetChildAt(loop);
 
-    if (contentsGenerated) {
-        PRUint32 count = aTemplateNode->GetChildCount();
+        if (! tmplKid)
+            break;
 
-        for (PRUint32 loop = 0; loop < count; ++loop) {
-            nsIContent *tmplKid = aTemplateNode->GetChildAt(loop);
-
-            if (! tmplKid)
-                break;
-
-            nsIContent *realKid = aRealElement->GetChildAt(loop);
+        nsIContent *realKid = aRealElement->GetChildAt(loop);
+        if (! realKid)
+            break;
 
-            if (! realKid)
-                break;
+        // check for text nodes and update them accordingly.
+        // This code is similar to that in BuildContentFromTemplate
+        if (tmplKid->NodeInfo()->Equals(nsGkAtoms::textnode,
+                                        kNameSpaceID_XUL)) {
+            PRUnichar attrbuf[128];
+            nsFixedString attrValue(attrbuf, NS_ARRAY_LENGTH(attrbuf), 0);
+            tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
+            if (!attrValue.IsEmpty()) {
+                nsAutoString value;
+                rv = SubstituteText(aResult, attrValue, value);
+                if (NS_FAILED(rv)) return rv;
+                realKid->SetText(value, PR_TRUE);
+            }
+        }
 
-            // check for text nodes and update them accordingly.
-            // This code is similar to that in BuildContentFromTemplate
-            if (tmplKid->NodeInfo()->Equals(nsGkAtoms::textnode,
-                                            kNameSpaceID_XUL)) {
-                PRUnichar attrbuf[128];
-                nsFixedString attrValue(attrbuf, NS_ARRAY_LENGTH(attrbuf), 0);
-                tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
-                if (!attrValue.IsEmpty()) {
-                    nsAutoString value;
-                    rv = SubstituteText(aResult, attrValue, value);
-                    if (NS_FAILED(rv)) return rv;
-                    realKid->SetText(value, PR_TRUE);
-                }
-            }
-
-            rv = SynchronizeUsingTemplate(tmplKid, realKid, aResult);
-            if (NS_FAILED(rv)) return rv;
-        }
+        rv = SynchronizeUsingTemplate(tmplKid, realKid, aResult);
+        if (NS_FAILED(rv)) return rv;
     }
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::RemoveMember(nsIContent* aContent)
 {
@@ -1105,170 +980,135 @@ nsXULContentBuilder::RemoveMember(nsICon
     // Remove from the template map
     mTemplateMap.Remove(aContent);
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
-                                                        PRBool aForceCreation,
-                                                        nsIContent** aContainer,
-                                                        PRInt32* aNewIndexInContainer)
+                                                        PRBool aForceCreation)
 {
     // Generate both 1) the template content for the current element,
     // and 2) recursive subcontent (if the current element refers to a
     // container result).
 
     PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
            ("nsXULContentBuilder::CreateTemplateAndContainerContents start - flags: %d",
             mFlags));
 
     if (! mQueryProcessor)
         return NS_OK;
 
-    // If we're asked to return the first generated child, then
-    // initialize to "none".
-    if (aContainer) {
-        *aContainer = nsnull;
-        *aNewIndexInContainer = -1;
-    }
-
-    // Create the current resource's contents from the template, if
-    // appropriate
-    nsCOMPtr<nsIContent> tmpl;
-    mTemplateMap.GetTemplateFor(aElement, getter_AddRefs(tmpl));
-
-    if (tmpl)
-        CreateTemplateContents(aElement, tmpl, aContainer, aNewIndexInContainer);
-
     // for the root element, get the ref attribute and generate content
     if (aElement == mRoot) {
         if (! mRootResult) {
             nsAutoString ref;
             mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref);
 
             if (! ref.IsEmpty()) {
                 nsresult rv = mQueryProcessor->TranslateRef(mDataSource, ref,
                                                             getter_AddRefs(mRootResult));
                 if (NS_FAILED(rv))
                     return rv;
             }
         }
 
         if (mRootResult) {
             CreateContainerContents(aElement, mRootResult, aForceCreation,
-                                    PR_FALSE, aContainer, aNewIndexInContainer);
+                                    PR_FALSE, PR_TRUE);
         }
     }
     else if (!(mFlags & eDontRecurse)) {
         // The content map will contain the generation elements (the ones that
         // are given ids) and only those elements, so get the reference point
         // from the corresponding match.
         nsTemplateMatch *match = nsnull;
         if (mContentSupportMap.Get(aElement, &match)) {
             // don't generate children if child processing isn't allowed
             PRBool mayProcessChildren;
             nsresult rv = match->mResult->GetMayProcessChildren(&mayProcessChildren);
             if (NS_FAILED(rv) || !mayProcessChildren)
                 return rv;
 
             CreateContainerContents(aElement, match->mResult, aForceCreation,
-                                    PR_FALSE, aContainer, aNewIndexInContainer);
+                                    PR_FALSE, PR_TRUE);
         }
     }
 
     PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
            ("nsXULContentBuilder::CreateTemplateAndContainerContents end"));
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::CreateContainerContents(nsIContent* aElement,
                                              nsIXULTemplateResult* aResult,
                                              PRBool aForceCreation,
                                              PRBool aNotify,
-                                             nsIContent** aContainer,
-                                             PRInt32* aNewIndexInContainer)
+                                             PRBool aNotifyAtEnd)
 {
+    if (!aForceCreation && !IsOpen(aElement))
+        return NS_OK;
+
     nsCOMPtr<nsIRDFResource> refResource;
     GetResultResource(aResult, getter_AddRefs(refResource));
     if (! refResource)
         return NS_ERROR_FAILURE;
 
     // Avoid re-entrant builds for the same resource.
     if (IsActivated(refResource))
         return NS_OK;
 
     ActivationEntry entry(refResource, &mTop);
 
-    // Create the contents of a container by iterating over all of the
-    // "containment" arcs out of the element's resource.
-    nsresult rv;
-
     // Compile the rules now, if they haven't been already.
     if (! mQueriesCompiled) {
-        rv = CompileQueries();
+        nsresult rv = CompileQueries();
         if (NS_FAILED(rv))
             return rv;
     }
 
     if (mQuerySets.Length() == 0)
         return NS_OK;
 
-    if (aContainer) {
-        // In case aContainer has already been initialized with a value go ahead
-        // and release it. 
-        NS_IF_RELEASE(*aContainer);
-        *aNewIndexInContainer = -1;
-    }
-
-    // The tree widget is special. If the item isn't open, then just
-    // "pretend" that there aren't any contents here. We'll create
-    // them when OpenContainer() gets called.
-    if (!aForceCreation && IsLazyWidgetItem(aElement) && !IsOpen(aElement))
-        return NS_OK;
-
     // See if the element's templates contents have been generated:
     // this prevents a re-entrant call from triggering another
     // generation.
     nsXULElement *xulcontent = nsXULElement::FromContent(aElement);
     if (xulcontent) {
-        if (xulcontent->GetLazyState(nsXULElement::eContainerContentsBuilt))
+        if (xulcontent->GetTemplateGenerated())
             return NS_OK;
 
         // Now mark the element's contents as being generated so that
         // any re-entrant calls don't trigger an infinite recursion.
-        xulcontent->SetLazyState(nsXULElement::eContainerContentsBuilt);
+        xulcontent->SetTemplateGenerated();
     }
-    else {
-        // HTML is always needs to be generated.
-        //
-        // XXX Big ass-umption here -- I am assuming that this will
-        // _only_ ever get called (in the case of an HTML element)
-        // when the XUL builder is descending thru the graph and
-        // stumbles on a template that is rooted at an HTML element.
-        // (/me crosses fingers...)
-    }
+
+    PRInt32 newIndexInContainer = -1;
+    nsIContent* container = nsnull;
 
     PRInt32 querySetCount = mQuerySets.Length();
 
     for (PRInt32 r = 0; r < querySetCount; r++) {
         nsTemplateQuerySet* queryset = mQuerySets[r];
 
         nsIAtom* tag = queryset->GetTag();
         if (tag && tag != aElement->Tag())
             continue;
 
-        // XXXndeakin need to revisit how aContainer and content notification
-        // is handled. Currently though, this code is similar to the old code.
-        // *aContainer will only be set if it is null
         CreateContainerContentsForQuerySet(aElement, aResult, aNotify, queryset,
-                                           aContainer, aNewIndexInContainer);
+                                           &container, &newIndexInContainer);
+    }
+
+    if (aNotifyAtEnd && container) {
+        MOZ_AUTO_DOC_UPDATE(container->GetCurrentDoc(), UPDATE_CONTENT_MODEL,
+                            PR_TRUE);
+        nsNodeUtils::ContentAppended(container, newIndexInContainer);
     }
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::CreateContainerContentsForQuerySet(nsIContent* aElement,
                                                         nsIXULTemplateResult* aResult,
@@ -1417,58 +1257,16 @@ nsXULContentBuilder::CreateContainerCont
             newmatch->mNext = existingmatch;
         }
     }
 
     return rv;
 }
 
 nsresult
-nsXULContentBuilder::CreateTemplateContents(nsIContent* aElement,
-                                            nsIContent* aTemplateElement,
-                                            nsIContent** aContainer,
-                                            PRInt32* aNewIndexInContainer)
-{
-    // Create the contents of an element using the templates.
-    // See if the element's templates contents have been generated:
-    // this prevents a re-entrant call from triggering another
-    // generation.
-    nsXULElement *xulcontent = nsXULElement::FromContent(aElement);
-    if (! xulcontent)
-        return NS_OK; // HTML content is _always_ generated up-front
-
-    if (xulcontent->GetLazyState(nsXULElement::eTemplateContentsBuilt))
-        return NS_OK;
-
-    // Now mark the element's contents as being generated so that
-    // any re-entrant calls don't trigger an infinite recursion.
-    xulcontent->SetLazyState(nsXULElement::eTemplateContentsBuilt);
-
-    // Crawl up the content model until we find a generation node
-    // (one that was generated from a node with a uri attribute)
-
-    nsTemplateMatch* match = nsnull;
-    nsCOMPtr<nsIContent> element;
-    for (element = aElement;
-         element && element != mRoot;
-         element = element->GetParent()) {
-
-        if (mContentSupportMap.Get(element, &match))
-            break;
-    }
-
-    if (!match)
-        return NS_ERROR_FAILURE;
-
-    return BuildContentFromTemplate(aTemplateElement, aElement, aElement,
-                                    PR_FALSE, PR_FALSE, match->mResult, PR_FALSE,
-                                    match, aContainer, aNewIndexInContainer);
-}
-
-nsresult
 nsXULContentBuilder::EnsureElementHasGenericChild(nsIContent* parent,
                                                   PRInt32 nameSpaceID,
                                                   nsIAtom* tag,
                                                   PRBool aNotify,
                                                   nsIContent** result)
 {
     nsresult rv;
 
@@ -1496,31 +1294,31 @@ nsXULContentBuilder::EnsureElementHasGen
     else {
         return NS_ELEMENT_WAS_THERE;
     }
 }
 
 PRBool
 nsXULContentBuilder::IsOpen(nsIContent* aElement)
 {
-    // XXXhyatt - use XBL service to obtain base tag.
-
-    nsIAtom *tag = aElement->Tag();
+    // Determine if this is a <treeitem> or <menu> element
+    if (!aElement->IsNodeOfType(nsINode::eXUL))
+        return PR_TRUE;
 
-    // Treat the 'root' element as always open, -unless- it's a
-    // menu/menupopup. We don't need to "fake" these as being open.
-    if ((aElement == mRoot) && aElement->IsNodeOfType(nsINode::eXUL) &&
-        (tag != nsGkAtoms::menu) &&
-        (tag != nsGkAtoms::menubutton) &&
-        (tag != nsGkAtoms::toolbarbutton) &&
-        (tag != nsGkAtoms::button))
-      return PR_TRUE;
-
-    return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
-                                 nsGkAtoms::_true, eCaseMatters);
+    // XXXhyatt Use the XBL service to obtain a base tag.
+    nsIAtom *tag = aElement->Tag();
+    if (tag == nsGkAtoms::menu ||
+        tag == nsGkAtoms::menulist ||
+        tag == nsGkAtoms::menubutton ||
+        tag == nsGkAtoms::toolbarbutton ||
+        tag == nsGkAtoms::button ||
+        tag == nsGkAtoms::treeitem)
+        return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
+                                     nsGkAtoms::_true, eCaseMatters);
+    return PR_TRUE;
 }
 
 nsresult
 nsXULContentBuilder::RemoveGeneratedContent(nsIContent* aElement)
 {
     // Keep a queue of "ungenerated" elements that we have to probe
     // for generated content.
     nsAutoVoidArray ungenerated;
@@ -1571,37 +1369,16 @@ nsXULContentBuilder::RemoveGeneratedCont
             // Remove from the template map
             mTemplateMap.Remove(child);
         }
     }
 
     return NS_OK;
 }
 
-PRBool
-nsXULContentBuilder::IsLazyWidgetItem(nsIContent* aElement)
-{
-    // Determine if this is a <tree>, <treeitem>, or <menu> element
-
-    if (!aElement->IsNodeOfType(nsINode::eXUL)) {
-        return PR_FALSE;
-    }
-
-    // XXXhyatt Use the XBL service to obtain a base tag.
-
-    nsIAtom *tag = aElement->Tag();
-
-    return (tag == nsGkAtoms::menu ||
-            tag == nsGkAtoms::menulist ||
-            tag == nsGkAtoms::menubutton ||
-            tag == nsGkAtoms::toolbarbutton ||
-            tag == nsGkAtoms::button ||
-            tag == nsGkAtoms::treeitem);
-}
-
 nsresult
 nsXULContentBuilder::GetElementsForResult(nsIXULTemplateResult* aResult,
                                           nsCOMArray<nsIContent>& aElements)
 {
     // if the root has been removed from the document, just return
     // since there won't be any generated content any more
     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetDocument());
     if (! xuldoc)
@@ -1686,30 +1463,22 @@ nsXULContentBuilder::SetContainerAttrs(n
 
 NS_IMETHODIMP
 nsXULContentBuilder::CreateContents(nsIContent* aElement, PRBool aForceCreation)
 {
     NS_PRECONDITION(aElement != nsnull, "null ptr");
     if (! aElement)
         return NS_ERROR_NULL_POINTER;
 
-    nsCOMPtr<nsIContent> container;
-    PRInt32 newIndex;
-    nsresult rv = CreateTemplateAndContainerContents(aElement, aForceCreation,
-                                                     getter_AddRefs(container), &newIndex);
-    NS_ENSURE_SUCCESS(rv, rv);
+    // don't build contents for closed elements. aForceCreation will be true
+    // when a menu is about to be opened, so the content should be built anyway.
+    if (!aForceCreation && !IsOpen(aElement))
+        return NS_OK;
 
-    // if forcing an element to be created, make sure to notify
-    if (aForceCreation && container) {
-        MOZ_AUTO_DOC_UPDATE(container->GetCurrentDoc(), UPDATE_CONTENT_MODEL,
-                            PR_TRUE);
-        nsNodeUtils::ContentAppended(container, newIndex);
-    }
-
-    return NS_OK;
+    return CreateTemplateAndContainerContents(aElement, aForceCreation);
 }
 
 NS_IMETHODIMP
 nsXULContentBuilder::HasGeneratedContent(nsIRDFResource* aResource,
                                          nsIAtom* aTag,
                                          PRBool* aGenerated)
 {
     *aGenerated = PR_FALSE;
@@ -1866,22 +1635,19 @@ nsXULContentBuilder::GetInsertionLocatio
         nsCOMPtr<nsIContent> content = (*aLocations)->SafeObjectAt(t);
 
         nsTemplateMatch* refmatch;
         if (content == mRoot || mContentSupportMap.Get(content, &refmatch)) {
             // See if we've built the container contents for "content"
             // yet. If not, we don't need to build any content. This
             // happens, for example, if we receive an assertion on a
             // closed folder in a tree widget or on a menu that hasn't
-            // yet been dropped.
+            // yet been opened.
             nsXULElement *xulcontent = nsXULElement::FromContent(content);
-            if (!xulcontent ||
-                xulcontent->GetLazyState(nsXULElement::eContainerContentsBuilt)) {
-                // non-XUL content is never built lazily, nor is content that's
-                // already been built
+            if (!xulcontent || xulcontent->GetTemplateGenerated()) {
                 found = PR_TRUE;
                 continue;
             }
         }
 
         // clear the item in the list since we don't want to insert there
         (*aLocations)->ReplaceObjectAt(nsnull, t);
     }
@@ -1985,25 +1751,17 @@ nsXULContentBuilder::SynchronizeResult(n
 //----------------------------------------------------------------------
 //
 // Implementation methods
 //
 
 nsresult
 nsXULContentBuilder::OpenContainer(nsIContent* aElement)
 {
-    // Get the result for this element if there is one. If it has no result,
-    // there's nothing that we need to be concerned about here.
-    nsCOMPtr<nsIXULTemplateResult> result;
-    if (aElement == mRoot) {
-        result = mRootResult;
-        if (!result)
-            return NS_OK;
-    }
-    else {
+    if (aElement != mRoot) {
         if (mFlags & eDontRecurse)
             return NS_OK;
 
         PRBool rightBuilder = PR_FALSE;
 
         nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aElement->GetDocument());
         if (! xuldoc)
             return NS_OK;
@@ -2019,118 +1777,56 @@ nsXULContentBuilder::OpenContainer(nsICo
                 break;
             }
 
             content = content->GetParent();
         } while (content);
 
         if (! rightBuilder)
             return NS_OK;
-
-        nsTemplateMatch* match;
-        if (mContentSupportMap.Get(aElement, &match))
-            result = match->mResult;
-
-        if (!result)
-            return NS_OK;
-
-        // don't open containers if child processing isn't allowed
-        PRBool mayProcessChildren;
-        nsresult rv = result->GetMayProcessChildren(&mayProcessChildren);
-        if (NS_FAILED(rv) || !mayProcessChildren)
-            return rv;
     }
 
-    // The element has a result so build its contents.
-    // Create the container's contents "quietly" (i.e., |aNotify ==
-    // PR_FALSE|), and then use the |container| and |newIndex| to
-    // notify layout where content got created.
-    nsCOMPtr<nsIContent> container;
-    PRInt32 newIndex;
-    CreateContainerContents(aElement, result, PR_FALSE,
-                            PR_FALSE, getter_AddRefs(container), &newIndex);
-
-    if (container && IsLazyWidgetItem(aElement)) {
-        // The tree widget is special, and has to be spanked every
-        // time we add content to a container.
-        MOZ_AUTO_DOC_UPDATE(container->GetCurrentDoc(), UPDATE_CONTENT_MODEL,
-                            PR_TRUE);
-        nsNodeUtils::ContentAppended(container, newIndex);
-    }
+    CreateTemplateAndContainerContents(aElement, PR_FALSE);
 
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::CloseContainer(nsIContent* aElement)
 {
     return NS_OK;
 }
 
 nsresult
 nsXULContentBuilder::RebuildAll()
 {
     NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED);
 
+    // Bail out early if we are being torn down.
     nsCOMPtr<nsIDocument> doc = mRoot->GetDocument();
-
-    // Bail out early if we are being torn down.
     if (!doc)
         return NS_OK;
 
-    // See if it's a XUL element whose contents have never even
-    // been generated. If so, short-circuit and bail; there's nothing
-    // for us to "rebuild" yet. They'll get built correctly the next
-    // time somebody asks for them.
-    nsXULElement *xulcontent = nsXULElement::FromContent(mRoot);
-
-/*
-    // XXXndeakin not sure if commenting this out is a good thing or not.
-    // Leaving it in causes templates where the ref is set dynamically to
-    // not work due to the order in which these state bits are set.
-
-    if (xulcontent &&
-        !xulcontent->GetLazyState(nsXULElement::eContainerContentsBuilt))
-        return NS_OK;
-*/
-
     if (mQueriesCompiled)
         Uninit(PR_FALSE);
 
-    // clear rebuild flag while processing the queries, or a recursive call to
-    // build children may occur.
-    if (xulcontent)
-        xulcontent->ClearLazyState(nsXULElement::eChildrenMustBeRebuilt);
-
     nsresult rv = CompileQueries();
     if (NS_FAILED(rv))
         return rv;
 
     if (mQuerySets.Length() == 0)
         return NS_OK;
 
-    // Forces the XUL element to remember that it needs to
-    // re-generate its children next time around.
-    if (xulcontent) {
-        xulcontent->SetLazyState(nsXULElement::eChildrenMustBeRebuilt);
-        xulcontent->ClearLazyState(nsXULElement::eTemplateContentsBuilt);
-        xulcontent->ClearLazyState(nsXULElement::eContainerContentsBuilt);
-    }
+    nsXULElement *xulcontent = nsXULElement::FromContent(mRoot);
+    if (xulcontent)
+        xulcontent->ClearTemplateGenerated();
 
     // Now, regenerate both the template- and container-generated
     // contents for the current element...
-    nsCOMPtr<nsIContent> container;
-    PRInt32 newIndex;
-    CreateTemplateAndContainerContents(mRoot, PR_FALSE, getter_AddRefs(container), &newIndex);
-
-    if (container) {
-        MOZ_AUTO_DOC_UPDATE(container->GetCurrentDoc(), UPDATE_CONTENT_MODEL,
-                            PR_TRUE);
-        nsNodeUtils::ContentAppended(container, newIndex);
-    }
+    CreateTemplateAndContainerContents(mRoot, PR_FALSE);
 
     return NS_OK;
 }
 
 /**** Sorting Methods ****/
 
 nsresult
 nsXULContentBuilder::CompareResultToNode(nsIXULTemplateResult* aResult,
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp
+++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp
@@ -1139,23 +1139,21 @@ nsXULTemplateBuilder::ContentRemoved(nsI
         Uninit(PR_FALSE);
 
         aDocument->RemoveObserver(this);
 
         nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aDocument);
         if (xuldoc)
             xuldoc->SetTemplateBuilderFor(mRoot, nsnull);
 
-        // clear the lazy state when removing content so that it will be
-        // regenerated again if the content is reinserted
+        // clear the template state when removing content so that template
+        // content will be regenerated again if the content is reinserted
         nsXULElement *xulcontent = nsXULElement::FromContent(mRoot);
-        if (xulcontent) {
-            xulcontent->ClearLazyState(nsXULElement::eTemplateContentsBuilt);
-            xulcontent->ClearLazyState(nsXULElement::eContainerContentsBuilt);
-        }
+        if (xulcontent)
+            xulcontent->ClearTemplateGenerated();
 
         mDB = nsnull;
         mCompDB = nsnull;
         mRoot = nsnull;
         mDataSource = nsnull;
     }
 }