LCOV - code coverage report
Current view: top level - dom/xul/templates - nsXULTemplateBuilder.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 30 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 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             : #ifndef nsXULTemplateBuilder_h__
       7             : #define nsXULTemplateBuilder_h__
       8             : 
       9             : #include "mozilla/dom/Element.h"
      10             : #include "nsStubDocumentObserver.h"
      11             : #include "nsIObserver.h"
      12             : #include "nsIXULTemplateBuilder.h"
      13             : #include "nsCOMArray.h"
      14             : #include "nsTArray.h"
      15             : #include "nsDataHashtable.h"
      16             : #include "nsCycleCollectionParticipant.h"
      17             : 
      18             : #include "mozilla/Logging.h"
      19             : extern mozilla::LazyLogModule gXULTemplateLog;
      20             : 
      21             : class nsIObserverService;
      22             : class nsIRDFCompositeDataSource;
      23             : class nsIRDFContainerUtils;
      24             : class nsIRDFDataSource;
      25             : class nsIRDFService;
      26             : class nsIScriptSecurityManager;
      27             : class nsIXULTemplateQueryProcessor;
      28             : class nsTemplateCondition;
      29             : class nsTemplateRule;
      30             : class nsTemplateMatch;
      31             : class nsTemplateQuerySet;
      32             : 
      33             : namespace mozilla {
      34             : namespace dom {
      35             : 
      36             : class XULBuilderListener;
      37             : 
      38             : } // namespace dom
      39             : } // namespace mozilla
      40             : 
      41             : 
      42             : /**
      43             :  * An object that translates an RDF graph into a presentation using a
      44             :  * set of rules.
      45             :  */
      46             : class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
      47             :                              public nsIObserver,
      48             :                              public nsStubDocumentObserver,
      49             :                              public nsWrapperCache
      50             : {
      51             :     void CleanUp(bool aIsFinal);
      52             :     void DestroyMatchMap();
      53             : 
      54             : public:
      55             :     nsresult Init();
      56             : 
      57             :     nsresult InitGlobals();
      58             : 
      59             :     /**
      60             :      * Clear the template builder structures. The aIsFinal flag is set to true
      61             :      * when the template is going away.
      62             :      */
      63             :     virtual void Uninit(bool aIsFinal);
      64             : 
      65             :     // nsISupports interface
      66             :     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
      67           0 :     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsXULTemplateBuilder,
      68             :                                                            nsIXULTemplateBuilder)
      69             : 
      70             :     virtual JSObject* WrapObject(JSContext* aCx,
      71             :                                  JS::Handle<JSObject*> aGivenProto) override;
      72           0 :     Element* GetParentObject()
      73             :     {
      74           0 :       return mRoot;
      75             :     }
      76             : 
      77           0 :     Element* GetRoot()
      78             :     {
      79           0 :         return mRoot;
      80             :     }
      81             :     nsISupports* GetDatasource();
      82             :     void SetDatasource(nsISupports* aDatasource, mozilla::ErrorResult& aError);
      83           0 :     nsIRDFCompositeDataSource* GetDatabase()
      84             :     {
      85           0 :         return mCompDB;
      86             :     }
      87           0 :     nsIXULTemplateResult* GetRootResult()
      88             :     {
      89           0 :         return mRootResult;
      90             :     }
      91             :     void Rebuild(mozilla::ErrorResult& aError);
      92             :     void Refresh(mozilla::ErrorResult& aError);
      93             :     void AddResult(nsIXULTemplateResult* aResult, nsINode& aQueryNode,
      94             :                    mozilla::ErrorResult& aError);
      95             :     void RemoveResult(nsIXULTemplateResult* aResult,
      96             :                       mozilla::ErrorResult& aError);
      97             :     void ReplaceResult(nsIXULTemplateResult* aOldResult,
      98             :                        nsIXULTemplateResult* aNewResult,
      99             :                        nsINode& aQueryNode,
     100             :                        mozilla::ErrorResult& aError);
     101             :     void ResultBindingChanged(nsIXULTemplateResult* aResult,
     102             :                               mozilla::ErrorResult& aError);
     103             :     nsIXULTemplateResult* GetResultForId(const nsAString& aId,
     104             :                                          mozilla::ErrorResult& aError);
     105           0 :     virtual nsIXULTemplateResult* GetResultForContent(Element& aElement)
     106             :     {
     107           0 :         return nullptr;
     108             :     }
     109           0 :     virtual bool HasGeneratedContent(nsIRDFResource* aResource,
     110             :                                      const nsAString& aTag,
     111             :                                      mozilla::ErrorResult& aError)
     112             :     {
     113           0 :         return false;
     114             :     }
     115             :     void AddRuleFilter(nsINode& aRule, nsIXULTemplateRuleFilter* aFilter,
     116             :                        mozilla::ErrorResult& aError);
     117             :     void AddListener(mozilla::dom::XULBuilderListener& aListener);
     118             :     void RemoveListener(mozilla::dom::XULBuilderListener& aListener);
     119             : 
     120             :     // nsIXULTemplateBuilder interface
     121             :     NS_DECL_NSIXULTEMPLATEBUILDER
     122             : 
     123             :     // nsIObserver Interface
     124             :     NS_DECL_NSIOBSERVER
     125             : 
     126             :     // nsIMutationObserver
     127             :     NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
     128             :     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     129             :     NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
     130             : 
     131             :     /**
     132             :      * Remove an old result and/or add a new result. This method will retrieve
     133             :      * the set of containers where the result could be inserted and either add
     134             :      * the new result to those containers, or remove the result from those
     135             :      * containers. UpdateResultInContainer is called for each container.
     136             :      *
     137             :      * @param aOldResult result to remove
     138             :      * @param aNewResult result to add
     139             :      * @param aQueryNode query node for new result
     140             :      */
     141             :     nsresult
     142             :     UpdateResult(nsIXULTemplateResult* aOldResult,
     143             :                  nsIXULTemplateResult* aNewResult,
     144             :                  nsINode* aQueryNode);
     145             : 
     146             :     /**
     147             :      * Remove an old result and/or add a new result from a specific container.
     148             :      *
     149             :      * @param aOldResult result to remove
     150             :      * @param aNewResult result to add
     151             :      * @param aQueryNode queryset for the new result
     152             :      * @param aOldId id of old result
     153             :      * @param aNewId id of new result
     154             :      * @param aInsertionPoint container to remove or add result inside
     155             :      */
     156             :     nsresult
     157             :     UpdateResultInContainer(nsIXULTemplateResult* aOldResult,
     158             :                             nsIXULTemplateResult* aNewResult,
     159             :                             nsTemplateQuerySet* aQuerySet,
     160             :                             nsIRDFResource* aOldId,
     161             :                             nsIRDFResource* aNewId,
     162             :                             nsIContent* aInsertionPoint);
     163             : 
     164             :     nsresult
     165             :     ComputeContainmentProperties();
     166             : 
     167             :     static bool
     168             :     IsTemplateElement(nsIContent* aContent);
     169             : 
     170             :     virtual nsresult
     171             :     RebuildAll() = 0; // must be implemented by subclasses
     172             : 
     173           0 :     void RunnableRebuild() { Rebuild(); }
     174           0 :     void RunnableLoadAndRebuild() {
     175           0 :       Uninit(false);  // Reset results
     176             : 
     177           0 :       nsCOMPtr<nsIDocument> doc = mRoot ? mRoot->GetComposedDoc() : nullptr;
     178           0 :       if (doc) {
     179             :         bool shouldDelay;
     180           0 :         LoadDataSources(doc, &shouldDelay);
     181           0 :         if (!shouldDelay) {
     182           0 :           Rebuild();
     183             :         }
     184             :       }
     185           0 :     }
     186             : 
     187             :     // mRoot should not be cleared until after Uninit is finished so that
     188             :     // generated content can be removed during uninitialization.
     189           0 :     void UninitFalse() { Uninit(false); mRoot = nullptr; }
     190           0 :     void UninitTrue() { Uninit(true); mRoot = nullptr; }
     191             : 
     192             :     /**
     193             :      * Find the <template> tag that applies for this builder
     194             :      */
     195             :     nsresult
     196             :     GetTemplateRoot(nsIContent** aResult);
     197             : 
     198             :     /**
     199             :      * Compile the template's queries
     200             :      */
     201             :     nsresult
     202             :     CompileQueries();
     203             : 
     204             :     /**
     205             :      * Compile the template given a <template> in aTemplate. This function
     206             :      * is called recursively to handle queries inside a queryset. For the
     207             :      * outer pass, aIsQuerySet will be false, while the inner pass this will
     208             :      * be true.
     209             :      *
     210             :      * aCanUseTemplate will be set to true if the template's queries could be
     211             :      * compiled, and false otherwise. If false, the entire template is
     212             :      * invalid.
     213             :      *
     214             :      * @param aTemplate <template> to compile
     215             :      * @param aQuerySet first queryset
     216             :      * @param aIsQuerySet true if
     217             :      * @param aPriority the queryset index, incremented when a new one is added
     218             :      * @param aCanUseTemplate true if template is valid
     219             :      */
     220             :     nsresult
     221             :     CompileTemplate(nsIContent* aTemplate,
     222             :                     nsTemplateQuerySet* aQuerySet,
     223             :                     bool aIsQuerySet,
     224             :                     int32_t* aPriority,
     225             :                     bool* aCanUseTemplate);
     226             : 
     227             :     /**
     228             :      * Compile a query using the extended syntax. For backwards compatible RDF
     229             :      * syntax where there is no <query>, the <conditions> becomes the query.
     230             :      *
     231             :      * @param aRuleElement <rule> element
     232             :      * @param aActionElement <action> element
     233             :      * @param aMemberVariable member variable for the query
     234             :      * @param aQuerySet the queryset
     235             :      */
     236             :     nsresult
     237             :     CompileExtendedQuery(nsIContent* aRuleElement,
     238             :                          nsIContent* aActionElement,
     239             :                          nsIAtom* aMemberVariable,
     240             :                          nsTemplateQuerySet* aQuerySet);
     241             : 
     242             :     /**
     243             :      * Determine the ref variable and tag from inside a RDF query.
     244             :      */
     245             :     void DetermineRDFQueryRef(nsIContent* aQueryElement, nsIAtom** tag);
     246             : 
     247             :     /**
     248             :      * Determine the member variable from inside an action body. It will be
     249             :      * the value of the uri attribute on a node.
     250             :      */
     251             :     already_AddRefed<nsIAtom> DetermineMemberVariable(nsIContent* aElement);
     252             : 
     253             :     /**
     254             :      * Compile a simple query. A simple query is one that doesn't have a
     255             :      * <query> and should use a default query which would normally just return
     256             :      * a list of children of the reference point.
     257             :      *
     258             :      * @param aRuleElement the <rule>
     259             :      * @param aQuerySet the query set
     260             :      * @param aCanUseTemplate true if the query is valid
     261             :      */
     262             :     nsresult
     263             :     CompileSimpleQuery(nsIContent* aRuleElement,
     264             :                        nsTemplateQuerySet* aQuerySet,
     265             :                        bool* aCanUseTemplate);
     266             : 
     267             :     /**
     268             :      * Compile the <conditions> tag in a rule
     269             :      *
     270             :      * @param aRule template rule
     271             :      * @param aConditions <conditions> element
     272             :      */
     273             :     nsresult
     274             :     CompileConditions(nsTemplateRule* aRule, nsIContent* aConditions);
     275             : 
     276             :     /**
     277             :      * Compile a <where> tag in a condition. The caller should set
     278             :      * *aCurrentCondition to null for the first condition. This value will be
     279             :      * updated to point to the new condition before returning. The conditions
     280             :      * will be added to the rule aRule by this method.
     281             :      *
     282             :      * @param aRule template rule
     283             :      * @param aCondition <where> element
     284             :      * @param aCurrentCondition compiled condition
     285             :      */
     286             :     nsresult
     287             :     CompileWhereCondition(nsTemplateRule* aRule,
     288             :                           nsIContent* aCondition,
     289             :                           nsTemplateCondition** aCurrentCondition);
     290             : 
     291             :     /**
     292             :      * Compile the <bindings> for an extended template syntax rule.
     293             :      */
     294             :     nsresult
     295             :     CompileBindings(nsTemplateRule* aRule, nsIContent* aBindings);
     296             : 
     297             :     /**
     298             :      * Compile a single binding for an extended template syntax rule.
     299             :      */
     300             :     nsresult
     301             :     CompileBinding(nsTemplateRule* aRule, nsIContent* aBinding);
     302             : 
     303             :     /**
     304             :      * Add automatic bindings for simple rules
     305             :      */
     306             :     nsresult
     307             :     AddSimpleRuleBindings(nsTemplateRule* aRule, nsIContent* aElement);
     308             : 
     309             :     static void
     310             :     AddBindingsFor(nsXULTemplateBuilder* aSelf,
     311             :                    const nsAString& aVariable,
     312             :                    void* aClosure);
     313             : 
     314             :     /**
     315             :      * Load the datasources for the template. shouldDelayBuilding is an out
     316             :      * parameter which will be set to true to indicate that content building
     317             :      * should not be performed yet as the datasource has not yet loaded. If
     318             :      * false, the datasource has already loaded so building can proceed
     319             :      * immediately. In the former case, the datasource or query processor
     320             :      * should either rebuild the template or update results when the
     321             :      * datasource is loaded as needed.
     322             :      */
     323             :     nsresult
     324             :     LoadDataSources(nsIDocument* aDoc, bool* shouldDelayBuilding);
     325             : 
     326             :     /**
     327             :      * Called by LoadDataSources to load a datasource given a uri list
     328             :      * in aDataSource. The list is a set of uris separated by spaces.
     329             :      * If aIsRDFQuery is true, then this is for an RDF datasource which
     330             :      * causes the method to check for additional flags specific to the
     331             :      * RDF processor.
     332             :      */
     333             :     nsresult
     334             :     LoadDataSourceUrls(nsIDocument* aDocument,
     335             :                        const nsAString& aDataSources,
     336             :                        bool aIsRDFQuery,
     337             :                        bool* aShouldDelayBuilding);
     338             : 
     339             :     nsresult
     340             :     InitHTMLTemplateRoot();
     341             : 
     342             :     /**
     343             :      * Determine which rule matches a given result. aContainer is used for
     344             :      * tag matching and is optional for non-content generating builders.
     345             :      * The returned matched rule is always one of the rules owned by the
     346             :      * query set aQuerySet.
     347             :      *
     348             :      * @param aContainer parent where generated content will be inserted
     349             :      * @param aResult result to match
     350             :      * @param aQuerySet query set to examine the rules of
     351             :      * @param aMatchedRule [out] rule that has matched, or null if any.
     352             :      * @param aRuleIndex [out] index of the rule
     353             :      */
     354             :     nsresult
     355             :     DetermineMatchedRule(nsIContent* aContainer,
     356             :                          nsIXULTemplateResult* aResult,
     357             :                          nsTemplateQuerySet* aQuerySet,
     358             :                          nsTemplateRule** aMatchedRule,
     359             :                          int16_t *aRuleIndex);
     360             : 
     361             :     // XXX sigh, the string template foo doesn't mix with
     362             :     // operator->*() on egcs-1.1.2, so we'll need to explicitly pass
     363             :     // "this" and use good ol' fashioned static callbacks.
     364             :     void
     365             :     ParseAttribute(const nsAString& aAttributeValue,
     366             :                    void (*aVariableCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
     367             :                    void (*aTextCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
     368             :                    void* aClosure);
     369             : 
     370             :     nsresult
     371             :     SubstituteText(nsIXULTemplateResult* aMatch,
     372             :                    const nsAString& aAttributeValue,
     373             :                    nsAString& aResult);
     374             : 
     375             :     static void
     376             :     SubstituteTextAppendText(nsXULTemplateBuilder* aThis, const nsAString& aText, void* aClosure);
     377             : 
     378             :     static void
     379             :     SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, const nsAString& aVariable, void* aClosure);
     380             : 
     381             :     nsresult
     382             :     IsSystemPrincipal(nsIPrincipal *principal, bool *result);
     383             : 
     384             :     /**
     385             :      * Convenience method which gets a resource for a result. If a result
     386             :      * doesn't have a resource set, it will create one from the result's id.
     387             :      */
     388             :     nsresult GetResultResource(nsIXULTemplateResult* aResult,
     389             :                                nsIRDFResource** aResource);
     390             : 
     391             : protected:
     392             :     explicit nsXULTemplateBuilder(Element* aElement);
     393             :     virtual ~nsXULTemplateBuilder();
     394             : 
     395             :     nsCOMPtr<nsISupports> mDataSource;
     396             :     nsCOMPtr<nsIRDFDataSource> mDB;
     397             :     nsCOMPtr<nsIRDFCompositeDataSource> mCompDB;
     398             : 
     399             :     /**
     400             :      * Circular reference, broken when the document is destroyed.
     401             :      */
     402             :     nsCOMPtr<Element> mRoot;
     403             : 
     404             :     /**
     405             :      * The root result, translated from the root element's ref
     406             :      */
     407             :     nsCOMPtr<nsIXULTemplateResult> mRootResult;
     408             : 
     409             :     nsTArray<nsCOMPtr<nsIXULBuilderListener>> mListeners;
     410             : 
     411             :     /**
     412             :      * The query processor which generates results
     413             :      */
     414             :     nsCOMPtr<nsIXULTemplateQueryProcessor> mQueryProcessor;
     415             : 
     416             :     /**
     417             :      * The list of querysets
     418             :      */
     419             :     nsTArray<nsTemplateQuerySet *> mQuerySets;
     420             : 
     421             :     /**
     422             :      * Set to true if the rules have already been compiled
     423             :      */
     424             :     bool          mQueriesCompiled;
     425             : 
     426             :     /**
     427             :      * The default reference and member variables.
     428             :      */
     429             :     nsCOMPtr<nsIAtom> mRefVariable;
     430             :     nsCOMPtr<nsIAtom> mMemberVariable;
     431             : 
     432             :     /**
     433             :      * The match map contains nsTemplateMatch objects, one for each unique
     434             :      * match found, keyed by the resource for that match. A particular match
     435             :      * will contain a linked list of all of the matches for that unique result
     436             :      * id. Only one is active at a time. When a match is retracted, look in
     437             :      * the match map, remove it, and apply the next valid match in sequence to
     438             :      * make active.
     439             :      */
     440             :     nsDataHashtable<nsISupportsHashKey, nsTemplateMatch*> mMatchMap;
     441             : 
     442             :     // pseudo-constants
     443             :     static nsrefcnt gRefCnt;
     444             :     static nsIRDFService*            gRDFService;
     445             :     static nsIRDFContainerUtils*     gRDFContainerUtils;
     446             :     static nsIScriptSecurityManager* gScriptSecurityManager;
     447             :     static nsIPrincipal*             gSystemPrincipal;
     448             :     static nsIObserverService*       gObserverService;
     449             : 
     450             :     enum {
     451             :         eDontTestEmpty = (1 << 0),
     452             :         eDontRecurse = (1 << 1),
     453             :         eLoggingEnabled = (1 << 2)
     454             :     };
     455             : 
     456             :     int32_t mFlags;
     457             : 
     458             :     /**
     459             :      * Stack-based helper class to maintain a list of ``activated''
     460             :      * resources; i.e., resources for which we are currently building
     461             :      * content.
     462             :      */
     463             :     class ActivationEntry {
     464             :     public:
     465             :         nsIRDFResource   *mResource;
     466             :         ActivationEntry  *mPrevious;
     467             :         ActivationEntry **mLink;
     468             : 
     469           0 :         ActivationEntry(nsIRDFResource *aResource, ActivationEntry **aLink)
     470           0 :             : mResource(aResource),
     471             :               mPrevious(*aLink),
     472           0 :               mLink(aLink) { *mLink = this; }
     473             : 
     474           0 :         ~ActivationEntry() { *mLink = mPrevious; }
     475             :     };
     476             : 
     477             :     /**
     478             :      * The top of the stack of resources that we're currently building
     479             :      * content for.
     480             :      */
     481             :     ActivationEntry *mTop;
     482             : 
     483             :     /**
     484             :      * Determine if a resource is currently on the activation stack.
     485             :      */
     486             :     bool
     487             :     IsActivated(nsIRDFResource *aResource);
     488             : 
     489             :     /**
     490             :      * Returns true if content may be generated for a result, or false if it
     491             :      * cannot, for example, if it would be created inside a closed container.
     492             :      * Those results will be generated when the container is opened.
     493             :      * If false is returned, no content should be generated. Possible
     494             :      * insertion locations may optionally be set for new content, depending on
     495             :      * the builder being used. Note that *aLocations or some items within
     496             :      * aLocations may be null.
     497             :      */
     498             :     virtual bool
     499             :     GetInsertionLocations(nsIXULTemplateResult* aResult,
     500             :                           nsCOMArray<nsIContent>** aLocations) = 0;
     501             : 
     502             :     /**
     503             :      * Must be implemented by subclasses. Handle removing the generated
     504             :      * output for aOldMatch and adding new output for aNewMatch. Either
     505             :      * aOldMatch or aNewMatch may be null. aContext is the location returned
     506             :      * from the call to MayGenerateResult.
     507             :      */
     508             :     virtual nsresult
     509             :     ReplaceMatch(nsIXULTemplateResult* aOldResult,
     510             :                  nsTemplateMatch* aNewMatch,
     511             :                  nsTemplateRule* aNewMatchRule,
     512             :                  void *aContext) = 0;
     513             : 
     514             :     /**
     515             :      * Must be implemented by subclasses. Handle change in bound
     516             :      * variable values for aResult. aModifiedVars contains the set
     517             :      * of variables that have changed.
     518             :      * @param aResult the ersult for which variable bindings has changed.
     519             :      * @param aModifiedVars the set of variables for which the bindings
     520             :      * have changed.
     521             :      */
     522             :     virtual nsresult
     523             :     SynchronizeResult(nsIXULTemplateResult* aResult) = 0;
     524             : 
     525             :     /**
     526             :      * Output a new match or removed match to the console.
     527             :      *
     528             :      * @param aId id of the result
     529             :      * @param aMatch new or removed match
     530             :      * @param aIsNew true for new matched, false for removed matches
     531             :      */
     532             :     void
     533             :     OutputMatchToLog(nsIRDFResource* aId,
     534             :                      nsTemplateMatch* aMatch,
     535             :                      bool aIsNew);
     536             : 
     537           0 :     virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const
     538             :     {
     539           0 :     }
     540             : 
     541             :     /**
     542             :      * Start observing events from the observer service and the given
     543             :      * document.
     544             :      *
     545             :      * @param aDocument the document to observe
     546             :      */
     547             :     void StartObserving(nsIDocument* aDocument);
     548             : 
     549             :     /**
     550             :      * Stop observing events from the observer service and any associated
     551             :      * document.
     552             :      */
     553             :     void StopObserving();
     554             : 
     555             :     /**
     556             :      * Document that we're observing. Weak ref!
     557             :      */
     558             :     nsIDocument* mObservedDocument;
     559             : };
     560             : 
     561             : nsresult NS_NewXULContentBuilder(Element* aElement,
     562             :                                  nsIXULTemplateBuilder** aBuilder);
     563             : 
     564             : #endif // nsXULTemplateBuilder_h__

Generated by: LCOV version 1.13