LCOV - code coverage report
Current view: top level - dom/xul/templates - nsXULContentBuilder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 741 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/ArrayUtils.h"
       7             : 
       8             : #include "nsContentCID.h"
       9             : #include "nsIDocument.h"
      10             : #include "nsIDOMNodeList.h"
      11             : #include "nsIDOMXULDocument.h"
      12             : #include "mozilla/dom/NodeInfo.h"
      13             : #include "nsIServiceManager.h"
      14             : #include "nsIXULDocument.h"
      15             : 
      16             : #include "nsContentSupportMap.h"
      17             : #include "nsRDFConMemberTestNode.h"
      18             : #include "nsRDFPropertyTestNode.h"
      19             : #include "nsXULSortService.h"
      20             : #include "nsTemplateRule.h"
      21             : #include "nsTemplateMap.h"
      22             : #include "nsTArray.h"
      23             : #include "nsXPIDLString.h"
      24             : #include "nsGkAtoms.h"
      25             : #include "nsXULContentUtils.h"
      26             : #include "nsXULElement.h"
      27             : #include "nsXULTemplateBuilder.h"
      28             : #include "nsNodeInfoManager.h"
      29             : #include "nsContentCreatorFunctions.h"
      30             : #include "nsContentUtils.h"
      31             : #include "nsAttrName.h"
      32             : #include "nsNodeUtils.h"
      33             : #include "mozAutoDocUpdate.h"
      34             : #include "nsTextNode.h"
      35             : #include "mozilla/dom/Element.h"
      36             : 
      37             : #include "PLDHashTable.h"
      38             : #include "rdf.h"
      39             : 
      40             : using namespace mozilla;
      41             : using namespace mozilla::dom;
      42             : 
      43             : //----------------------------------------------------------------------
      44             : //
      45             : // Return values for EnsureElementHasGenericChild()
      46             : //
      47             : #define NS_ELEMENT_GOT_CREATED NS_RDF_NO_VALUE
      48             : #define NS_ELEMENT_WAS_THERE   NS_OK
      49             : 
      50             : //----------------------------------------------------------------------
      51             : //
      52             : // nsXULContentBuilder
      53             : //
      54             : 
      55             : /**
      56             :  * The content builder generates DOM nodes from a template. The actual content
      57             :  * generation is done entirely inside BuildContentFromTemplate.
      58             :  *
      59             :  * Content generation is centered around the generation node (the node with
      60             :  * uri="?member" on it). Nodes above the generation node are unique and
      61             :  * generated only once. BuildContentFromTemplate will be passed the unique
      62             :  * flag as an argument for content at this point and will recurse until it
      63             :  * finds the generation node.
      64             :  *
      65             :  * Once the generation node has been found, the results for that content node
      66             :  * are added to the content map, stored in mContentSupportMap.
      67             :  *
      68             :  * If recursion is allowed, generation continues, where the generation node
      69             :  * becomes the container to insert into.
      70             :  */
      71           0 : class nsXULContentBuilder : public nsXULTemplateBuilder
      72             : {
      73             : public:
      74             :     // nsIXULTemplateBuilder interface
      75             :     NS_IMETHOD CreateContents(nsIContent* aElement, bool aForceCreation) override;
      76             : 
      77             :     using nsIXULTemplateBuilder::HasGeneratedContent;
      78             :     bool HasGeneratedContent(nsIRDFResource* aResource,
      79             :                              const nsAString& aTag,
      80             :                              ErrorResult& aError) override;
      81             : 
      82             :     using nsIXULTemplateBuilder::GetResultForContent;
      83             :     nsIXULTemplateResult* GetResultForContent(Element& aElement) override;
      84             : 
      85             :     // nsIMutationObserver interface
      86             :     NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
      87             :     NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
      88             : 
      89             : protected:
      90             :     friend nsresult
      91             :     NS_NewXULContentBuilder(Element* aElement, nsIXULTemplateBuilder** aBuilder);
      92             : 
      93             :     explicit nsXULContentBuilder(Element* aElement);
      94             : 
      95           0 :     void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
      96             :     {
      97           0 :         mSortState.Traverse(aCb);
      98           0 :     }
      99             : 
     100             :     virtual void Uninit(bool aIsFinal) override;
     101             : 
     102             :     // Implementation methods
     103             :     nsresult
     104             :     OpenContainer(nsIContent* aElement);
     105             : 
     106             :     nsresult
     107             :     CloseContainer(nsIContent* aElement);
     108             : 
     109             :     /**
     110             :      * Build content from a template for a given result. This will be called
     111             :      * recursively or on demand and will be called for every node in the
     112             :      * generated content tree.
     113             :      */
     114             :     nsresult
     115             :     BuildContentFromTemplate(nsIContent *aTemplateNode,
     116             :                              nsIContent *aResourceNode,
     117             :                              nsIContent *aRealNode,
     118             :                              bool aIsUnique,
     119             :                              bool aIsSelfReference,
     120             :                              nsIXULTemplateResult* aChild,
     121             :                              bool aNotify,
     122             :                              nsTemplateMatch* aMatch,
     123             :                              nsIContent** aContainer,
     124             :                              int32_t* aNewIndexInContainer);
     125             : 
     126             :     /**
     127             :      * Copy the attributes from the template node to the node generated
     128             :      * from it, performing any substitutions.
     129             :      *
     130             :      * @param aTemplateNode node within template
     131             :      * @param aRealNode generated node to set attibutes upon
     132             :      * @param aResult result to look up variable->value bindings in
     133             :      * @param aNotify true to notify of DOM changes
     134             :      */
     135             :     nsresult
     136             :     CopyAttributesToElement(nsIContent* aTemplateNode,
     137             :                             nsIContent* aRealNode,
     138             :                             nsIXULTemplateResult* aResult,
     139             :                             bool aNotify);
     140             : 
     141             :     /**
     142             :      * Add any necessary persistent attributes (persist="...") from the
     143             :      * local store to a generated node.
     144             :      *
     145             :      * @param aTemplateNode node within template
     146             :      * @param aRealNode generated node to set persisted attibutes upon
     147             :      * @param aResult result to look up variable->value bindings in
     148             :      */
     149             :     nsresult
     150             :     AddPersistentAttributes(Element* aTemplateNode,
     151             :                             nsIXULTemplateResult* aResult,
     152             :                             nsIContent* aRealNode);
     153             : 
     154             :     /**
     155             :      * Recalculate any attributes that have variable references. This will
     156             :      * be called when a binding has been changed to update the attributes.
     157             :      * The attributes are copied from the node aTemplateNode in the template
     158             :      * to the generated node aRealNode, using the values from the result
     159             :      * aResult. This method will operate recursively.
     160             :      *
     161             :      * @param aTemplateNode node within template
     162             :      * @param aRealNode generated node to set attibutes upon
     163             :      * @param aResult result to look up variable->value bindings in
     164             :      */
     165             :     nsresult
     166             :     SynchronizeUsingTemplate(nsIContent *aTemplateNode,
     167             :                              nsIContent* aRealNode,
     168             :                              nsIXULTemplateResult* aResult);
     169             : 
     170             :     /**
     171             :      * Remove the generated node aContent from the DOM and the hashtables
     172             :      * used by the content builder.
     173             :      */
     174             :     nsresult
     175             :     RemoveMember(nsIContent* aContent);
     176             : 
     177             :     /**
     178             :      * Create the appropriate generated content for aElement, by calling
     179             :      * CreateContainerContents.
     180             :      *
     181             :      * @param aElement element to generate content inside
     182             :      * @param aForceCreation true to force creation for closed items such as menus
     183             :      */
     184             :     nsresult
     185             :     CreateTemplateAndContainerContents(nsIContent* aElement,
     186             :                                        bool aForceCreation);
     187             : 
     188             :     /**
     189             :      * Generate the results for a template, by calling
     190             :      * CreateContainerContentsForQuerySet for each queryset.
     191             :      *
     192             :      * @param aElement element to generate content inside
     193             :      * @param aResult reference point for query
     194             :      * @param aForceCreation true to force creation for closed items such as menus
     195             :      * @param aNotify true to notify of DOM changes as each element is inserted
     196             :      * @param aNotifyAtEnd notify at the end of all DOM changes
     197             :      */
     198             :     nsresult
     199             :     CreateContainerContents(nsIContent* aElement,
     200             :                             nsIXULTemplateResult* aResult,
     201             :                             bool aForceCreation,
     202             :                             bool aNotify,
     203             :                             bool aNotifyAtEnd);
     204             : 
     205             :     /**
     206             :      * Generate the results for a query.
     207             :      *
     208             :      * @param aElement element to generate content inside
     209             :      * @param aResult reference point for query
     210             :      * @param aNotify true to notify of DOM changes
     211             :      * @param aContainer container content was added inside
     212             :      * @param aNewIndexInContainer index with container in which content was added
     213             :      */
     214             :     nsresult
     215             :     CreateContainerContentsForQuerySet(nsIContent* aElement,
     216             :                                        nsIXULTemplateResult* aResult,
     217             :                                        bool aNotify,
     218             :                                        nsTemplateQuerySet* aQuerySet,
     219             :                                        nsIContent** aContainer,
     220             :                                        int32_t* aNewIndexInContainer);
     221             : 
     222             :     /**
     223             :      * Check if an element with a particular tag exists with a container.
     224             :      * If it is not present, append a new element with that tag into the
     225             :      * container.
     226             :      *
     227             :      * @param aParent parent container
     228             :      * @param aNameSpaceID namespace of tag to locate or create
     229             :      * @param aTag tag to locate or create
     230             :      * @param aNotify true to notify of DOM changes
     231             :      * @param aResult set to the found or created node.
     232             :      */
     233             :     nsresult
     234             :     EnsureElementHasGenericChild(nsIContent* aParent,
     235             :                                  int32_t aNameSpaceID,
     236             :                                  nsIAtom* aTag,
     237             :                                  bool aNotify,
     238             :                                  nsIContent** aResult);
     239             : 
     240             :     bool
     241             :     IsOpen(nsIContent* aElement);
     242             : 
     243             :     nsresult
     244             :     RemoveGeneratedContent(nsIContent* aElement);
     245             : 
     246             :     nsresult
     247             :     GetElementsForResult(nsIXULTemplateResult* aResult,
     248             :                          nsCOMArray<nsIContent>& aElements);
     249             : 
     250             :     nsresult
     251             :     CreateElement(int32_t aNameSpaceID,
     252             :                   nsIAtom* aTag,
     253             :                   Element** aResult);
     254             : 
     255             :     /**
     256             :      * Set the container and empty attributes on a node. If
     257             :      * aIgnoreNonContainers is true, then the element is not changed
     258             :      * for non-containers. Otherwise, the container attribute will be set to
     259             :      * false.
     260             :      *
     261             :      * @param aElement element to set attributes on
     262             :      * @param aResult result to use to determine state of attributes
     263             :      * @param aIgnoreNonContainers true to not change for non-containers
     264             :      * @param aNotify true to notify of DOM changes
     265             :      */
     266             :     nsresult
     267             :     SetContainerAttrs(nsIContent *aElement,
     268             :                       nsIXULTemplateResult* aResult,
     269             :                       bool aIgnoreNonContainers,
     270             :                       bool aNotify);
     271             : 
     272             :     virtual nsresult
     273             :     RebuildAll() override;
     274             : 
     275             :     // GetInsertionLocations, ReplaceMatch and SynchronizeResult are inherited
     276             :     // from nsXULTemplateBuilder
     277             : 
     278             :     /**
     279             :      * Return true if the result can be inserted into the template as
     280             :      * generated content. For the content builder, aLocations will be set
     281             :      * to the list of containers where the content should be inserted.
     282             :      */
     283             :     virtual bool
     284             :     GetInsertionLocations(nsIXULTemplateResult* aOldResult,
     285             :                           nsCOMArray<nsIContent>** aLocations) override;
     286             : 
     287             :     /**
     288             :      * Remove the content associated with aOldResult which no longer matches,
     289             :      * and/or generate content for a new match.
     290             :      */
     291             :     virtual nsresult
     292             :     ReplaceMatch(nsIXULTemplateResult* aOldResult,
     293             :                  nsTemplateMatch* aNewMatch,
     294             :                  nsTemplateRule* aNewMatchRule,
     295             :                  void *aContext) override;
     296             : 
     297             :     /**
     298             :      * Synchronize a result bindings with the generated content for that
     299             :      * result. This will be called as a result of the template builder's
     300             :      * ResultBindingChanged method.
     301             :      */
     302             :     virtual nsresult
     303             :     SynchronizeResult(nsIXULTemplateResult* aResult) override;
     304             : 
     305             :     /**
     306             :      * Compare a result to a content node. If the generated content for the
     307             :      * result should come before aContent, set aSortOrder to -1. If it should
     308             :      * come after, set sortOrder to 1. If both are equal, set to 0.
     309             :      */
     310             :     nsresult
     311             :     CompareResultToNode(nsIXULTemplateResult* aResult, nsIContent* aContent,
     312             :                         int32_t* aSortOrder);
     313             : 
     314             :     /**
     315             :      * Insert a generated node into the container where it should go according
     316             :      * to the current sort. aNode is the generated content node and aResult is
     317             :      * the result for the generated node.
     318             :      */
     319             :     nsresult
     320             :     InsertSortedNode(nsIContent* aContainer,
     321             :                      nsIContent* aNode,
     322             :                      nsIXULTemplateResult* aResult,
     323             :                      bool aNotify);
     324             : 
     325             :     /**
     326             :      * Maintains a mapping between elements in the DOM and the matches
     327             :      * that they support.
     328             :      */
     329             :     nsContentSupportMap mContentSupportMap;
     330             : 
     331             :     /**
     332             :      * Maintains a mapping from an element in the DOM to the template
     333             :      * element that it was created from.
     334             :      */
     335             :     nsTemplateMap mTemplateMap;
     336             : 
     337             :     /**
     338             :      * Information about the currently active sort
     339             :      */
     340             :     nsSortState mSortState;
     341             : };
     342             : 
     343             : nsresult
     344           0 : NS_NewXULContentBuilder(Element* aElement, nsIXULTemplateBuilder** aBuilder)
     345             : {
     346           0 :     RefPtr<nsXULContentBuilder> builder = new nsXULContentBuilder(aElement);
     347           0 :     nsresult rv = builder->Init();
     348           0 :     NS_ENSURE_SUCCESS(rv, rv);
     349             : 
     350           0 :     builder.forget(aBuilder);
     351           0 :     return NS_OK;
     352             : }
     353             : 
     354           0 : nsXULContentBuilder::nsXULContentBuilder(Element* aElement)
     355           0 :   : nsXULTemplateBuilder(aElement)
     356             : {
     357           0 :   mSortState.initialized = false;
     358           0 : }
     359             : 
     360             : void
     361           0 : nsXULContentBuilder::Uninit(bool aIsFinal)
     362             : {
     363           0 :     if (! aIsFinal && mRoot) {
     364           0 :         nsresult rv = RemoveGeneratedContent(mRoot);
     365           0 :         if (NS_FAILED(rv))
     366           0 :             return;
     367             :     }
     368             : 
     369             :     // Nuke the content support map completely.
     370           0 :     mContentSupportMap.Clear();
     371           0 :     mTemplateMap.Clear();
     372             : 
     373           0 :     mSortState.initialized = false;
     374             : 
     375           0 :     nsXULTemplateBuilder::Uninit(aIsFinal);
     376             : }
     377             : 
     378             : nsresult
     379           0 : nsXULContentBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
     380             :                                               nsIContent *aResourceNode,
     381             :                                               nsIContent *aRealNode,
     382             :                                               bool aIsUnique,
     383             :                                               bool aIsSelfReference,
     384             :                                               nsIXULTemplateResult* aChild,
     385             :                                               bool aNotify,
     386             :                                               nsTemplateMatch* aMatch,
     387             :                                               nsIContent** aContainer,
     388             :                                               int32_t* aNewIndexInContainer)
     389             : {
     390             :     // This is the mother lode. Here is where we grovel through an
     391             :     // element in the template, copying children from the template
     392             :     // into the "real" content tree, performing substitution as we go
     393             :     // by looking stuff up using the results.
     394             :     //
     395             :     //   |aTemplateNode| is the element in the "template tree", whose
     396             :     //   children we will duplicate and move into the "real" content
     397             :     //   tree.
     398             :     //
     399             :     //   |aResourceNode| is the element in the "real" content tree that
     400             :     //   has the "id" attribute set to an result's id. This is
     401             :     //   not directly used here, but rather passed down to the XUL
     402             :     //   sort service to perform container-level sort.
     403             :     //
     404             :     //   |aRealNode| is the element in the "real" content tree to which
     405             :     //   the new elements will be copied.
     406             :     //
     407             :     //   |aIsUnique| is set to "true" so long as content has been
     408             :     //   "unique" (or "above" the resource element) so far in the
     409             :     //   template.
     410             :     //
     411             :     //   |aIsSelfReference| should be set to "true" for cases where
     412             :     //   the reference and member variables are the same, indicating
     413             :     //   that the generated node is the same as the reference point,
     414             :     //   so generation should not recurse, or else an infinite loop
     415             :     //   would occur.
     416             :     //
     417             :     //   |aChild| is the result for which we are building content.
     418             :     //
     419             :     //   |aNotify| is set to "true" if content should be constructed
     420             :     //   "noisily"; that is, whether the document observers should be
     421             :     //   notified when new content is added to the content model.
     422             :     //
     423             :     //   |aContainer| is an out parameter that will be set to the first
     424             :     //   container element in the "real" content tree to which content
     425             :     //   was appended.
     426             :     //
     427             :     //   |aNewIndexInContainer| is an out parameter that will be set to
     428             :     //   the index in aContainer at which new content is first
     429             :     //   constructed.
     430             :     //
     431             :     // If |aNotify| is "false", then |aContainer| and
     432             :     // |aNewIndexInContainer| are used to determine where in the
     433             :     // content model new content is constructed. This allows a single
     434             :     // notification to be propagated to document observers.
     435             :     //
     436             : 
     437             :     nsresult rv;
     438             : 
     439           0 :     if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
     440           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
     441             :                ("nsXULContentBuilder::BuildContentFromTemplate (is unique: %d)",
     442             :                aIsUnique));
     443             : 
     444           0 :         nsAutoString id;
     445           0 :         aChild->GetId(id);
     446             : 
     447           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
     448             :                ("Tags: [Template: %s  Resource: %s  Real: %s] for id %s",
     449             :                 nsAtomCString(aTemplateNode->NodeInfo()->NameAtom()).get(),
     450             :                 nsAtomCString(aResourceNode->NodeInfo()->NameAtom()).get(),
     451             :                 nsAtomCString(aRealNode->NodeInfo()->NameAtom()).get(), NS_ConvertUTF16toUTF8(id).get()));
     452             :     }
     453             : 
     454             :     // Iterate through all of the template children, constructing
     455             :     // "real" content model nodes for each "template" child.
     456           0 :     for (nsIContent* tmplKid = aTemplateNode->GetFirstChild();
     457           0 :          tmplKid;
     458           0 :          tmplKid = tmplKid->GetNextSibling()) {
     459             : 
     460           0 :         int32_t nameSpaceID = tmplKid->GetNameSpaceID();
     461             : 
     462             :         // Check whether this element is the generation element. The generation
     463             :         // element is the element that is cookie-cutter copied once for each
     464             :         // different result specified by |aChild|.
     465             :         //
     466             :         // Nodes that appear -above- the generation element
     467             :         // (that is, are ancestors of the generation element in the
     468             :         // content model) are unique across all values of |aChild|,
     469             :         // and are created only once.
     470             :         //
     471             :         // Nodes that appear -below- the generation element (that is,
     472             :         // are descendants of the generation element in the content
     473             :         // model), are cookie-cutter copied for each distinct value of
     474             :         // |aChild|.
     475             :         //
     476             :         // For example, in a <tree> template:
     477             :         //
     478             :         //   <tree>
     479             :         //     <template>
     480             :         //       <treechildren> [1]
     481             :         //         <treeitem uri="rdf:*"> [2]
     482             :         //           <treerow> [3]
     483             :         //             <treecell value="rdf:urn:foo" /> [4]
     484             :         //             <treecell value="rdf:urn:bar" /> [5]
     485             :         //           </treerow>
     486             :         //         </treeitem>
     487             :         //       </treechildren>
     488             :         //     </template>
     489             :         //   </tree>
     490             :         //
     491             :         // The <treeitem> element [2] is the generation element. This
     492             :         // element, and all of its descendants ([3], [4], and [5])
     493             :         // will be duplicated for each different |aChild|.
     494             :         // It's ancestor <treechildren> [1] is unique, and
     495             :         // will only be created -once-, no matter how many <treeitem>s
     496             :         // are created below it.
     497             :         //
     498             :         // isUnique will be true for nodes above the generation element,
     499             :         // isGenerationElement will be true for the generation element,
     500             :         // and both will be false for descendants
     501           0 :         bool isGenerationElement = false;
     502           0 :         bool isUnique = aIsUnique;
     503             : 
     504             :         // We identify the resource element by presence of a
     505             :         // "uri='rdf:*'" attribute. (We also support the older
     506             :         // "uri='...'" syntax.)
     507           0 :         if (tmplKid->HasAttr(kNameSpaceID_None, nsGkAtoms::uri) && aMatch->IsActive()) {
     508           0 :             isGenerationElement = true;
     509           0 :             isUnique = false;
     510             :         }
     511             : 
     512           0 :         MOZ_ASSERT_IF(isGenerationElement, tmplKid->IsElement());
     513             : 
     514           0 :         nsIAtom *tag = tmplKid->NodeInfo()->NameAtom();
     515             : 
     516           0 :         if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
     517           0 :             MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
     518             :                    ("xultemplate[%p]     building %s %s %s",
     519             :                     this, nsAtomCString(tag).get(),
     520             :                     (isGenerationElement ? "[resource]" : ""),
     521             :                     (isUnique ? "[unique]" : "")));
     522             :         }
     523             : 
     524             :         // Set to true if the child we're trying to create now
     525             :         // already existed in the content model.
     526           0 :         bool realKidAlreadyExisted = false;
     527             : 
     528           0 :         nsCOMPtr<nsIContent> realKid;
     529           0 :         if (isUnique) {
     530             :             // The content is "unique"; that is, we haven't descended
     531             :             // far enough into the template to hit the generation
     532             :             // element yet. |EnsureElementHasGenericChild()| will
     533             :             // conditionally create the element iff it isn't there
     534             :             // already.
     535           0 :             rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));
     536           0 :             if (NS_FAILED(rv))
     537           0 :                 return rv;
     538             : 
     539           0 :             if (rv == NS_ELEMENT_WAS_THERE) {
     540           0 :                 realKidAlreadyExisted = true;
     541             :             }
     542             :             else {
     543             :                 // Potentially remember the index of this element as the first
     544             :                 // element that we've generated. Note that we remember
     545             :                 // this -before- we recurse!
     546           0 :                 if (aContainer && !*aContainer) {
     547           0 :                     *aContainer = aRealNode;
     548           0 :                     NS_ADDREF(*aContainer);
     549             : 
     550           0 :                     uint32_t indx = aRealNode->GetChildCount();
     551             : 
     552             :                     // Since EnsureElementHasGenericChild() added us, make
     553             :                     // sure to subtract one for our real index.
     554           0 :                     *aNewIndexInContainer = indx - 1;
     555             :                 }
     556             :             }
     557             : 
     558             :             // Recurse until we get to the resource element. Since
     559             :             // -we're- unique, assume that our child will be
     560             :             // unique. The check for the "resource" element at the top
     561             :             // of the function will trip this to |false| as soon as we
     562             :             // encounter it.
     563           0 :             rv = BuildContentFromTemplate(tmplKid, aResourceNode, realKid, true,
     564             :                                           aIsSelfReference, aChild, aNotify, aMatch,
     565           0 :                                           aContainer, aNewIndexInContainer);
     566             : 
     567           0 :             if (NS_FAILED(rv))
     568           0 :                 return rv;
     569             :         }
     570           0 :         else if (isGenerationElement) {
     571             :             // It's the "resource" element. Create a new element using
     572             :             // the namespace ID and tag from the template element.
     573           0 :             nsCOMPtr<Element> element;
     574           0 :             rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element));
     575           0 :             if (NS_FAILED(rv))
     576           0 :                 return rv;
     577           0 :             realKid = element.forget();
     578             : 
     579             :             // Add the resource element to the content support map so
     580             :             // we can remove the match based on the content node later.
     581           0 :             mContentSupportMap.Put(realKid, aMatch);
     582             : 
     583             :             // Assign the element an 'id' attribute using result's id
     584           0 :             nsAutoString id;
     585           0 :             rv = aChild->GetId(id);
     586           0 :             if (NS_FAILED(rv))
     587           0 :                 return rv;
     588             : 
     589           0 :             rv = realKid->SetAttr(kNameSpaceID_None, nsGkAtoms::id, id, false);
     590           0 :             if (NS_FAILED(rv))
     591           0 :                 return rv;
     592             : 
     593             :             // Set up the element's 'container' and 'empty' attributes.
     594           0 :             SetContainerAttrs(realKid, aChild, true, false);
     595             :         }
     596           0 :         else if (tag == nsGkAtoms::textnode &&
     597             :                  nameSpaceID == kNameSpaceID_XUL) {
     598             :             // <xul:text value="..."> is replaced by text of the
     599             :             // actual value of the 'rdf:resource' attribute for the
     600             :             // given node.
     601             :             // SynchronizeUsingTemplate contains code used to update textnodes,
     602             :             // so make sure to modify both when changing this
     603             :             char16_t attrbuf[128];
     604           0 :             nsFixedString attrValue(attrbuf, ArrayLength(attrbuf), 0);
     605           0 :             tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
     606           0 :             if (!attrValue.IsEmpty()) {
     607           0 :                 nsAutoString value;
     608           0 :                 rv = SubstituteText(aChild, attrValue, value);
     609           0 :                 if (NS_FAILED(rv)) return rv;
     610             : 
     611             :                 RefPtr<nsTextNode> content =
     612           0 :                   new nsTextNode(mRoot->NodeInfo()->NodeInfoManager());
     613             : 
     614           0 :                 content->SetText(value, false);
     615             : 
     616           0 :                 rv = aRealNode->AppendChildTo(content, aNotify);
     617           0 :                 if (NS_FAILED(rv)) return rv;
     618             : 
     619             :                 // XXX Don't bother remembering text nodes as the
     620             :                 // first element we've generated?
     621           0 :             }
     622             :         }
     623           0 :         else if (tmplKid->IsNodeOfType(nsINode::eTEXT)) {
     624           0 :             nsCOMPtr<nsIDOMNode> tmplTextNode = do_QueryInterface(tmplKid);
     625           0 :             if (!tmplTextNode) {
     626           0 :                 NS_ERROR("textnode not implementing nsIDOMNode??");
     627           0 :                 return NS_ERROR_FAILURE;
     628             :             }
     629           0 :             nsCOMPtr<nsIDOMNode> clonedNode;
     630           0 :             tmplTextNode->CloneNode(false, 1, getter_AddRefs(clonedNode));
     631           0 :             nsCOMPtr<nsIContent> clonedContent = do_QueryInterface(clonedNode);
     632           0 :             if (!clonedContent) {
     633           0 :                 NS_ERROR("failed to clone textnode");
     634           0 :                 return NS_ERROR_FAILURE;
     635             :             }
     636           0 :             rv = aRealNode->AppendChildTo(clonedContent, aNotify);
     637           0 :             if (NS_FAILED(rv)) return rv;
     638             :         }
     639             :         else {
     640             :             // It's just a generic element. Create it!
     641           0 :             nsCOMPtr<Element> element;
     642           0 :             rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element));
     643           0 :             if (NS_FAILED(rv)) return rv;
     644           0 :             realKid = element.forget();
     645             :         }
     646             : 
     647           0 :         if (realKid && !realKidAlreadyExisted) {
     648             :             // Potentially remember the index of this element as the
     649             :             // first element that we've generated.
     650           0 :             if (aContainer && !*aContainer) {
     651           0 :                 *aContainer = aRealNode;
     652           0 :                 NS_ADDREF(*aContainer);
     653             : 
     654           0 :                 uint32_t indx = aRealNode->GetChildCount();
     655             : 
     656             :                 // Since we haven't inserted any content yet, our new
     657             :                 // index in the container will be the current count of
     658             :                 // elements in the container.
     659           0 :                 *aNewIndexInContainer = indx;
     660             :             }
     661             : 
     662             :             // Remember the template kid from which we created the
     663             :             // real kid. This allows us to sync back up with the
     664             :             // template to incrementally build content.
     665           0 :             mTemplateMap.Put(realKid, tmplKid);
     666             : 
     667           0 :             rv = CopyAttributesToElement(tmplKid, realKid, aChild, false);
     668           0 :             if (NS_FAILED(rv)) return rv;
     669             : 
     670             :             // Add any persistent attributes
     671           0 :             if (isGenerationElement) {
     672           0 :                 rv = AddPersistentAttributes(tmplKid->AsElement(), aChild,
     673           0 :                                              realKid);
     674           0 :                 if (NS_FAILED(rv)) return rv;
     675             :             }
     676             : 
     677             :             // the unique content recurses up above. Also, don't recurse if
     678             :             // this is a self reference (a reference to the same resource)
     679             :             // or we'll end up regenerating the same content.
     680           0 :             if (!aIsSelfReference && !isUnique) {
     681             :                 // this call creates the content inside the generation node,
     682             :                 // for example the label below:
     683             :                 //  <vbox uri="?">
     684             :                 //    <label value="?title"/>
     685             :                 //  </vbox>
     686           0 :                 rv = BuildContentFromTemplate(tmplKid, aResourceNode, realKid, false,
     687             :                                               false, aChild, false, aMatch,
     688             :                                               nullptr /* don't care */,
     689           0 :                                               nullptr /* don't care */);
     690           0 :                 if (NS_FAILED(rv)) return rv;
     691             : 
     692           0 :                 if (isGenerationElement) {
     693             :                     // build the next level of children
     694           0 :                     rv = CreateContainerContents(realKid, aChild, false,
     695           0 :                                                  false, false);
     696           0 :                     if (NS_FAILED(rv)) return rv;
     697             :                 }
     698             :             }
     699             : 
     700             :             // We'll _already_ have added the unique elements; but if
     701             :             // it's -not- unique, then use the XUL sort service now to
     702             :             // append the element to the content model.
     703           0 :             if (! isUnique) {
     704           0 :                 rv = NS_ERROR_UNEXPECTED;
     705             : 
     706           0 :                 if (isGenerationElement)
     707           0 :                     rv = InsertSortedNode(aRealNode, realKid, aChild, aNotify);
     708             : 
     709           0 :                 if (NS_FAILED(rv)) {
     710           0 :                     rv = aRealNode->AppendChildTo(realKid, aNotify);
     711           0 :                     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element");
     712             :                 }
     713             :             }
     714             :         }
     715             :     }
     716             : 
     717           0 :     return NS_OK;
     718             : }
     719             : 
     720             : nsresult
     721           0 : nsXULContentBuilder::CopyAttributesToElement(nsIContent* aTemplateNode,
     722             :                                              nsIContent* aRealNode,
     723             :                                              nsIXULTemplateResult* aResult,
     724             :                                              bool aNotify)
     725             : {
     726             :     nsresult rv;
     727             : 
     728             :     // Copy all attributes from the template to the new element
     729           0 :     uint32_t numAttribs = aTemplateNode->GetAttrCount();
     730             : 
     731           0 :     for (uint32_t attr = 0; attr < numAttribs; attr++) {
     732           0 :         const nsAttrName* name = aTemplateNode->GetAttrNameAt(attr);
     733           0 :         int32_t attribNameSpaceID = name->NamespaceID();
     734             :         // Hold a strong reference here so that the atom doesn't go away
     735             :         // during UnsetAttr.
     736           0 :         nsCOMPtr<nsIAtom> attribName = name->LocalName();
     737             : 
     738             :         // XXXndeakin ignore namespaces until bug 321182 is fixed
     739           0 :         if (attribName != nsGkAtoms::id && attribName != nsGkAtoms::uri) {
     740             :             // Create a buffer here, because there's a chance that an
     741             :             // attribute in the template is going to be an RDF URI, which is
     742             :             // usually longish.
     743             :             char16_t attrbuf[128];
     744           0 :             nsFixedString attribValue(attrbuf, ArrayLength(attrbuf), 0);
     745           0 :             aTemplateNode->GetAttr(attribNameSpaceID, attribName, attribValue);
     746           0 :             if (!attribValue.IsEmpty()) {
     747           0 :                 nsAutoString value;
     748           0 :                 rv = SubstituteText(aResult, attribValue, value);
     749           0 :                 if (NS_FAILED(rv))
     750           0 :                     return rv;
     751             : 
     752             :                 // if the string is empty after substitutions, remove the
     753             :                 // attribute
     754           0 :                 if (!value.IsEmpty()) {
     755           0 :                     rv = aRealNode->SetAttr(attribNameSpaceID,
     756             :                                             attribName,
     757             :                                             name->GetPrefix(),
     758             :                                             value,
     759           0 :                                             aNotify);
     760             :                 }
     761             :                 else {
     762           0 :                     rv = aRealNode->UnsetAttr(attribNameSpaceID,
     763             :                                               attribName,
     764           0 :                                               aNotify);
     765             :                 }
     766             : 
     767           0 :                 if (NS_FAILED(rv))
     768           0 :                     return rv;
     769             :             }
     770             :         }
     771             :     }
     772             : 
     773           0 :     return NS_OK;
     774             : }
     775             : 
     776             : nsresult
     777           0 : nsXULContentBuilder::AddPersistentAttributes(Element* aTemplateNode,
     778             :                                              nsIXULTemplateResult* aResult,
     779             :                                              nsIContent* aRealNode)
     780             : {
     781           0 :     if (!mRoot)
     782           0 :         return NS_OK;
     783             : 
     784           0 :     nsCOMPtr<nsIRDFResource> resource;
     785           0 :     nsresult rv = GetResultResource(aResult, getter_AddRefs(resource));
     786           0 :     NS_ENSURE_SUCCESS(rv, rv);
     787             : 
     788           0 :     nsAutoString attribute, persist;
     789           0 :     aTemplateNode->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
     790             : 
     791           0 :     while (!persist.IsEmpty()) {
     792           0 :         attribute.Truncate();
     793             : 
     794           0 :         int32_t offset = persist.FindCharInSet(" ,");
     795           0 :         if (offset > 0) {
     796           0 :             persist.Left(attribute, offset);
     797           0 :             persist.Cut(0, offset + 1);
     798             :         }
     799             :         else {
     800           0 :             attribute = persist;
     801           0 :             persist.Truncate();
     802             :         }
     803             : 
     804           0 :         attribute.Trim(" ");
     805             : 
     806           0 :         if (attribute.IsEmpty())
     807           0 :             break;
     808             : 
     809           0 :         nsCOMPtr<nsIAtom> tag;
     810             :         int32_t nameSpaceID;
     811             : 
     812             :         RefPtr<mozilla::dom::NodeInfo> ni =
     813           0 :             aTemplateNode->GetExistingAttrNameFromQName(attribute);
     814           0 :         if (ni) {
     815           0 :             tag = ni->NameAtom();
     816           0 :             nameSpaceID = ni->NamespaceID();
     817             :         }
     818             :         else {
     819           0 :             tag = NS_Atomize(attribute);
     820           0 :             NS_ENSURE_TRUE(tag, NS_ERROR_OUT_OF_MEMORY);
     821             : 
     822           0 :             nameSpaceID = kNameSpaceID_None;
     823             :         }
     824             : 
     825           0 :         nsCOMPtr<nsIRDFResource> property;
     826           0 :         rv = nsXULContentUtils::GetResource(nameSpaceID, tag, getter_AddRefs(property));
     827           0 :         NS_ENSURE_SUCCESS(rv, rv);
     828             : 
     829           0 :         nsCOMPtr<nsIRDFNode> target;
     830           0 :         rv = mDB->GetTarget(resource, property, true, getter_AddRefs(target));
     831           0 :         NS_ENSURE_SUCCESS(rv, rv);
     832             : 
     833           0 :         if (! target)
     834           0 :             continue;
     835             : 
     836           0 :         nsCOMPtr<nsIRDFLiteral> value = do_QueryInterface(target);
     837           0 :         NS_ASSERTION(value != nullptr, "unable to stomach that sort of node");
     838           0 :         if (! value)
     839           0 :             continue;
     840             : 
     841             :         const char16_t* valueStr;
     842           0 :         rv = value->GetValueConst(&valueStr);
     843           0 :         NS_ENSURE_SUCCESS(rv, rv);
     844             : 
     845           0 :         rv = aRealNode->SetAttr(nameSpaceID, tag, nsDependentString(valueStr),
     846           0 :                                 false);
     847           0 :         NS_ENSURE_SUCCESS(rv, rv);
     848             :     }
     849             : 
     850           0 :     return NS_OK;
     851             : }
     852             : 
     853             : nsresult
     854           0 : nsXULContentBuilder::SynchronizeUsingTemplate(nsIContent* aTemplateNode,
     855             :                                               nsIContent* aRealElement,
     856             :                                               nsIXULTemplateResult* aResult)
     857             : {
     858             :     // check all attributes on the template node; if they reference a resource,
     859             :     // update the equivalent attribute on the content node
     860             :     nsresult rv;
     861           0 :     rv = CopyAttributesToElement(aTemplateNode, aRealElement, aResult, true);
     862           0 :     if (NS_FAILED(rv))
     863           0 :         return rv;
     864             : 
     865           0 :     uint32_t count = aTemplateNode->GetChildCount();
     866             : 
     867           0 :     for (uint32_t loop = 0; loop < count; ++loop) {
     868           0 :         nsIContent *tmplKid = aTemplateNode->GetChildAt(loop);
     869             : 
     870           0 :         if (! tmplKid)
     871           0 :             break;
     872             : 
     873           0 :         nsIContent *realKid = aRealElement->GetChildAt(loop);
     874           0 :         if (! realKid)
     875           0 :             break;
     876             : 
     877             :         // check for text nodes and update them accordingly.
     878             :         // This code is similar to that in BuildContentFromTemplate
     879           0 :         if (tmplKid->NodeInfo()->Equals(nsGkAtoms::textnode,
     880             :                                         kNameSpaceID_XUL)) {
     881             :             char16_t attrbuf[128];
     882           0 :             nsFixedString attrValue(attrbuf, ArrayLength(attrbuf), 0);
     883           0 :             tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
     884           0 :             if (!attrValue.IsEmpty()) {
     885           0 :                 nsAutoString value;
     886           0 :                 rv = SubstituteText(aResult, attrValue, value);
     887           0 :                 if (NS_FAILED(rv)) return rv;
     888           0 :                 realKid->SetText(value, true);
     889             :             }
     890             :         }
     891             : 
     892           0 :         rv = SynchronizeUsingTemplate(tmplKid, realKid, aResult);
     893           0 :         if (NS_FAILED(rv)) return rv;
     894             :     }
     895             : 
     896           0 :     return NS_OK;
     897             : }
     898             : 
     899             : nsresult
     900           0 : nsXULContentBuilder::RemoveMember(nsIContent* aContent)
     901             : {
     902           0 :     nsCOMPtr<nsIContent> parent = aContent->GetParent();
     903           0 :     if (parent) {
     904           0 :         int32_t pos = parent->IndexOf(aContent);
     905             : 
     906           0 :         NS_ASSERTION(pos >= 0, "parent doesn't think this child has an index");
     907           0 :         if (pos < 0) return NS_OK;
     908             : 
     909             :         // Note: RemoveChildAt sets |child|'s document to null so that
     910             :         // it'll get knocked out of the XUL doc's resource-to-element
     911             :         // map.
     912           0 :         parent->RemoveChildAt(pos, true);
     913             :     }
     914             : 
     915             :     // Remove from the content support map.
     916           0 :     mContentSupportMap.Remove(aContent);
     917             : 
     918             :     // Remove from the template map
     919           0 :     mTemplateMap.Remove(aContent);
     920             : 
     921           0 :     return NS_OK;
     922             : }
     923             : 
     924             : nsresult
     925           0 : nsXULContentBuilder::CreateTemplateAndContainerContents(nsIContent* aElement,
     926             :                                                         bool aForceCreation)
     927             : {
     928             :     // Generate both 1) the template content for the current element,
     929             :     // and 2) recursive subcontent (if the current element refers to a
     930             :     // container result).
     931             : 
     932           0 :     MOZ_LOG(gXULTemplateLog, LogLevel::Info,
     933             :            ("nsXULContentBuilder::CreateTemplateAndContainerContents start - flags: %d",
     934             :             mFlags));
     935             : 
     936           0 :     if (! mQueryProcessor)
     937           0 :         return NS_OK;
     938             : 
     939             :     // for the root element, get the ref attribute and generate content
     940           0 :     if (aElement == mRoot) {
     941           0 :         if (! mRootResult) {
     942           0 :             nsAutoString ref;
     943           0 :             mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref);
     944             : 
     945           0 :             if (! ref.IsEmpty()) {
     946           0 :                 nsresult rv = mQueryProcessor->TranslateRef(mDataSource, ref,
     947           0 :                                                             getter_AddRefs(mRootResult));
     948           0 :                 if (NS_FAILED(rv))
     949           0 :                     return rv;
     950             :             }
     951             :         }
     952             : 
     953           0 :         if (mRootResult) {
     954           0 :             CreateContainerContents(aElement, mRootResult, aForceCreation,
     955           0 :                                     false, true);
     956             :         }
     957             :     }
     958           0 :     else if (!(mFlags & eDontRecurse)) {
     959             :         // The content map will contain the generation elements (the ones that
     960             :         // are given ids) and only those elements, so get the reference point
     961             :         // from the corresponding match.
     962           0 :         nsTemplateMatch *match = nullptr;
     963           0 :         if (mContentSupportMap.Get(aElement, &match))
     964           0 :             CreateContainerContents(aElement, match->mResult, aForceCreation,
     965           0 :                                     false, true);
     966             :     }
     967             : 
     968           0 :     MOZ_LOG(gXULTemplateLog, LogLevel::Info,
     969             :            ("nsXULContentBuilder::CreateTemplateAndContainerContents end"));
     970             : 
     971           0 :     return NS_OK;
     972             : }
     973             : 
     974             : nsresult
     975           0 : nsXULContentBuilder::CreateContainerContents(nsIContent* aElement,
     976             :                                              nsIXULTemplateResult* aResult,
     977             :                                              bool aForceCreation,
     978             :                                              bool aNotify,
     979             :                                              bool aNotifyAtEnd)
     980             : {
     981           0 :     if (!aForceCreation && !IsOpen(aElement))
     982           0 :         return NS_OK;
     983             : 
     984             :     // don't generate children if recursion or child processing isn't allowed
     985           0 :     if (aResult != mRootResult) {
     986           0 :         if (mFlags & eDontRecurse)
     987           0 :             return NS_OK;
     988             : 
     989             :         bool mayProcessChildren;
     990           0 :         nsresult rv = aResult->GetMayProcessChildren(&mayProcessChildren);
     991           0 :         if (NS_FAILED(rv) || !mayProcessChildren)
     992           0 :             return rv;
     993             :     }
     994             : 
     995           0 :     nsCOMPtr<nsIRDFResource> refResource;
     996           0 :     GetResultResource(aResult, getter_AddRefs(refResource));
     997           0 :     if (! refResource)
     998           0 :         return NS_ERROR_FAILURE;
     999             : 
    1000             :     // Avoid re-entrant builds for the same resource.
    1001           0 :     if (IsActivated(refResource))
    1002           0 :         return NS_OK;
    1003             : 
    1004           0 :     ActivationEntry entry(refResource, &mTop);
    1005             : 
    1006             :     // Compile the rules now, if they haven't been already.
    1007           0 :     if (! mQueriesCompiled) {
    1008           0 :         nsresult rv = CompileQueries();
    1009           0 :         if (NS_FAILED(rv))
    1010           0 :             return rv;
    1011             :     }
    1012             : 
    1013           0 :     if (mQuerySets.Length() == 0)
    1014           0 :         return NS_OK;
    1015             : 
    1016             :     // See if the element's templates contents have been generated:
    1017             :     // this prevents a re-entrant call from triggering another
    1018             :     // generation.
    1019           0 :     nsXULElement *xulcontent = nsXULElement::FromContent(aElement);
    1020           0 :     if (xulcontent) {
    1021           0 :         if (xulcontent->GetTemplateGenerated())
    1022           0 :             return NS_OK;
    1023             : 
    1024             :         // Now mark the element's contents as being generated so that
    1025             :         // any re-entrant calls don't trigger an infinite recursion.
    1026           0 :         xulcontent->SetTemplateGenerated();
    1027             :     }
    1028             : 
    1029           0 :     int32_t newIndexInContainer = -1;
    1030           0 :     nsIContent* container = nullptr;
    1031             : 
    1032           0 :     int32_t querySetCount = mQuerySets.Length();
    1033             : 
    1034           0 :     for (int32_t r = 0; r < querySetCount; r++) {
    1035           0 :         nsTemplateQuerySet* queryset = mQuerySets[r];
    1036             : 
    1037           0 :         nsIAtom* tag = queryset->GetTag();
    1038           0 :         if (tag && tag != aElement->NodeInfo()->NameAtom())
    1039           0 :             continue;
    1040             : 
    1041           0 :         CreateContainerContentsForQuerySet(aElement, aResult, aNotify, queryset,
    1042           0 :                                            &container, &newIndexInContainer);
    1043             :     }
    1044             : 
    1045           0 :     if (aNotifyAtEnd && container) {
    1046           0 :         MOZ_AUTO_DOC_UPDATE(container->GetUncomposedDoc(), UPDATE_CONTENT_MODEL,
    1047             :                             true);
    1048           0 :         nsNodeUtils::ContentAppended(container,
    1049           0 :                                      container->GetChildAt(newIndexInContainer),
    1050           0 :                                      newIndexInContainer);
    1051             :     }
    1052             : 
    1053           0 :     NS_IF_RELEASE(container);
    1054             : 
    1055           0 :     return NS_OK;
    1056             : }
    1057             : 
    1058             : nsresult
    1059           0 : nsXULContentBuilder::CreateContainerContentsForQuerySet(nsIContent* aElement,
    1060             :                                                         nsIXULTemplateResult* aResult,
    1061             :                                                         bool aNotify,
    1062             :                                                         nsTemplateQuerySet* aQuerySet,
    1063             :                                                         nsIContent** aContainer,
    1064             :                                                         int32_t* aNewIndexInContainer)
    1065             : {
    1066           0 :     if (MOZ_LOG_TEST(gXULTemplateLog, LogLevel::Debug)) {
    1067           0 :         nsAutoString id;
    1068           0 :         aResult->GetId(id);
    1069           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
    1070             :                ("nsXULContentBuilder::CreateContainerContentsForQuerySet start for ref %s\n",
    1071             :                NS_ConvertUTF16toUTF8(id).get()));
    1072             :     }
    1073             : 
    1074           0 :     if (! mQueryProcessor)
    1075           0 :         return NS_OK;
    1076             : 
    1077           0 :     nsCOMPtr<nsISimpleEnumerator> results;
    1078           0 :     nsresult rv = mQueryProcessor->GenerateResults(mDataSource, aResult,
    1079             :                                                    aQuerySet->mCompiledQuery,
    1080           0 :                                                    getter_AddRefs(results));
    1081           0 :     if (NS_FAILED(rv) || !results)
    1082           0 :         return rv;
    1083             : 
    1084             :     bool hasMoreResults;
    1085           0 :     rv = results->HasMoreElements(&hasMoreResults);
    1086             : 
    1087           0 :     for (; NS_SUCCEEDED(rv) && hasMoreResults;
    1088           0 :            rv = results->HasMoreElements(&hasMoreResults)) {
    1089           0 :         nsCOMPtr<nsISupports> nr;
    1090           0 :         rv = results->GetNext(getter_AddRefs(nr));
    1091           0 :         if (NS_FAILED(rv))
    1092           0 :             return rv;
    1093             : 
    1094           0 :         nsCOMPtr<nsIXULTemplateResult> nextresult = do_QueryInterface(nr);
    1095           0 :         if (!nextresult)
    1096           0 :             return NS_ERROR_UNEXPECTED;
    1097             : 
    1098           0 :         nsCOMPtr<nsIRDFResource> resultid;
    1099           0 :         rv = GetResultResource(nextresult, getter_AddRefs(resultid));
    1100           0 :         if (NS_FAILED(rv))
    1101           0 :             return rv;
    1102             : 
    1103           0 :         if (!resultid)
    1104           0 :             continue;
    1105             : 
    1106             :         nsTemplateMatch *newmatch =
    1107           0 :             nsTemplateMatch::Create(aQuerySet->Priority(),
    1108           0 :                                     nextresult, aElement);
    1109           0 :         if (!newmatch)
    1110           0 :             return NS_ERROR_OUT_OF_MEMORY;
    1111             : 
    1112             :         // check if there is already an existing match. If so, a previous
    1113             :         // query already generated content so the match is just added to the
    1114             :         // end of the set of matches.
    1115             : 
    1116           0 :         bool generateContent = true;
    1117             : 
    1118           0 :         nsTemplateMatch* prevmatch = nullptr;
    1119           0 :         nsTemplateMatch* existingmatch = nullptr;
    1120           0 :         nsTemplateMatch* removematch = nullptr;
    1121           0 :         if (mMatchMap.Get(resultid, &existingmatch)){
    1122             :             // check if there is an existing match that matched a rule
    1123           0 :             while (existingmatch) {
    1124             :                 // break out once we've reached a query in the list with a
    1125             :                 // higher priority, as the new match list is sorted by
    1126             :                 // priority, and the new match should be inserted here
    1127           0 :                 int32_t priority = existingmatch->QuerySetPriority();
    1128           0 :                 if (priority > aQuerySet->Priority())
    1129           0 :                     break;
    1130             : 
    1131             :                 // skip over non-matching containers
    1132           0 :                 if (existingmatch->GetContainer() == aElement) {
    1133             :                     // if the same priority is already found, replace it. This can happen
    1134             :                     // when a container is removed and readded
    1135           0 :                     if (priority == aQuerySet->Priority()) {
    1136           0 :                         removematch = existingmatch;
    1137           0 :                         break;
    1138             :                     }
    1139             : 
    1140           0 :                     if (existingmatch->IsActive())
    1141           0 :                         generateContent = false;
    1142             :                 }
    1143             : 
    1144           0 :                 prevmatch = existingmatch;
    1145           0 :                 existingmatch = existingmatch->mNext;
    1146             :             }
    1147             :         }
    1148             : 
    1149           0 :         if (removematch) {
    1150             :             // remove the generated content for the existing match
    1151           0 :             rv = ReplaceMatch(removematch->mResult, nullptr, nullptr, aElement);
    1152           0 :             if (NS_FAILED(rv))
    1153           0 :                 return rv;
    1154             : 
    1155           0 :             if (mFlags & eLoggingEnabled)
    1156           0 :                 OutputMatchToLog(resultid, removematch, false);
    1157             :         }
    1158             : 
    1159           0 :         if (generateContent) {
    1160             :             // find the rule that matches. If none match, the content does not
    1161             :             // need to be generated
    1162             : 
    1163             :             int16_t ruleindex;
    1164           0 :             nsTemplateRule* matchedrule = nullptr;
    1165           0 :             rv = DetermineMatchedRule(aElement, nextresult, aQuerySet,
    1166           0 :                                       &matchedrule, &ruleindex);
    1167           0 :             if (NS_FAILED(rv)) {
    1168           0 :                 nsTemplateMatch::Destroy(newmatch, false);
    1169           0 :                 return rv;
    1170             :             }
    1171             : 
    1172           0 :             if (matchedrule) {
    1173           0 :                 rv = newmatch->RuleMatched(aQuerySet, matchedrule,
    1174           0 :                                            ruleindex, nextresult);
    1175           0 :                 if (NS_FAILED(rv)) {
    1176           0 :                     nsTemplateMatch::Destroy(newmatch, false);
    1177           0 :                     return rv;
    1178             :                 }
    1179             : 
    1180             :                 // Grab the template node
    1181           0 :                 nsCOMPtr<nsIContent> action = matchedrule->GetAction();
    1182           0 :                 BuildContentFromTemplate(action, aElement, aElement, true,
    1183           0 :                                          mRefVariable == matchedrule->GetMemberVariable(),
    1184             :                                          nextresult, aNotify, newmatch,
    1185           0 :                                          aContainer, aNewIndexInContainer);
    1186             :             }
    1187             :         }
    1188             : 
    1189           0 :         if (mFlags & eLoggingEnabled)
    1190           0 :             OutputMatchToLog(resultid, newmatch, true);
    1191             : 
    1192           0 :         if (prevmatch) {
    1193           0 :             prevmatch->mNext = newmatch;
    1194             :         }
    1195             :         else {
    1196           0 :             mMatchMap.Put(resultid, newmatch);
    1197             :         }
    1198             : 
    1199           0 :         if (removematch) {
    1200           0 :             newmatch->mNext = removematch->mNext;
    1201           0 :             nsTemplateMatch::Destroy(removematch, true);
    1202             :         }
    1203             :         else {
    1204           0 :             newmatch->mNext = existingmatch;
    1205             :         }
    1206             :     }
    1207             : 
    1208           0 :     return rv;
    1209             : }
    1210             : 
    1211             : nsresult
    1212           0 : nsXULContentBuilder::EnsureElementHasGenericChild(nsIContent* parent,
    1213             :                                                   int32_t nameSpaceID,
    1214             :                                                   nsIAtom* tag,
    1215             :                                                   bool aNotify,
    1216             :                                                   nsIContent** result)
    1217             : {
    1218             :     nsresult rv;
    1219             : 
    1220           0 :     rv = nsXULContentUtils::FindChildByTag(parent, nameSpaceID, tag, result);
    1221           0 :     if (NS_FAILED(rv))
    1222           0 :         return rv;
    1223             : 
    1224           0 :     if (rv == NS_RDF_NO_VALUE) {
    1225             :         // we need to construct a new child element.
    1226           0 :         nsCOMPtr<Element> element;
    1227             : 
    1228           0 :         rv = CreateElement(nameSpaceID, tag, getter_AddRefs(element));
    1229           0 :         if (NS_FAILED(rv))
    1230           0 :             return rv;
    1231             : 
    1232             :         // XXX Note that the notification ensures we won't batch insertions! This could be bad! - Dave
    1233           0 :         rv = parent->AppendChildTo(element, aNotify);
    1234           0 :         if (NS_FAILED(rv))
    1235           0 :             return rv;
    1236             : 
    1237           0 :         element.forget(result);
    1238           0 :         return NS_ELEMENT_GOT_CREATED;
    1239             :     }
    1240             :     else {
    1241           0 :         return NS_ELEMENT_WAS_THERE;
    1242             :     }
    1243             : }
    1244             : 
    1245             : bool
    1246           0 : nsXULContentBuilder::IsOpen(nsIContent* aElement)
    1247             : {
    1248             :     // Determine if this is a <treeitem> or <menu> element
    1249             : 
    1250             :     // XXXhyatt Use the XBL service to obtain a base tag.
    1251           0 :     if (aElement->IsAnyOfXULElements(nsGkAtoms::menu,
    1252             :                                      nsGkAtoms::menubutton,
    1253             :                                      nsGkAtoms::toolbarbutton,
    1254             :                                      nsGkAtoms::button,
    1255             :                                      nsGkAtoms::treeitem))
    1256           0 :         return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
    1257           0 :                                      nsGkAtoms::_true, eCaseMatters);
    1258           0 :     return true;
    1259             : }
    1260             : 
    1261             : nsresult
    1262           0 : nsXULContentBuilder::RemoveGeneratedContent(nsIContent* aElement)
    1263             : {
    1264             :     // Keep a queue of "ungenerated" elements that we have to probe
    1265             :     // for generated content.
    1266           0 :     AutoTArray<nsIContent*, 8> ungenerated;
    1267           0 :     if (ungenerated.AppendElement(aElement) == nullptr)
    1268           0 :         return NS_ERROR_OUT_OF_MEMORY;
    1269             : 
    1270             :     uint32_t count;
    1271           0 :     while (0 != (count = ungenerated.Length())) {
    1272             :         // Pull the next "ungenerated" element off the queue.
    1273           0 :         uint32_t last = count - 1;
    1274           0 :         nsCOMPtr<nsIContent> element = ungenerated[last];
    1275           0 :         ungenerated.RemoveElementAt(last);
    1276             : 
    1277           0 :         uint32_t i = element->GetChildCount();
    1278             : 
    1279           0 :         while (i-- > 0) {
    1280           0 :             nsCOMPtr<nsIContent> child = element->GetChildAt(i);
    1281             : 
    1282             :             // Optimize for the <template> element, because we *know*
    1283             :             // it won't have any generated content: there's no reason
    1284             :             // to even check this subtree.
    1285             :             // XXX should this check |child| rather than |element|? Otherwise
    1286             :             //     it should be moved outside the inner loop. Bug 297290.
    1287           0 :             if (element->NodeInfo()->Equals(nsGkAtoms::_template,
    1288           0 :                                             kNameSpaceID_XUL) ||
    1289           0 :                 !element->IsElement())
    1290           0 :                 continue;
    1291             : 
    1292             :             // If the element is in the template map, then we
    1293             :             // assume it's been generated and nuke it.
    1294           0 :             nsCOMPtr<nsIContent> tmpl;
    1295           0 :             mTemplateMap.GetTemplateFor(child, getter_AddRefs(tmpl));
    1296             : 
    1297           0 :             if (! tmpl) {
    1298             :                 // No 'template' attribute, so this must not have been
    1299             :                 // generated. We'll need to examine its kids.
    1300           0 :                 if (ungenerated.AppendElement(child) == nullptr)
    1301           0 :                     return NS_ERROR_OUT_OF_MEMORY;
    1302           0 :                 continue;
    1303             :             }
    1304             : 
    1305             :             // If we get here, it's "generated". Bye bye!
    1306           0 :             element->RemoveChildAt(i, true);
    1307             : 
    1308             :             // Remove this and any children from the content support map.
    1309           0 :             mContentSupportMap.Remove(child);
    1310             : 
    1311             :             // Remove from the template map
    1312           0 :             mTemplateMap.Remove(child);
    1313             :         }
    1314             :     }
    1315             : 
    1316           0 :     return NS_OK;
    1317             : }
    1318             : 
    1319             : nsresult
    1320           0 : nsXULContentBuilder::GetElementsForResult(nsIXULTemplateResult* aResult,
    1321             :                                           nsCOMArray<nsIContent>& aElements)
    1322             : {
    1323             :     // if the root has been removed from the document, just return
    1324             :     // since there won't be any generated content any more
    1325           0 :     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc());
    1326           0 :     if (! xuldoc)
    1327           0 :         return NS_OK;
    1328             : 
    1329           0 :     nsAutoString id;
    1330           0 :     aResult->GetId(id);
    1331             : 
    1332           0 :     xuldoc->GetElementsForID(id, aElements);
    1333             : 
    1334           0 :     return NS_OK;
    1335             : }
    1336             : 
    1337             : nsresult
    1338           0 : nsXULContentBuilder::CreateElement(int32_t aNameSpaceID,
    1339             :                                    nsIAtom* aTag,
    1340             :                                    Element** aResult)
    1341             : {
    1342           0 :     nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc();
    1343           0 :     NS_ASSERTION(doc != nullptr, "not initialized");
    1344           0 :     if (! doc)
    1345           0 :         return NS_ERROR_NOT_INITIALIZED;
    1346             : 
    1347             :     RefPtr<mozilla::dom::NodeInfo> nodeInfo =
    1348           0 :         doc->NodeInfoManager()->GetNodeInfo(aTag, nullptr, aNameSpaceID,
    1349           0 :                                             nsIDOMNode::ELEMENT_NODE);
    1350             : 
    1351           0 :     return NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER);
    1352             : }
    1353             : 
    1354             : nsresult
    1355           0 : nsXULContentBuilder::SetContainerAttrs(nsIContent *aElement,
    1356             :                                        nsIXULTemplateResult* aResult,
    1357             :                                        bool aIgnoreNonContainers,
    1358             :                                        bool aNotify)
    1359             : {
    1360           0 :     NS_PRECONDITION(aResult != nullptr, "null ptr");
    1361           0 :     if (! aResult)
    1362           0 :         return NS_ERROR_NULL_POINTER;
    1363             : 
    1364             :     bool iscontainer;
    1365           0 :     aResult->GetIsContainer(&iscontainer);
    1366             : 
    1367           0 :     if (aIgnoreNonContainers && !iscontainer)
    1368           0 :         return NS_OK;
    1369             : 
    1370           0 :     NS_NAMED_LITERAL_STRING(true_, "true");
    1371           0 :     NS_NAMED_LITERAL_STRING(false_, "false");
    1372             : 
    1373             :     const nsAString& newcontainer =
    1374           0 :         iscontainer ? true_ : false_;
    1375             : 
    1376           0 :     aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::container,
    1377           0 :                       newcontainer, aNotify);
    1378             : 
    1379           0 :     if (iscontainer && !(mFlags & eDontTestEmpty)) {
    1380             :         bool isempty;
    1381           0 :         aResult->GetIsEmpty(&isempty);
    1382             : 
    1383             :         const nsAString& newempty =
    1384           0 :             (iscontainer && isempty) ? true_ : false_;
    1385             : 
    1386           0 :         aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::empty,
    1387           0 :                           newempty, aNotify);
    1388             :     }
    1389             : 
    1390           0 :     return NS_OK;
    1391             : }
    1392             : 
    1393             : 
    1394             : //----------------------------------------------------------------------
    1395             : //
    1396             : // nsIXULTemplateBuilder methods
    1397             : //
    1398             : 
    1399             : NS_IMETHODIMP
    1400           0 : nsXULContentBuilder::CreateContents(nsIContent* aElement, bool aForceCreation)
    1401             : {
    1402           0 :     NS_PRECONDITION(aElement != nullptr, "null ptr");
    1403           0 :     if (! aElement)
    1404           0 :         return NS_ERROR_NULL_POINTER;
    1405             : 
    1406             :     // don't build contents for closed elements. aForceCreation will be true
    1407             :     // when a menu is about to be opened, so the content should be built anyway.
    1408           0 :     if (!aForceCreation && !IsOpen(aElement))
    1409           0 :         return NS_OK;
    1410             : 
    1411           0 :     return CreateTemplateAndContainerContents(aElement, aForceCreation);
    1412             : }
    1413             : 
    1414             : bool
    1415           0 : nsXULContentBuilder::HasGeneratedContent(nsIRDFResource* aResource,
    1416             :                                          const nsAString& aTag,
    1417             :                                          ErrorResult& aError)
    1418             : {
    1419           0 :     if (!mRoot || !mRootResult) {
    1420           0 :         aError.Throw(NS_ERROR_NOT_INITIALIZED);
    1421           0 :         return false;
    1422             :     }
    1423             : 
    1424           0 :     nsCOMPtr<nsIRDFResource> rootresource;
    1425           0 :     aError = mRootResult->GetResource(getter_AddRefs(rootresource));
    1426           0 :     if (aError.Failed()) {
    1427           0 :         return false;
    1428             :     }
    1429             : 
    1430             :     // the root resource is always acceptable
    1431           0 :     if (aResource == rootresource) {
    1432           0 :         return DOMStringIsNull(aTag) || mRoot->NodeInfo()->LocalName().Equals(aTag);
    1433             :     }
    1434             : 
    1435             :     const char* uri;
    1436           0 :     aResource->GetValueConst(&uri);
    1437             : 
    1438           0 :     NS_ConvertUTF8toUTF16 refID(uri);
    1439             : 
    1440             :     // just return if the node is no longer in a document
    1441           0 :     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc());
    1442           0 :     if (!xuldoc) {
    1443           0 :         return false;
    1444             :     }
    1445             : 
    1446           0 :     nsCOMArray<nsIContent> elements;
    1447           0 :     xuldoc->GetElementsForID(refID, elements);
    1448             : 
    1449           0 :     uint32_t cnt = elements.Count();
    1450             : 
    1451           0 :     for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
    1452           0 :         nsCOMPtr<nsIContent> content = elements.SafeObjectAt(i);
    1453             : 
    1454           0 :         do {
    1455             :             nsTemplateMatch* match;
    1456           0 :             if (content == mRoot || mContentSupportMap.Get(content, &match)) {
    1457             :                 // If we've got a tag, check it to ensure we're consistent.
    1458           0 :                 if (DOMStringIsNull(aTag) || content->NodeInfo()->LocalName().Equals(aTag)) {
    1459           0 :                     return true;
    1460             :                 }
    1461             :             }
    1462             : 
    1463           0 :             content = content->GetParent();
    1464             :         } while (content);
    1465             :     }
    1466             : 
    1467           0 :     return false;
    1468             : }
    1469             : 
    1470             : nsIXULTemplateResult*
    1471           0 : nsXULContentBuilder::GetResultForContent(Element& aElement)
    1472             : {
    1473           0 :     if (&aElement == mRoot) {
    1474           0 :         return mRootResult;
    1475             :     }
    1476             : 
    1477             :     nsTemplateMatch* match;
    1478           0 :     return mContentSupportMap.Get(&aElement, &match) ? match->mResult.get() : nullptr;
    1479             : }
    1480             : 
    1481             : //----------------------------------------------------------------------
    1482             : //
    1483             : // nsIDocumentObserver methods
    1484             : //
    1485             : 
    1486             : void
    1487           0 : nsXULContentBuilder::AttributeChanged(nsIDocument* aDocument,
    1488             :                                       Element*     aElement,
    1489             :                                       int32_t      aNameSpaceID,
    1490             :                                       nsIAtom*     aAttribute,
    1491             :                                       int32_t      aModType,
    1492             :                                       const nsAttrValue* aOldValue)
    1493             : {
    1494           0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1495             : 
    1496             :     // Handle "open" and "close" cases. We do this handling before
    1497             :     // we've notified the observer, so that content is already created
    1498             :     // for the frame system to walk.
    1499           0 :     if (aElement->GetNameSpaceID() == kNameSpaceID_XUL &&
    1500           0 :         aAttribute == nsGkAtoms::open) {
    1501             :         // We're on a XUL tag, and an ``open'' attribute changed.
    1502           0 :         if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
    1503             :                                   nsGkAtoms::_true, eCaseMatters))
    1504           0 :             OpenContainer(aElement);
    1505             :         else
    1506           0 :             CloseContainer(aElement);
    1507             :     }
    1508             : 
    1509           0 :     if ((aNameSpaceID == kNameSpaceID_XUL) &&
    1510           0 :         ((aAttribute == nsGkAtoms::sort) ||
    1511           0 :          (aAttribute == nsGkAtoms::sortDirection) ||
    1512           0 :          (aAttribute == nsGkAtoms::sortResource) ||
    1513           0 :          (aAttribute == nsGkAtoms::sortResource2)))
    1514           0 :         mSortState.initialized = false;
    1515             : 
    1516             :     // Pass along to the generic template builder.
    1517           0 :     nsXULTemplateBuilder::AttributeChanged(aDocument, aElement, aNameSpaceID,
    1518           0 :                                            aAttribute, aModType, aOldValue);
    1519           0 : }
    1520             : 
    1521             : void
    1522           0 : nsXULContentBuilder::NodeWillBeDestroyed(const nsINode* aNode)
    1523             : {
    1524           0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1525             :     // Break circular references
    1526           0 :     mContentSupportMap.Clear();
    1527             : 
    1528           0 :     nsXULTemplateBuilder::NodeWillBeDestroyed(aNode);
    1529           0 : }
    1530             : 
    1531             : 
    1532             : //----------------------------------------------------------------------
    1533             : //
    1534             : // nsXULTemplateBuilder methods
    1535             : //
    1536             : 
    1537             : bool
    1538           0 : nsXULContentBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
    1539             :                                            nsCOMArray<nsIContent>** aLocations)
    1540             : {
    1541           0 :     *aLocations = nullptr;
    1542             : 
    1543           0 :     nsAutoString ref;
    1544           0 :     nsresult rv = aResult->GetBindingFor(mRefVariable, ref);
    1545           0 :     if (NS_FAILED(rv))
    1546           0 :         return false;
    1547             : 
    1548           0 :     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mRoot->GetComposedDoc());
    1549           0 :     if (! xuldoc)
    1550           0 :         return false;
    1551             : 
    1552           0 :     *aLocations = new nsCOMArray<nsIContent>;
    1553           0 :     NS_ENSURE_TRUE(*aLocations, false);
    1554             : 
    1555           0 :     xuldoc->GetElementsForID(ref, **aLocations);
    1556           0 :     uint32_t count = (*aLocations)->Count();
    1557             : 
    1558           0 :     bool found = false;
    1559             : 
    1560           0 :     for (uint32_t t = 0; t < count; t++) {
    1561           0 :         nsCOMPtr<nsIContent> content = (*aLocations)->SafeObjectAt(t);
    1562             : 
    1563             :         nsTemplateMatch* refmatch;
    1564           0 :         if (content == mRoot || mContentSupportMap.Get(content, &refmatch)) {
    1565             :             // See if we've built the container contents for "content"
    1566             :             // yet. If not, we don't need to build any content. This
    1567             :             // happens, for example, if we receive an assertion on a
    1568             :             // closed folder in a tree widget or on a menu that hasn't
    1569             :             // yet been opened.
    1570           0 :             nsXULElement *xulcontent = nsXULElement::FromContent(content);
    1571           0 :             if (!xulcontent || xulcontent->GetTemplateGenerated()) {
    1572           0 :                 found = true;
    1573           0 :                 continue;
    1574             :             }
    1575             :         }
    1576             : 
    1577             :         // clear the item in the list since we don't want to insert there
    1578           0 :         (*aLocations)->ReplaceObjectAt(nullptr, t);
    1579             :     }
    1580             : 
    1581           0 :     return found;
    1582             : }
    1583             : 
    1584             : nsresult
    1585           0 : nsXULContentBuilder::ReplaceMatch(nsIXULTemplateResult* aOldResult,
    1586             :                                   nsTemplateMatch* aNewMatch,
    1587             :                                   nsTemplateRule* aNewMatchRule,
    1588             :                                   void *aContext)
    1589             : 
    1590             : {
    1591             :     nsresult rv;
    1592           0 :     nsIContent* content = static_cast<nsIContent*>(aContext);
    1593             : 
    1594             :     // update the container attributes for the match
    1595           0 :     if (content) {
    1596           0 :         nsAutoString ref;
    1597           0 :         if (aNewMatch)
    1598           0 :             rv = aNewMatch->mResult->GetBindingFor(mRefVariable, ref);
    1599             :         else
    1600           0 :             rv = aOldResult->GetBindingFor(mRefVariable, ref);
    1601           0 :         if (NS_FAILED(rv))
    1602           0 :             return rv;
    1603             : 
    1604           0 :         if (!ref.IsEmpty()) {
    1605           0 :             nsCOMPtr<nsIXULTemplateResult> refResult;
    1606           0 :             rv = GetResultForId(ref, getter_AddRefs(refResult));
    1607           0 :             if (NS_FAILED(rv))
    1608           0 :                 return rv;
    1609             : 
    1610           0 :             if (refResult)
    1611           0 :                 SetContainerAttrs(content, refResult, false, true);
    1612             :         }
    1613             :     }
    1614             : 
    1615           0 :     if (aOldResult) {
    1616           0 :         nsCOMArray<nsIContent> elements;
    1617           0 :         rv = GetElementsForResult(aOldResult, elements);
    1618           0 :         if (NS_FAILED(rv))
    1619           0 :             return rv;
    1620             : 
    1621           0 :         uint32_t count = elements.Count();
    1622             : 
    1623           0 :         for (int32_t e = int32_t(count) - 1; e >= 0; --e) {
    1624           0 :             nsCOMPtr<nsIContent> child = elements.SafeObjectAt(e);
    1625             : 
    1626             :             nsTemplateMatch* match;
    1627           0 :             if (mContentSupportMap.Get(child, &match)) {
    1628           0 :                 if (content == match->GetContainer())
    1629           0 :                     RemoveMember(child);
    1630             :             }
    1631             :         }
    1632             :     }
    1633             : 
    1634           0 :     if (aNewMatch) {
    1635           0 :         nsCOMPtr<nsIContent> action = aNewMatchRule->GetAction();
    1636           0 :         return BuildContentFromTemplate(action, content, content, true,
    1637           0 :                                         mRefVariable == aNewMatchRule->GetMemberVariable(),
    1638             :                                         aNewMatch->mResult, true, aNewMatch,
    1639           0 :                                         nullptr, nullptr);
    1640             :     }
    1641             : 
    1642           0 :     return NS_OK;
    1643             : }
    1644             : 
    1645             : 
    1646             : nsresult
    1647           0 : nsXULContentBuilder::SynchronizeResult(nsIXULTemplateResult* aResult)
    1648             : {
    1649           0 :     nsCOMArray<nsIContent> elements;
    1650           0 :     GetElementsForResult(aResult, elements);
    1651             : 
    1652           0 :     uint32_t cnt = elements.Count();
    1653             : 
    1654           0 :     for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
    1655           0 :         nsCOMPtr<nsIContent> element = elements.SafeObjectAt(i);
    1656             : 
    1657             :         nsTemplateMatch* match;
    1658           0 :         if (! mContentSupportMap.Get(element, &match))
    1659           0 :             continue;
    1660             : 
    1661           0 :         nsCOMPtr<nsIContent> templateNode;
    1662           0 :         mTemplateMap.GetTemplateFor(element, getter_AddRefs(templateNode));
    1663             : 
    1664           0 :         NS_ASSERTION(templateNode, "couldn't find template node for element");
    1665           0 :         if (! templateNode)
    1666           0 :             continue;
    1667             : 
    1668             :         // this node was created by a XUL template, so update it accordingly
    1669           0 :         SynchronizeUsingTemplate(templateNode, element, aResult);
    1670             :     }
    1671             : 
    1672           0 :     return NS_OK;
    1673             : }
    1674             : 
    1675             : //----------------------------------------------------------------------
    1676             : //
    1677             : // Implementation methods
    1678             : //
    1679             : 
    1680             : nsresult
    1681           0 : nsXULContentBuilder::OpenContainer(nsIContent* aElement)
    1682             : {
    1683           0 :     if (aElement != mRoot) {
    1684           0 :         if (mFlags & eDontRecurse)
    1685           0 :             return NS_OK;
    1686             : 
    1687           0 :         bool rightBuilder = false;
    1688             : 
    1689           0 :         nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(aElement->GetComposedDoc());
    1690           0 :         if (! xuldoc)
    1691           0 :             return NS_OK;
    1692             : 
    1693             :         // See if we're responsible for this element
    1694           0 :         nsIContent* content = aElement;
    1695           0 :         do {
    1696           0 :             nsCOMPtr<nsIXULTemplateBuilder> builder;
    1697           0 :             xuldoc->GetTemplateBuilderFor(content, getter_AddRefs(builder));
    1698           0 :             if (builder) {
    1699           0 :                 if (builder == this)
    1700           0 :                     rightBuilder = true;
    1701           0 :                 break;
    1702             :             }
    1703             : 
    1704           0 :             content = content->GetParent();
    1705           0 :         } while (content);
    1706             : 
    1707           0 :         if (! rightBuilder)
    1708           0 :             return NS_OK;
    1709             :     }
    1710             : 
    1711           0 :     CreateTemplateAndContainerContents(aElement, false);
    1712             : 
    1713           0 :     return NS_OK;
    1714             : }
    1715             : 
    1716             : nsresult
    1717           0 : nsXULContentBuilder::CloseContainer(nsIContent* aElement)
    1718             : {
    1719           0 :     return NS_OK;
    1720             : }
    1721             : 
    1722             : nsresult
    1723           0 : nsXULContentBuilder::RebuildAll()
    1724             : {
    1725           0 :     NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED);
    1726             : 
    1727             :     // Bail out early if we are being torn down.
    1728           0 :     nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc();
    1729           0 :     if (!doc)
    1730           0 :         return NS_OK;
    1731             : 
    1732           0 :     if (mQueriesCompiled)
    1733           0 :         Uninit(false);
    1734             : 
    1735           0 :     nsresult rv = CompileQueries();
    1736           0 :     if (NS_FAILED(rv))
    1737           0 :         return rv;
    1738             : 
    1739           0 :     if (mQuerySets.Length() == 0)
    1740           0 :         return NS_OK;
    1741             : 
    1742           0 :     nsXULElement *xulcontent = nsXULElement::FromContent(mRoot);
    1743           0 :     if (xulcontent)
    1744           0 :         xulcontent->ClearTemplateGenerated();
    1745             : 
    1746             :     // Now, regenerate both the template- and container-generated
    1747             :     // contents for the current element...
    1748           0 :     CreateTemplateAndContainerContents(mRoot, false);
    1749             : 
    1750           0 :     return NS_OK;
    1751             : }
    1752             : 
    1753             : /**** Sorting Methods ****/
    1754             : 
    1755             : nsresult
    1756           0 : nsXULContentBuilder::CompareResultToNode(nsIXULTemplateResult* aResult,
    1757             :                                          nsIContent* aContent,
    1758             :                                          int32_t* aSortOrder)
    1759             : {
    1760           0 :     NS_ASSERTION(aSortOrder, "CompareResultToNode: null out param aSortOrder");
    1761             : 
    1762           0 :     *aSortOrder = 0;
    1763             : 
    1764           0 :     nsTemplateMatch *match = nullptr;
    1765           0 :     if (!mContentSupportMap.Get(aContent, &match)) {
    1766           0 :         *aSortOrder = mSortState.sortStaticsLast ? -1 : 1;
    1767           0 :         return NS_OK;
    1768             :     }
    1769             : 
    1770           0 :     if (!mQueryProcessor)
    1771           0 :         return NS_OK;
    1772             : 
    1773           0 :     if (mSortState.direction == nsSortState_natural) {
    1774             :         // sort in natural order
    1775           0 :         nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult,
    1776             :                                                       nullptr, mSortState.sortHints,
    1777           0 :                                                       aSortOrder);
    1778           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1779             :     }
    1780             :     else {
    1781             :         // iterate over each sort key and compare. If the nodes are equal,
    1782             :         // continue to compare using the next sort key. If not equal, stop.
    1783           0 :         int32_t length = mSortState.sortKeys.Count();
    1784           0 :         for (int32_t t = 0; t < length; t++) {
    1785           0 :             nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult,
    1786             :                                                           mSortState.sortKeys[t],
    1787           0 :                                                           mSortState.sortHints, aSortOrder);
    1788           0 :             NS_ENSURE_SUCCESS(rv, rv);
    1789             : 
    1790           0 :             if (*aSortOrder)
    1791           0 :                 break;
    1792             :         }
    1793             :     }
    1794             : 
    1795             :     // flip the sort order if performing a descending sorting
    1796           0 :     if (mSortState.direction == nsSortState_descending)
    1797           0 :         *aSortOrder = -*aSortOrder;
    1798             : 
    1799           0 :     return NS_OK;
    1800             : }
    1801             : 
    1802             : nsresult
    1803           0 : nsXULContentBuilder::InsertSortedNode(nsIContent* aContainer,
    1804             :                                       nsIContent* aNode,
    1805             :                                       nsIXULTemplateResult* aResult,
    1806             :                                       bool aNotify)
    1807             : {
    1808             :     nsresult rv;
    1809             : 
    1810           0 :     if (!mSortState.initialized) {
    1811           0 :         nsAutoString sort, sortDirection, sortHints;
    1812           0 :         mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
    1813           0 :         mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, sortDirection);
    1814           0 :         mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, sortHints);
    1815           0 :         sortDirection += ' ';
    1816           0 :         sortDirection += sortHints;
    1817           0 :         rv = XULSortServiceImpl::InitializeSortState(mRoot, aContainer,
    1818           0 :                                                      sort, sortDirection, &mSortState);
    1819           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1820             :     }
    1821             : 
    1822             :     // when doing a natural sort, items will typically be sorted according to
    1823             :     // the order they appear in the datasource. For RDF, cache whether the
    1824             :     // reference parent is an RDF Seq. That way, the items can be sorted in the
    1825             :     // order they are in the Seq.
    1826           0 :     mSortState.isContainerRDFSeq = false;
    1827           0 :     if (mSortState.direction == nsSortState_natural) {
    1828           0 :         nsCOMPtr<nsISupports> ref;
    1829           0 :         nsresult rv = aResult->GetBindingObjectFor(mRefVariable, getter_AddRefs(ref));
    1830           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1831             : 
    1832           0 :         nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
    1833             : 
    1834           0 :         if (container) {
    1835           0 :             rv = gRDFContainerUtils->IsSeq(mDB, container, &mSortState.isContainerRDFSeq);
    1836           0 :             NS_ENSURE_SUCCESS(rv, rv);
    1837             :         }
    1838             :     }
    1839             : 
    1840           0 :     bool childAdded = false;
    1841           0 :     uint32_t numChildren = aContainer->GetChildCount();
    1842             : 
    1843           0 :     if (mSortState.direction != nsSortState_natural ||
    1844           0 :         (mSortState.direction == nsSortState_natural && mSortState.isContainerRDFSeq))
    1845             :     {
    1846             :         // because numChildren gets modified
    1847           0 :         int32_t realNumChildren = numChildren;
    1848           0 :         nsIContent *child = nullptr;
    1849             : 
    1850             :         // rjc says: determine where static XUL ends and generated XUL/RDF begins
    1851           0 :         int32_t staticCount = 0;
    1852             : 
    1853           0 :         nsAutoString staticValue;
    1854           0 :         aContainer->GetAttr(kNameSpaceID_None, nsGkAtoms::staticHint, staticValue);
    1855           0 :         if (!staticValue.IsEmpty())
    1856             :         {
    1857             :             // found "static" XUL element count hint
    1858           0 :             nsresult strErr = NS_OK;
    1859           0 :             staticCount = staticValue.ToInteger(&strErr);
    1860           0 :             if (NS_FAILED(strErr))
    1861           0 :                 staticCount = 0;
    1862             :         } else {
    1863             :             // compute the "static" XUL element count
    1864           0 :             for (nsIContent* child = aContainer->GetFirstChild();
    1865           0 :                  child;
    1866           0 :                  child = child->GetNextSibling()) {
    1867             : 
    1868           0 :                 if (nsContentUtils::HasNonEmptyAttr(child, kNameSpaceID_None,
    1869             :                                                     nsGkAtoms::_template))
    1870           0 :                     break;
    1871             :                 else
    1872           0 :                     ++staticCount;
    1873             :             }
    1874             : 
    1875           0 :             if (mSortState.sortStaticsLast) {
    1876             :                 // indicate that static XUL comes after RDF-generated content by
    1877             :                 // making negative
    1878           0 :                 staticCount = -staticCount;
    1879             :             }
    1880             : 
    1881             :             // save the "static" XUL element count hint
    1882           0 :             nsAutoString valueStr;
    1883           0 :             valueStr.AppendInt(staticCount);
    1884           0 :             aContainer->SetAttr(kNameSpaceID_None, nsGkAtoms::staticHint, valueStr, false);
    1885             :         }
    1886             : 
    1887           0 :         if (staticCount <= 0) {
    1888           0 :             numChildren += staticCount;
    1889           0 :             staticCount = 0;
    1890           0 :         } else if (staticCount > (int32_t)numChildren) {
    1891           0 :             staticCount = numChildren;
    1892           0 :             numChildren -= staticCount;
    1893             :         }
    1894             : 
    1895             :         // figure out where to insert the node when a sort order is being imposed
    1896           0 :         if (numChildren > 0) {
    1897             :             nsIContent *temp;
    1898             :             int32_t direction;
    1899             : 
    1900             :             // rjc says: The following is an implementation of a fairly optimal
    1901             :             // binary search insertion sort... with interpolation at either end-point.
    1902             : 
    1903           0 :             if (mSortState.lastWasFirst) {
    1904           0 :                 child = aContainer->GetChildAt(staticCount);
    1905           0 :                 temp = child;
    1906           0 :                 rv = CompareResultToNode(aResult, temp, &direction);
    1907           0 :                 if (direction < 0) {
    1908           0 :                     aContainer->InsertChildAt(aNode, staticCount, aNotify);
    1909           0 :                     childAdded = true;
    1910             :                 } else
    1911           0 :                     mSortState.lastWasFirst = false;
    1912           0 :             } else if (mSortState.lastWasLast) {
    1913           0 :                 child = aContainer->GetChildAt(realNumChildren - 1);
    1914           0 :                 temp = child;
    1915           0 :                 rv = CompareResultToNode(aResult, temp, &direction);
    1916           0 :                 if (direction > 0) {
    1917           0 :                     aContainer->InsertChildAt(aNode, realNumChildren, aNotify);
    1918           0 :                     childAdded = true;
    1919             :                 } else
    1920           0 :                     mSortState.lastWasLast = false;
    1921             :             }
    1922             : 
    1923           0 :             int32_t left = staticCount + 1, right = realNumChildren, x;
    1924           0 :             while (!childAdded && right >= left) {
    1925           0 :                 x = (left + right) / 2;
    1926           0 :                 child = aContainer->GetChildAt(x - 1);
    1927           0 :                 temp = child;
    1928             : 
    1929           0 :                 rv = CompareResultToNode(aResult, temp, &direction);
    1930           0 :                 if ((x == left && direction < 0) ||
    1931           0 :                     (x == right && direction >= 0) ||
    1932             :                     left == right)
    1933             :                 {
    1934           0 :                     int32_t thePos = (direction > 0 ? x : x - 1);
    1935           0 :                     aContainer->InsertChildAt(aNode, thePos, aNotify);
    1936           0 :                     childAdded = true;
    1937             : 
    1938           0 :                     mSortState.lastWasFirst = (thePos == staticCount);
    1939           0 :                     mSortState.lastWasLast = (thePos >= realNumChildren);
    1940             : 
    1941           0 :                     break;
    1942             :                 }
    1943           0 :                 if (direction < 0)
    1944           0 :                     right = x - 1;
    1945             :                 else
    1946           0 :                     left = x + 1;
    1947             :             }
    1948             :         }
    1949             :     }
    1950             : 
    1951             :     // if the child hasn't been inserted yet, just add it at the end. Note
    1952             :     // that an append isn't done as there may be static content afterwards.
    1953           0 :     if (!childAdded)
    1954           0 :         aContainer->InsertChildAt(aNode, numChildren, aNotify);
    1955             : 
    1956           0 :     return NS_OK;
    1957             : }

Generated by: LCOV version 1.13