content/base/src/nsDOMTokenList.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 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6  * Implementation of DOMTokenList specified by HTML5.
     7  */
     9 #include "nsDOMTokenList.h"
    11 #include "nsAttrValue.h"
    12 #include "nsContentUtils.h"
    13 #include "nsError.h"
    14 #include "mozilla/dom/Element.h"
    15 #include "mozilla/dom/DOMTokenListBinding.h"
    16 #include "mozilla/ErrorResult.h"
    18 using namespace mozilla;
    19 using namespace mozilla::dom;
    21 nsDOMTokenList::nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom)
    22   : mElement(aElement),
    23     mAttrAtom(aAttrAtom)
    24 {
    25   // We don't add a reference to our element. If it goes away,
    26   // we'll be told to drop our reference
    27   SetIsDOMBinding();
    28 }
    30 nsDOMTokenList::~nsDOMTokenList() { }
    32 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMTokenList, mElement)
    34 NS_INTERFACE_MAP_BEGIN(nsDOMTokenList)
    35   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    36   NS_INTERFACE_MAP_ENTRY(nsISupports)
    37   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMTokenList)
    38 NS_INTERFACE_MAP_END
    40 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTokenList)
    41 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTokenList)
    43 const nsAttrValue*
    44 nsDOMTokenList::GetParsedAttr()
    45 {
    46   if (!mElement) {
    47     return nullptr;
    48   }
    49   return mElement->GetAttrInfo(kNameSpaceID_None, mAttrAtom).mValue;
    50 }
    52 uint32_t
    53 nsDOMTokenList::Length()
    54 {
    55   const nsAttrValue* attr = GetParsedAttr();
    56   if (!attr) {
    57     return 0;
    58   }
    60   return attr->GetAtomCount();
    61 }
    63 void
    64 nsDOMTokenList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult)
    65 {
    66   const nsAttrValue* attr = GetParsedAttr();
    68   if (attr && aIndex < static_cast<uint32_t>(attr->GetAtomCount())) {
    69     aFound = true;
    70     attr->AtomAt(aIndex)->ToString(aResult);
    71   } else {
    72     aFound = false;
    73   }
    74 }
    76 nsresult
    77 nsDOMTokenList::CheckToken(const nsAString& aStr)
    78 {
    79   if (aStr.IsEmpty()) {
    80     return NS_ERROR_DOM_SYNTAX_ERR;
    81   }
    83   nsAString::const_iterator iter, end;
    84   aStr.BeginReading(iter);
    85   aStr.EndReading(end);
    87   while (iter != end) {
    88     if (nsContentUtils::IsHTMLWhitespace(*iter))
    89       return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
    90     ++iter;
    91   }
    93   return NS_OK;
    94 }
    96 nsresult
    97 nsDOMTokenList::CheckTokens(const nsTArray<nsString>& aTokens)
    98 {
    99   for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
   100     nsresult rv = CheckToken(aTokens[i]);
   101     if (NS_FAILED(rv)) {
   102       return rv;
   103     }
   104   }
   106   return NS_OK;
   107 }
   109 bool
   110 nsDOMTokenList::Contains(const nsAString& aToken, ErrorResult& aError)
   111 {
   112   aError = CheckToken(aToken);
   113   if (aError.Failed()) {
   114     return false;
   115   }
   117   const nsAttrValue* attr = GetParsedAttr();
   118   return attr && attr->Contains(aToken);
   119 }
   121 void
   122 nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
   123                             const nsTArray<nsString>& aTokens)
   124 {
   125   if (!mElement) {
   126     return;
   127   }
   129   nsAutoString resultStr;
   131   if (aAttr) {
   132     aAttr->ToString(resultStr);
   133   }
   135   bool oneWasAdded = false;
   136   nsAutoTArray<nsString, 10> addedClasses;
   138   for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
   139     const nsString& aToken = aTokens[i];
   141     if ((aAttr && aAttr->Contains(aToken)) ||
   142         addedClasses.Contains(aToken)) {
   143       continue;
   144     }
   146     if (oneWasAdded ||
   147         (!resultStr.IsEmpty() &&
   148         !nsContentUtils::IsHTMLWhitespace(resultStr.Last()))) {
   149       resultStr.Append(NS_LITERAL_STRING(" ") + aToken);
   150     } else {
   151       resultStr.Append(aToken);
   152     }
   154     oneWasAdded = true;
   155     addedClasses.AppendElement(aToken);
   156   }
   158   mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
   159 }
   161 void
   162 nsDOMTokenList::Add(const nsTArray<nsString>& aTokens, ErrorResult& aError)
   163 {
   164   aError = CheckTokens(aTokens);
   165   if (aError.Failed()) {
   166     return;
   167   }
   169   const nsAttrValue* attr = GetParsedAttr();
   170   AddInternal(attr, aTokens);
   171 }
   173 void
   174 nsDOMTokenList::Add(const nsAString& aToken, mozilla::ErrorResult& aError)
   175 {
   176   nsAutoTArray<nsString, 1> tokens;
   177   tokens.AppendElement(aToken);
   178   Add(tokens, aError);
   179 }
   181 void
   182 nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
   183                                const nsTArray<nsString>& aTokens)
   184 {
   185   NS_ABORT_IF_FALSE(aAttr, "Need an attribute");
   187   nsAutoString input;
   188   aAttr->ToString(input);
   190   nsAString::const_iterator copyStart, tokenStart, iter, end;
   191   input.BeginReading(iter);
   192   input.EndReading(end);
   193   copyStart = iter;
   195   nsAutoString output;
   196   bool lastTokenRemoved = false;
   198   while (iter != end) {
   199     // skip whitespace.
   200     while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
   201       ++iter;
   202     }
   204     if (iter == end) {
   205       // At this point we're sure the last seen token (if any) wasn't to be
   206       // removed. So the trailing spaces will need to be kept.
   207       NS_ABORT_IF_FALSE(!lastTokenRemoved, "How did this happen?");
   209       output.Append(Substring(copyStart, end));
   210       break;
   211     }
   213     tokenStart = iter;
   214     do {
   215       ++iter;
   216     } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
   218     if (aTokens.Contains(Substring(tokenStart, iter))) {
   220       // Skip whitespace after the token, it will be collapsed.
   221       while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
   222         ++iter;
   223       }
   224       copyStart = iter;
   225       lastTokenRemoved = true;
   227     } else {
   229       if (lastTokenRemoved && !output.IsEmpty()) {
   230         NS_ABORT_IF_FALSE(!nsContentUtils::IsHTMLWhitespace(
   231           output.Last()), "Invalid last output token");
   232         output.Append(char16_t(' '));
   233       }
   234       lastTokenRemoved = false;
   235       output.Append(Substring(copyStart, iter));
   236       copyStart = iter;
   237     }
   238   }
   240   mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, true);
   241 }
   243 void
   244 nsDOMTokenList::Remove(const nsTArray<nsString>& aTokens, ErrorResult& aError)
   245 {
   246   aError = CheckTokens(aTokens);
   247   if (aError.Failed()) {
   248     return;
   249   }
   251   const nsAttrValue* attr = GetParsedAttr();
   252   if (!attr) {
   253     return;
   254   }
   256   RemoveInternal(attr, aTokens);
   257 }
   259 void
   260 nsDOMTokenList::Remove(const nsAString& aToken, mozilla::ErrorResult& aError)
   261 {
   262   nsAutoTArray<nsString, 1> tokens;
   263   tokens.AppendElement(aToken);
   264   Remove(tokens, aError);
   265 }
   267 bool
   268 nsDOMTokenList::Toggle(const nsAString& aToken,
   269                        const Optional<bool>& aForce,
   270                        ErrorResult& aError)
   271 {
   272   aError = CheckToken(aToken);
   273   if (aError.Failed()) {
   274     return false;
   275   }
   277   const nsAttrValue* attr = GetParsedAttr();
   278   const bool forceOn = aForce.WasPassed() && aForce.Value();
   279   const bool forceOff = aForce.WasPassed() && !aForce.Value();
   281   bool isPresent = attr && attr->Contains(aToken);
   282   nsAutoTArray<nsString, 1> tokens;
   283   (*tokens.AppendElement()).Rebind(aToken.Data(), aToken.Length());
   285   if (isPresent) {
   286     if (!forceOn) {
   287       RemoveInternal(attr, tokens);
   288       isPresent = false;
   289     }
   290   } else {
   291     if (!forceOff) {
   292       AddInternal(attr, tokens);
   293       isPresent = true;
   294     }
   295   }
   297   return isPresent;
   298 }
   300 void
   301 nsDOMTokenList::Stringify(nsAString& aResult)
   302 {
   303   if (!mElement) {
   304     aResult.Truncate();
   305     return;
   306   }
   308   mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
   309 }
   311 JSObject*
   312 nsDOMTokenList::WrapObject(JSContext *cx)
   313 {
   314   return DOMTokenListBinding::Wrap(cx, this);
   315 }

mercurial