diff options
Diffstat (limited to 'dom/xul/templates/nsTemplateRule.h')
-rw-r--r-- | dom/xul/templates/nsTemplateRule.h | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/dom/xul/templates/nsTemplateRule.h b/dom/xul/templates/nsTemplateRule.h new file mode 100644 index 000000000..d7821ba29 --- /dev/null +++ b/dom/xul/templates/nsTemplateRule.h @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsTemplateRule_h__ +#define nsTemplateRule_h__ + +#include "nsCOMPtr.h" +#include "nsIAtom.h" +#include "nsIRDFDataSource.h" +#include "nsIRDFResource.h" +#include "nsIContent.h" +#include "nsIDOMNode.h" +#include "nsTArray.h" +#include "nsString.h" +#include "nsIXULTemplateRuleFilter.h" +#include "nsCycleCollectionParticipant.h" + +class nsIXULTemplateQueryProcessor; +class nsTemplateQuerySet; + +class nsTemplateCondition +{ +public: + // relations that may be used in a rule. They may be negated with the + // negate flag. Less and Greater are used for numeric comparisons and + // Before and After are used for string comparisons. For Less, Greater, + // Before, After, Startswith, Endswith, and Contains, the source is + // conceptually on the left of the relation and the target is on the + // right. For example, if the relation is Contains, that means Match if + // the source contains the target. + enum ConditionRelation { + eUnknown, + eEquals, + eLess, + eGreater, + eBefore, + eAfter, + eStartswith, + eEndswith, + eContains + }; + + nsTemplateCondition(nsIAtom* aSourceVariable, + const nsAString& aRelation, + nsIAtom* aTargetVariable, + bool mIgnoreCase, + bool mNegate); + + nsTemplateCondition(nsIAtom* aSourceVariable, + const nsAString& aRelation, + const nsAString& aTargets, + bool mIgnoreCase, + bool mNegate, + bool aIsMultiple); + + nsTemplateCondition(const nsAString& aSource, + const nsAString& aRelation, + nsIAtom* aTargetVariable, + bool mIgnoreCase, + bool mNegate); + + ~nsTemplateCondition() { MOZ_COUNT_DTOR(nsTemplateCondition); } + + nsTemplateCondition* GetNext() { return mNext; } + void SetNext(nsTemplateCondition* aNext) { mNext = aNext; } + + void SetRelation(const nsAString& aRelation); + + bool + CheckMatch(nsIXULTemplateResult* aResult); + + bool + CheckMatchStrings(const nsAString& aLeftString, + const nsAString& aRightString); +protected: + + nsCOMPtr<nsIAtom> mSourceVariable; + nsString mSource; + ConditionRelation mRelation; + nsCOMPtr<nsIAtom> mTargetVariable; + nsTArray<nsString> mTargetList; + bool mIgnoreCase; + bool mNegate; + + nsTemplateCondition* mNext; +}; + +/** + * A rule consists of: + * + * - Conditions, a set of unbound variables with consistency + * constraints that specify the values that each variable can + * assume. The conditions must be completely and consistently + * "bound" for the rule to be considered "matched". + * + * - Bindings, a set of unbound variables with consistency constraints + * that specify the values that each variable can assume. Unlike the + * conditions, the bindings need not be bound for the rule to be + * considered matched. + * + * - Content that should be constructed when the rule is "activated". + * + */ +class nsTemplateRule +{ +public: + nsTemplateRule(nsIContent* aRuleNode, + nsIContent* aAction, + nsTemplateQuerySet* aQuerySet); + /** + * The copy-constructor should only be called from nsTArray when appending + * a new rule, otherwise things break because the copy constructor expects + * mBindings and mConditions to be nullptr. + */ + nsTemplateRule(const nsTemplateRule& aOtherRule); + + ~nsTemplateRule(); + + /** + * Return the <action> node that this rule was constructed from, or its + * logical equivalent for shorthand syntaxes. That is, the parent node of + * the content that should be generated for this rule. + */ + nsIContent* GetAction() const { return mAction; } + + /** + * Return the <rule> content node that this rule was constructed from. + * @param aResult an out parameter, which will contain the rule node + * @return NS_OK if no errors occur. + */ + nsresult GetRuleNode(nsIDOMNode** aResult) const; + + void SetVars(nsIAtom* aRefVariable, nsIAtom* aMemberVariable) + { + mRefVariable = aRefVariable; + mMemberVariable = aMemberVariable; + } + + void SetRuleFilter(nsIXULTemplateRuleFilter* aRuleFilter) + { + mRuleFilter = aRuleFilter; + } + + nsIAtom* GetTag() { return mTag; } + void SetTag(nsIAtom* aTag) { mTag = aTag; } + + nsIAtom* GetMemberVariable() { return mMemberVariable; } + + /** + * Set the first condition for the rule. Other conditions are linked + * to it using the condition's SetNext method. + */ + void SetCondition(nsTemplateCondition* aConditions); + + /** + * Check if the result matches the rule by first looking at the conditions. + * If the results is accepted by the conditions, the rule filter, if any + * was set, is checked. If either check rejects a result, a match cannot + * occur for this rule and result. + */ + bool + CheckMatch(nsIXULTemplateResult* aResult) const; + + /** + * Determine if the rule has the specified binding + */ + bool + HasBinding(nsIAtom* aSourceVariable, + nsAString& aExpr, + nsIAtom* aTargetVariable) const; + + /** + * Add a binding to the rule. A binding consists of an already-bound + * source variable, and the RDF property that should be tested to + * generate a target value. The target value is bound to a target + * variable. + * + * @param aSourceVariable the source variable that will be used in + * the RDF query. + * @param aExpr the expression that will be used in the query. + * @param aTargetVariable the variable whose value will be bound + * to the RDF node that is returned when querying the binding + * @return NS_OK if no errors occur. + */ + nsresult AddBinding(nsIAtom* aSourceVariable, + nsAString& aExpr, + nsIAtom* aTargetVariable); + + /** + * Inform the query processor of the bindings that are set for a rule. + * This should be called after all the bindings for a rule are compiled. + */ + nsresult + AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor); + + void Traverse(nsCycleCollectionTraversalCallback &cb) const + { + cb.NoteXPCOMChild(mRuleNode); + cb.NoteXPCOMChild(mAction); + } + +protected: + + struct Binding { + nsCOMPtr<nsIAtom> mSourceVariable; + nsCOMPtr<nsIAtom> mTargetVariable; + nsString mExpr; + Binding* mNext; + Binding* mParent; + }; + + // backreference to the query set which owns this rule + nsTemplateQuerySet* mQuerySet; + + // the <rule> node, or the <template> node if there is no <rule> + nsCOMPtr<nsIDOMNode> mRuleNode; + + // the <action> node, or, if there is no <action>, the container node + // which contains the content to generate + nsCOMPtr<nsIContent> mAction; + + // the rule filter set by the builder's SetRuleFilter function + nsCOMPtr<nsIXULTemplateRuleFilter> mRuleFilter; + + // indicates that the rule will only match when generating content + // to be inserted into a container with this tag + nsCOMPtr<nsIAtom> mTag; + + // linked-list of the bindings for the rule, owned by the rule. + Binding* mBindings; + + nsCOMPtr<nsIAtom> mRefVariable; + nsCOMPtr<nsIAtom> mMemberVariable; + + nsTemplateCondition* mConditions; // owned by nsTemplateRule +}; + +/** nsTemplateQuerySet + * + * A single <queryset> which holds the query node and the rules for it. + * All builders have at least one queryset, which may be created with an + * explicit <queryset> tag or implied if the tag is not used. + * + * These queryset objects are created and owned by the builder in its + * mQuerySets array. + */ +class nsTemplateQuerySet +{ +protected: + nsTArray<nsTemplateRule> mRules; + + // a number which increments for each successive queryset. It is stored so + // it can be used as an optimization when updating results so that it is + // known where to insert them into a match. + int32_t mPriority; + +public: + + // <query> node + nsCOMPtr<nsIContent> mQueryNode; + + // compiled opaque query object returned by the query processor's + // CompileQuery call + nsCOMPtr<nsISupports> mCompiledQuery; + + // indicates that the query will only generate content to be inserted into + // a container with this tag + nsCOMPtr<nsIAtom> mTag; + + explicit nsTemplateQuerySet(int32_t aPriority) + : mPriority(aPriority) + { + MOZ_COUNT_CTOR(nsTemplateQuerySet); + } + + ~nsTemplateQuerySet() + { + MOZ_COUNT_DTOR(nsTemplateQuerySet); + } + + int32_t Priority() const + { + return mPriority; + } + + nsIAtom* GetTag() { return mTag; } + void SetTag(nsIAtom* aTag) { mTag = aTag; } + + nsTemplateRule* NewRule(nsIContent* aRuleNode, + nsIContent* aAction, + nsTemplateQuerySet* aQuerySet) + { + // nsTemplateMatch stores the index as a 16-bit value, + // so check to make sure for overflow + if (mRules.Length() == INT16_MAX) + return nullptr; + + return mRules.AppendElement(nsTemplateRule(aRuleNode, aAction, + aQuerySet)); + } + + void RemoveRule(nsTemplateRule *aRule) + { + mRules.RemoveElementAt(aRule - mRules.Elements()); + } + + int16_t RuleCount() const + { + return mRules.Length(); + } + + nsTemplateRule* GetRuleAt(int16_t aIndex) + { + if (uint32_t(aIndex) < mRules.Length()) { + return &mRules[aIndex]; + } + return nullptr; + } + + void Clear() + { + mRules.Clear(); + } +}; + +#endif // nsTemplateRule_h__ |