content/xul/templates/src/nsTemplateRule.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 #include "nsTemplateRule.h"
     7 #include "nsTemplateMatch.h"
     8 #include "nsXULContentUtils.h"
     9 #include "nsUnicharUtils.h"
    10 #include "nsReadableUtils.h"
    11 #include "nsICollation.h"
    13 nsTemplateCondition::nsTemplateCondition(nsIAtom* aSourceVariable,
    14                                          const nsAString& aRelation,
    15                                          nsIAtom* aTargetVariable,
    16                                          bool aIgnoreCase,
    17                                          bool aNegate)
    18     : mSourceVariable(aSourceVariable),
    19       mTargetVariable(aTargetVariable),
    20       mIgnoreCase(aIgnoreCase),
    21       mNegate(aNegate),
    22       mNext(nullptr)
    23 {
    24     SetRelation(aRelation);
    26     MOZ_COUNT_CTOR(nsTemplateCondition);
    27 }
    29 nsTemplateCondition::nsTemplateCondition(nsIAtom* aSourceVariable,
    30                                          const nsAString& aRelation,
    31                                          const nsAString& aTargets,
    32                                          bool aIgnoreCase,
    33                                          bool aNegate,
    34                                          bool aIsMultiple)
    35     : mSourceVariable(aSourceVariable),
    36       mIgnoreCase(aIgnoreCase),
    37       mNegate(aNegate),
    38       mNext(nullptr)
    39 {
    40     SetRelation(aRelation);
    42     if (aIsMultiple) {
    43         int32_t start = 0, end = 0;
    44         while ((end = aTargets.FindChar(',',start)) >= 0) {
    45             if (end > start) {
    46                 mTargetList.AppendElement(Substring(aTargets, start, end - start));
    47             }
    48             start = end + 1;
    49         }
    50         if (start < int32_t(aTargets.Length())) {
    51             mTargetList.AppendElement(Substring(aTargets, start));
    52         }
    53     }
    54     else {
    55         mTargetList.AppendElement(aTargets);
    56     }
    58     MOZ_COUNT_CTOR(nsTemplateCondition);
    59 }
    61 nsTemplateCondition::nsTemplateCondition(const nsAString& aSource,
    62                                          const nsAString& aRelation,
    63                                          nsIAtom* aTargetVariable,
    64                                          bool aIgnoreCase,
    65                                          bool aNegate)
    66     : mSource(aSource),
    67       mTargetVariable(aTargetVariable),
    68       mIgnoreCase(aIgnoreCase),
    69       mNegate(aNegate),
    70       mNext(nullptr)
    71 {
    72     SetRelation(aRelation);
    74     MOZ_COUNT_CTOR(nsTemplateCondition);
    75 }
    77 void
    78 nsTemplateCondition::SetRelation(const nsAString& aRelation)
    79 {
    80     if (aRelation.EqualsLiteral("equals") || aRelation.IsEmpty())
    81         mRelation = eEquals;
    82     else if (aRelation.EqualsLiteral("less"))
    83         mRelation = eLess;
    84     else if (aRelation.EqualsLiteral("greater"))
    85         mRelation = eGreater;
    86     else if (aRelation.EqualsLiteral("before"))
    87         mRelation = eBefore;
    88     else if (aRelation.EqualsLiteral("after"))
    89         mRelation = eAfter;
    90     else if (aRelation.EqualsLiteral("startswith"))
    91         mRelation = eStartswith;
    92     else if (aRelation.EqualsLiteral("endswith"))
    93         mRelation = eEndswith;
    94     else if (aRelation.EqualsLiteral("contains"))
    95         mRelation = eContains;
    96     else
    97         mRelation = eUnknown;
    98 }
   100 bool
   101 nsTemplateCondition::CheckMatch(nsIXULTemplateResult* aResult)
   102 {
   103     bool match = false;
   105     nsAutoString leftString;
   106     if (mSourceVariable)
   107       aResult->GetBindingFor(mSourceVariable, leftString);
   108     else
   109       leftString.Assign(mSource);
   111     if (mTargetVariable) {
   112         nsAutoString rightString;
   113         aResult->GetBindingFor(mTargetVariable, rightString);
   115         match = CheckMatchStrings(leftString, rightString);
   116     }
   117     else {
   118         // iterate over the strings in the target and determine
   119         // whether there is a match.
   120         uint32_t length = mTargetList.Length();
   121         for (uint32_t t = 0; t < length; t++) {
   122             match = CheckMatchStrings(leftString, mTargetList[t]);
   124             // stop once a match is found. In negate mode, stop once a
   125             // target does not match.
   126             if (match != mNegate) break;
   127         }
   128     }
   130     return match;
   131 }
   134 bool
   135 nsTemplateCondition::CheckMatchStrings(const nsAString& aLeftString,
   136                                        const nsAString& aRightString)
   137 {
   138     bool match = false;
   140     if (aRightString.IsEmpty()) {
   141         if ((mRelation == eEquals) && aLeftString.IsEmpty())
   142             match = true;
   143     }
   144     else {
   145         switch (mRelation) {
   146             case eEquals:
   147                 if (mIgnoreCase)
   148                     match = aLeftString.Equals(aRightString,
   149                                                nsCaseInsensitiveStringComparator());
   150                 else
   151                     match = aLeftString.Equals(aRightString);
   152                 break;
   154             case eLess:
   155             case eGreater:
   156             {
   157                 // non-numbers always compare false
   158                 nsresult err;
   159                 int32_t leftint = PromiseFlatString(aLeftString).ToInteger(&err);
   160                 if (NS_SUCCEEDED(err)) {
   161                     int32_t rightint = PromiseFlatString(aRightString).ToInteger(&err);
   162                     if (NS_SUCCEEDED(err)) {
   163                         match = (mRelation == eLess) ? (leftint < rightint) :
   164                                                        (leftint > rightint);
   165                     }
   166                 }
   168                 break;
   169             }
   171             case eBefore:
   172             {
   173                 nsICollation* collation = nsXULContentUtils::GetCollation();
   174                 if (collation) {
   175                     int32_t sortOrder;
   176                     collation->CompareString((mIgnoreCase ?
   177                                               static_cast<int32_t>(nsICollation::kCollationCaseInSensitive) :
   178                                               static_cast<int32_t>(nsICollation::kCollationCaseSensitive)),
   179                                               aLeftString,
   180                                               aRightString,
   181                                               &sortOrder);
   182                     match = (sortOrder < 0);
   183                 }
   184                 else if (mIgnoreCase) {
   185                     match = (Compare(aLeftString, aRightString,
   186                                      nsCaseInsensitiveStringComparator()) < 0);
   187                 }
   188                 else {
   189                     match = (Compare(aLeftString, aRightString) < 0);
   190                 }
   191                 break;
   192             }
   194             case eAfter:
   195             {
   196                 nsICollation* collation = nsXULContentUtils::GetCollation();
   197                 if (collation) {
   198                     int32_t sortOrder;
   199                     collation->CompareString((mIgnoreCase ?
   200                                               static_cast<int32_t>(nsICollation::kCollationCaseInSensitive) :
   201                                               static_cast<int32_t>(nsICollation::kCollationCaseSensitive)),
   202                                               aLeftString,
   203                                               aRightString,
   204                                               &sortOrder);
   205                     match = (sortOrder > 0);
   206                 }
   207                 else if (mIgnoreCase) {
   208                     match = (Compare(aLeftString, aRightString,
   209                                      nsCaseInsensitiveStringComparator()) > 0);
   210                 }
   211                 else {
   212                     match = (Compare(aLeftString, aRightString) > 0);
   213                 }
   214                 break;
   215             }
   217             case eStartswith:
   218                 if (mIgnoreCase)
   219                     match = (StringBeginsWith(aLeftString, aRightString,
   220                                               nsCaseInsensitiveStringComparator()));
   221                 else
   222                     match = (StringBeginsWith(aLeftString, aRightString));
   223                 break;
   225             case eEndswith:
   226                 if (mIgnoreCase)
   227                     match = (StringEndsWith(aLeftString, aRightString,
   228                                             nsCaseInsensitiveStringComparator()));
   229                 else
   230                     match = (StringEndsWith(aLeftString, aRightString));
   231                 break;
   233             case eContains:
   234             {
   235                 nsAString::const_iterator start, end;
   236                 aLeftString.BeginReading(start);
   237                 aLeftString.EndReading(end);
   238                 if (mIgnoreCase)
   239                     match = CaseInsensitiveFindInReadable(aRightString, start, end);
   240                 else
   241                     match = FindInReadable(aRightString, start, end);
   242                 break;
   243             }
   245             default:
   246                 break;
   247         }
   248     }
   250     if (mNegate) match = !match;
   252     return match;
   253 }
   255 nsTemplateRule::nsTemplateRule(nsIContent* aRuleNode,
   256                                nsIContent* aAction,
   257                                nsTemplateQuerySet* aQuerySet)
   258         : mQuerySet(aQuerySet),
   259           mAction(aAction),
   260           mBindings(nullptr),
   261           mConditions(nullptr)
   262 {
   263     MOZ_COUNT_CTOR(nsTemplateRule);
   264     mRuleNode = do_QueryInterface(aRuleNode);
   265 }
   267 nsTemplateRule::nsTemplateRule(const nsTemplateRule& aOtherRule)
   268         : mQuerySet(aOtherRule.mQuerySet),
   269           mRuleNode(aOtherRule.mRuleNode),
   270           mAction(aOtherRule.mAction),
   271           mBindings(nullptr),
   272           mConditions(nullptr)
   273 {
   274     MOZ_COUNT_CTOR(nsTemplateRule);
   275 }
   277 nsTemplateRule::~nsTemplateRule()
   278 {
   279     MOZ_COUNT_DTOR(nsTemplateRule);
   281     while (mBindings) {
   282         Binding* doomed = mBindings;
   283         mBindings = mBindings->mNext;
   284         delete doomed;
   285     }
   287     while (mConditions) {
   288         nsTemplateCondition* cdel = mConditions;
   289         mConditions = mConditions->GetNext();
   290         delete cdel;
   291     }
   292 }
   294 nsresult
   295 nsTemplateRule::GetRuleNode(nsIDOMNode** aRuleNode) const
   296 {
   297     *aRuleNode = mRuleNode;
   298     NS_IF_ADDREF(*aRuleNode);
   299     return NS_OK;
   300 }
   302 void nsTemplateRule::SetCondition(nsTemplateCondition* aCondition)
   303 {
   304     while (mConditions) {
   305         nsTemplateCondition* cdel = mConditions;
   306         mConditions = mConditions->GetNext();
   307         delete cdel;
   308     }
   310     mConditions = aCondition;
   311 }
   313 bool
   314 nsTemplateRule::CheckMatch(nsIXULTemplateResult* aResult) const
   315 {
   316     // check the conditions in the rule first
   317     nsTemplateCondition* condition = mConditions;
   318     while (condition) {
   319         if (!condition->CheckMatch(aResult))
   320             return false;
   322         condition = condition->GetNext();
   323     }
   325     if (mRuleFilter) {
   326         // if a rule filter was set, check it for a match. If an error occurs,
   327         // assume that the match was acceptable
   328         bool match;
   329         nsresult rv = mRuleFilter->Match(aResult, mRuleNode, &match);
   330         return NS_FAILED(rv) || match;
   331     }
   333     return true;
   334 }
   336 bool
   337 nsTemplateRule::HasBinding(nsIAtom* aSourceVariable,
   338                            nsAString& aExpr,
   339                            nsIAtom* aTargetVariable) const
   340 {
   341     for (Binding* binding = mBindings; binding != nullptr; binding = binding->mNext) {
   342         if ((binding->mSourceVariable == aSourceVariable) &&
   343             (binding->mExpr.Equals(aExpr)) &&
   344             (binding->mTargetVariable == aTargetVariable))
   345             return true;
   346     }
   348     return false;
   349 }
   351 nsresult
   352 nsTemplateRule::AddBinding(nsIAtom* aSourceVariable,
   353                            nsAString& aExpr,
   354                            nsIAtom* aTargetVariable)
   355 {
   356     NS_PRECONDITION(aSourceVariable != 0, "no source variable!");
   357     if (! aSourceVariable)
   358         return NS_ERROR_INVALID_ARG;
   360     NS_PRECONDITION(aTargetVariable != 0, "no target variable!");
   361     if (! aTargetVariable)
   362         return NS_ERROR_INVALID_ARG;
   364     NS_ASSERTION(! HasBinding(aSourceVariable, aExpr, aTargetVariable),
   365                  "binding added twice");
   367     Binding* newbinding = new Binding;
   368     if (! newbinding)
   369         return NS_ERROR_OUT_OF_MEMORY;
   371     newbinding->mSourceVariable = aSourceVariable;
   372     newbinding->mTargetVariable = aTargetVariable;
   373     newbinding->mParent         = nullptr;
   375     newbinding->mExpr.Assign(aExpr);
   377     Binding* binding = mBindings;
   378     Binding** link = &mBindings;
   380     // Insert it at the end, unless we detect that an existing
   381     // binding's source is dependent on the newbinding's target.
   382     //
   383     // XXXwaterson this isn't enough to make sure that we get all of
   384     // the dependencies worked out right, but it'll do for now. For
   385     // example, if you have (ab, bc, cd), and insert them in the order
   386     // (cd, ab, bc), you'll get (bc, cd, ab). The good news is, if the
   387     // person uses a natural ordering when writing the XUL, it'll all
   388     // work out ok.
   389     while (binding) {
   390         if (binding->mSourceVariable == newbinding->mTargetVariable) {
   391             binding->mParent = newbinding;
   392             break;
   393         }
   394         else if (binding->mTargetVariable == newbinding->mSourceVariable) {
   395             newbinding->mParent = binding;
   396         }
   398         link = &binding->mNext;
   399         binding = binding->mNext;
   400     }
   402     // Insert the newbinding
   403     *link = newbinding;
   404     newbinding->mNext = binding;
   405     return NS_OK;
   406 }
   408 nsresult
   409 nsTemplateRule::AddBindingsToQueryProcessor(nsIXULTemplateQueryProcessor* aProcessor)
   410 {
   411     Binding* binding = mBindings;
   413     while (binding) {
   414         nsresult rv = aProcessor->AddBinding(mRuleNode, binding->mTargetVariable,
   415                                              binding->mSourceVariable, binding->mExpr);
   416         if (NS_FAILED(rv)) return rv;
   418         binding = binding->mNext;
   419     }
   421     return NS_OK;
   422 }

mercurial