content/xul/templates/src/nsXULTemplateBuilder.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/xul/templates/src/nsXULTemplateBuilder.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,503 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef nsXULTemplateBuilder_h__
    1.10 +#define nsXULTemplateBuilder_h__
    1.11 +
    1.12 +#include "nsStubDocumentObserver.h"
    1.13 +#include "nsIScriptSecurityManager.h"
    1.14 +#include "nsIObserver.h"
    1.15 +#include "nsIRDFCompositeDataSource.h"
    1.16 +#include "nsIRDFContainer.h"
    1.17 +#include "nsIRDFContainerUtils.h"
    1.18 +#include "nsIRDFDataSource.h"
    1.19 +#include "nsIRDFObserver.h"
    1.20 +#include "nsIRDFService.h"
    1.21 +#include "nsIXULTemplateBuilder.h"
    1.22 +
    1.23 +#include "nsCOMArray.h"
    1.24 +#include "nsTArray.h"
    1.25 +#include "nsDataHashtable.h"
    1.26 +#include "nsTemplateRule.h"
    1.27 +#include "nsTemplateMatch.h"
    1.28 +#include "nsIXULTemplateQueryProcessor.h"
    1.29 +#include "nsCycleCollectionParticipant.h"
    1.30 +
    1.31 +#include "prlog.h"
    1.32 +#ifdef PR_LOGGING
    1.33 +extern PRLogModuleInfo* gXULTemplateLog;
    1.34 +#endif
    1.35 +
    1.36 +class nsIContent;
    1.37 +class nsIObserverService;
    1.38 +class nsIRDFCompositeDataSource;
    1.39 +class nsIXULDocument;
    1.40 +
    1.41 +/**
    1.42 + * An object that translates an RDF graph into a presentation using a
    1.43 + * set of rules.
    1.44 + */
    1.45 +class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
    1.46 +                             public nsIObserver,
    1.47 +                             public nsStubDocumentObserver
    1.48 +{
    1.49 +    void CleanUp(bool aIsFinal);
    1.50 +
    1.51 +public:
    1.52 +    nsXULTemplateBuilder();
    1.53 +    virtual ~nsXULTemplateBuilder();
    1.54 +
    1.55 +    nsresult InitGlobals();
    1.56 +
    1.57 +    /**
    1.58 +     * Clear the template builder structures. The aIsFinal flag is set to true
    1.59 +     * when the template is going away.
    1.60 +     */
    1.61 +    virtual void Uninit(bool aIsFinal);
    1.62 +
    1.63 +    // nsISupports interface
    1.64 +    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    1.65 +    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULTemplateBuilder,
    1.66 +                                             nsIXULTemplateBuilder)
    1.67 +
    1.68 +    // nsIXULTemplateBuilder interface
    1.69 +    NS_DECL_NSIXULTEMPLATEBUILDER
    1.70 +
    1.71 +    // nsIObserver Interface
    1.72 +    NS_DECL_NSIOBSERVER
    1.73 +
    1.74 +    // nsIMutationObserver
    1.75 +    NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
    1.76 +    NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
    1.77 +    NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
    1.78 +
    1.79 +    /**
    1.80 +     * Remove an old result and/or add a new result. This method will retrieve
    1.81 +     * the set of containers where the result could be inserted and either add
    1.82 +     * the new result to those containers, or remove the result from those
    1.83 +     * containers. UpdateResultInContainer is called for each container.
    1.84 +     *
    1.85 +     * @param aOldResult result to remove
    1.86 +     * @param aNewResult result to add
    1.87 +     * @param aQueryNode query node for new result
    1.88 +     */
    1.89 +    nsresult
    1.90 +    UpdateResult(nsIXULTemplateResult* aOldResult,
    1.91 +                 nsIXULTemplateResult* aNewResult,
    1.92 +                 nsIDOMNode* aQueryNode);
    1.93 +
    1.94 +    /**
    1.95 +     * Remove an old result and/or add a new result from a specific container.
    1.96 +     *
    1.97 +     * @param aOldResult result to remove
    1.98 +     * @param aNewResult result to add
    1.99 +     * @param aQueryNode queryset for the new result
   1.100 +     * @param aOldId id of old result
   1.101 +     * @param aNewId id of new result
   1.102 +     * @param aInsertionPoint container to remove or add result inside
   1.103 +     */
   1.104 +    nsresult
   1.105 +    UpdateResultInContainer(nsIXULTemplateResult* aOldResult,
   1.106 +                            nsIXULTemplateResult* aNewResult,
   1.107 +                            nsTemplateQuerySet* aQuerySet,
   1.108 +                            nsIRDFResource* aOldId,
   1.109 +                            nsIRDFResource* aNewId,
   1.110 +                            nsIContent* aInsertionPoint);
   1.111 +
   1.112 +    nsresult
   1.113 +    ComputeContainmentProperties();
   1.114 +
   1.115 +    static bool
   1.116 +    IsTemplateElement(nsIContent* aContent);
   1.117 +
   1.118 +    virtual nsresult
   1.119 +    RebuildAll() = 0; // must be implemented by subclasses
   1.120 +
   1.121 +    void RunnableRebuild() { Rebuild(); }
   1.122 +    void RunnableLoadAndRebuild() {
   1.123 +      Uninit(false);  // Reset results
   1.124 +
   1.125 +      nsCOMPtr<nsIDocument> doc = mRoot ? mRoot->GetDocument() : nullptr;
   1.126 +      if (doc) {
   1.127 +        bool shouldDelay;
   1.128 +        LoadDataSources(doc, &shouldDelay);
   1.129 +        if (!shouldDelay) {
   1.130 +          Rebuild();
   1.131 +        }
   1.132 +      }
   1.133 +    }
   1.134 +
   1.135 +    // mRoot should not be cleared until after Uninit is finished so that
   1.136 +    // generated content can be removed during uninitialization.
   1.137 +    void UninitFalse() { Uninit(false); mRoot = nullptr; }
   1.138 +    void UninitTrue() { Uninit(true); mRoot = nullptr; }
   1.139 +
   1.140 +    /**
   1.141 +     * Find the <template> tag that applies for this builder
   1.142 +     */
   1.143 +    nsresult
   1.144 +    GetTemplateRoot(nsIContent** aResult);
   1.145 +
   1.146 +    /**
   1.147 +     * Compile the template's queries
   1.148 +     */
   1.149 +    nsresult
   1.150 +    CompileQueries();
   1.151 +
   1.152 +    /**
   1.153 +     * Compile the template given a <template> in aTemplate. This function
   1.154 +     * is called recursively to handle queries inside a queryset. For the
   1.155 +     * outer pass, aIsQuerySet will be false, while the inner pass this will
   1.156 +     * be true.
   1.157 +     *
   1.158 +     * aCanUseTemplate will be set to true if the template's queries could be
   1.159 +     * compiled, and false otherwise. If false, the entire template is
   1.160 +     * invalid.
   1.161 +     *
   1.162 +     * @param aTemplate <template> to compile
   1.163 +     * @param aQuerySet first queryset
   1.164 +     * @param aIsQuerySet true if 
   1.165 +     * @param aPriority the queryset index, incremented when a new one is added
   1.166 +     * @param aCanUseTemplate true if template is valid
   1.167 +     */
   1.168 +    nsresult
   1.169 +    CompileTemplate(nsIContent* aTemplate,
   1.170 +                    nsTemplateQuerySet* aQuerySet,
   1.171 +                    bool aIsQuerySet,
   1.172 +                    int32_t* aPriority,
   1.173 +                    bool* aCanUseTemplate);
   1.174 +
   1.175 +    /**
   1.176 +     * Compile a query using the extended syntax. For backwards compatible RDF
   1.177 +     * syntax where there is no <query>, the <conditions> becomes the query.
   1.178 +     *
   1.179 +     * @param aRuleElement <rule> element
   1.180 +     * @param aActionElement <action> element
   1.181 +     * @param aMemberVariable member variable for the query
   1.182 +     * @param aQuerySet the queryset
   1.183 +     */
   1.184 +    nsresult 
   1.185 +    CompileExtendedQuery(nsIContent* aRuleElement,
   1.186 +                         nsIContent* aActionElement,
   1.187 +                         nsIAtom* aMemberVariable,
   1.188 +                         nsTemplateQuerySet* aQuerySet);
   1.189 +
   1.190 +    /**
   1.191 +     * Determine the ref variable and tag from inside a RDF query.
   1.192 +     */
   1.193 +    void DetermineRDFQueryRef(nsIContent* aQueryElement, nsIAtom** tag);
   1.194 +
   1.195 +    /**
   1.196 +     * Determine the member variable from inside an action body. It will be
   1.197 +     * the value of the uri attribute on a node.
   1.198 +     */
   1.199 +    already_AddRefed<nsIAtom> DetermineMemberVariable(nsIContent* aElement);
   1.200 +
   1.201 +    /**
   1.202 +     * Compile a simple query. A simple query is one that doesn't have a
   1.203 +     * <query> and should use a default query which would normally just return
   1.204 +     * a list of children of the reference point.
   1.205 +     *
   1.206 +     * @param aRuleElement the <rule>
   1.207 +     * @param aQuerySet the query set
   1.208 +     * @param aCanUseTemplate true if the query is valid
   1.209 +     */
   1.210 +    nsresult 
   1.211 +    CompileSimpleQuery(nsIContent* aRuleElement,
   1.212 +                       nsTemplateQuerySet* aQuerySet,
   1.213 +                       bool* aCanUseTemplate);
   1.214 +
   1.215 +    /**
   1.216 +     * Compile the <conditions> tag in a rule
   1.217 +     *
   1.218 +     * @param aRule template rule
   1.219 +     * @param aConditions <conditions> element
   1.220 +     */
   1.221 +    nsresult
   1.222 +    CompileConditions(nsTemplateRule* aRule, nsIContent* aConditions);
   1.223 +
   1.224 +    /**
   1.225 +     * Compile a <where> tag in a condition. The caller should set
   1.226 +     * *aCurrentCondition to null for the first condition. This value will be
   1.227 +     * updated to point to the new condition before returning. The conditions
   1.228 +     * will be added to the rule aRule by this method.
   1.229 +     *
   1.230 +     * @param aRule template rule
   1.231 +     * @param aCondition <where> element
   1.232 +     * @param aCurrentCondition compiled condition
   1.233 +     */
   1.234 +    nsresult
   1.235 +    CompileWhereCondition(nsTemplateRule* aRule,
   1.236 +                          nsIContent* aCondition,
   1.237 +                          nsTemplateCondition** aCurrentCondition);
   1.238 +
   1.239 +    /**
   1.240 +     * Compile the <bindings> for an extended template syntax rule.
   1.241 +     */
   1.242 +    nsresult
   1.243 +    CompileBindings(nsTemplateRule* aRule, nsIContent* aBindings);
   1.244 +
   1.245 +    /**
   1.246 +     * Compile a single binding for an extended template syntax rule.
   1.247 +     */
   1.248 +    nsresult
   1.249 +    CompileBinding(nsTemplateRule* aRule, nsIContent* aBinding);
   1.250 +
   1.251 +    /**
   1.252 +     * Add automatic bindings for simple rules
   1.253 +     */
   1.254 +    nsresult
   1.255 +    AddSimpleRuleBindings(nsTemplateRule* aRule, nsIContent* aElement);
   1.256 +
   1.257 +    static void
   1.258 +    AddBindingsFor(nsXULTemplateBuilder* aSelf,
   1.259 +                   const nsAString& aVariable,
   1.260 +                   void* aClosure);
   1.261 +
   1.262 +    /**
   1.263 +     * Load the datasources for the template. shouldDelayBuilding is an out
   1.264 +     * parameter which will be set to true to indicate that content building
   1.265 +     * should not be performed yet as the datasource has not yet loaded. If
   1.266 +     * false, the datasource has already loaded so building can proceed
   1.267 +     * immediately. In the former case, the datasource or query processor
   1.268 +     * should either rebuild the template or update results when the
   1.269 +     * datasource is loaded as needed.
   1.270 +     */
   1.271 +    nsresult
   1.272 +    LoadDataSources(nsIDocument* aDoc, bool* shouldDelayBuilding);
   1.273 +
   1.274 +    /**
   1.275 +     * Called by LoadDataSources to load a datasource given a uri list
   1.276 +     * in aDataSource. The list is a set of uris separated by spaces.
   1.277 +     * If aIsRDFQuery is true, then this is for an RDF datasource which
   1.278 +     * causes the method to check for additional flags specific to the
   1.279 +     * RDF processor.
   1.280 +     */
   1.281 +    nsresult
   1.282 +    LoadDataSourceUrls(nsIDocument* aDocument,
   1.283 +                       const nsAString& aDataSources,
   1.284 +                       bool aIsRDFQuery,
   1.285 +                       bool* aShouldDelayBuilding);
   1.286 +
   1.287 +    nsresult
   1.288 +    InitHTMLTemplateRoot();
   1.289 +
   1.290 +    /**
   1.291 +     * Determine which rule matches a given result. aContainer is used for
   1.292 +     * tag matching and is optional for non-content generating builders.
   1.293 +     * The returned matched rule is always one of the rules owned by the
   1.294 +     * query set aQuerySet.
   1.295 +     *
   1.296 +     * @param aContainer parent where generated content will be inserted
   1.297 +     * @param aResult result to match
   1.298 +     * @param aQuerySet query set to examine the rules of
   1.299 +     * @param aMatchedRule [out] rule that has matched, or null if any.
   1.300 +     * @param aRuleIndex [out] index of the rule
   1.301 +     */
   1.302 +    nsresult
   1.303 +    DetermineMatchedRule(nsIContent* aContainer,
   1.304 +                         nsIXULTemplateResult* aResult,
   1.305 +                         nsTemplateQuerySet* aQuerySet,
   1.306 +                         nsTemplateRule** aMatchedRule,
   1.307 +                         int16_t *aRuleIndex);
   1.308 +
   1.309 +    // XXX sigh, the string template foo doesn't mix with
   1.310 +    // operator->*() on egcs-1.1.2, so we'll need to explicitly pass
   1.311 +    // "this" and use good ol' fashioned static callbacks.
   1.312 +    void
   1.313 +    ParseAttribute(const nsAString& aAttributeValue,
   1.314 +                   void (*aVariableCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
   1.315 +                   void (*aTextCallback)(nsXULTemplateBuilder* aThis, const nsAString&, void*),
   1.316 +                   void* aClosure);
   1.317 +
   1.318 +    nsresult
   1.319 +    SubstituteText(nsIXULTemplateResult* aMatch,
   1.320 +                   const nsAString& aAttributeValue,
   1.321 +                   nsAString& aResult);
   1.322 +
   1.323 +    static void
   1.324 +    SubstituteTextAppendText(nsXULTemplateBuilder* aThis, const nsAString& aText, void* aClosure);
   1.325 +
   1.326 +    static void
   1.327 +    SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, const nsAString& aVariable, void* aClosure);    
   1.328 +
   1.329 +    nsresult 
   1.330 +    IsSystemPrincipal(nsIPrincipal *principal, bool *result);
   1.331 +
   1.332 +    /**
   1.333 +     * Convenience method which gets a resource for a result. If a result
   1.334 +     * doesn't have a resource set, it will create one from the result's id.
   1.335 +     */
   1.336 +    nsresult GetResultResource(nsIXULTemplateResult* aResult,
   1.337 +                               nsIRDFResource** aResource);
   1.338 +
   1.339 +protected:
   1.340 +    nsCOMPtr<nsISupports> mDataSource;
   1.341 +    nsCOMPtr<nsIRDFDataSource> mDB;
   1.342 +    nsCOMPtr<nsIRDFCompositeDataSource> mCompDB;
   1.343 +
   1.344 +    /**
   1.345 +     * Circular reference, broken when the document is destroyed.
   1.346 +     */
   1.347 +    nsCOMPtr<nsIContent> mRoot;
   1.348 +
   1.349 +    /**
   1.350 +     * The root result, translated from the root element's ref
   1.351 +     */
   1.352 +    nsCOMPtr<nsIXULTemplateResult> mRootResult;
   1.353 +
   1.354 +    nsCOMArray<nsIXULBuilderListener> mListeners;
   1.355 +
   1.356 +    /**
   1.357 +     * The query processor which generates results
   1.358 +     */
   1.359 +    nsCOMPtr<nsIXULTemplateQueryProcessor> mQueryProcessor;
   1.360 +
   1.361 +    /**
   1.362 +     * The list of querysets
   1.363 +     */
   1.364 +    nsTArray<nsTemplateQuerySet *> mQuerySets;
   1.365 +
   1.366 +    /**
   1.367 +     * Set to true if the rules have already been compiled
   1.368 +     */
   1.369 +    bool          mQueriesCompiled;
   1.370 +
   1.371 +    /**
   1.372 +     * The default reference and member variables.
   1.373 +     */
   1.374 +    nsCOMPtr<nsIAtom> mRefVariable;
   1.375 +    nsCOMPtr<nsIAtom> mMemberVariable;
   1.376 +
   1.377 +    /**
   1.378 +     * The match map contains nsTemplateMatch objects, one for each unique
   1.379 +     * match found, keyed by the resource for that match. A particular match
   1.380 +     * will contain a linked list of all of the matches for that unique result
   1.381 +     * id. Only one is active at a time. When a match is retracted, look in
   1.382 +     * the match map, remove it, and apply the next valid match in sequence to
   1.383 +     * make active.
   1.384 +     */
   1.385 +    nsDataHashtable<nsISupportsHashKey, nsTemplateMatch*> mMatchMap;
   1.386 +
   1.387 +    // pseudo-constants
   1.388 +    static nsrefcnt gRefCnt;
   1.389 +    static nsIRDFService*            gRDFService;
   1.390 +    static nsIRDFContainerUtils*     gRDFContainerUtils;
   1.391 +    static nsIScriptSecurityManager* gScriptSecurityManager;
   1.392 +    static nsIPrincipal*             gSystemPrincipal;
   1.393 +    static nsIObserverService*       gObserverService;
   1.394 +
   1.395 +    enum {
   1.396 +        eDontTestEmpty = (1 << 0),
   1.397 +        eDontRecurse = (1 << 1),
   1.398 +        eLoggingEnabled = (1 << 2)
   1.399 +    };
   1.400 +
   1.401 +    int32_t mFlags;
   1.402 +
   1.403 +    /**
   1.404 +     * Stack-based helper class to maintain a list of ``activated''
   1.405 +     * resources; i.e., resources for which we are currently building
   1.406 +     * content.
   1.407 +     */
   1.408 +    class ActivationEntry {
   1.409 +    public:
   1.410 +        nsIRDFResource   *mResource;
   1.411 +        ActivationEntry  *mPrevious;
   1.412 +        ActivationEntry **mLink;
   1.413 +
   1.414 +        ActivationEntry(nsIRDFResource *aResource, ActivationEntry **aLink)
   1.415 +            : mResource(aResource),
   1.416 +              mPrevious(*aLink),
   1.417 +              mLink(aLink) { *mLink = this; }
   1.418 +
   1.419 +        ~ActivationEntry() { *mLink = mPrevious; }
   1.420 +    };
   1.421 +
   1.422 +    /**
   1.423 +     * The top of the stack of resources that we're currently building
   1.424 +     * content for.
   1.425 +     */
   1.426 +    ActivationEntry *mTop;
   1.427 +
   1.428 +    /**
   1.429 +     * Determine if a resource is currently on the activation stack.
   1.430 +     */
   1.431 +    bool
   1.432 +    IsActivated(nsIRDFResource *aResource);
   1.433 +
   1.434 +    /**
   1.435 +     * Returns true if content may be generated for a result, or false if it
   1.436 +     * cannot, for example, if it would be created inside a closed container.
   1.437 +     * Those results will be generated when the container is opened.
   1.438 +     * If false is returned, no content should be generated. Possible 
   1.439 +     * insertion locations may optionally be set for new content, depending on
   1.440 +     * the builder being used. Note that *aLocations or some items within
   1.441 +     * aLocations may be null.
   1.442 +     */
   1.443 +    virtual bool
   1.444 +    GetInsertionLocations(nsIXULTemplateResult* aResult,
   1.445 +                          nsCOMArray<nsIContent>** aLocations) = 0;
   1.446 +
   1.447 +    /**
   1.448 +     * Must be implemented by subclasses. Handle removing the generated
   1.449 +     * output for aOldMatch and adding new output for aNewMatch. Either
   1.450 +     * aOldMatch or aNewMatch may be null. aContext is the location returned
   1.451 +     * from the call to MayGenerateResult.
   1.452 +     */
   1.453 +    virtual nsresult
   1.454 +    ReplaceMatch(nsIXULTemplateResult* aOldResult,
   1.455 +                 nsTemplateMatch* aNewMatch,
   1.456 +                 nsTemplateRule* aNewMatchRule,
   1.457 +                 void *aContext) = 0;
   1.458 +
   1.459 +    /**
   1.460 +     * Must be implemented by subclasses. Handle change in bound
   1.461 +     * variable values for aResult. aModifiedVars contains the set
   1.462 +     * of variables that have changed.
   1.463 +     * @param aResult the ersult for which variable bindings has changed.
   1.464 +     * @param aModifiedVars the set of variables for which the bindings
   1.465 +     * have changed.
   1.466 +     */
   1.467 +    virtual nsresult
   1.468 +    SynchronizeResult(nsIXULTemplateResult* aResult) = 0;
   1.469 +
   1.470 +    /**
   1.471 +     * Output a new match or removed match to the console.
   1.472 +     *
   1.473 +     * @param aId id of the result
   1.474 +     * @param aMatch new or removed match
   1.475 +     * @param aIsNew true for new matched, false for removed matches
   1.476 +     */
   1.477 +    void
   1.478 +    OutputMatchToLog(nsIRDFResource* aId,
   1.479 +                     nsTemplateMatch* aMatch,
   1.480 +                     bool aIsNew);
   1.481 +
   1.482 +    virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const
   1.483 +    {
   1.484 +    }
   1.485 +
   1.486 +    /**
   1.487 +     * Start observing events from the observer service and the given
   1.488 +     * document.
   1.489 +     *
   1.490 +     * @param aDocument the document to observe
   1.491 +     */
   1.492 +    void StartObserving(nsIDocument* aDocument);
   1.493 +
   1.494 +    /**
   1.495 +     * Stop observing events from the observer service and any associated
   1.496 +     * document.
   1.497 +     */
   1.498 +    void StopObserving();
   1.499 +
   1.500 +    /**
   1.501 +     * Document that we're observing. Weak ref!
   1.502 +     */
   1.503 +    nsIDocument* mObservedDocument;
   1.504 +};
   1.505 +
   1.506 +#endif // nsXULTemplateBuilder_h__

mercurial