1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/xul/templates/src/nsTemplateRule.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,328 @@ 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 nsTemplateRule_h__ 1.10 +#define nsTemplateRule_h__ 1.11 + 1.12 +#include "nsCOMPtr.h" 1.13 +#include "nsIAtom.h" 1.14 +#include "nsIRDFDataSource.h" 1.15 +#include "nsIRDFResource.h" 1.16 +#include "nsIContent.h" 1.17 +#include "nsIDOMNode.h" 1.18 +#include "nsTArray.h" 1.19 +#include "nsString.h" 1.20 +#include "nsIXULTemplateRuleFilter.h" 1.21 +#include "nsCycleCollectionParticipant.h" 1.22 + 1.23 +class nsIXULTemplateQueryProcessor; 1.24 +class nsTemplateQuerySet; 1.25 + 1.26 +class nsTemplateCondition 1.27 +{ 1.28 +public: 1.29 + // relations that may be used in a rule. They may be negated with the 1.30 + // negate flag. Less and Greater are used for numeric comparisons and 1.31 + // Before and After are used for string comparisons. For Less, Greater, 1.32 + // Before, After, Startswith, Endswith, and Contains, the source is 1.33 + // conceptually on the left of the relation and the target is on the 1.34 + // right. For example, if the relation is Contains, that means Match if 1.35 + // the source contains the target. 1.36 + enum ConditionRelation { 1.37 + eUnknown, 1.38 + eEquals, 1.39 + eLess, 1.40 + eGreater, 1.41 + eBefore, 1.42 + eAfter, 1.43 + eStartswith, 1.44 + eEndswith, 1.45 + eContains 1.46 + }; 1.47 + 1.48 + nsTemplateCondition(nsIAtom* aSourceVariable, 1.49 + const nsAString& aRelation, 1.50 + nsIAtom* aTargetVariable, 1.51 + bool mIgnoreCase, 1.52 + bool mNegate); 1.53 + 1.54 + nsTemplateCondition(nsIAtom* aSourceVariable, 1.55 + const nsAString& aRelation, 1.56 + const nsAString& aTargets, 1.57 + bool mIgnoreCase, 1.58 + bool mNegate, 1.59 + bool aIsMultiple); 1.60 + 1.61 + nsTemplateCondition(const nsAString& aSource, 1.62 + const nsAString& aRelation, 1.63 + nsIAtom* aTargetVariable, 1.64 + bool mIgnoreCase, 1.65 + bool mNegate); 1.66 + 1.67 + ~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); } 1.68 + 1.69 + nsTemplateCondition* GetNext() { return mNext; } 1.70 + void SetNext(nsTemplateCondition* aNext) { mNext = aNext; } 1.71 + 1.72 + void SetRelation(const nsAString& aRelation); 1.73 + 1.74 + bool 1.75 + CheckMatch(nsIXULTemplateResult* aResult); 1.76 + 1.77 + bool 1.78 + CheckMatchStrings(const nsAString& aLeftString, 1.79 + const nsAString& aRightString); 1.80 +protected: 1.81 + 1.82 + nsCOMPtr<nsIAtom> mSourceVariable; 1.83 + nsString mSource; 1.84 + ConditionRelation mRelation; 1.85 + nsCOMPtr<nsIAtom> mTargetVariable; 1.86 + nsTArray<nsString> mTargetList; 1.87 + bool mIgnoreCase; 1.88 + bool mNegate; 1.89 + 1.90 + nsTemplateCondition* mNext; 1.91 +}; 1.92 + 1.93 +/** 1.94 + * A rule consists of: 1.95 + * 1.96 + * - Conditions, a set of unbound variables with consistency 1.97 + * constraints that specify the values that each variable can 1.98 + * assume. The conditions must be completely and consistently 1.99 + * "bound" for the rule to be considered "matched". 1.100 + * 1.101 + * - Bindings, a set of unbound variables with consistency constraints 1.102 + * that specify the values that each variable can assume. Unlike the 1.103 + * conditions, the bindings need not be bound for the rule to be 1.104 + * considered matched. 1.105 + * 1.106 + * - Content that should be constructed when the rule is "activated". 1.107 + * 1.108 + */ 1.109 +class nsTemplateRule 1.110 +{ 1.111 +public: 1.112 + nsTemplateRule(nsIContent* aRuleNode, 1.113 + nsIContent* aAction, 1.114 + nsTemplateQuerySet* aQuerySet); 1.115 + /** 1.116 + * The copy-constructor should only be called from nsTArray when appending 1.117 + * a new rule, otherwise things break because the copy constructor expects 1.118 + * mBindings and mConditions to be nullptr. 1.119 + */ 1.120 + nsTemplateRule(const nsTemplateRule& aOtherRule); 1.121 + 1.122 + ~nsTemplateRule(); 1.123 + 1.124 + /** 1.125 + * Return the <action> node that this rule was constructed from, or its 1.126 + * logical equivalent for shorthand syntaxes. That is, the parent node of 1.127 + * the content that should be generated for this rule. 1.128 + */ 1.129 + nsIContent* GetAction() const { return mAction; } 1.130 + 1.131 + /** 1.132 + * Return the <rule> content node that this rule was constructed from. 1.133 + * @param aResult an out parameter, which will contain the rule node 1.134 + * @return NS_OK if no errors occur. 1.135 + */ 1.136 + nsresult GetRuleNode(nsIDOMNode** aResult) const; 1.137 + 1.138 + void SetVars(nsIAtom* aRefVariable, nsIAtom* aMemberVariable) 1.139 + { 1.140 + mRefVariable = aRefVariable; 1.141 + mMemberVariable = aMemberVariable; 1.142 + } 1.143 + 1.144 + void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter) 1.145 + { 1.146 + mRuleFilter = aRuleFilter; 1.147 + } 1.148 + 1.149 + nsIAtom* GetTag() { return mTag; } 1.150 + void SetTag(nsIAtom* aTag) { mTag = aTag; } 1.151 + 1.152 + nsIAtom* GetMemberVariable() { return mMemberVariable; } 1.153 + 1.154 + /** 1.155 + * Set the first condition for the rule. Other conditions are linked 1.156 + * to it using the condition's SetNext method. 1.157 + */ 1.158 + void SetCondition(nsTemplateCondition* aConditions); 1.159 + 1.160 + /** 1.161 + * Check if the result matches the rule by first looking at the conditions. 1.162 + * If the results is accepted by the conditions, the rule filter, if any 1.163 + * was set, is checked. If either check rejects a result, a match cannot 1.164 + * occur for this rule and result. 1.165 + */ 1.166 + bool 1.167 + CheckMatch(nsIXULTemplateResult* aResult) const; 1.168 + 1.169 + /** 1.170 + * Determine if the rule has the specified binding 1.171 + */ 1.172 + bool 1.173 + HasBinding(nsIAtom* aSourceVariable, 1.174 + nsAString& aExpr, 1.175 + nsIAtom* aTargetVariable) const; 1.176 + 1.177 + /** 1.178 + * Add a binding to the rule. A binding consists of an already-bound 1.179 + * source variable, and the RDF property that should be tested to 1.180 + * generate a target value. The target value is bound to a target 1.181 + * variable. 1.182 + * 1.183 + * @param aSourceVariable the source variable that will be used in 1.184 + * the RDF query. 1.185 + * @param aExpr the expression that will be used in the query. 1.186 + * @param aTargetVariable the variable whose value will be bound 1.187 + * to the RDF node that is returned when querying the binding 1.188 + * @return NS_OK if no errors occur. 1.189 + */ 1.190 + nsresult AddBinding(nsIAtom* aSourceVariable, 1.191 + nsAString& aExpr, 1.192 + nsIAtom* aTargetVariable); 1.193 + 1.194 + /** 1.195 + * Inform the query processor of the bindings that are set for a rule. 1.196 + * This should be called after all the bindings for a rule are compiled. 1.197 + */ 1.198 + nsresult 1.199 + AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor); 1.200 + 1.201 + void Traverse(nsCycleCollectionTraversalCallback &cb) const 1.202 + { 1.203 + cb.NoteXPCOMChild(mRuleNode); 1.204 + cb.NoteXPCOMChild(mAction); 1.205 + } 1.206 + 1.207 +protected: 1.208 + 1.209 + struct Binding { 1.210 + nsCOMPtr<nsIAtom> mSourceVariable; 1.211 + nsCOMPtr<nsIAtom> mTargetVariable; 1.212 + nsString mExpr; 1.213 + Binding* mNext; 1.214 + Binding* mParent; 1.215 + }; 1.216 + 1.217 + // backreference to the query set which owns this rule 1.218 + nsTemplateQuerySet* mQuerySet; 1.219 + 1.220 + // the <rule> node, or the <template> node if there is no <rule> 1.221 + nsCOMPtr<nsIDOMNode> mRuleNode; 1.222 + 1.223 + // the <action> node, or, if there is no <action>, the container node 1.224 + // which contains the content to generate 1.225 + nsCOMPtr<nsIContent> mAction; 1.226 + 1.227 + // the rule filter set by the builder's SetRuleFilter function 1.228 + nsCOMPtr<nsIXULTemplateRuleFilter> mRuleFilter; 1.229 + 1.230 + // indicates that the rule will only match when generating content 1.231 + // to be inserted into a container with this tag 1.232 + nsCOMPtr<nsIAtom> mTag; 1.233 + 1.234 + // linked-list of the bindings for the rule, owned by the rule. 1.235 + Binding* mBindings; 1.236 + 1.237 + nsCOMPtr<nsIAtom> mRefVariable; 1.238 + nsCOMPtr<nsIAtom> mMemberVariable; 1.239 + 1.240 + nsTemplateCondition* mConditions; // owned by nsTemplateRule 1.241 +}; 1.242 + 1.243 +/** nsTemplateQuerySet 1.244 + * 1.245 + * A single <queryset> which holds the query node and the rules for it. 1.246 + * All builders have at least one queryset, which may be created with an 1.247 + * explicit <queryset> tag or implied if the tag is not used. 1.248 + * 1.249 + * These queryset objects are created and owned by the builder in its 1.250 + * mQuerySets array. 1.251 + */ 1.252 +class nsTemplateQuerySet 1.253 +{ 1.254 +protected: 1.255 + nsTArray<nsTemplateRule> mRules; 1.256 + 1.257 + // a number which increments for each successive queryset. It is stored so 1.258 + // it can be used as an optimization when updating results so that it is 1.259 + // known where to insert them into a match. 1.260 + int32_t mPriority; 1.261 + 1.262 +public: 1.263 + 1.264 + // <query> node 1.265 + nsCOMPtr<nsIContent> mQueryNode; 1.266 + 1.267 + // compiled opaque query object returned by the query processor's 1.268 + // CompileQuery call 1.269 + nsCOMPtr<nsISupports> mCompiledQuery; 1.270 + 1.271 + // indicates that the query will only generate content to be inserted into 1.272 + // a container with this tag 1.273 + nsCOMPtr<nsIAtom> mTag; 1.274 + 1.275 + nsTemplateQuerySet(int32_t aPriority) 1.276 + : mPriority(aPriority) 1.277 + { 1.278 + MOZ_COUNT_CTOR(nsTemplateQuerySet); 1.279 + } 1.280 + 1.281 + ~nsTemplateQuerySet() 1.282 + { 1.283 + MOZ_COUNT_DTOR(nsTemplateQuerySet); 1.284 + } 1.285 + 1.286 + int32_t Priority() const 1.287 + { 1.288 + return mPriority; 1.289 + } 1.290 + 1.291 + nsIAtom* GetTag() { return mTag; } 1.292 + void SetTag(nsIAtom* aTag) { mTag = aTag; } 1.293 + 1.294 + nsTemplateRule* NewRule(nsIContent* aRuleNode, 1.295 + nsIContent* aAction, 1.296 + nsTemplateQuerySet* aQuerySet) 1.297 + { 1.298 + // nsTemplateMatch stores the index as a 16-bit value, 1.299 + // so check to make sure for overflow 1.300 + if (mRules.Length() == INT16_MAX) 1.301 + return nullptr; 1.302 + 1.303 + return mRules.AppendElement(nsTemplateRule(aRuleNode, aAction, 1.304 + aQuerySet)); 1.305 + } 1.306 + 1.307 + void RemoveRule(nsTemplateRule *aRule) 1.308 + { 1.309 + mRules.RemoveElementAt(aRule - mRules.Elements()); 1.310 + } 1.311 + 1.312 + int16_t RuleCount() const 1.313 + { 1.314 + return mRules.Length(); 1.315 + } 1.316 + 1.317 + nsTemplateRule* GetRuleAt(int16_t aIndex) 1.318 + { 1.319 + if (uint32_t(aIndex) < mRules.Length()) { 1.320 + return &mRules[aIndex]; 1.321 + } 1.322 + return nullptr; 1.323 + } 1.324 + 1.325 + void Clear() 1.326 + { 1.327 + mRules.Clear(); 1.328 + } 1.329 +}; 1.330 + 1.331 +#endif // nsTemplateRule_h__