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.

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

mercurial