1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsAttrValue.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1999 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * A struct that represents the value (type and actual data) of an 1.11 + * attribute. 1.12 + */ 1.13 + 1.14 +#include "mozilla/DebugOnly.h" 1.15 +#include "mozilla/HashFunctions.h" 1.16 + 1.17 +#include "nsAttrValue.h" 1.18 +#include "nsAttrValueInlines.h" 1.19 +#include "nsIAtom.h" 1.20 +#include "nsUnicharUtils.h" 1.21 +#include "mozilla/MemoryReporting.h" 1.22 +#include "mozilla/css/StyleRule.h" 1.23 +#include "mozilla/css/Declaration.h" 1.24 +#include "nsContentUtils.h" 1.25 +#include "nsReadableUtils.h" 1.26 +#include "prprf.h" 1.27 +#include "nsHTMLCSSStyleSheet.h" 1.28 +#include "nsCSSParser.h" 1.29 +#include "nsStyledElement.h" 1.30 +#include "nsIURI.h" 1.31 +#include "nsIDocument.h" 1.32 +#include <algorithm> 1.33 + 1.34 +using namespace mozilla; 1.35 + 1.36 +#define MISC_STR_PTR(_cont) \ 1.37 + reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK) 1.38 + 1.39 +bool 1.40 +MiscContainer::GetString(nsAString& aString) const 1.41 +{ 1.42 + void* ptr = MISC_STR_PTR(this); 1.43 + 1.44 + if (!ptr) { 1.45 + return false; 1.46 + } 1.47 + 1.48 + if (static_cast<nsAttrValue::ValueBaseType>(mStringBits & 1.49 + NS_ATTRVALUE_BASETYPE_MASK) == 1.50 + nsAttrValue::eStringBase) { 1.51 + nsStringBuffer* buffer = static_cast<nsStringBuffer*>(ptr); 1.52 + if (!buffer) { 1.53 + return false; 1.54 + } 1.55 + 1.56 + buffer->ToString(buffer->StorageSize() / sizeof(char16_t) - 1, aString); 1.57 + return true; 1.58 + } 1.59 + 1.60 + nsIAtom* atom = static_cast<nsIAtom*>(ptr); 1.61 + if (!atom) { 1.62 + return false; 1.63 + } 1.64 + 1.65 + atom->ToString(aString); 1.66 + return true; 1.67 +} 1.68 + 1.69 +void 1.70 +MiscContainer::Cache() 1.71 +{ 1.72 + // Not implemented for anything else yet. 1.73 + MOZ_ASSERT(mType == nsAttrValue::eCSSStyleRule); 1.74 + MOZ_ASSERT(IsRefCounted()); 1.75 + MOZ_ASSERT(mValue.mRefCount > 0); 1.76 + MOZ_ASSERT(!mValue.mCached); 1.77 + 1.78 + css::StyleRule* rule = mValue.mCSSStyleRule; 1.79 + nsHTMLCSSStyleSheet* sheet = rule->GetHTMLCSSStyleSheet(); 1.80 + if (!sheet) { 1.81 + return; 1.82 + } 1.83 + 1.84 + nsString str; 1.85 + bool gotString = GetString(str); 1.86 + if (!gotString) { 1.87 + return; 1.88 + } 1.89 + 1.90 + sheet->CacheStyleAttr(str, this); 1.91 + mValue.mCached = 1; 1.92 + 1.93 + // This has to be immutable once it goes into the cache. 1.94 + css::Declaration* decl = rule->GetDeclaration(); 1.95 + if (decl) { 1.96 + decl->SetImmutable(); 1.97 + } 1.98 +} 1.99 + 1.100 +void 1.101 +MiscContainer::Evict() 1.102 +{ 1.103 + // Not implemented for anything else yet. 1.104 + MOZ_ASSERT(mType == nsAttrValue::eCSSStyleRule); 1.105 + MOZ_ASSERT(IsRefCounted()); 1.106 + MOZ_ASSERT(mValue.mRefCount == 0); 1.107 + 1.108 + if (!mValue.mCached) { 1.109 + return; 1.110 + } 1.111 + 1.112 + css::StyleRule* rule = mValue.mCSSStyleRule; 1.113 + nsHTMLCSSStyleSheet* sheet = rule->GetHTMLCSSStyleSheet(); 1.114 + MOZ_ASSERT(sheet); 1.115 + 1.116 + nsString str; 1.117 + DebugOnly<bool> gotString = GetString(str); 1.118 + MOZ_ASSERT(gotString); 1.119 + 1.120 + sheet->EvictStyleAttr(str, this); 1.121 + mValue.mCached = 0; 1.122 +} 1.123 + 1.124 +nsTArray<const nsAttrValue::EnumTable*>* nsAttrValue::sEnumTableArray = nullptr; 1.125 + 1.126 +nsAttrValue::nsAttrValue() 1.127 + : mBits(0) 1.128 +{ 1.129 +} 1.130 + 1.131 +nsAttrValue::nsAttrValue(const nsAttrValue& aOther) 1.132 + : mBits(0) 1.133 +{ 1.134 + SetTo(aOther); 1.135 +} 1.136 + 1.137 +nsAttrValue::nsAttrValue(const nsAString& aValue) 1.138 + : mBits(0) 1.139 +{ 1.140 + SetTo(aValue); 1.141 +} 1.142 + 1.143 +nsAttrValue::nsAttrValue(nsIAtom* aValue) 1.144 + : mBits(0) 1.145 +{ 1.146 + SetTo(aValue); 1.147 +} 1.148 + 1.149 +nsAttrValue::nsAttrValue(css::StyleRule* aValue, const nsAString* aSerialized) 1.150 + : mBits(0) 1.151 +{ 1.152 + SetTo(aValue, aSerialized); 1.153 +} 1.154 + 1.155 +nsAttrValue::nsAttrValue(const nsIntMargin& aValue) 1.156 + : mBits(0) 1.157 +{ 1.158 + SetTo(aValue); 1.159 +} 1.160 + 1.161 +nsAttrValue::~nsAttrValue() 1.162 +{ 1.163 + ResetIfSet(); 1.164 +} 1.165 + 1.166 +/* static */ 1.167 +nsresult 1.168 +nsAttrValue::Init() 1.169 +{ 1.170 + NS_ASSERTION(!sEnumTableArray, "nsAttrValue already initialized"); 1.171 + 1.172 + sEnumTableArray = new nsTArray<const EnumTable*>; 1.173 + NS_ENSURE_TRUE(sEnumTableArray, NS_ERROR_OUT_OF_MEMORY); 1.174 + 1.175 + return NS_OK; 1.176 +} 1.177 + 1.178 +/* static */ 1.179 +void 1.180 +nsAttrValue::Shutdown() 1.181 +{ 1.182 + delete sEnumTableArray; 1.183 + sEnumTableArray = nullptr; 1.184 +} 1.185 + 1.186 +nsAttrValue::ValueType 1.187 +nsAttrValue::Type() const 1.188 +{ 1.189 + switch (BaseType()) { 1.190 + case eIntegerBase: 1.191 + { 1.192 + return static_cast<ValueType>(mBits & NS_ATTRVALUE_INTEGERTYPE_MASK); 1.193 + } 1.194 + case eOtherBase: 1.195 + { 1.196 + return GetMiscContainer()->mType; 1.197 + } 1.198 + default: 1.199 + { 1.200 + return static_cast<ValueType>(static_cast<uint16_t>(BaseType())); 1.201 + } 1.202 + } 1.203 +} 1.204 + 1.205 +void 1.206 +nsAttrValue::Reset() 1.207 +{ 1.208 + switch(BaseType()) { 1.209 + case eStringBase: 1.210 + { 1.211 + nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); 1.212 + if (str) { 1.213 + str->Release(); 1.214 + } 1.215 + 1.216 + break; 1.217 + } 1.218 + case eOtherBase: 1.219 + { 1.220 + MiscContainer* cont = GetMiscContainer(); 1.221 + if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) { 1.222 + NS_RELEASE(cont); 1.223 + break; 1.224 + } 1.225 + 1.226 + delete ClearMiscContainer(); 1.227 + 1.228 + break; 1.229 + } 1.230 + case eAtomBase: 1.231 + { 1.232 + nsIAtom* atom = GetAtomValue(); 1.233 + NS_RELEASE(atom); 1.234 + 1.235 + break; 1.236 + } 1.237 + case eIntegerBase: 1.238 + { 1.239 + break; 1.240 + } 1.241 + } 1.242 + 1.243 + mBits = 0; 1.244 +} 1.245 + 1.246 +void 1.247 +nsAttrValue::SetTo(const nsAttrValue& aOther) 1.248 +{ 1.249 + if (this == &aOther) { 1.250 + return; 1.251 + } 1.252 + 1.253 + switch (aOther.BaseType()) { 1.254 + case eStringBase: 1.255 + { 1.256 + ResetIfSet(); 1.257 + nsStringBuffer* str = static_cast<nsStringBuffer*>(aOther.GetPtr()); 1.258 + if (str) { 1.259 + str->AddRef(); 1.260 + SetPtrValueAndType(str, eStringBase); 1.261 + } 1.262 + return; 1.263 + } 1.264 + case eOtherBase: 1.265 + { 1.266 + break; 1.267 + } 1.268 + case eAtomBase: 1.269 + { 1.270 + ResetIfSet(); 1.271 + nsIAtom* atom = aOther.GetAtomValue(); 1.272 + NS_ADDREF(atom); 1.273 + SetPtrValueAndType(atom, eAtomBase); 1.274 + return; 1.275 + } 1.276 + case eIntegerBase: 1.277 + { 1.278 + ResetIfSet(); 1.279 + mBits = aOther.mBits; 1.280 + return; 1.281 + } 1.282 + } 1.283 + 1.284 + MiscContainer* otherCont = aOther.GetMiscContainer(); 1.285 + if (otherCont->IsRefCounted()) { 1.286 + delete ClearMiscContainer(); 1.287 + NS_ADDREF(otherCont); 1.288 + SetPtrValueAndType(otherCont, eOtherBase); 1.289 + return; 1.290 + } 1.291 + 1.292 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.293 + switch (otherCont->mType) { 1.294 + case eInteger: 1.295 + { 1.296 + cont->mValue.mInteger = otherCont->mValue.mInteger; 1.297 + break; 1.298 + } 1.299 + case eEnum: 1.300 + { 1.301 + cont->mValue.mEnumValue = otherCont->mValue.mEnumValue; 1.302 + break; 1.303 + } 1.304 + case ePercent: 1.305 + { 1.306 + cont->mValue.mPercent = otherCont->mValue.mPercent; 1.307 + break; 1.308 + } 1.309 + case eColor: 1.310 + { 1.311 + cont->mValue.mColor = otherCont->mValue.mColor; 1.312 + break; 1.313 + } 1.314 + case eCSSStyleRule: 1.315 + { 1.316 + MOZ_CRASH("These should be refcounted!"); 1.317 + } 1.318 + case eURL: 1.319 + { 1.320 + NS_ADDREF(cont->mValue.mURL = otherCont->mValue.mURL); 1.321 + break; 1.322 + } 1.323 + case eImage: 1.324 + { 1.325 + NS_ADDREF(cont->mValue.mImage = otherCont->mValue.mImage); 1.326 + break; 1.327 + } 1.328 + case eAtomArray: 1.329 + { 1.330 + if (!EnsureEmptyAtomArray() || 1.331 + !GetAtomArrayValue()->AppendElements(*otherCont->mValue.mAtomArray)) { 1.332 + Reset(); 1.333 + return; 1.334 + } 1.335 + break; 1.336 + } 1.337 + case eDoubleValue: 1.338 + { 1.339 + cont->mDoubleValue = otherCont->mDoubleValue; 1.340 + break; 1.341 + } 1.342 + case eIntMarginValue: 1.343 + { 1.344 + if (otherCont->mValue.mIntMargin) 1.345 + cont->mValue.mIntMargin = 1.346 + new nsIntMargin(*otherCont->mValue.mIntMargin); 1.347 + break; 1.348 + } 1.349 + default: 1.350 + { 1.351 + if (IsSVGType(otherCont->mType)) { 1.352 + // All SVG types are just pointers to classes and will therefore have 1.353 + // the same size so it doesn't really matter which one we assign 1.354 + cont->mValue.mSVGAngle = otherCont->mValue.mSVGAngle; 1.355 + } else { 1.356 + NS_NOTREACHED("unknown type stored in MiscContainer"); 1.357 + } 1.358 + break; 1.359 + } 1.360 + } 1.361 + 1.362 + void* otherPtr = MISC_STR_PTR(otherCont); 1.363 + if (otherPtr) { 1.364 + if (static_cast<ValueBaseType>(otherCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == 1.365 + eStringBase) { 1.366 + static_cast<nsStringBuffer*>(otherPtr)->AddRef(); 1.367 + } else { 1.368 + static_cast<nsIAtom*>(otherPtr)->AddRef(); 1.369 + } 1.370 + cont->mStringBits = otherCont->mStringBits; 1.371 + } 1.372 + // Note, set mType after switch-case, otherwise EnsureEmptyAtomArray doesn't 1.373 + // work correctly. 1.374 + cont->mType = otherCont->mType; 1.375 +} 1.376 + 1.377 +void 1.378 +nsAttrValue::SetTo(const nsAString& aValue) 1.379 +{ 1.380 + ResetIfSet(); 1.381 + nsStringBuffer* buf = GetStringBuffer(aValue).take(); 1.382 + if (buf) { 1.383 + SetPtrValueAndType(buf, eStringBase); 1.384 + } 1.385 +} 1.386 + 1.387 +void 1.388 +nsAttrValue::SetTo(nsIAtom* aValue) 1.389 +{ 1.390 + ResetIfSet(); 1.391 + if (aValue) { 1.392 + NS_ADDREF(aValue); 1.393 + SetPtrValueAndType(aValue, eAtomBase); 1.394 + } 1.395 +} 1.396 + 1.397 +void 1.398 +nsAttrValue::SetTo(int16_t aInt) 1.399 +{ 1.400 + ResetIfSet(); 1.401 + SetIntValueAndType(aInt, eInteger, nullptr); 1.402 +} 1.403 + 1.404 +void 1.405 +nsAttrValue::SetTo(int32_t aInt, const nsAString* aSerialized) 1.406 +{ 1.407 + ResetIfSet(); 1.408 + SetIntValueAndType(aInt, eInteger, aSerialized); 1.409 +} 1.410 + 1.411 +void 1.412 +nsAttrValue::SetTo(double aValue, const nsAString* aSerialized) 1.413 +{ 1.414 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.415 + cont->mDoubleValue = aValue; 1.416 + cont->mType = eDoubleValue; 1.417 + SetMiscAtomOrString(aSerialized); 1.418 +} 1.419 + 1.420 +void 1.421 +nsAttrValue::SetTo(css::StyleRule* aValue, const nsAString* aSerialized) 1.422 +{ 1.423 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.424 + MOZ_ASSERT(cont->mValue.mRefCount == 0); 1.425 + NS_ADDREF(cont->mValue.mCSSStyleRule = aValue); 1.426 + cont->mType = eCSSStyleRule; 1.427 + NS_ADDREF(cont); 1.428 + SetMiscAtomOrString(aSerialized); 1.429 + MOZ_ASSERT(cont->mValue.mRefCount == 1); 1.430 +} 1.431 + 1.432 +void 1.433 +nsAttrValue::SetTo(css::URLValue* aValue, const nsAString* aSerialized) 1.434 +{ 1.435 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.436 + NS_ADDREF(cont->mValue.mURL = aValue); 1.437 + cont->mType = eURL; 1.438 + SetMiscAtomOrString(aSerialized); 1.439 +} 1.440 + 1.441 +void 1.442 +nsAttrValue::SetTo(const nsIntMargin& aValue) 1.443 +{ 1.444 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.445 + cont->mValue.mIntMargin = new nsIntMargin(aValue); 1.446 + cont->mType = eIntMarginValue; 1.447 +} 1.448 + 1.449 +void 1.450 +nsAttrValue::SetToSerialized(const nsAttrValue& aOther) 1.451 +{ 1.452 + if (aOther.Type() != nsAttrValue::eString && 1.453 + aOther.Type() != nsAttrValue::eAtom) { 1.454 + nsAutoString val; 1.455 + aOther.ToString(val); 1.456 + SetTo(val); 1.457 + } else { 1.458 + SetTo(aOther); 1.459 + } 1.460 +} 1.461 + 1.462 +void 1.463 +nsAttrValue::SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized) 1.464 +{ 1.465 + SetSVGType(eSVGAngle, &aValue, aSerialized); 1.466 +} 1.467 + 1.468 +void 1.469 +nsAttrValue::SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized) 1.470 +{ 1.471 + SetSVGType(eSVGIntegerPair, &aValue, aSerialized); 1.472 +} 1.473 + 1.474 +void 1.475 +nsAttrValue::SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized) 1.476 +{ 1.477 + SetSVGType(eSVGLength, &aValue, aSerialized); 1.478 +} 1.479 + 1.480 +void 1.481 +nsAttrValue::SetTo(const SVGLengthList& aValue, 1.482 + const nsAString* aSerialized) 1.483 +{ 1.484 + // While an empty string will parse as a length list, there's no need to store 1.485 + // it (and SetMiscAtomOrString will assert if we try) 1.486 + if (aSerialized && aSerialized->IsEmpty()) { 1.487 + aSerialized = nullptr; 1.488 + } 1.489 + SetSVGType(eSVGLengthList, &aValue, aSerialized); 1.490 +} 1.491 + 1.492 +void 1.493 +nsAttrValue::SetTo(const SVGNumberList& aValue, 1.494 + const nsAString* aSerialized) 1.495 +{ 1.496 + // While an empty string will parse as a number list, there's no need to store 1.497 + // it (and SetMiscAtomOrString will assert if we try) 1.498 + if (aSerialized && aSerialized->IsEmpty()) { 1.499 + aSerialized = nullptr; 1.500 + } 1.501 + SetSVGType(eSVGNumberList, &aValue, aSerialized); 1.502 +} 1.503 + 1.504 +void 1.505 +nsAttrValue::SetTo(const nsSVGNumberPair& aValue, const nsAString* aSerialized) 1.506 +{ 1.507 + SetSVGType(eSVGNumberPair, &aValue, aSerialized); 1.508 +} 1.509 + 1.510 +void 1.511 +nsAttrValue::SetTo(const SVGPathData& aValue, 1.512 + const nsAString* aSerialized) 1.513 +{ 1.514 + // While an empty string will parse as path data, there's no need to store it 1.515 + // (and SetMiscAtomOrString will assert if we try) 1.516 + if (aSerialized && aSerialized->IsEmpty()) { 1.517 + aSerialized = nullptr; 1.518 + } 1.519 + SetSVGType(eSVGPathData, &aValue, aSerialized); 1.520 +} 1.521 + 1.522 +void 1.523 +nsAttrValue::SetTo(const SVGPointList& aValue, 1.524 + const nsAString* aSerialized) 1.525 +{ 1.526 + // While an empty string will parse as a point list, there's no need to store 1.527 + // it (and SetMiscAtomOrString will assert if we try) 1.528 + if (aSerialized && aSerialized->IsEmpty()) { 1.529 + aSerialized = nullptr; 1.530 + } 1.531 + SetSVGType(eSVGPointList, &aValue, aSerialized); 1.532 +} 1.533 + 1.534 +void 1.535 +nsAttrValue::SetTo(const SVGAnimatedPreserveAspectRatio& aValue, 1.536 + const nsAString* aSerialized) 1.537 +{ 1.538 + SetSVGType(eSVGPreserveAspectRatio, &aValue, aSerialized); 1.539 +} 1.540 + 1.541 +void 1.542 +nsAttrValue::SetTo(const SVGStringList& aValue, 1.543 + const nsAString* aSerialized) 1.544 +{ 1.545 + // While an empty string will parse as a string list, there's no need to store 1.546 + // it (and SetMiscAtomOrString will assert if we try) 1.547 + if (aSerialized && aSerialized->IsEmpty()) { 1.548 + aSerialized = nullptr; 1.549 + } 1.550 + SetSVGType(eSVGStringList, &aValue, aSerialized); 1.551 +} 1.552 + 1.553 +void 1.554 +nsAttrValue::SetTo(const SVGTransformList& aValue, 1.555 + const nsAString* aSerialized) 1.556 +{ 1.557 + // While an empty string will parse as a transform list, there's no need to 1.558 + // store it (and SetMiscAtomOrString will assert if we try) 1.559 + if (aSerialized && aSerialized->IsEmpty()) { 1.560 + aSerialized = nullptr; 1.561 + } 1.562 + SetSVGType(eSVGTransformList, &aValue, aSerialized); 1.563 +} 1.564 + 1.565 +void 1.566 +nsAttrValue::SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized) 1.567 +{ 1.568 + SetSVGType(eSVGViewBox, &aValue, aSerialized); 1.569 +} 1.570 + 1.571 +void 1.572 +nsAttrValue::SwapValueWith(nsAttrValue& aOther) 1.573 +{ 1.574 + uintptr_t tmp = aOther.mBits; 1.575 + aOther.mBits = mBits; 1.576 + mBits = tmp; 1.577 +} 1.578 + 1.579 +void 1.580 +nsAttrValue::ToString(nsAString& aResult) const 1.581 +{ 1.582 + MiscContainer* cont = nullptr; 1.583 + if (BaseType() == eOtherBase) { 1.584 + cont = GetMiscContainer(); 1.585 + 1.586 + if (cont->GetString(aResult)) { 1.587 + return; 1.588 + } 1.589 + } 1.590 + 1.591 + switch(Type()) { 1.592 + case eString: 1.593 + { 1.594 + nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); 1.595 + if (str) { 1.596 + str->ToString(str->StorageSize()/sizeof(char16_t) - 1, aResult); 1.597 + } 1.598 + else { 1.599 + aResult.Truncate(); 1.600 + } 1.601 + break; 1.602 + } 1.603 + case eAtom: 1.604 + { 1.605 + nsIAtom *atom = static_cast<nsIAtom*>(GetPtr()); 1.606 + atom->ToString(aResult); 1.607 + 1.608 + break; 1.609 + } 1.610 + case eInteger: 1.611 + { 1.612 + nsAutoString intStr; 1.613 + intStr.AppendInt(GetIntegerValue()); 1.614 + aResult = intStr; 1.615 + 1.616 + break; 1.617 + } 1.618 +#ifdef DEBUG 1.619 + case eColor: 1.620 + { 1.621 + NS_NOTREACHED("color attribute without string data"); 1.622 + aResult.Truncate(); 1.623 + break; 1.624 + } 1.625 +#endif 1.626 + case eEnum: 1.627 + { 1.628 + GetEnumString(aResult, false); 1.629 + break; 1.630 + } 1.631 + case ePercent: 1.632 + { 1.633 + nsAutoString intStr; 1.634 + intStr.AppendInt(cont ? cont->mValue.mPercent : GetIntInternal()); 1.635 + aResult = intStr + NS_LITERAL_STRING("%"); 1.636 + 1.637 + break; 1.638 + } 1.639 + case eCSSStyleRule: 1.640 + { 1.641 + aResult.Truncate(); 1.642 + MiscContainer *container = GetMiscContainer(); 1.643 + css::Declaration *decl = 1.644 + container->mValue.mCSSStyleRule->GetDeclaration(); 1.645 + if (decl) { 1.646 + decl->ToString(aResult); 1.647 + } 1.648 + const_cast<nsAttrValue*>(this)->SetMiscAtomOrString(&aResult); 1.649 + 1.650 + break; 1.651 + } 1.652 + case eDoubleValue: 1.653 + { 1.654 + aResult.Truncate(); 1.655 + aResult.AppendFloat(GetDoubleValue()); 1.656 + break; 1.657 + } 1.658 + case eSVGAngle: 1.659 + { 1.660 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGAngle, 1.661 + aResult); 1.662 + break; 1.663 + } 1.664 + case eSVGIntegerPair: 1.665 + { 1.666 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGIntegerPair, 1.667 + aResult); 1.668 + break; 1.669 + } 1.670 + case eSVGLength: 1.671 + { 1.672 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLength, 1.673 + aResult); 1.674 + break; 1.675 + } 1.676 + case eSVGLengthList: 1.677 + { 1.678 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLengthList, 1.679 + aResult); 1.680 + break; 1.681 + } 1.682 + case eSVGNumberList: 1.683 + { 1.684 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberList, 1.685 + aResult); 1.686 + break; 1.687 + } 1.688 + case eSVGNumberPair: 1.689 + { 1.690 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberPair, 1.691 + aResult); 1.692 + break; 1.693 + } 1.694 + case eSVGPathData: 1.695 + { 1.696 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPathData, 1.697 + aResult); 1.698 + break; 1.699 + } 1.700 + case eSVGPointList: 1.701 + { 1.702 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPointList, 1.703 + aResult); 1.704 + break; 1.705 + } 1.706 + case eSVGPreserveAspectRatio: 1.707 + { 1.708 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPreserveAspectRatio, 1.709 + aResult); 1.710 + break; 1.711 + } 1.712 + case eSVGStringList: 1.713 + { 1.714 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGStringList, 1.715 + aResult); 1.716 + break; 1.717 + } 1.718 + case eSVGTransformList: 1.719 + { 1.720 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGTransformList, 1.721 + aResult); 1.722 + break; 1.723 + } 1.724 + case eSVGViewBox: 1.725 + { 1.726 + SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGViewBox, 1.727 + aResult); 1.728 + break; 1.729 + } 1.730 + default: 1.731 + { 1.732 + aResult.Truncate(); 1.733 + break; 1.734 + } 1.735 + } 1.736 +} 1.737 + 1.738 +already_AddRefed<nsIAtom> 1.739 +nsAttrValue::GetAsAtom() const 1.740 +{ 1.741 + switch (Type()) { 1.742 + case eString: 1.743 + return do_GetAtom(GetStringValue()); 1.744 + 1.745 + case eAtom: 1.746 + { 1.747 + nsCOMPtr<nsIAtom> atom = GetAtomValue(); 1.748 + return atom.forget(); 1.749 + } 1.750 + 1.751 + default: 1.752 + { 1.753 + nsAutoString val; 1.754 + ToString(val); 1.755 + return do_GetAtom(val); 1.756 + } 1.757 + } 1.758 +} 1.759 + 1.760 +const nsCheapString 1.761 +nsAttrValue::GetStringValue() const 1.762 +{ 1.763 + NS_PRECONDITION(Type() == eString, "wrong type"); 1.764 + 1.765 + return nsCheapString(static_cast<nsStringBuffer*>(GetPtr())); 1.766 +} 1.767 + 1.768 +bool 1.769 +nsAttrValue::GetColorValue(nscolor& aColor) const 1.770 +{ 1.771 + if (Type() != eColor) { 1.772 + // Unparseable value, treat as unset. 1.773 + NS_ASSERTION(Type() == eString, "unexpected type for color-valued attr"); 1.774 + return false; 1.775 + } 1.776 + 1.777 + aColor = GetMiscContainer()->mValue.mColor; 1.778 + return true; 1.779 +} 1.780 + 1.781 +void 1.782 +nsAttrValue::GetEnumString(nsAString& aResult, bool aRealTag) const 1.783 +{ 1.784 + NS_PRECONDITION(Type() == eEnum, "wrong type"); 1.785 + 1.786 + uint32_t allEnumBits = 1.787 + (BaseType() == eIntegerBase) ? static_cast<uint32_t>(GetIntInternal()) 1.788 + : GetMiscContainer()->mValue.mEnumValue; 1.789 + int16_t val = allEnumBits >> NS_ATTRVALUE_ENUMTABLEINDEX_BITS; 1.790 + const EnumTable* table = sEnumTableArray-> 1.791 + ElementAt(allEnumBits & NS_ATTRVALUE_ENUMTABLEINDEX_MASK); 1.792 + 1.793 + while (table->tag) { 1.794 + if (table->value == val) { 1.795 + aResult.AssignASCII(table->tag); 1.796 + if (!aRealTag && allEnumBits & NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER) { 1.797 + nsContentUtils::ASCIIToUpper(aResult); 1.798 + } 1.799 + return; 1.800 + } 1.801 + table++; 1.802 + } 1.803 + 1.804 + NS_NOTREACHED("couldn't find value in EnumTable"); 1.805 +} 1.806 + 1.807 +uint32_t 1.808 +nsAttrValue::GetAtomCount() const 1.809 +{ 1.810 + ValueType type = Type(); 1.811 + 1.812 + if (type == eAtom) { 1.813 + return 1; 1.814 + } 1.815 + 1.816 + if (type == eAtomArray) { 1.817 + return GetAtomArrayValue()->Length(); 1.818 + } 1.819 + 1.820 + return 0; 1.821 +} 1.822 + 1.823 +nsIAtom* 1.824 +nsAttrValue::AtomAt(int32_t aIndex) const 1.825 +{ 1.826 + NS_PRECONDITION(aIndex >= 0, "Index must not be negative"); 1.827 + NS_PRECONDITION(GetAtomCount() > uint32_t(aIndex), "aIndex out of range"); 1.828 + 1.829 + if (BaseType() == eAtomBase) { 1.830 + return GetAtomValue(); 1.831 + } 1.832 + 1.833 + NS_ASSERTION(Type() == eAtomArray, "GetAtomCount must be confused"); 1.834 + 1.835 + return GetAtomArrayValue()->ElementAt(aIndex); 1.836 +} 1.837 + 1.838 +uint32_t 1.839 +nsAttrValue::HashValue() const 1.840 +{ 1.841 + switch(BaseType()) { 1.842 + case eStringBase: 1.843 + { 1.844 + nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); 1.845 + if (str) { 1.846 + uint32_t len = str->StorageSize()/sizeof(char16_t) - 1; 1.847 + return HashString(static_cast<char16_t*>(str->Data()), len); 1.848 + } 1.849 + 1.850 + return 0; 1.851 + } 1.852 + case eOtherBase: 1.853 + { 1.854 + break; 1.855 + } 1.856 + case eAtomBase: 1.857 + case eIntegerBase: 1.858 + { 1.859 + // mBits and uint32_t might have different size. This should silence 1.860 + // any warnings or compile-errors. This is what the implementation of 1.861 + // NS_PTR_TO_INT32 does to take care of the same problem. 1.862 + return mBits - 0; 1.863 + } 1.864 + } 1.865 + 1.866 + MiscContainer* cont = GetMiscContainer(); 1.867 + if (static_cast<ValueBaseType>(cont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) 1.868 + == eAtomBase) { 1.869 + return cont->mStringBits - 0; 1.870 + } 1.871 + 1.872 + switch (cont->mType) { 1.873 + case eInteger: 1.874 + { 1.875 + return cont->mValue.mInteger; 1.876 + } 1.877 + case eEnum: 1.878 + { 1.879 + return cont->mValue.mEnumValue; 1.880 + } 1.881 + case ePercent: 1.882 + { 1.883 + return cont->mValue.mPercent; 1.884 + } 1.885 + case eColor: 1.886 + { 1.887 + return cont->mValue.mColor; 1.888 + } 1.889 + case eCSSStyleRule: 1.890 + { 1.891 + return NS_PTR_TO_INT32(cont->mValue.mCSSStyleRule); 1.892 + } 1.893 + // Intentionally identical, so that loading the image does not change the 1.894 + // hash code. 1.895 + case eURL: 1.896 + case eImage: 1.897 + { 1.898 + nsString str; 1.899 + ToString(str); 1.900 + return HashString(str); 1.901 + } 1.902 + case eAtomArray: 1.903 + { 1.904 + uint32_t hash = 0; 1.905 + uint32_t count = cont->mValue.mAtomArray->Length(); 1.906 + for (nsCOMPtr<nsIAtom> *cur = cont->mValue.mAtomArray->Elements(), 1.907 + *end = cur + count; 1.908 + cur != end; ++cur) { 1.909 + hash = AddToHash(hash, cur->get()); 1.910 + } 1.911 + return hash; 1.912 + } 1.913 + case eDoubleValue: 1.914 + { 1.915 + // XXX this is crappy, but oh well 1.916 + return cont->mDoubleValue; 1.917 + } 1.918 + case eIntMarginValue: 1.919 + { 1.920 + return NS_PTR_TO_INT32(cont->mValue.mIntMargin); 1.921 + } 1.922 + default: 1.923 + { 1.924 + if (IsSVGType(cont->mType)) { 1.925 + // All SVG types are just pointers to classes so we can treat them alike 1.926 + return NS_PTR_TO_INT32(cont->mValue.mSVGAngle); 1.927 + } 1.928 + NS_NOTREACHED("unknown type stored in MiscContainer"); 1.929 + return 0; 1.930 + } 1.931 + } 1.932 +} 1.933 + 1.934 +bool 1.935 +nsAttrValue::Equals(const nsAttrValue& aOther) const 1.936 +{ 1.937 + if (BaseType() != aOther.BaseType()) { 1.938 + return false; 1.939 + } 1.940 + 1.941 + switch(BaseType()) { 1.942 + case eStringBase: 1.943 + { 1.944 + return GetStringValue().Equals(aOther.GetStringValue()); 1.945 + } 1.946 + case eOtherBase: 1.947 + { 1.948 + break; 1.949 + } 1.950 + case eAtomBase: 1.951 + case eIntegerBase: 1.952 + { 1.953 + return mBits == aOther.mBits; 1.954 + } 1.955 + } 1.956 + 1.957 + MiscContainer* thisCont = GetMiscContainer(); 1.958 + MiscContainer* otherCont = aOther.GetMiscContainer(); 1.959 + if (thisCont == otherCont) { 1.960 + return true; 1.961 + } 1.962 + 1.963 + if (thisCont->mType != otherCont->mType) { 1.964 + return false; 1.965 + } 1.966 + 1.967 + bool needsStringComparison = false; 1.968 + 1.969 + switch (thisCont->mType) { 1.970 + case eInteger: 1.971 + { 1.972 + if (thisCont->mValue.mInteger == otherCont->mValue.mInteger) { 1.973 + needsStringComparison = true; 1.974 + } 1.975 + break; 1.976 + } 1.977 + case eEnum: 1.978 + { 1.979 + if (thisCont->mValue.mEnumValue == otherCont->mValue.mEnumValue) { 1.980 + needsStringComparison = true; 1.981 + } 1.982 + break; 1.983 + } 1.984 + case ePercent: 1.985 + { 1.986 + if (thisCont->mValue.mPercent == otherCont->mValue.mPercent) { 1.987 + needsStringComparison = true; 1.988 + } 1.989 + break; 1.990 + } 1.991 + case eColor: 1.992 + { 1.993 + if (thisCont->mValue.mColor == otherCont->mValue.mColor) { 1.994 + needsStringComparison = true; 1.995 + } 1.996 + break; 1.997 + } 1.998 + case eCSSStyleRule: 1.999 + { 1.1000 + return thisCont->mValue.mCSSStyleRule == otherCont->mValue.mCSSStyleRule; 1.1001 + } 1.1002 + case eURL: 1.1003 + { 1.1004 + return thisCont->mValue.mURL == otherCont->mValue.mURL; 1.1005 + } 1.1006 + case eImage: 1.1007 + { 1.1008 + return thisCont->mValue.mImage == otherCont->mValue.mImage; 1.1009 + } 1.1010 + case eAtomArray: 1.1011 + { 1.1012 + // For classlists we could be insensitive to order, however 1.1013 + // classlists are never mapped attributes so they are never compared. 1.1014 + 1.1015 + if (!(*thisCont->mValue.mAtomArray == *otherCont->mValue.mAtomArray)) { 1.1016 + return false; 1.1017 + } 1.1018 + 1.1019 + needsStringComparison = true; 1.1020 + break; 1.1021 + } 1.1022 + case eDoubleValue: 1.1023 + { 1.1024 + return thisCont->mDoubleValue == otherCont->mDoubleValue; 1.1025 + } 1.1026 + case eIntMarginValue: 1.1027 + { 1.1028 + return thisCont->mValue.mIntMargin == otherCont->mValue.mIntMargin; 1.1029 + } 1.1030 + default: 1.1031 + { 1.1032 + if (IsSVGType(thisCont->mType)) { 1.1033 + // Currently this method is never called for nsAttrValue objects that 1.1034 + // point to SVG data types. 1.1035 + // If that changes then we probably want to add methods to the 1.1036 + // corresponding SVG types to compare their base values. 1.1037 + // As a shortcut, however, we can begin by comparing the pointers. 1.1038 + NS_ABORT_IF_FALSE(false, "Comparing nsAttrValues that point to SVG " 1.1039 + "data"); 1.1040 + return false; 1.1041 + } 1.1042 + NS_NOTREACHED("unknown type stored in MiscContainer"); 1.1043 + return false; 1.1044 + } 1.1045 + } 1.1046 + if (needsStringComparison) { 1.1047 + if (thisCont->mStringBits == otherCont->mStringBits) { 1.1048 + return true; 1.1049 + } 1.1050 + if ((static_cast<ValueBaseType>(thisCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == 1.1051 + eStringBase) && 1.1052 + (static_cast<ValueBaseType>(otherCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == 1.1053 + eStringBase)) { 1.1054 + return nsCheapString(reinterpret_cast<nsStringBuffer*>(thisCont->mStringBits)).Equals( 1.1055 + nsCheapString(reinterpret_cast<nsStringBuffer*>(otherCont->mStringBits))); 1.1056 + } 1.1057 + } 1.1058 + return false; 1.1059 +} 1.1060 + 1.1061 +bool 1.1062 +nsAttrValue::Equals(const nsAString& aValue, 1.1063 + nsCaseTreatment aCaseSensitive) const 1.1064 +{ 1.1065 + switch (BaseType()) { 1.1066 + case eStringBase: 1.1067 + { 1.1068 + nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); 1.1069 + if (str) { 1.1070 + nsDependentString dep(static_cast<char16_t*>(str->Data()), 1.1071 + str->StorageSize()/sizeof(char16_t) - 1); 1.1072 + return aCaseSensitive == eCaseMatters ? aValue.Equals(dep) : 1.1073 + nsContentUtils::EqualsIgnoreASCIICase(aValue, dep); 1.1074 + } 1.1075 + return aValue.IsEmpty(); 1.1076 + } 1.1077 + case eAtomBase: 1.1078 + if (aCaseSensitive == eCaseMatters) { 1.1079 + return static_cast<nsIAtom*>(GetPtr())->Equals(aValue); 1.1080 + } 1.1081 + return nsContentUtils::EqualsIgnoreASCIICase( 1.1082 + nsDependentAtomString(static_cast<nsIAtom*>(GetPtr())), 1.1083 + aValue); 1.1084 + default: 1.1085 + break; 1.1086 + } 1.1087 + 1.1088 + nsAutoString val; 1.1089 + ToString(val); 1.1090 + return aCaseSensitive == eCaseMatters ? val.Equals(aValue) : 1.1091 + nsContentUtils::EqualsIgnoreASCIICase(val, aValue); 1.1092 +} 1.1093 + 1.1094 +bool 1.1095 +nsAttrValue::Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const 1.1096 +{ 1.1097 + if (aCaseSensitive != eCaseMatters) { 1.1098 + // Need a better way to handle this! 1.1099 + nsAutoString value; 1.1100 + aValue->ToString(value); 1.1101 + return Equals(value, aCaseSensitive); 1.1102 + } 1.1103 + 1.1104 + switch (BaseType()) { 1.1105 + case eStringBase: 1.1106 + { 1.1107 + nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); 1.1108 + if (str) { 1.1109 + nsDependentString dep(static_cast<char16_t*>(str->Data()), 1.1110 + str->StorageSize()/sizeof(char16_t) - 1); 1.1111 + return aValue->Equals(dep); 1.1112 + } 1.1113 + return aValue == nsGkAtoms::_empty; 1.1114 + } 1.1115 + case eAtomBase: 1.1116 + { 1.1117 + return static_cast<nsIAtom*>(GetPtr()) == aValue; 1.1118 + } 1.1119 + default: 1.1120 + break; 1.1121 + } 1.1122 + 1.1123 + nsAutoString val; 1.1124 + ToString(val); 1.1125 + return aValue->Equals(val); 1.1126 +} 1.1127 + 1.1128 +bool 1.1129 +nsAttrValue::EqualsAsStrings(const nsAttrValue& aOther) const 1.1130 +{ 1.1131 + if (Type() == aOther.Type()) { 1.1132 + return Equals(aOther); 1.1133 + } 1.1134 + 1.1135 + // We need to serialize at least one nsAttrValue before passing to 1.1136 + // Equals(const nsAString&), but we can avoid unnecessarily serializing both 1.1137 + // by checking if one is already of a string type. 1.1138 + bool thisIsString = (BaseType() == eStringBase || BaseType() == eAtomBase); 1.1139 + const nsAttrValue& lhs = thisIsString ? *this : aOther; 1.1140 + const nsAttrValue& rhs = thisIsString ? aOther : *this; 1.1141 + 1.1142 + switch (rhs.BaseType()) { 1.1143 + case eAtomBase: 1.1144 + return lhs.Equals(rhs.GetAtomValue(), eCaseMatters); 1.1145 + 1.1146 + case eStringBase: 1.1147 + return lhs.Equals(rhs.GetStringValue(), eCaseMatters); 1.1148 + 1.1149 + default: 1.1150 + { 1.1151 + nsAutoString val; 1.1152 + rhs.ToString(val); 1.1153 + return lhs.Equals(val, eCaseMatters); 1.1154 + } 1.1155 + } 1.1156 +} 1.1157 + 1.1158 +bool 1.1159 +nsAttrValue::Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const 1.1160 +{ 1.1161 + switch (BaseType()) { 1.1162 + case eAtomBase: 1.1163 + { 1.1164 + nsIAtom* atom = GetAtomValue(); 1.1165 + 1.1166 + if (aCaseSensitive == eCaseMatters) { 1.1167 + return aValue == atom; 1.1168 + } 1.1169 + 1.1170 + // For performance reasons, don't do a full on unicode case insensitive 1.1171 + // string comparison. This is only used for quirks mode anyway. 1.1172 + return 1.1173 + nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(aValue), 1.1174 + nsDependentAtomString(atom)); 1.1175 + } 1.1176 + default: 1.1177 + { 1.1178 + if (Type() == eAtomArray) { 1.1179 + AtomArray* array = GetAtomArrayValue(); 1.1180 + if (aCaseSensitive == eCaseMatters) { 1.1181 + return array->Contains(aValue); 1.1182 + } 1.1183 + 1.1184 + nsDependentAtomString val1(aValue); 1.1185 + 1.1186 + for (nsCOMPtr<nsIAtom> *cur = array->Elements(), 1.1187 + *end = cur + array->Length(); 1.1188 + cur != end; ++cur) { 1.1189 + // For performance reasons, don't do a full on unicode case 1.1190 + // insensitive string comparison. This is only used for quirks mode 1.1191 + // anyway. 1.1192 + if (nsContentUtils::EqualsIgnoreASCIICase(val1, 1.1193 + nsDependentAtomString(*cur))) { 1.1194 + return true; 1.1195 + } 1.1196 + } 1.1197 + } 1.1198 + } 1.1199 + } 1.1200 + 1.1201 + return false; 1.1202 +} 1.1203 + 1.1204 +struct AtomArrayStringComparator { 1.1205 + bool Equals(nsIAtom* atom, const nsAString& string) const { 1.1206 + return atom->Equals(string); 1.1207 + } 1.1208 +}; 1.1209 + 1.1210 +bool 1.1211 +nsAttrValue::Contains(const nsAString& aValue) const 1.1212 +{ 1.1213 + switch (BaseType()) { 1.1214 + case eAtomBase: 1.1215 + { 1.1216 + nsIAtom* atom = GetAtomValue(); 1.1217 + return atom->Equals(aValue); 1.1218 + } 1.1219 + default: 1.1220 + { 1.1221 + if (Type() == eAtomArray) { 1.1222 + AtomArray* array = GetAtomArrayValue(); 1.1223 + return array->Contains(aValue, AtomArrayStringComparator()); 1.1224 + } 1.1225 + } 1.1226 + } 1.1227 + 1.1228 + return false; 1.1229 +} 1.1230 + 1.1231 +void 1.1232 +nsAttrValue::ParseAtom(const nsAString& aValue) 1.1233 +{ 1.1234 + ResetIfSet(); 1.1235 + 1.1236 + nsCOMPtr<nsIAtom> atom = NS_NewAtom(aValue); 1.1237 + if (atom) { 1.1238 + SetPtrValueAndType(atom.forget().take(), eAtomBase); 1.1239 + } 1.1240 +} 1.1241 + 1.1242 +void 1.1243 +nsAttrValue::ParseAtomArray(const nsAString& aValue) 1.1244 +{ 1.1245 + nsAString::const_iterator iter, end; 1.1246 + aValue.BeginReading(iter); 1.1247 + aValue.EndReading(end); 1.1248 + bool hasSpace = false; 1.1249 + 1.1250 + // skip initial whitespace 1.1251 + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { 1.1252 + hasSpace = true; 1.1253 + ++iter; 1.1254 + } 1.1255 + 1.1256 + if (iter == end) { 1.1257 + SetTo(aValue); 1.1258 + return; 1.1259 + } 1.1260 + 1.1261 + nsAString::const_iterator start(iter); 1.1262 + 1.1263 + // get first - and often only - atom 1.1264 + do { 1.1265 + ++iter; 1.1266 + } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); 1.1267 + 1.1268 + nsCOMPtr<nsIAtom> classAtom = do_GetAtom(Substring(start, iter)); 1.1269 + if (!classAtom) { 1.1270 + Reset(); 1.1271 + return; 1.1272 + } 1.1273 + 1.1274 + // skip whitespace 1.1275 + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { 1.1276 + hasSpace = true; 1.1277 + ++iter; 1.1278 + } 1.1279 + 1.1280 + if (iter == end && !hasSpace) { 1.1281 + // we only found one classname and there was no whitespace so 1.1282 + // don't bother storing a list 1.1283 + ResetIfSet(); 1.1284 + nsIAtom* atom = nullptr; 1.1285 + classAtom.swap(atom); 1.1286 + SetPtrValueAndType(atom, eAtomBase); 1.1287 + return; 1.1288 + } 1.1289 + 1.1290 + if (!EnsureEmptyAtomArray()) { 1.1291 + return; 1.1292 + } 1.1293 + 1.1294 + AtomArray* array = GetAtomArrayValue(); 1.1295 + 1.1296 + if (!array->AppendElement(classAtom)) { 1.1297 + Reset(); 1.1298 + return; 1.1299 + } 1.1300 + 1.1301 + // parse the rest of the classnames 1.1302 + while (iter != end) { 1.1303 + start = iter; 1.1304 + 1.1305 + do { 1.1306 + ++iter; 1.1307 + } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); 1.1308 + 1.1309 + classAtom = do_GetAtom(Substring(start, iter)); 1.1310 + 1.1311 + if (!array->AppendElement(classAtom)) { 1.1312 + Reset(); 1.1313 + return; 1.1314 + } 1.1315 + 1.1316 + // skip whitespace 1.1317 + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { 1.1318 + ++iter; 1.1319 + } 1.1320 + } 1.1321 + 1.1322 + SetMiscAtomOrString(&aValue); 1.1323 + return; 1.1324 +} 1.1325 + 1.1326 +void 1.1327 +nsAttrValue::ParseStringOrAtom(const nsAString& aValue) 1.1328 +{ 1.1329 + uint32_t len = aValue.Length(); 1.1330 + // Don't bother with atoms if it's an empty string since 1.1331 + // we can store those efficently anyway. 1.1332 + if (len && len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) { 1.1333 + ParseAtom(aValue); 1.1334 + } 1.1335 + else { 1.1336 + SetTo(aValue); 1.1337 + } 1.1338 +} 1.1339 + 1.1340 +void 1.1341 +nsAttrValue::SetIntValueAndType(int32_t aValue, ValueType aType, 1.1342 + const nsAString* aStringValue) 1.1343 +{ 1.1344 + if (aStringValue || aValue > NS_ATTRVALUE_INTEGERTYPE_MAXVALUE || 1.1345 + aValue < NS_ATTRVALUE_INTEGERTYPE_MINVALUE) { 1.1346 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.1347 + switch (aType) { 1.1348 + case eInteger: 1.1349 + { 1.1350 + cont->mValue.mInteger = aValue; 1.1351 + break; 1.1352 + } 1.1353 + case ePercent: 1.1354 + { 1.1355 + cont->mValue.mPercent = aValue; 1.1356 + break; 1.1357 + } 1.1358 + case eEnum: 1.1359 + { 1.1360 + cont->mValue.mEnumValue = aValue; 1.1361 + break; 1.1362 + } 1.1363 + default: 1.1364 + { 1.1365 + NS_NOTREACHED("unknown integer type"); 1.1366 + break; 1.1367 + } 1.1368 + } 1.1369 + cont->mType = aType; 1.1370 + SetMiscAtomOrString(aStringValue); 1.1371 + } else { 1.1372 + NS_ASSERTION(!mBits, "Reset before calling SetIntValueAndType!"); 1.1373 + mBits = (aValue * NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER) | aType; 1.1374 + } 1.1375 +} 1.1376 + 1.1377 +int16_t 1.1378 +nsAttrValue::GetEnumTableIndex(const EnumTable* aTable) 1.1379 +{ 1.1380 + int16_t index = sEnumTableArray->IndexOf(aTable); 1.1381 + if (index < 0) { 1.1382 + index = sEnumTableArray->Length(); 1.1383 + NS_ASSERTION(index <= NS_ATTRVALUE_ENUMTABLEINDEX_MAXVALUE, 1.1384 + "too many enum tables"); 1.1385 + sEnumTableArray->AppendElement(aTable); 1.1386 + } 1.1387 + 1.1388 + return index; 1.1389 +} 1.1390 + 1.1391 +int32_t 1.1392 +nsAttrValue::EnumTableEntryToValue(const EnumTable* aEnumTable, 1.1393 + const EnumTable* aTableEntry) 1.1394 +{ 1.1395 + int16_t index = GetEnumTableIndex(aEnumTable); 1.1396 + int32_t value = (aTableEntry->value << NS_ATTRVALUE_ENUMTABLEINDEX_BITS) + 1.1397 + index; 1.1398 + return value; 1.1399 +} 1.1400 + 1.1401 +bool 1.1402 +nsAttrValue::ParseEnumValue(const nsAString& aValue, 1.1403 + const EnumTable* aTable, 1.1404 + bool aCaseSensitive, 1.1405 + const EnumTable* aDefaultValue) 1.1406 +{ 1.1407 + ResetIfSet(); 1.1408 + const EnumTable* tableEntry = aTable; 1.1409 + 1.1410 + while (tableEntry->tag) { 1.1411 + if (aCaseSensitive ? aValue.EqualsASCII(tableEntry->tag) : 1.1412 + aValue.LowerCaseEqualsASCII(tableEntry->tag)) { 1.1413 + int32_t value = EnumTableEntryToValue(aTable, tableEntry); 1.1414 + 1.1415 + bool equals = aCaseSensitive || aValue.EqualsASCII(tableEntry->tag); 1.1416 + if (!equals) { 1.1417 + nsAutoString tag; 1.1418 + tag.AssignASCII(tableEntry->tag); 1.1419 + nsContentUtils::ASCIIToUpper(tag); 1.1420 + if ((equals = tag.Equals(aValue))) { 1.1421 + value |= NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER; 1.1422 + } 1.1423 + } 1.1424 + SetIntValueAndType(value, eEnum, equals ? nullptr : &aValue); 1.1425 + NS_ASSERTION(GetEnumValue() == tableEntry->value, 1.1426 + "failed to store enum properly"); 1.1427 + 1.1428 + return true; 1.1429 + } 1.1430 + tableEntry++; 1.1431 + } 1.1432 + 1.1433 + if (aDefaultValue) { 1.1434 + NS_PRECONDITION(aTable <= aDefaultValue && aDefaultValue < tableEntry, 1.1435 + "aDefaultValue not inside aTable?"); 1.1436 + SetIntValueAndType(EnumTableEntryToValue(aTable, aDefaultValue), 1.1437 + eEnum, &aValue); 1.1438 + return true; 1.1439 + } 1.1440 + 1.1441 + return false; 1.1442 +} 1.1443 + 1.1444 +bool 1.1445 +nsAttrValue::ParseSpecialIntValue(const nsAString& aString) 1.1446 +{ 1.1447 + ResetIfSet(); 1.1448 + 1.1449 + nsresult ec; 1.1450 + bool strict; 1.1451 + bool isPercent = false; 1.1452 + nsAutoString tmp(aString); 1.1453 + int32_t originalVal = StringToInteger(aString, &strict, &ec, true, &isPercent); 1.1454 + 1.1455 + if (NS_FAILED(ec)) { 1.1456 + return false; 1.1457 + } 1.1458 + 1.1459 + int32_t val = std::max(originalVal, 0); 1.1460 + 1.1461 + // % (percent) 1.1462 + if (isPercent || tmp.RFindChar('%') >= 0) { 1.1463 + isPercent = true; 1.1464 + } 1.1465 + 1.1466 + strict = strict && (originalVal == val); 1.1467 + 1.1468 + SetIntValueAndType(val, 1.1469 + isPercent ? ePercent : eInteger, 1.1470 + strict ? nullptr : &aString); 1.1471 + return true; 1.1472 +} 1.1473 + 1.1474 +bool 1.1475 +nsAttrValue::ParseIntWithBounds(const nsAString& aString, 1.1476 + int32_t aMin, int32_t aMax) 1.1477 +{ 1.1478 + NS_PRECONDITION(aMin < aMax, "bad boundaries"); 1.1479 + 1.1480 + ResetIfSet(); 1.1481 + 1.1482 + nsresult ec; 1.1483 + bool strict; 1.1484 + int32_t originalVal = StringToInteger(aString, &strict, &ec); 1.1485 + if (NS_FAILED(ec)) { 1.1486 + return false; 1.1487 + } 1.1488 + 1.1489 + int32_t val = std::max(originalVal, aMin); 1.1490 + val = std::min(val, aMax); 1.1491 + strict = strict && (originalVal == val); 1.1492 + SetIntValueAndType(val, eInteger, strict ? nullptr : &aString); 1.1493 + 1.1494 + return true; 1.1495 +} 1.1496 + 1.1497 +bool 1.1498 +nsAttrValue::ParseNonNegativeIntValue(const nsAString& aString) 1.1499 +{ 1.1500 + ResetIfSet(); 1.1501 + 1.1502 + nsresult ec; 1.1503 + bool strict; 1.1504 + int32_t originalVal = StringToInteger(aString, &strict, &ec); 1.1505 + if (NS_FAILED(ec) || originalVal < 0) { 1.1506 + return false; 1.1507 + } 1.1508 + 1.1509 + SetIntValueAndType(originalVal, eInteger, strict ? nullptr : &aString); 1.1510 + 1.1511 + return true; 1.1512 +} 1.1513 + 1.1514 +bool 1.1515 +nsAttrValue::ParsePositiveIntValue(const nsAString& aString) 1.1516 +{ 1.1517 + ResetIfSet(); 1.1518 + 1.1519 + nsresult ec; 1.1520 + bool strict; 1.1521 + int32_t originalVal = StringToInteger(aString, &strict, &ec); 1.1522 + if (NS_FAILED(ec) || originalVal <= 0) { 1.1523 + return false; 1.1524 + } 1.1525 + 1.1526 + SetIntValueAndType(originalVal, eInteger, strict ? nullptr : &aString); 1.1527 + 1.1528 + return true; 1.1529 +} 1.1530 + 1.1531 +void 1.1532 +nsAttrValue::SetColorValue(nscolor aColor, const nsAString& aString) 1.1533 +{ 1.1534 + nsStringBuffer* buf = GetStringBuffer(aString).take(); 1.1535 + if (!buf) { 1.1536 + return; 1.1537 + } 1.1538 + 1.1539 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.1540 + cont->mValue.mColor = aColor; 1.1541 + cont->mType = eColor; 1.1542 + 1.1543 + // Save the literal string we were passed for round-tripping. 1.1544 + cont->mStringBits = reinterpret_cast<uintptr_t>(buf) | eStringBase; 1.1545 +} 1.1546 + 1.1547 +bool 1.1548 +nsAttrValue::ParseColor(const nsAString& aString) 1.1549 +{ 1.1550 + ResetIfSet(); 1.1551 + 1.1552 + // FIXME (partially, at least): HTML5's algorithm says we shouldn't do 1.1553 + // the whitespace compression, trimming, or the test for emptiness. 1.1554 + // (I'm a little skeptical that we shouldn't do the whitespace 1.1555 + // trimming; WebKit also does it.) 1.1556 + nsAutoString colorStr(aString); 1.1557 + colorStr.CompressWhitespace(true, true); 1.1558 + if (colorStr.IsEmpty()) { 1.1559 + return false; 1.1560 + } 1.1561 + 1.1562 + nscolor color; 1.1563 + // No color names begin with a '#'; in standards mode, all acceptable 1.1564 + // numeric colors do. 1.1565 + if (colorStr.First() == '#') { 1.1566 + nsDependentString withoutHash(colorStr.get() + 1, colorStr.Length() - 1); 1.1567 + if (NS_HexToRGB(withoutHash, &color)) { 1.1568 + SetColorValue(color, aString); 1.1569 + return true; 1.1570 + } 1.1571 + } else { 1.1572 + if (NS_ColorNameToRGB(colorStr, &color)) { 1.1573 + SetColorValue(color, aString); 1.1574 + return true; 1.1575 + } 1.1576 + } 1.1577 + 1.1578 + // FIXME (maybe): HTML5 says we should handle system colors. This 1.1579 + // means we probably need another storage type, since we'd need to 1.1580 + // handle dynamic changes. However, I think this is a bad idea: 1.1581 + // http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2010-May/026449.html 1.1582 + 1.1583 + // Use NS_LooseHexToRGB as a fallback if nothing above worked. 1.1584 + if (NS_LooseHexToRGB(colorStr, &color)) { 1.1585 + SetColorValue(color, aString); 1.1586 + return true; 1.1587 + } 1.1588 + 1.1589 + return false; 1.1590 +} 1.1591 + 1.1592 +bool nsAttrValue::ParseDoubleValue(const nsAString& aString) 1.1593 +{ 1.1594 + ResetIfSet(); 1.1595 + 1.1596 + nsresult ec; 1.1597 + double val = PromiseFlatString(aString).ToDouble(&ec); 1.1598 + if (NS_FAILED(ec)) { 1.1599 + return false; 1.1600 + } 1.1601 + 1.1602 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.1603 + cont->mDoubleValue = val; 1.1604 + cont->mType = eDoubleValue; 1.1605 + nsAutoString serializedFloat; 1.1606 + serializedFloat.AppendFloat(val); 1.1607 + SetMiscAtomOrString(serializedFloat.Equals(aString) ? nullptr : &aString); 1.1608 + return true; 1.1609 +} 1.1610 + 1.1611 +bool 1.1612 +nsAttrValue::ParseIntMarginValue(const nsAString& aString) 1.1613 +{ 1.1614 + ResetIfSet(); 1.1615 + 1.1616 + nsIntMargin margins; 1.1617 + if (!nsContentUtils::ParseIntMarginValue(aString, margins)) 1.1618 + return false; 1.1619 + 1.1620 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.1621 + cont->mValue.mIntMargin = new nsIntMargin(margins); 1.1622 + cont->mType = eIntMarginValue; 1.1623 + SetMiscAtomOrString(&aString); 1.1624 + return true; 1.1625 +} 1.1626 + 1.1627 +void 1.1628 +nsAttrValue::LoadImage(nsIDocument* aDocument) 1.1629 +{ 1.1630 + NS_ASSERTION(Type() == eURL, "wrong type"); 1.1631 + 1.1632 +#ifdef DEBUG 1.1633 + { 1.1634 + nsString val; 1.1635 + ToString(val); 1.1636 + NS_ASSERTION(!val.IsEmpty(), 1.1637 + "How did we end up with an empty string for eURL"); 1.1638 + } 1.1639 +#endif 1.1640 + 1.1641 + MiscContainer* cont = GetMiscContainer(); 1.1642 + mozilla::css::URLValue* url = cont->mValue.mURL; 1.1643 + mozilla::css::ImageValue* image = 1.1644 + new css::ImageValue(url->GetURI(), url->mString, url->mReferrer, 1.1645 + url->mOriginPrincipal, aDocument); 1.1646 + 1.1647 + NS_ADDREF(image); 1.1648 + cont->mValue.mImage = image; 1.1649 + NS_RELEASE(url); 1.1650 + cont->mType = eImage; 1.1651 +} 1.1652 + 1.1653 +bool 1.1654 +nsAttrValue::ParseStyleAttribute(const nsAString& aString, 1.1655 + nsStyledElementNotElementCSSInlineStyle* aElement) 1.1656 +{ 1.1657 + nsIDocument* ownerDoc = aElement->OwnerDoc(); 1.1658 + nsHTMLCSSStyleSheet* sheet = ownerDoc->GetInlineStyleSheet(); 1.1659 + nsCOMPtr<nsIURI> baseURI = aElement->GetBaseURI(); 1.1660 + nsIURI* docURI = ownerDoc->GetDocumentURI(); 1.1661 + 1.1662 + NS_ASSERTION(aElement->NodePrincipal() == ownerDoc->NodePrincipal(), 1.1663 + "This is unexpected"); 1.1664 + 1.1665 + // If the (immutable) document URI does not match the element's base URI 1.1666 + // (the common case is that they do match) do not cache the rule. This is 1.1667 + // because the results of the CSS parser are dependent on these URIs, and we 1.1668 + // do not want to have to account for the URIs in the hash lookup. 1.1669 + bool cachingAllowed = sheet && baseURI == docURI; 1.1670 + if (cachingAllowed) { 1.1671 + MiscContainer* cont = sheet->LookupStyleAttr(aString); 1.1672 + if (cont) { 1.1673 + // Set our MiscContainer to the cached one. 1.1674 + NS_ADDREF(cont); 1.1675 + SetPtrValueAndType(cont, eOtherBase); 1.1676 + return true; 1.1677 + } 1.1678 + } 1.1679 + 1.1680 + css::Loader* cssLoader = ownerDoc->CSSLoader(); 1.1681 + nsCSSParser cssParser(cssLoader); 1.1682 + 1.1683 + nsRefPtr<css::StyleRule> rule; 1.1684 + cssParser.ParseStyleAttribute(aString, docURI, baseURI, 1.1685 + aElement->NodePrincipal(), 1.1686 + getter_AddRefs(rule)); 1.1687 + if (rule) { 1.1688 + rule->SetHTMLCSSStyleSheet(sheet); 1.1689 + SetTo(rule, &aString); 1.1690 + if (cachingAllowed) { 1.1691 + MiscContainer* cont = GetMiscContainer(); 1.1692 + cont->Cache(); 1.1693 + } 1.1694 + 1.1695 + return true; 1.1696 + } 1.1697 + 1.1698 + return false; 1.1699 +} 1.1700 + 1.1701 +void 1.1702 +nsAttrValue::SetMiscAtomOrString(const nsAString* aValue) 1.1703 +{ 1.1704 + NS_ASSERTION(GetMiscContainer(), "Must have MiscContainer!"); 1.1705 + NS_ASSERTION(!GetMiscContainer()->mStringBits, 1.1706 + "Trying to re-set atom or string!"); 1.1707 + if (aValue) { 1.1708 + uint32_t len = aValue->Length(); 1.1709 + // * We're allowing eCSSStyleRule attributes to store empty strings as it 1.1710 + // can be beneficial to store an empty style attribute as a parsed rule. 1.1711 + // * We're allowing enumerated values because sometimes the empty 1.1712 + // string corresponds to a particular enumerated value, especially 1.1713 + // for enumerated values that are not limited enumerated. 1.1714 + // Add other types as needed. 1.1715 + NS_ASSERTION(len || Type() == eCSSStyleRule || Type() == eEnum, 1.1716 + "Empty string?"); 1.1717 + MiscContainer* cont = GetMiscContainer(); 1.1718 + if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) { 1.1719 + nsCOMPtr<nsIAtom> atom = NS_NewAtom(*aValue); 1.1720 + if (atom) { 1.1721 + cont->mStringBits = 1.1722 + reinterpret_cast<uintptr_t>(atom.forget().take()) | eAtomBase; 1.1723 + } 1.1724 + } else { 1.1725 + nsStringBuffer* buf = GetStringBuffer(*aValue).take(); 1.1726 + if (buf) { 1.1727 + cont->mStringBits = reinterpret_cast<uintptr_t>(buf) | eStringBase; 1.1728 + } 1.1729 + } 1.1730 + } 1.1731 +} 1.1732 + 1.1733 +void 1.1734 +nsAttrValue::ResetMiscAtomOrString() 1.1735 +{ 1.1736 + MiscContainer* cont = GetMiscContainer(); 1.1737 + void* ptr = MISC_STR_PTR(cont); 1.1738 + if (ptr) { 1.1739 + if (static_cast<ValueBaseType>(cont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == 1.1740 + eStringBase) { 1.1741 + static_cast<nsStringBuffer*>(ptr)->Release(); 1.1742 + } else { 1.1743 + static_cast<nsIAtom*>(ptr)->Release(); 1.1744 + } 1.1745 + cont->mStringBits = 0; 1.1746 + } 1.1747 +} 1.1748 + 1.1749 +void 1.1750 +nsAttrValue::SetSVGType(ValueType aType, const void* aValue, 1.1751 + const nsAString* aSerialized) { 1.1752 + NS_ABORT_IF_FALSE(IsSVGType(aType), "Not an SVG type"); 1.1753 + 1.1754 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.1755 + // All SVG types are just pointers to classes so just setting any of them 1.1756 + // will do. We'll lose type-safety but the signature of the calling 1.1757 + // function should ensure we don't get anything unexpected, and once we 1.1758 + // stick aValue in a union we lose type information anyway. 1.1759 + cont->mValue.mSVGAngle = static_cast<const nsSVGAngle*>(aValue); 1.1760 + cont->mType = aType; 1.1761 + SetMiscAtomOrString(aSerialized); 1.1762 +} 1.1763 + 1.1764 +MiscContainer* 1.1765 +nsAttrValue::ClearMiscContainer() 1.1766 +{ 1.1767 + MiscContainer* cont = nullptr; 1.1768 + if (BaseType() == eOtherBase) { 1.1769 + cont = GetMiscContainer(); 1.1770 + if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) { 1.1771 + // This MiscContainer is shared, we need a new one. 1.1772 + NS_RELEASE(cont); 1.1773 + 1.1774 + cont = new MiscContainer; 1.1775 + SetPtrValueAndType(cont, eOtherBase); 1.1776 + } 1.1777 + else { 1.1778 + switch (cont->mType) { 1.1779 + case eCSSStyleRule: 1.1780 + { 1.1781 + MOZ_ASSERT(cont->mValue.mRefCount == 1); 1.1782 + cont->Release(); 1.1783 + cont->Evict(); 1.1784 + NS_RELEASE(cont->mValue.mCSSStyleRule); 1.1785 + break; 1.1786 + } 1.1787 + case eURL: 1.1788 + { 1.1789 + NS_RELEASE(cont->mValue.mURL); 1.1790 + break; 1.1791 + } 1.1792 + case eImage: 1.1793 + { 1.1794 + NS_RELEASE(cont->mValue.mImage); 1.1795 + break; 1.1796 + } 1.1797 + case eAtomArray: 1.1798 + { 1.1799 + delete cont->mValue.mAtomArray; 1.1800 + break; 1.1801 + } 1.1802 + case eIntMarginValue: 1.1803 + { 1.1804 + delete cont->mValue.mIntMargin; 1.1805 + break; 1.1806 + } 1.1807 + default: 1.1808 + { 1.1809 + break; 1.1810 + } 1.1811 + } 1.1812 + } 1.1813 + ResetMiscAtomOrString(); 1.1814 + } 1.1815 + else { 1.1816 + ResetIfSet(); 1.1817 + } 1.1818 + 1.1819 + return cont; 1.1820 +} 1.1821 + 1.1822 +MiscContainer* 1.1823 +nsAttrValue::EnsureEmptyMiscContainer() 1.1824 +{ 1.1825 + MiscContainer* cont = ClearMiscContainer(); 1.1826 + if (cont) { 1.1827 + MOZ_ASSERT(BaseType() == eOtherBase); 1.1828 + ResetMiscAtomOrString(); 1.1829 + cont = GetMiscContainer(); 1.1830 + } 1.1831 + else { 1.1832 + cont = new MiscContainer; 1.1833 + SetPtrValueAndType(cont, eOtherBase); 1.1834 + } 1.1835 + 1.1836 + return cont; 1.1837 +} 1.1838 + 1.1839 +bool 1.1840 +nsAttrValue::EnsureEmptyAtomArray() 1.1841 +{ 1.1842 + if (Type() == eAtomArray) { 1.1843 + ResetMiscAtomOrString(); 1.1844 + GetAtomArrayValue()->Clear(); 1.1845 + return true; 1.1846 + } 1.1847 + 1.1848 + AtomArray* array = new AtomArray; 1.1849 + if (!array) { 1.1850 + Reset(); 1.1851 + return false; 1.1852 + } 1.1853 + 1.1854 + MiscContainer* cont = EnsureEmptyMiscContainer(); 1.1855 + cont->mValue.mAtomArray = array; 1.1856 + cont->mType = eAtomArray; 1.1857 + 1.1858 + return true; 1.1859 +} 1.1860 + 1.1861 +already_AddRefed<nsStringBuffer> 1.1862 +nsAttrValue::GetStringBuffer(const nsAString& aValue) const 1.1863 +{ 1.1864 + uint32_t len = aValue.Length(); 1.1865 + if (!len) { 1.1866 + return nullptr; 1.1867 + } 1.1868 + 1.1869 + nsRefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aValue); 1.1870 + if (buf && (buf->StorageSize()/sizeof(char16_t) - 1) == len) { 1.1871 + return buf.forget(); 1.1872 + } 1.1873 + 1.1874 + buf = nsStringBuffer::Alloc((len + 1) * sizeof(char16_t)); 1.1875 + if (!buf) { 1.1876 + return nullptr; 1.1877 + } 1.1878 + char16_t *data = static_cast<char16_t*>(buf->Data()); 1.1879 + CopyUnicodeTo(aValue, 0, data, len); 1.1880 + data[len] = char16_t(0); 1.1881 + return buf.forget(); 1.1882 +} 1.1883 + 1.1884 +int32_t 1.1885 +nsAttrValue::StringToInteger(const nsAString& aValue, bool* aStrict, 1.1886 + nsresult* aErrorCode, 1.1887 + bool aCanBePercent, 1.1888 + bool* aIsPercent) const 1.1889 +{ 1.1890 + *aStrict = true; 1.1891 + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; 1.1892 + if (aCanBePercent) { 1.1893 + *aIsPercent = false; 1.1894 + } 1.1895 + 1.1896 + nsAString::const_iterator iter, end; 1.1897 + aValue.BeginReading(iter); 1.1898 + aValue.EndReading(end); 1.1899 + 1.1900 + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { 1.1901 + *aStrict = false; 1.1902 + ++iter; 1.1903 + } 1.1904 + 1.1905 + if (iter == end) { 1.1906 + return 0; 1.1907 + } 1.1908 + 1.1909 + bool negate = false; 1.1910 + if (*iter == char16_t('-')) { 1.1911 + negate = true; 1.1912 + ++iter; 1.1913 + } else if (*iter == char16_t('+')) { 1.1914 + *aStrict = false; 1.1915 + ++iter; 1.1916 + } 1.1917 + 1.1918 + int32_t value = 0; 1.1919 + int32_t pValue = 0; // Previous value, used to check integer overflow 1.1920 + while (iter != end) { 1.1921 + if (*iter >= char16_t('0') && *iter <= char16_t('9')) { 1.1922 + value = (value * 10) + (*iter - char16_t('0')); 1.1923 + ++iter; 1.1924 + // Checking for integer overflow. 1.1925 + if (pValue > value) { 1.1926 + *aStrict = false; 1.1927 + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; 1.1928 + break; 1.1929 + } else { 1.1930 + pValue = value; 1.1931 + *aErrorCode = NS_OK; 1.1932 + } 1.1933 + } else if (aCanBePercent && *iter == char16_t('%')) { 1.1934 + ++iter; 1.1935 + *aIsPercent = true; 1.1936 + if (iter != end) { 1.1937 + *aStrict = false; 1.1938 + break; 1.1939 + } 1.1940 + } else { 1.1941 + *aStrict = false; 1.1942 + break; 1.1943 + } 1.1944 + } 1.1945 + if (negate) { 1.1946 + value = -value; 1.1947 + // Checking the special case of -0. 1.1948 + if (!value) { 1.1949 + *aStrict = false; 1.1950 + } 1.1951 + } 1.1952 + 1.1953 + return value; 1.1954 +} 1.1955 + 1.1956 +size_t 1.1957 +nsAttrValue::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.1958 +{ 1.1959 + size_t n = 0; 1.1960 + 1.1961 + switch (BaseType()) { 1.1962 + case eStringBase: 1.1963 + { 1.1964 + nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); 1.1965 + n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0; 1.1966 + break; 1.1967 + } 1.1968 + case eOtherBase: 1.1969 + { 1.1970 + MiscContainer* container = GetMiscContainer(); 1.1971 + if (!container) { 1.1972 + break; 1.1973 + } 1.1974 + n += aMallocSizeOf(container); 1.1975 + 1.1976 + void* otherPtr = MISC_STR_PTR(container); 1.1977 + // We only count the size of the object pointed by otherPtr if it's a 1.1978 + // string. When it's an atom, it's counted separatly. 1.1979 + if (otherPtr && 1.1980 + static_cast<ValueBaseType>(container->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == eStringBase) { 1.1981 + nsStringBuffer* str = static_cast<nsStringBuffer*>(otherPtr); 1.1982 + n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0; 1.1983 + } 1.1984 + 1.1985 + if (Type() == eCSSStyleRule && container->mValue.mCSSStyleRule) { 1.1986 + // TODO: mCSSStyleRule might be owned by another object which would 1.1987 + // make us count them twice, bug 677493. 1.1988 + //n += container->mCSSStyleRule->SizeOfIncludingThis(aMallocSizeOf); 1.1989 + } else if (Type() == eAtomArray && container->mValue.mAtomArray) { 1.1990 + // Don't measure each nsIAtom, they are measured separatly. 1.1991 + n += container->mValue.mAtomArray->SizeOfIncludingThis(aMallocSizeOf); 1.1992 + } 1.1993 + break; 1.1994 + } 1.1995 + case eAtomBase: // Atoms are counted separately. 1.1996 + case eIntegerBase: // The value is in mBits, nothing to do. 1.1997 + break; 1.1998 + } 1.1999 + 1.2000 + return n; 1.2001 +} 1.2002 +