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.

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

mercurial