LCOV - code coverage report
Current view: top level - dom/base - nsAttrValue.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 414 956 43.3 %
Date: 2017-07-14 16:53:18 Functions: 45 79 57.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * A struct that represents the value (type and actual data) of an
       9             :  * attribute.
      10             :  */
      11             : 
      12             : #include "mozilla/DebugOnly.h"
      13             : #include "mozilla/HashFunctions.h"
      14             : 
      15             : #include "nsAttrValue.h"
      16             : #include "nsAttrValueInlines.h"
      17             : #include "nsIAtom.h"
      18             : #include "nsUnicharUtils.h"
      19             : #include "mozilla/MemoryReporting.h"
      20             : #include "mozilla/ServoBindingTypes.h"
      21             : #include "mozilla/ServoStyleSet.h"
      22             : #include "mozilla/DeclarationBlockInlines.h"
      23             : #include "nsContentUtils.h"
      24             : #include "nsReadableUtils.h"
      25             : #include "nsHTMLCSSStyleSheet.h"
      26             : #include "nsCSSParser.h"
      27             : #include "nsStyledElement.h"
      28             : #include "nsIURI.h"
      29             : #include "nsIDocument.h"
      30             : #include <algorithm>
      31             : 
      32             : #ifdef LoadImage
      33             : // Undefine LoadImage to prevent naming conflict with Windows.
      34             : #undef LoadImage
      35             : #endif
      36             : 
      37             : using namespace mozilla;
      38             : 
      39             : #define MISC_STR_PTR(_cont) \
      40             :   reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK)
      41             : 
      42             : bool
      43          90 : MiscContainer::GetString(nsAString& aString) const
      44             : {
      45          90 :   void* ptr = MISC_STR_PTR(this);
      46             : 
      47          90 :   if (!ptr) {
      48           0 :     return false;
      49             :   }
      50             : 
      51          90 :   if (static_cast<nsAttrValue::ValueBaseType>(mStringBits &
      52             :                                               NS_ATTRVALUE_BASETYPE_MASK) ==
      53             :       nsAttrValue::eStringBase) {
      54          36 :     nsStringBuffer* buffer = static_cast<nsStringBuffer*>(ptr);
      55          36 :     if (!buffer) {
      56           0 :       return false;
      57             :     }
      58             : 
      59          36 :     buffer->ToString(buffer->StorageSize() / sizeof(char16_t) - 1, aString);
      60          36 :     return true;
      61             :   }
      62             : 
      63          54 :   nsIAtom* atom = static_cast<nsIAtom*>(ptr);
      64          54 :   if (!atom) {
      65           0 :     return false;
      66             :   }
      67             : 
      68          54 :   atom->ToString(aString);
      69          54 :   return true;
      70             : }
      71             : 
      72             : void
      73           0 : MiscContainer::Cache()
      74             : {
      75             :   // Not implemented for anything else yet.
      76           0 :   if (mType != nsAttrValue::eCSSDeclaration) {
      77           0 :     MOZ_ASSERT_UNREACHABLE("unexpected cached nsAttrValue type");
      78             :     return;
      79             :   }
      80             : 
      81           0 :   MOZ_ASSERT(IsRefCounted());
      82           0 :   MOZ_ASSERT(mValue.mRefCount > 0);
      83           0 :   MOZ_ASSERT(!mValue.mCached);
      84             : 
      85           0 :   nsHTMLCSSStyleSheet* sheet = mValue.mCSSDeclaration->GetHTMLCSSStyleSheet();
      86           0 :   if (!sheet) {
      87           0 :     return;
      88             :   }
      89             : 
      90           0 :   nsString str;
      91           0 :   bool gotString = GetString(str);
      92           0 :   if (!gotString) {
      93           0 :     return;
      94             :   }
      95             : 
      96           0 :   sheet->CacheStyleAttr(str, this);
      97           0 :   mValue.mCached = 1;
      98             : 
      99             :   // This has to be immutable once it goes into the cache.
     100           0 :   mValue.mCSSDeclaration->SetImmutable();
     101             : }
     102             : 
     103             : void
     104          10 : MiscContainer::Evict()
     105             : {
     106             :   // Not implemented for anything else yet.
     107          10 :   if (mType != nsAttrValue::eCSSDeclaration) {
     108           0 :     MOZ_ASSERT_UNREACHABLE("unexpected cached nsAttrValue type");
     109             :     return;
     110             :   }
     111          10 :   MOZ_ASSERT(IsRefCounted());
     112          10 :   MOZ_ASSERT(mValue.mRefCount == 0);
     113             : 
     114          10 :   if (!mValue.mCached) {
     115          10 :     return;
     116             :   }
     117             : 
     118           0 :   nsHTMLCSSStyleSheet* sheet = mValue.mCSSDeclaration->GetHTMLCSSStyleSheet();
     119           0 :   MOZ_ASSERT(sheet);
     120             : 
     121           0 :   nsString str;
     122           0 :   DebugOnly<bool> gotString = GetString(str);
     123           0 :   MOZ_ASSERT(gotString);
     124             : 
     125           0 :   sheet->EvictStyleAttr(str, this);
     126           0 :   mValue.mCached = 0;
     127             : }
     128             : 
     129             : nsTArray<const nsAttrValue::EnumTable*>* nsAttrValue::sEnumTableArray = nullptr;
     130             : 
     131       25766 : nsAttrValue::nsAttrValue()
     132       25766 :     : mBits(0)
     133             : {
     134       25766 : }
     135             : 
     136           0 : nsAttrValue::nsAttrValue(const nsAttrValue& aOther)
     137           0 :     : mBits(0)
     138             : {
     139           0 :   SetTo(aOther);
     140           0 : }
     141             : 
     142           0 : nsAttrValue::nsAttrValue(const nsAString& aValue)
     143           0 :     : mBits(0)
     144             : {
     145           0 :   SetTo(aValue);
     146           0 : }
     147             : 
     148           0 : nsAttrValue::nsAttrValue(nsIAtom* aValue)
     149           0 :     : mBits(0)
     150             : {
     151           0 :   SetTo(aValue);
     152           0 : }
     153             : 
     154           9 : nsAttrValue::nsAttrValue(already_AddRefed<DeclarationBlock> aValue,
     155           9 :                          const nsAString* aSerialized)
     156           9 :     : mBits(0)
     157             : {
     158           9 :   SetTo(Move(aValue), aSerialized);
     159           9 : }
     160             : 
     161           0 : nsAttrValue::nsAttrValue(const nsIntMargin& aValue)
     162           0 :     : mBits(0)
     163             : {
     164           0 :   SetTo(aValue);
     165           0 : }
     166             : 
     167       27522 : nsAttrValue::~nsAttrValue()
     168             : {
     169       13761 :   ResetIfSet();
     170       13761 : }
     171             : 
     172             : /* static */
     173             : nsresult
     174           3 : nsAttrValue::Init()
     175             : {
     176           3 :   NS_ASSERTION(!sEnumTableArray, "nsAttrValue already initialized");
     177           3 :   sEnumTableArray = new nsTArray<const EnumTable*>;
     178           3 :   return NS_OK;
     179             : }
     180             : 
     181             : /* static */
     182             : void
     183           0 : nsAttrValue::Shutdown()
     184             : {
     185           0 :   delete sEnumTableArray;
     186           0 :   sEnumTableArray = nullptr;
     187           0 : }
     188             : 
     189             : nsAttrValue::ValueType
     190      133430 : nsAttrValue::Type() const
     191             : {
     192      133430 :   switch (BaseType()) {
     193             :     case eIntegerBase:
     194             :     {
     195         253 :       return static_cast<ValueType>(mBits & NS_ATTRVALUE_INTEGERTYPE_MASK);
     196             :     }
     197             :     case eOtherBase:
     198             :     {
     199       19687 :       return GetMiscContainer()->mType;
     200             :     }
     201             :     default:
     202             :     {
     203      113490 :       return static_cast<ValueType>(static_cast<uint16_t>(BaseType()));
     204             :     }
     205             :   }
     206             : }
     207             : 
     208             : void
     209        3240 : nsAttrValue::Reset()
     210             : {
     211        3240 :   switch(BaseType()) {
     212             :     case eStringBase:
     213             :     {
     214        1152 :       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
     215        1152 :       if (str) {
     216        1152 :         str->Release();
     217             :       }
     218             : 
     219        1152 :       break;
     220             :     }
     221             :     case eOtherBase:
     222             :     {
     223         263 :       MiscContainer* cont = GetMiscContainer();
     224         263 :       if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) {
     225           0 :         NS_RELEASE(cont);
     226           0 :         break;
     227             :       }
     228             : 
     229         263 :       delete ClearMiscContainer();
     230             : 
     231         263 :       break;
     232             :     }
     233             :     case eAtomBase:
     234             :     {
     235        1824 :       nsIAtom* atom = GetAtomValue();
     236        1824 :       NS_RELEASE(atom);
     237             : 
     238        1824 :       break;
     239             :     }
     240             :     case eIntegerBase:
     241             :     {
     242           1 :       break;
     243             :     }
     244             :   }
     245             : 
     246        3240 :   mBits = 0;
     247        3240 : }
     248             : 
     249             : void
     250        8371 : nsAttrValue::SetTo(const nsAttrValue& aOther)
     251             : {
     252        8371 :   if (this == &aOther) {
     253           0 :     return;
     254             :   }
     255             : 
     256        8371 :   switch (aOther.BaseType()) {
     257             :     case eStringBase:
     258             :     {
     259        2679 :       ResetIfSet();
     260        2679 :       nsStringBuffer* str = static_cast<nsStringBuffer*>(aOther.GetPtr());
     261        2679 :       if (str) {
     262        2654 :         str->AddRef();
     263        2654 :         SetPtrValueAndType(str, eStringBase);
     264             :       }
     265        2679 :       return;
     266             :     }
     267             :     case eOtherBase:
     268             :     {
     269         389 :       break;
     270             :     }
     271             :     case eAtomBase:
     272             :     {
     273        5302 :       ResetIfSet();
     274        5302 :       nsIAtom* atom = aOther.GetAtomValue();
     275        5302 :       NS_ADDREF(atom);
     276        5302 :       SetPtrValueAndType(atom, eAtomBase);
     277        5302 :       return;
     278             :     }
     279             :     case eIntegerBase:
     280             :     {
     281           1 :       ResetIfSet();
     282           1 :       mBits = aOther.mBits;
     283           1 :       return;
     284             :     }
     285             :   }
     286             : 
     287         389 :   MiscContainer* otherCont = aOther.GetMiscContainer();
     288         389 :   if (otherCont->IsRefCounted()) {
     289           0 :     delete ClearMiscContainer();
     290           0 :     NS_ADDREF(otherCont);
     291           0 :     SetPtrValueAndType(otherCont, eOtherBase);
     292           0 :     return;
     293             :   }
     294             : 
     295         389 :   MiscContainer* cont = EnsureEmptyMiscContainer();
     296         389 :   switch (otherCont->mType) {
     297             :     case eInteger:
     298             :     {
     299           0 :       cont->mValue.mInteger = otherCont->mValue.mInteger;
     300           0 :       break;
     301             :     }
     302             :     case eEnum:
     303             :     {
     304           0 :       cont->mValue.mEnumValue = otherCont->mValue.mEnumValue;
     305           0 :       break;
     306             :     }
     307             :     case ePercent:
     308             :     {
     309           0 :       cont->mValue.mPercent = otherCont->mValue.mPercent;
     310           0 :       break;
     311             :     }
     312             :     case eColor:
     313             :     {
     314           0 :       cont->mValue.mColor = otherCont->mValue.mColor;
     315           0 :       break;
     316             :     }
     317             :     case eCSSDeclaration:
     318             :     {
     319           0 :       MOZ_CRASH("These should be refcounted!");
     320             :     }
     321             :     case eURL:
     322             :     {
     323           0 :       NS_ADDREF(cont->mValue.mURL = otherCont->mValue.mURL);
     324           0 :       break;
     325             :     }
     326             :     case eImage:
     327             :     {
     328           0 :       NS_ADDREF(cont->mValue.mImage = otherCont->mValue.mImage);
     329           0 :       break;
     330             :     }
     331             :     case eAtomArray:
     332             :     {
     333         398 :       if (!EnsureEmptyAtomArray() ||
     334         199 :           !GetAtomArrayValue()->AppendElements(*otherCont->mValue.mAtomArray)) {
     335           0 :         Reset();
     336           0 :         return;
     337             :       }
     338         199 :       break;
     339             :     }
     340             :     case eDoubleValue:
     341             :     {
     342           0 :       cont->mDoubleValue = otherCont->mDoubleValue;
     343           0 :       break;
     344             :     }
     345             :     case eIntMarginValue:
     346             :     {
     347           0 :       if (otherCont->mValue.mIntMargin)
     348           0 :         cont->mValue.mIntMargin =
     349           0 :           new nsIntMargin(*otherCont->mValue.mIntMargin);
     350           0 :       break;
     351             :     }
     352             :     default:
     353             :     {
     354         190 :       if (IsSVGType(otherCont->mType)) {
     355             :         // All SVG types are just pointers to classes and will therefore have
     356             :         // the same size so it doesn't really matter which one we assign
     357         190 :         cont->mValue.mSVGAngle = otherCont->mValue.mSVGAngle;
     358             :       } else {
     359           0 :         NS_NOTREACHED("unknown type stored in MiscContainer");
     360             :       }
     361         190 :       break;
     362             :     }
     363             :   }
     364             : 
     365         389 :   void* otherPtr = MISC_STR_PTR(otherCont);
     366         389 :   if (otherPtr) {
     367         389 :     if (static_cast<ValueBaseType>(otherCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
     368             :         eStringBase) {
     369         264 :       static_cast<nsStringBuffer*>(otherPtr)->AddRef();
     370             :     } else {
     371         125 :       static_cast<nsIAtom*>(otherPtr)->AddRef();
     372             :     }
     373         389 :     cont->mStringBits = otherCont->mStringBits;
     374             :   }
     375             :   // Note, set mType after switch-case, otherwise EnsureEmptyAtomArray doesn't
     376             :   // work correctly.
     377         389 :   cont->mType = otherCont->mType;
     378             : }
     379             : 
     380             : void
     381        2273 : nsAttrValue::SetTo(const nsAString& aValue)
     382             : {
     383        2273 :   ResetIfSet();
     384        2273 :   nsStringBuffer* buf = GetStringBuffer(aValue).take();
     385        2273 :   if (buf) {
     386        2249 :     SetPtrValueAndType(buf, eStringBase);
     387             :   }
     388        2273 : }
     389             : 
     390             : void
     391           6 : nsAttrValue::SetTo(nsIAtom* aValue)
     392             : {
     393           6 :   ResetIfSet();
     394           6 :   if (aValue) {
     395           6 :     NS_ADDREF(aValue);
     396           6 :     SetPtrValueAndType(aValue, eAtomBase);
     397             :   }
     398           6 : }
     399             : 
     400             : void
     401           0 : nsAttrValue::SetTo(int16_t aInt)
     402             : {
     403           0 :   ResetIfSet();
     404           0 :   SetIntValueAndType(aInt, eInteger, nullptr);
     405           0 : }
     406             : 
     407             : void
     408           0 : nsAttrValue::SetTo(int32_t aInt, const nsAString* aSerialized)
     409             : {
     410           0 :   ResetIfSet();
     411           0 :   SetIntValueAndType(aInt, eInteger, aSerialized);
     412           0 : }
     413             : 
     414             : void
     415           0 : nsAttrValue::SetTo(double aValue, const nsAString* aSerialized)
     416             : {
     417           0 :   MiscContainer* cont = EnsureEmptyMiscContainer();
     418           0 :   cont->mDoubleValue = aValue;
     419           0 :   cont->mType = eDoubleValue;
     420           0 :   SetMiscAtomOrString(aSerialized);
     421           0 : }
     422             : 
     423             : void
     424          26 : nsAttrValue::SetTo(already_AddRefed<DeclarationBlock> aValue,
     425             :                    const nsAString* aSerialized)
     426             : {
     427          26 :   MiscContainer* cont = EnsureEmptyMiscContainer();
     428          26 :   MOZ_ASSERT(cont->mValue.mRefCount == 0);
     429          26 :   cont->mValue.mCSSDeclaration = aValue.take();
     430          26 :   cont->mType = eCSSDeclaration;
     431          26 :   NS_ADDREF(cont);
     432          26 :   SetMiscAtomOrString(aSerialized);
     433          26 :   MOZ_ASSERT(cont->mValue.mRefCount == 1);
     434          26 : }
     435             : 
     436             : void
     437           0 : nsAttrValue::SetTo(css::URLValue* aValue, const nsAString* aSerialized)
     438             : {
     439           0 :   MiscContainer* cont = EnsureEmptyMiscContainer();
     440           0 :   NS_ADDREF(cont->mValue.mURL = aValue);
     441           0 :   cont->mType = eURL;
     442           0 :   SetMiscAtomOrString(aSerialized);
     443           0 : }
     444             : 
     445             : void
     446           0 : nsAttrValue::SetTo(const nsIntMargin& aValue)
     447             : {
     448           0 :   MiscContainer* cont = EnsureEmptyMiscContainer();
     449           0 :   cont->mValue.mIntMargin = new nsIntMargin(aValue);
     450           0 :   cont->mType = eIntMarginValue;
     451           0 : }
     452             : 
     453             : void
     454           0 : nsAttrValue::SetToSerialized(const nsAttrValue& aOther)
     455             : {
     456           0 :   if (aOther.Type() != nsAttrValue::eString &&
     457           0 :       aOther.Type() != nsAttrValue::eAtom) {
     458           0 :     nsAutoString val;
     459           0 :     aOther.ToString(val);
     460           0 :     SetTo(val);
     461             :   } else {
     462           0 :     SetTo(aOther);
     463             :   }
     464           0 : }
     465             : 
     466             : void
     467           0 : nsAttrValue::SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized)
     468             : {
     469           0 :   SetSVGType(eSVGAngle, &aValue, aSerialized);
     470           0 : }
     471             : 
     472             : void
     473           0 : nsAttrValue::SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized)
     474             : {
     475           0 :   SetSVGType(eSVGIntegerPair, &aValue, aSerialized);
     476           0 : }
     477             : 
     478             : void
     479         106 : nsAttrValue::SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized)
     480             : {
     481         106 :   SetSVGType(eSVGLength, &aValue, aSerialized);
     482         106 : }
     483             : 
     484             : void
     485           0 : nsAttrValue::SetTo(const SVGLengthList& aValue,
     486             :                    const nsAString* aSerialized)
     487             : {
     488             :   // While an empty string will parse as a length list, there's no need to store
     489             :   // it (and SetMiscAtomOrString will assert if we try)
     490           0 :   if (aSerialized && aSerialized->IsEmpty()) {
     491           0 :     aSerialized = nullptr;
     492             :   }
     493           0 :   SetSVGType(eSVGLengthList, &aValue, aSerialized);
     494           0 : }
     495             : 
     496             : void
     497           0 : nsAttrValue::SetTo(const SVGNumberList& aValue,
     498             :                    const nsAString* aSerialized)
     499             : {
     500             :   // While an empty string will parse as a number list, there's no need to store
     501             :   // it (and SetMiscAtomOrString will assert if we try)
     502           0 :   if (aSerialized && aSerialized->IsEmpty()) {
     503           0 :     aSerialized = nullptr;
     504             :   }
     505           0 :   SetSVGType(eSVGNumberList, &aValue, aSerialized);
     506           0 : }
     507             : 
     508             : void
     509           0 : nsAttrValue::SetTo(const nsSVGNumberPair& aValue, const nsAString* aSerialized)
     510             : {
     511           0 :   SetSVGType(eSVGNumberPair, &aValue, aSerialized);
     512           0 : }
     513             : 
     514             : void
     515          44 : nsAttrValue::SetTo(const SVGPathData& aValue,
     516             :                    const nsAString* aSerialized)
     517             : {
     518             :   // While an empty string will parse as path data, there's no need to store it
     519             :   // (and SetMiscAtomOrString will assert if we try)
     520          44 :   if (aSerialized && aSerialized->IsEmpty()) {
     521           0 :     aSerialized = nullptr;
     522             :   }
     523          44 :   SetSVGType(eSVGPathData, &aValue, aSerialized);
     524          44 : }
     525             : 
     526             : void
     527          14 : nsAttrValue::SetTo(const SVGPointList& aValue,
     528             :                    const nsAString* aSerialized)
     529             : {
     530             :   // While an empty string will parse as a point list, there's no need to store
     531             :   // it (and SetMiscAtomOrString will assert if we try)
     532          14 :   if (aSerialized && aSerialized->IsEmpty()) {
     533           0 :     aSerialized = nullptr;
     534             :   }
     535          14 :   SetSVGType(eSVGPointList, &aValue, aSerialized);
     536          14 : }
     537             : 
     538             : void
     539           3 : nsAttrValue::SetTo(const SVGAnimatedPreserveAspectRatio& aValue,
     540             :                    const nsAString* aSerialized)
     541             : {
     542           3 :   SetSVGType(eSVGPreserveAspectRatio, &aValue, aSerialized);
     543           3 : }
     544             : 
     545             : void
     546           0 : nsAttrValue::SetTo(const SVGStringList& aValue,
     547             :                    const nsAString* aSerialized)
     548             : {
     549             :   // While an empty string will parse as a string list, there's no need to store
     550             :   // it (and SetMiscAtomOrString will assert if we try)
     551           0 :   if (aSerialized && aSerialized->IsEmpty()) {
     552           0 :     aSerialized = nullptr;
     553             :   }
     554           0 :   SetSVGType(eSVGStringList, &aValue, aSerialized);
     555           0 : }
     556             : 
     557             : void
     558           7 : nsAttrValue::SetTo(const SVGTransformList& aValue,
     559             :                    const nsAString* aSerialized)
     560             : {
     561             :   // While an empty string will parse as a transform list, there's no need to
     562             :   // store it (and SetMiscAtomOrString will assert if we try)
     563           7 :   if (aSerialized && aSerialized->IsEmpty()) {
     564           0 :     aSerialized = nullptr;
     565             :   }
     566           7 :   SetSVGType(eSVGTransformList, &aValue, aSerialized);
     567           7 : }
     568             : 
     569             : void
     570          16 : nsAttrValue::SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized)
     571             : {
     572          16 :   SetSVGType(eSVGViewBox, &aValue, aSerialized);
     573          16 : }
     574             : 
     575             : void
     576        8526 : nsAttrValue::SwapValueWith(nsAttrValue& aOther)
     577             : {
     578        8526 :   uintptr_t tmp = aOther.mBits;
     579        8526 :   aOther.mBits = mBits;
     580        8526 :   mBits = tmp;
     581        8526 : }
     582             : 
     583             : void
     584         560 : nsAttrValue::ToString(nsAString& aResult) const
     585             : {
     586         560 :   MiscContainer* cont = nullptr;
     587         560 :   if (BaseType() == eOtherBase) {
     588          90 :     cont = GetMiscContainer();
     589             : 
     590          90 :     if (cont->GetString(aResult)) {
     591          90 :       return;
     592             :     }
     593             :   }
     594             : 
     595         470 :   switch(Type()) {
     596             :     case eString:
     597             :     {
     598         336 :       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
     599         336 :       if (str) {
     600         336 :         str->ToString(str->StorageSize()/sizeof(char16_t) - 1, aResult);
     601             :       }
     602             :       else {
     603           0 :         aResult.Truncate();
     604             :       }
     605         336 :       break;
     606             :     }
     607             :     case eAtom:
     608             :     {
     609          42 :       nsIAtom *atom = static_cast<nsIAtom*>(GetPtr());
     610          42 :       atom->ToString(aResult);
     611             : 
     612          42 :       break;
     613             :     }
     614             :     case eInteger:
     615             :     {
     616           0 :       nsAutoString intStr;
     617           0 :       intStr.AppendInt(GetIntegerValue());
     618           0 :       aResult = intStr;
     619             : 
     620           0 :       break;
     621             :     }
     622             : #ifdef DEBUG
     623             :     case eColor:
     624             :     {
     625           0 :       NS_NOTREACHED("color attribute without string data");
     626           0 :       aResult.Truncate();
     627           0 :       break;
     628             :     }
     629             : #endif
     630             :     case eEnum:
     631             :     {
     632          92 :       GetEnumString(aResult, false);
     633          92 :       break;
     634             :     }
     635             :     case ePercent:
     636             :     {
     637           0 :       nsAutoString intStr;
     638           0 :       intStr.AppendInt(cont ? cont->mValue.mPercent : GetIntInternal());
     639           0 :       aResult = intStr + NS_LITERAL_STRING("%");
     640             : 
     641           0 :       break;
     642             :     }
     643             :     case eCSSDeclaration:
     644             :     {
     645           0 :       aResult.Truncate();
     646           0 :       MiscContainer *container = GetMiscContainer();
     647           0 :       if (DeclarationBlock* decl = container->mValue.mCSSDeclaration) {
     648           0 :         decl->ToString(aResult);
     649             :       }
     650             : 
     651             :       // We can reach this during parallel style traversal. If that happens,
     652             :       // don't cache the string. The TLS overhead should't hurt us here, since
     653             :       // main thread consumers will subsequently use the cache, and
     654             :       // off-main-thread consumers only reach this in the rare case of selector
     655             :       // matching on the "style" attribute.
     656           0 :       if (!ServoStyleSet::IsInServoTraversal()) {
     657           0 :         const_cast<nsAttrValue*>(this)->SetMiscAtomOrString(&aResult);
     658             :       }
     659             : 
     660           0 :       break;
     661             :     }
     662             :     case eDoubleValue:
     663             :     {
     664           0 :       aResult.Truncate();
     665           0 :       aResult.AppendFloat(GetDoubleValue());
     666           0 :       break;
     667             :     }
     668             :     case eSVGAngle:
     669             :     {
     670           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGAngle,
     671           0 :                                     aResult);
     672           0 :       break;
     673             :     }
     674             :     case eSVGIntegerPair:
     675             :     {
     676           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGIntegerPair,
     677           0 :                                     aResult);
     678           0 :       break;
     679             :     }
     680             :     case eSVGLength:
     681             :     {
     682           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLength,
     683           0 :                                     aResult);
     684           0 :       break;
     685             :     }
     686             :     case eSVGLengthList:
     687             :     {
     688           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLengthList,
     689           0 :                                     aResult);
     690           0 :       break;
     691             :     }
     692             :     case eSVGNumberList:
     693             :     {
     694           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberList,
     695           0 :                                     aResult);
     696           0 :       break;
     697             :     }
     698             :     case eSVGNumberPair:
     699             :     {
     700           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGNumberPair,
     701           0 :                                     aResult);
     702           0 :       break;
     703             :     }
     704             :     case eSVGPathData:
     705             :     {
     706           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPathData,
     707           0 :                                     aResult);
     708           0 :       break;
     709             :     }
     710             :     case eSVGPointList:
     711             :     {
     712           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPointList,
     713           0 :                                     aResult);
     714           0 :       break;
     715             :     }
     716             :     case eSVGPreserveAspectRatio:
     717             :     {
     718           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGPreserveAspectRatio,
     719           0 :                                     aResult);
     720           0 :       break;
     721             :     }
     722             :     case eSVGStringList:
     723             :     {
     724           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGStringList,
     725           0 :                                     aResult);
     726           0 :       break;
     727             :     }
     728             :     case eSVGTransformList:
     729             :     {
     730           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGTransformList,
     731           0 :                                     aResult);
     732           0 :       break;
     733             :     }
     734             :     case eSVGViewBox:
     735             :     {
     736           0 :       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGViewBox,
     737           0 :                                     aResult);
     738           0 :       break;
     739             :     }
     740             :     default:
     741             :     {
     742           0 :       aResult.Truncate();
     743           0 :       break;
     744             :     }
     745             :   }
     746             : }
     747             : 
     748             : already_AddRefed<nsIAtom>
     749           0 : nsAttrValue::GetAsAtom() const
     750             : {
     751           0 :   switch (Type()) {
     752             :     case eString:
     753           0 :       return NS_AtomizeMainThread(GetStringValue());
     754             : 
     755             :     case eAtom:
     756             :       {
     757           0 :         nsCOMPtr<nsIAtom> atom = GetAtomValue();
     758           0 :         return atom.forget();
     759             :       }
     760             : 
     761             :     default:
     762             :       {
     763           0 :         nsAutoString val;
     764           0 :         ToString(val);
     765           0 :         return NS_AtomizeMainThread(val);
     766             :       }
     767             :   }
     768             : }
     769             : 
     770             : const nsCheapString
     771          63 : nsAttrValue::GetStringValue() const
     772             : {
     773          63 :   NS_PRECONDITION(Type() == eString, "wrong type");
     774             : 
     775          63 :   return nsCheapString(static_cast<nsStringBuffer*>(GetPtr()));
     776             : }
     777             : 
     778             : bool
     779           0 : nsAttrValue::GetColorValue(nscolor& aColor) const
     780             : {
     781           0 :   if (Type() != eColor) {
     782             :     // Unparseable value, treat as unset.
     783           0 :     NS_ASSERTION(Type() == eString, "unexpected type for color-valued attr");
     784           0 :     return false;
     785             :   }
     786             : 
     787           0 :   aColor = GetMiscContainer()->mValue.mColor;
     788           0 :   return true;
     789             : }
     790             : 
     791             : void
     792          92 : nsAttrValue::GetEnumString(nsAString& aResult, bool aRealTag) const
     793             : {
     794          92 :   NS_PRECONDITION(Type() == eEnum, "wrong type");
     795             : 
     796             :   uint32_t allEnumBits =
     797          92 :     (BaseType() == eIntegerBase) ? static_cast<uint32_t>(GetIntInternal())
     798          92 :                                    : GetMiscContainer()->mValue.mEnumValue;
     799          92 :   int16_t val = allEnumBits >> NS_ATTRVALUE_ENUMTABLEINDEX_BITS;
     800             :   const EnumTable* table = sEnumTableArray->
     801          92 :     ElementAt(allEnumBits & NS_ATTRVALUE_ENUMTABLEINDEX_MASK);
     802             : 
     803        2852 :   while (table->tag) {
     804        1472 :     if (table->value == val) {
     805          92 :       aResult.AssignASCII(table->tag);
     806          92 :       if (!aRealTag && allEnumBits & NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER) {
     807           0 :         nsContentUtils::ASCIIToUpper(aResult);
     808             :       }
     809          92 :       return;
     810             :     }
     811        1380 :     table++;
     812             :   }
     813             : 
     814           0 :   NS_NOTREACHED("couldn't find value in EnumTable");
     815             : }
     816             : 
     817             : uint32_t
     818       12109 : nsAttrValue::GetAtomCount() const
     819             : {
     820       12109 :   ValueType type = Type();
     821             : 
     822       12109 :   if (type == eAtom) {
     823        8635 :     return 1;
     824             :   }
     825             : 
     826        3474 :   if (type == eAtomArray) {
     827        3463 :     return GetAtomArrayValue()->Length();
     828             :   }
     829             : 
     830          11 :   return 0;
     831             : }
     832             : 
     833             : nsIAtom*
     834        6282 : nsAttrValue::AtomAt(int32_t aIndex) const
     835             : {
     836        6282 :   NS_PRECONDITION(aIndex >= 0, "Index must not be negative");
     837        6282 :   NS_PRECONDITION(GetAtomCount() > uint32_t(aIndex), "aIndex out of range");
     838             : 
     839        6282 :   if (BaseType() == eAtomBase) {
     840        4045 :     return GetAtomValue();
     841             :   }
     842             : 
     843        2237 :   NS_ASSERTION(Type() == eAtomArray, "GetAtomCount must be confused");
     844             : 
     845        2237 :   return GetAtomArrayValue()->ElementAt(aIndex);
     846             : }
     847             : 
     848             : uint32_t
     849          26 : nsAttrValue::HashValue() const
     850             : {
     851          26 :   switch(BaseType()) {
     852             :     case eStringBase:
     853             :     {
     854          25 :       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
     855          25 :       if (str) {
     856          25 :         uint32_t len = str->StorageSize()/sizeof(char16_t) - 1;
     857          25 :         return HashString(static_cast<char16_t*>(str->Data()), len);
     858             :       }
     859             : 
     860           0 :       return 0;
     861             :     }
     862             :     case eOtherBase:
     863             :     {
     864           0 :       break;
     865             :     }
     866             :     case eAtomBase:
     867             :     case eIntegerBase:
     868             :     {
     869             :       // mBits and uint32_t might have different size. This should silence
     870             :       // any warnings or compile-errors. This is what the implementation of
     871             :       // NS_PTR_TO_INT32 does to take care of the same problem.
     872           1 :       return mBits - 0;
     873             :     }
     874             :   }
     875             : 
     876           0 :   MiscContainer* cont = GetMiscContainer();
     877           0 :   if (static_cast<ValueBaseType>(cont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK)
     878             :       == eAtomBase) {
     879           0 :     return cont->mStringBits - 0;
     880             :   }
     881             : 
     882           0 :   switch (cont->mType) {
     883             :     case eInteger:
     884             :     {
     885           0 :       return cont->mValue.mInteger;
     886             :     }
     887             :     case eEnum:
     888             :     {
     889           0 :       return cont->mValue.mEnumValue;
     890             :     }
     891             :     case ePercent:
     892             :     {
     893           0 :       return cont->mValue.mPercent;
     894             :     }
     895             :     case eColor:
     896             :     {
     897           0 :       return cont->mValue.mColor;
     898             :     }
     899             :     case eCSSDeclaration:
     900             :     {
     901           0 :       return NS_PTR_TO_INT32(cont->mValue.mCSSDeclaration);
     902             :     }
     903             :     // Intentionally identical, so that loading the image does not change the
     904             :     // hash code.
     905             :     case eURL:
     906             :     case eImage:
     907             :     {
     908           0 :       nsString str;
     909           0 :       ToString(str);
     910           0 :       return HashString(str);
     911             :     }
     912             :     case eAtomArray:
     913             :     {
     914           0 :       uint32_t hash = 0;
     915           0 :       uint32_t count = cont->mValue.mAtomArray->Length();
     916           0 :       for (nsCOMPtr<nsIAtom> *cur = cont->mValue.mAtomArray->Elements(),
     917           0 :                              *end = cur + count;
     918           0 :            cur != end; ++cur) {
     919           0 :         hash = AddToHash(hash, cur->get());
     920             :       }
     921           0 :       return hash;
     922             :     }
     923             :     case eDoubleValue:
     924             :     {
     925             :       // XXX this is crappy, but oh well
     926           0 :       return cont->mDoubleValue;
     927             :     }
     928             :     case eIntMarginValue:
     929             :     {
     930           0 :       return NS_PTR_TO_INT32(cont->mValue.mIntMargin);
     931             :     }
     932             :     default:
     933             :     {
     934           0 :       if (IsSVGType(cont->mType)) {
     935             :         // All SVG types are just pointers to classes so we can treat them alike
     936           0 :         return NS_PTR_TO_INT32(cont->mValue.mSVGAngle);
     937             :       }
     938           0 :       NS_NOTREACHED("unknown type stored in MiscContainer");
     939           0 :       return 0;
     940             :     }
     941             :   }
     942             : }
     943             : 
     944             : bool
     945           1 : nsAttrValue::Equals(const nsAttrValue& aOther) const
     946             : {
     947           1 :   if (BaseType() != aOther.BaseType()) {
     948           0 :     return false;
     949             :   }
     950             : 
     951           1 :   switch(BaseType()) {
     952             :     case eStringBase:
     953             :     {
     954           1 :       return GetStringValue().Equals(aOther.GetStringValue());
     955             :     }
     956             :     case eOtherBase:
     957             :     {
     958           0 :       break;
     959             :     }
     960             :     case eAtomBase:
     961             :     case eIntegerBase:
     962             :     {
     963           0 :       return mBits == aOther.mBits;
     964             :     }
     965             :   }
     966             : 
     967           0 :   MiscContainer* thisCont = GetMiscContainer();
     968           0 :   MiscContainer* otherCont = aOther.GetMiscContainer();
     969           0 :   if (thisCont == otherCont) {
     970           0 :     return true;
     971             :   }
     972             : 
     973           0 :   if (thisCont->mType != otherCont->mType) {
     974           0 :     return false;
     975             :   }
     976             : 
     977           0 :   bool needsStringComparison = false;
     978             : 
     979           0 :   switch (thisCont->mType) {
     980             :     case eInteger:
     981             :     {
     982           0 :       if (thisCont->mValue.mInteger == otherCont->mValue.mInteger) {
     983           0 :         needsStringComparison = true;
     984             :       }
     985           0 :       break;
     986             :     }
     987             :     case eEnum:
     988             :     {
     989           0 :       if (thisCont->mValue.mEnumValue == otherCont->mValue.mEnumValue) {
     990           0 :         needsStringComparison = true;
     991             :       }
     992           0 :       break;
     993             :     }
     994             :     case ePercent:
     995             :     {
     996           0 :       if (thisCont->mValue.mPercent == otherCont->mValue.mPercent) {
     997           0 :         needsStringComparison = true;
     998             :       }
     999           0 :       break;
    1000             :     }
    1001             :     case eColor:
    1002             :     {
    1003           0 :       if (thisCont->mValue.mColor == otherCont->mValue.mColor) {
    1004           0 :         needsStringComparison = true;
    1005             :       }
    1006           0 :       break;
    1007             :     }
    1008             :     case eCSSDeclaration:
    1009             :     {
    1010           0 :       return thisCont->mValue.mCSSDeclaration ==
    1011           0 :                otherCont->mValue.mCSSDeclaration;
    1012             :     }
    1013             :     case eURL:
    1014             :     {
    1015           0 :       return thisCont->mValue.mURL == otherCont->mValue.mURL;
    1016             :     }
    1017             :     case eImage:
    1018             :     {
    1019           0 :       return thisCont->mValue.mImage == otherCont->mValue.mImage;
    1020             :     }
    1021             :     case eAtomArray:
    1022             :     {
    1023             :       // For classlists we could be insensitive to order, however
    1024             :       // classlists are never mapped attributes so they are never compared.
    1025             : 
    1026           0 :       if (!(*thisCont->mValue.mAtomArray == *otherCont->mValue.mAtomArray)) {
    1027           0 :         return false;
    1028             :       }
    1029             : 
    1030           0 :       needsStringComparison = true;
    1031           0 :       break;
    1032             :     }
    1033             :     case eDoubleValue:
    1034             :     {
    1035           0 :       return thisCont->mDoubleValue == otherCont->mDoubleValue;
    1036             :     }
    1037             :     case eIntMarginValue:
    1038             :     {
    1039           0 :       return thisCont->mValue.mIntMargin == otherCont->mValue.mIntMargin;
    1040             :     }
    1041             :     default:
    1042             :     {
    1043           0 :       if (IsSVGType(thisCont->mType)) {
    1044             :         // Currently this method is never called for nsAttrValue objects that
    1045             :         // point to SVG data types.
    1046             :         // If that changes then we probably want to add methods to the
    1047             :         // corresponding SVG types to compare their base values.
    1048             :         // As a shortcut, however, we can begin by comparing the pointers.
    1049           0 :         MOZ_ASSERT(false, "Comparing nsAttrValues that point to SVG data");
    1050             :         return false;
    1051             :       }
    1052           0 :       NS_NOTREACHED("unknown type stored in MiscContainer");
    1053           0 :       return false;
    1054             :     }
    1055             :   }
    1056           0 :   if (needsStringComparison) {
    1057           0 :     if (thisCont->mStringBits == otherCont->mStringBits) {
    1058           0 :       return true;
    1059             :     }
    1060           0 :     if ((static_cast<ValueBaseType>(thisCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
    1061           0 :          eStringBase) &&
    1062           0 :         (static_cast<ValueBaseType>(otherCont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
    1063             :          eStringBase)) {
    1064           0 :       return nsCheapString(reinterpret_cast<nsStringBuffer*>(thisCont->mStringBits)).Equals(
    1065           0 :         nsCheapString(reinterpret_cast<nsStringBuffer*>(otherCont->mStringBits)));
    1066             :     }
    1067             :   }
    1068           0 :   return false;
    1069             : }
    1070             : 
    1071             : bool
    1072        3703 : nsAttrValue::Equals(const nsAString& aValue,
    1073             :                     nsCaseTreatment aCaseSensitive) const
    1074             : {
    1075        3703 :   switch (BaseType()) {
    1076             :     case eStringBase:
    1077             :     {
    1078         266 :       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
    1079         266 :       if (str) {
    1080         239 :         nsDependentString dep(static_cast<char16_t*>(str->Data()),
    1081         717 :                               str->StorageSize()/sizeof(char16_t) - 1);
    1082         239 :         return aCaseSensitive == eCaseMatters ? aValue.Equals(dep) :
    1083         239 :           nsContentUtils::EqualsIgnoreASCIICase(aValue, dep);
    1084             :       }
    1085          27 :       return aValue.IsEmpty();
    1086             :     }
    1087             :     case eAtomBase:
    1088        3345 :       if (aCaseSensitive == eCaseMatters) {
    1089        3339 :         return static_cast<nsIAtom*>(GetPtr())->Equals(aValue);
    1090             :       }
    1091             :       return nsContentUtils::EqualsIgnoreASCIICase(
    1092          12 :           nsDependentAtomString(static_cast<nsIAtom*>(GetPtr())),
    1093           6 :           aValue);
    1094             :     default:
    1095          92 :       break;
    1096             :   }
    1097             : 
    1098         184 :   nsAutoString val;
    1099          92 :   ToString(val);
    1100          92 :   return aCaseSensitive == eCaseMatters ? val.Equals(aValue) :
    1101          92 :     nsContentUtils::EqualsIgnoreASCIICase(val, aValue);
    1102             : }
    1103             : 
    1104             : bool
    1105         723 : nsAttrValue::Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
    1106             : {
    1107         723 :   if (aCaseSensitive != eCaseMatters) {
    1108             :     // Need a better way to handle this!
    1109          12 :     nsAutoString value;
    1110           6 :     aValue->ToString(value);
    1111           6 :     return Equals(value, aCaseSensitive);
    1112             :   }
    1113             : 
    1114         717 :   switch (BaseType()) {
    1115             :     case eStringBase:
    1116             :     {
    1117           9 :       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
    1118           9 :       if (str) {
    1119           9 :         nsDependentString dep(static_cast<char16_t*>(str->Data()),
    1120          27 :                               str->StorageSize()/sizeof(char16_t) - 1);
    1121           9 :         return aValue->Equals(dep);
    1122             :       }
    1123           0 :       return aValue == nsGkAtoms::_empty;
    1124             :     }
    1125             :     case eAtomBase:
    1126             :     {
    1127         708 :       return static_cast<nsIAtom*>(GetPtr()) == aValue;
    1128             :     }
    1129             :     default:
    1130           0 :       break;
    1131             :   }
    1132             : 
    1133           0 :   nsAutoString val;
    1134           0 :   ToString(val);
    1135           0 :   return aValue->Equals(val);
    1136             : }
    1137             : 
    1138             : bool
    1139           0 : nsAttrValue::EqualsAsStrings(const nsAttrValue& aOther) const
    1140             : {
    1141           0 :   if (Type() == aOther.Type()) {
    1142           0 :     return Equals(aOther);
    1143             :   }
    1144             : 
    1145             :   // We need to serialize at least one nsAttrValue before passing to
    1146             :   // Equals(const nsAString&), but we can avoid unnecessarily serializing both
    1147             :   // by checking if one is already of a string type.
    1148           0 :   bool thisIsString = (BaseType() == eStringBase || BaseType() == eAtomBase);
    1149           0 :   const nsAttrValue& lhs = thisIsString ? *this : aOther;
    1150           0 :   const nsAttrValue& rhs = thisIsString ? aOther : *this;
    1151             : 
    1152           0 :   switch (rhs.BaseType()) {
    1153             :     case eAtomBase:
    1154           0 :       return lhs.Equals(rhs.GetAtomValue(), eCaseMatters);
    1155             : 
    1156             :     case eStringBase:
    1157           0 :       return lhs.Equals(rhs.GetStringValue(), eCaseMatters);
    1158             : 
    1159             :     default:
    1160             :     {
    1161           0 :       nsAutoString val;
    1162           0 :       rhs.ToString(val);
    1163           0 :       return lhs.Equals(val, eCaseMatters);
    1164             :     }
    1165             :   }
    1166             : }
    1167             : 
    1168             : bool
    1169       12963 : nsAttrValue::Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
    1170             : {
    1171       12963 :   switch (BaseType()) {
    1172             :     case eAtomBase:
    1173             :     {
    1174        9398 :       nsIAtom* atom = GetAtomValue();
    1175             : 
    1176        9398 :       if (aCaseSensitive == eCaseMatters) {
    1177        9396 :         return aValue == atom;
    1178             :       }
    1179             : 
    1180             :       // For performance reasons, don't do a full on unicode case insensitive
    1181             :       // string comparison. This is only used for quirks mode anyway.
    1182             :       return
    1183           4 :         nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(aValue),
    1184           6 :                                               nsDependentAtomString(atom));
    1185             :     }
    1186             :     default:
    1187             :     {
    1188        3565 :       if (Type() == eAtomArray) {
    1189        3565 :         AtomArray* array = GetAtomArrayValue();
    1190        3565 :         if (aCaseSensitive == eCaseMatters) {
    1191        7130 :           return array->Contains(aValue);
    1192             :         }
    1193             : 
    1194           0 :         nsDependentAtomString val1(aValue);
    1195             : 
    1196           0 :         for (nsCOMPtr<nsIAtom> *cur = array->Elements(),
    1197           0 :                                *end = cur + array->Length();
    1198           0 :              cur != end; ++cur) {
    1199             :           // For performance reasons, don't do a full on unicode case
    1200             :           // insensitive string comparison. This is only used for quirks mode
    1201             :           // anyway.
    1202           0 :           if (nsContentUtils::EqualsIgnoreASCIICase(val1,
    1203           0 :                 nsDependentAtomString(*cur))) {
    1204           0 :             return true;
    1205             :           }
    1206             :         }
    1207             :       }
    1208             :     }
    1209             :   }
    1210             : 
    1211           0 :   return false;
    1212             : }
    1213             : 
    1214             : struct AtomArrayStringComparator {
    1215           0 :   bool Equals(nsIAtom* atom, const nsAString& string) const {
    1216           0 :     return atom->Equals(string);
    1217             :   }
    1218             : };
    1219             : 
    1220             : bool
    1221           4 : nsAttrValue::Contains(const nsAString& aValue) const
    1222             : {
    1223           4 :   switch (BaseType()) {
    1224             :     case eAtomBase:
    1225             :     {
    1226           4 :       nsIAtom* atom = GetAtomValue();
    1227           4 :       return atom->Equals(aValue);
    1228             :     }
    1229             :     default:
    1230             :     {
    1231           0 :       if (Type() == eAtomArray) {
    1232           0 :         AtomArray* array = GetAtomArrayValue();
    1233           0 :         return array->Contains(aValue, AtomArrayStringComparator());
    1234             :       }
    1235             :     }
    1236             :   }
    1237             : 
    1238           0 :   return false;
    1239             : }
    1240             : 
    1241             : void
    1242        3710 : nsAttrValue::ParseAtom(const nsAString& aValue)
    1243             : {
    1244        3710 :   ResetIfSet();
    1245             : 
    1246        7420 :   nsCOMPtr<nsIAtom> atom = NS_Atomize(aValue);
    1247        3710 :   if (atom) {
    1248        3710 :     SetPtrValueAndType(atom.forget().take(), eAtomBase);
    1249             :   }
    1250        3710 : }
    1251             : 
    1252             : void
    1253         695 : nsAttrValue::ParseAtomArray(const nsAString& aValue)
    1254             : {
    1255         695 :   nsAString::const_iterator iter, end;
    1256         695 :   aValue.BeginReading(iter);
    1257         695 :   aValue.EndReading(end);
    1258         695 :   bool hasSpace = false;
    1259             : 
    1260             :   // skip initial whitespace
    1261         695 :   while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
    1262           0 :     hasSpace = true;
    1263           0 :     ++iter;
    1264             :   }
    1265             : 
    1266         695 :   if (iter == end) {
    1267           0 :     SetTo(aValue);
    1268           0 :     return;
    1269             :   }
    1270             : 
    1271         695 :   nsAString::const_iterator start(iter);
    1272             : 
    1273             :   // get first - and often only - atom
    1274       13476 :   do {
    1275       13476 :     ++iter;
    1276       13476 :   } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
    1277             : 
    1278        1390 :   nsCOMPtr<nsIAtom> classAtom = NS_AtomizeMainThread(Substring(start, iter));
    1279         695 :   if (!classAtom) {
    1280           0 :     Reset();
    1281           0 :     return;
    1282             :   }
    1283             : 
    1284             :   // skip whitespace
    1285         161 :   while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
    1286         161 :     hasSpace = true;
    1287         161 :     ++iter;
    1288             :   }
    1289             : 
    1290         695 :   if (iter == end && !hasSpace) {
    1291             :     // we only found one classname and there was no whitespace so
    1292             :     // don't bother storing a list
    1293         534 :     ResetIfSet();
    1294         534 :     nsIAtom* atom = nullptr;
    1295         534 :     classAtom.swap(atom);
    1296         534 :     SetPtrValueAndType(atom, eAtomBase);
    1297         534 :     return;
    1298             :   }
    1299             : 
    1300         161 :   if (!EnsureEmptyAtomArray()) {
    1301           0 :     return;
    1302             :   }
    1303             : 
    1304         161 :   AtomArray* array = GetAtomArrayValue();
    1305             : 
    1306         161 :   if (!array->AppendElement(classAtom)) {
    1307           0 :     Reset();
    1308           0 :     return;
    1309             :   }
    1310             : 
    1311             :   // parse the rest of the classnames
    1312         547 :   while (iter != end) {
    1313         193 :     start = iter;
    1314             : 
    1315        3448 :     do {
    1316        3448 :       ++iter;
    1317        3448 :     } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
    1318             : 
    1319         193 :     classAtom = NS_AtomizeMainThread(Substring(start, iter));
    1320             : 
    1321         193 :     if (!array->AppendElement(classAtom)) {
    1322           0 :       Reset();
    1323           0 :       return;
    1324             :     }
    1325             : 
    1326             :     // skip whitespace
    1327          32 :     while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
    1328          32 :       ++iter;
    1329             :     }
    1330             :   }
    1331             : 
    1332         161 :   SetMiscAtomOrString(&aValue);
    1333         161 :   return;
    1334             : }
    1335             : 
    1336             : void
    1337        4388 : nsAttrValue::ParseStringOrAtom(const nsAString& aValue)
    1338             : {
    1339        4388 :   uint32_t len = aValue.Length();
    1340             :   // Don't bother with atoms if it's an empty string since
    1341             :   // we can store those efficently anyway.
    1342        4388 :   if (len && len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
    1343        2610 :     ParseAtom(aValue);
    1344             :   }
    1345             :   else {
    1346        1778 :     SetTo(aValue);
    1347             :   }
    1348        4388 : }
    1349             : 
    1350             : void
    1351           1 : nsAttrValue::SetIntValueAndType(int32_t aValue, ValueType aType,
    1352             :                                 const nsAString* aStringValue)
    1353             : {
    1354           1 :   if (aStringValue || aValue > NS_ATTRVALUE_INTEGERTYPE_MAXVALUE ||
    1355             :       aValue < NS_ATTRVALUE_INTEGERTYPE_MINVALUE) {
    1356           0 :     MiscContainer* cont = EnsureEmptyMiscContainer();
    1357           0 :     switch (aType) {
    1358             :       case eInteger:
    1359             :       {
    1360           0 :         cont->mValue.mInteger = aValue;
    1361           0 :         break;
    1362             :       }
    1363             :       case ePercent:
    1364             :       {
    1365           0 :         cont->mValue.mPercent = aValue;
    1366           0 :         break;
    1367             :       }
    1368             :       case eEnum:
    1369             :       {
    1370           0 :         cont->mValue.mEnumValue = aValue;
    1371           0 :         break;
    1372             :       }
    1373             :       default:
    1374             :       {
    1375           0 :         NS_NOTREACHED("unknown integer type");
    1376           0 :         break;
    1377             :       }
    1378             :     }
    1379           0 :     cont->mType = aType;
    1380           0 :     SetMiscAtomOrString(aStringValue);
    1381             :   } else {
    1382           1 :     NS_ASSERTION(!mBits, "Reset before calling SetIntValueAndType!");
    1383           1 :     mBits = (aValue * NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER) | aType;
    1384             :   }
    1385           1 : }
    1386             : 
    1387             : int16_t
    1388           1 : nsAttrValue::GetEnumTableIndex(const EnumTable* aTable)
    1389             : {
    1390           1 :   int16_t index = sEnumTableArray->IndexOf(aTable);
    1391           1 :   if (index < 0) {
    1392           1 :     index = sEnumTableArray->Length();
    1393           1 :     NS_ASSERTION(index <= NS_ATTRVALUE_ENUMTABLEINDEX_MAXVALUE,
    1394             :         "too many enum tables");
    1395           1 :     sEnumTableArray->AppendElement(aTable);
    1396             :   }
    1397             : 
    1398           1 :   return index;
    1399             : }
    1400             : 
    1401             : int32_t
    1402           1 : nsAttrValue::EnumTableEntryToValue(const EnumTable* aEnumTable,
    1403             :                                    const EnumTable* aTableEntry)
    1404             : {
    1405           1 :   int16_t index = GetEnumTableIndex(aEnumTable);
    1406           1 :   int32_t value = (aTableEntry->value << NS_ATTRVALUE_ENUMTABLEINDEX_BITS) +
    1407           1 :                   index;
    1408           1 :   return value;
    1409             : }
    1410             : 
    1411             : bool
    1412           3 : nsAttrValue::ParseEnumValue(const nsAString& aValue,
    1413             :                             const EnumTable* aTable,
    1414             :                             bool aCaseSensitive,
    1415             :                             const EnumTable* aDefaultValue)
    1416             : {
    1417           3 :   ResetIfSet();
    1418           3 :   const EnumTable* tableEntry = aTable;
    1419             : 
    1420          61 :   while (tableEntry->tag) {
    1421          60 :     if (aCaseSensitive ? aValue.EqualsASCII(tableEntry->tag) :
    1422          30 :                          aValue.LowerCaseEqualsASCII(tableEntry->tag)) {
    1423           1 :       int32_t value = EnumTableEntryToValue(aTable, tableEntry);
    1424             : 
    1425           1 :       bool equals = aCaseSensitive || aValue.EqualsASCII(tableEntry->tag);
    1426           1 :       if (!equals) {
    1427           0 :         nsAutoString tag;
    1428           0 :         tag.AssignASCII(tableEntry->tag);
    1429           0 :         nsContentUtils::ASCIIToUpper(tag);
    1430           0 :         if ((equals = tag.Equals(aValue))) {
    1431           0 :           value |= NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER;
    1432             :         }
    1433             :       }
    1434           1 :       SetIntValueAndType(value, eEnum, equals ? nullptr : &aValue);
    1435           1 :       NS_ASSERTION(GetEnumValue() == tableEntry->value,
    1436             :                    "failed to store enum properly");
    1437             : 
    1438           1 :       return true;
    1439             :     }
    1440          29 :     tableEntry++;
    1441             :   }
    1442             : 
    1443           2 :   if (aDefaultValue) {
    1444           0 :     NS_PRECONDITION(aTable <= aDefaultValue && aDefaultValue < tableEntry,
    1445             :                     "aDefaultValue not inside aTable?");
    1446           0 :     SetIntValueAndType(EnumTableEntryToValue(aTable, aDefaultValue),
    1447           0 :                        eEnum, &aValue);
    1448           0 :     return true;
    1449             :   }
    1450             : 
    1451           2 :   return false;
    1452             : }
    1453             : 
    1454             : bool
    1455           0 : nsAttrValue::ParseSpecialIntValue(const nsAString& aString)
    1456             : {
    1457           0 :   ResetIfSet();
    1458             : 
    1459           0 :   nsAutoString tmp(aString);
    1460             :   nsContentUtils::ParseHTMLIntegerResultFlags result;
    1461           0 :   int32_t originalVal = nsContentUtils::ParseHTMLInteger(aString, &result);
    1462             : 
    1463           0 :   if (result & nsContentUtils::eParseHTMLInteger_Error) {
    1464           0 :     return false;
    1465             :   }
    1466             : 
    1467           0 :   bool isPercent = result & nsContentUtils::eParseHTMLInteger_IsPercent;
    1468           0 :   int32_t val = std::max(originalVal, 0);
    1469           0 :   bool nonStrict = val != originalVal ||
    1470           0 :                    (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
    1471           0 :                    (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
    1472             : 
    1473             :   // % (percent)
    1474           0 :   if (isPercent || tmp.RFindChar('%') >= 0) {
    1475           0 :     isPercent = true;
    1476             :   }
    1477             : 
    1478           0 :   SetIntValueAndType(val, isPercent ? ePercent : eInteger,
    1479           0 :                      nonStrict ? &aString : nullptr);
    1480           0 :   return true;
    1481             : }
    1482             : 
    1483             : bool
    1484           0 : nsAttrValue::ParseIntWithBounds(const nsAString& aString,
    1485             :                                 int32_t aMin, int32_t aMax)
    1486             : {
    1487           0 :   NS_PRECONDITION(aMin < aMax, "bad boundaries");
    1488             : 
    1489           0 :   ResetIfSet();
    1490             : 
    1491             :   nsContentUtils::ParseHTMLIntegerResultFlags result;
    1492           0 :   int32_t originalVal = nsContentUtils::ParseHTMLInteger(aString, &result);
    1493           0 :   if (result & nsContentUtils::eParseHTMLInteger_Error) {
    1494           0 :     return false;
    1495             :   }
    1496             : 
    1497           0 :   int32_t val = std::max(originalVal, aMin);
    1498           0 :   val = std::min(val, aMax);
    1499           0 :   bool nonStrict = (val != originalVal) ||
    1500           0 :                    (result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
    1501           0 :                    (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
    1502           0 :                    (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
    1503             : 
    1504           0 :   SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
    1505             : 
    1506           0 :   return true;
    1507             : }
    1508             : 
    1509             : void
    1510           0 : nsAttrValue::ParseIntWithFallback(const nsAString& aString, int32_t aDefault,
    1511             :                                   int32_t aMax)
    1512             : {
    1513           0 :   ResetIfSet();
    1514             : 
    1515             :   nsContentUtils::ParseHTMLIntegerResultFlags result;
    1516           0 :   int32_t val = nsContentUtils::ParseHTMLInteger(aString, &result);
    1517           0 :   bool nonStrict = false;
    1518           0 :   if ((result & nsContentUtils::eParseHTMLInteger_Error) || val < 1) {
    1519           0 :     val = aDefault;
    1520           0 :     nonStrict = true;
    1521             :   }
    1522             : 
    1523           0 :   if (val > aMax) {
    1524           0 :     val = aMax;
    1525           0 :     nonStrict = true;
    1526             :   }
    1527             : 
    1528           0 :   if ((result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
    1529           0 :       (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
    1530           0 :       (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput)) {
    1531           0 :     nonStrict = true;
    1532             :   }
    1533             : 
    1534           0 :   SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
    1535           0 : }
    1536             : 
    1537             : void
    1538           0 : nsAttrValue::ParseClampedNonNegativeInt(const nsAString& aString,
    1539             :                                         int32_t aDefault, int32_t aMin,
    1540             :                                         int32_t aMax)
    1541             : {
    1542           0 :   ResetIfSet();
    1543             : 
    1544             :   nsContentUtils::ParseHTMLIntegerResultFlags result;
    1545           0 :   int32_t val = nsContentUtils::ParseHTMLInteger(aString, &result);
    1546           0 :   bool nonStrict = (result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
    1547           0 :                    (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
    1548           0 :                    (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
    1549             : 
    1550           0 :   if (result & nsContentUtils::eParseHTMLInteger_ErrorOverflow) {
    1551           0 :     if (result & nsContentUtils::eParseHTMLInteger_Negative) {
    1552           0 :       val = aDefault;
    1553             :     } else {
    1554           0 :       val = aMax;
    1555             :     }
    1556           0 :     nonStrict = true;
    1557           0 :   } else if ((result & nsContentUtils::eParseHTMLInteger_Error) || val < 0) {
    1558           0 :     val = aDefault;
    1559           0 :     nonStrict = true;
    1560           0 :   } else if (val < aMin) {
    1561           0 :     val = aMin;
    1562           0 :     nonStrict = true;
    1563           0 :   } else if (val > aMax) {
    1564           0 :     val = aMax;
    1565           0 :     nonStrict = true;
    1566             :   }
    1567             : 
    1568           0 :   SetIntValueAndType(val, eInteger, nonStrict ? &aString : nullptr);
    1569           0 : }
    1570             : 
    1571             : bool
    1572           0 : nsAttrValue::ParseNonNegativeIntValue(const nsAString& aString)
    1573             : {
    1574           0 :   ResetIfSet();
    1575             : 
    1576             :   nsContentUtils::ParseHTMLIntegerResultFlags result;
    1577           0 :   int32_t originalVal = nsContentUtils::ParseHTMLInteger(aString, &result);
    1578           0 :   if ((result & nsContentUtils::eParseHTMLInteger_Error) || originalVal < 0) {
    1579           0 :     return false;
    1580             :   }
    1581             : 
    1582           0 :   bool nonStrict = (result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
    1583           0 :                    (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
    1584           0 :                    (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
    1585             : 
    1586           0 :   SetIntValueAndType(originalVal, eInteger, nonStrict ? &aString : nullptr);
    1587             : 
    1588           0 :   return true;
    1589             : }
    1590             : 
    1591             : bool
    1592           0 : nsAttrValue::ParsePositiveIntValue(const nsAString& aString)
    1593             : {
    1594           0 :   ResetIfSet();
    1595             : 
    1596             :   nsContentUtils::ParseHTMLIntegerResultFlags result;
    1597           0 :   int32_t originalVal = nsContentUtils::ParseHTMLInteger(aString, &result);
    1598           0 :   if ((result & nsContentUtils::eParseHTMLInteger_Error) || originalVal <= 0) {
    1599           0 :     return false;
    1600             :   }
    1601             : 
    1602           0 :   bool nonStrict = (result & nsContentUtils::eParseHTMLInteger_IsPercent) ||
    1603           0 :                    (result & nsContentUtils::eParseHTMLInteger_NonStandard) ||
    1604           0 :                    (result & nsContentUtils::eParseHTMLInteger_DidNotConsumeAllInput);
    1605             : 
    1606           0 :   SetIntValueAndType(originalVal, eInteger, nonStrict ? &aString : nullptr);
    1607             : 
    1608           0 :   return true;
    1609             : }
    1610             : 
    1611             : void
    1612           0 : nsAttrValue::SetColorValue(nscolor aColor, const nsAString& aString)
    1613             : {
    1614           0 :   nsStringBuffer* buf = GetStringBuffer(aString).take();
    1615           0 :   if (!buf) {
    1616           0 :     return;
    1617             :   }
    1618             : 
    1619           0 :   MiscContainer* cont = EnsureEmptyMiscContainer();
    1620           0 :   cont->mValue.mColor = aColor;
    1621           0 :   cont->mType = eColor;
    1622             : 
    1623             :   // Save the literal string we were passed for round-tripping.
    1624           0 :   cont->mStringBits = reinterpret_cast<uintptr_t>(buf) | eStringBase;
    1625             : }
    1626             : 
    1627             : bool
    1628           0 : nsAttrValue::ParseColor(const nsAString& aString)
    1629             : {
    1630           0 :   ResetIfSet();
    1631             : 
    1632             :   // FIXME (partially, at least): HTML5's algorithm says we shouldn't do
    1633             :   // the whitespace compression, trimming, or the test for emptiness.
    1634             :   // (I'm a little skeptical that we shouldn't do the whitespace
    1635             :   // trimming; WebKit also does it.)
    1636           0 :   nsAutoString colorStr(aString);
    1637           0 :   colorStr.CompressWhitespace(true, true);
    1638           0 :   if (colorStr.IsEmpty()) {
    1639           0 :     return false;
    1640             :   }
    1641             : 
    1642             :   nscolor color;
    1643             :   // No color names begin with a '#'; in standards mode, all acceptable
    1644             :   // numeric colors do.
    1645           0 :   if (colorStr.First() == '#') {
    1646           0 :     nsDependentString withoutHash(colorStr.get() + 1, colorStr.Length() - 1);
    1647           0 :     if (NS_HexToRGBA(withoutHash, nsHexColorType::NoAlpha, &color)) {
    1648           0 :       SetColorValue(color, aString);
    1649           0 :       return true;
    1650             :     }
    1651             :   } else {
    1652           0 :     if (NS_ColorNameToRGB(colorStr, &color)) {
    1653           0 :       SetColorValue(color, aString);
    1654           0 :       return true;
    1655             :     }
    1656             :   }
    1657             : 
    1658             :   // FIXME (maybe): HTML5 says we should handle system colors.  This
    1659             :   // means we probably need another storage type, since we'd need to
    1660             :   // handle dynamic changes.  However, I think this is a bad idea:
    1661             :   // http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2010-May/026449.html
    1662             : 
    1663             :   // Use NS_LooseHexToRGB as a fallback if nothing above worked.
    1664           0 :   if (NS_LooseHexToRGB(colorStr, &color)) {
    1665           0 :     SetColorValue(color, aString);
    1666           0 :     return true;
    1667             :   }
    1668             : 
    1669           0 :   return false;
    1670             : }
    1671             : 
    1672           0 : bool nsAttrValue::ParseDoubleValue(const nsAString& aString)
    1673             : {
    1674           0 :   ResetIfSet();
    1675             : 
    1676             :   nsresult ec;
    1677           0 :   double val = PromiseFlatString(aString).ToDouble(&ec);
    1678           0 :   if (NS_FAILED(ec)) {
    1679           0 :     return false;
    1680             :   }
    1681             : 
    1682           0 :   MiscContainer* cont = EnsureEmptyMiscContainer();
    1683           0 :   cont->mDoubleValue = val;
    1684           0 :   cont->mType = eDoubleValue;
    1685           0 :   nsAutoString serializedFloat;
    1686           0 :   serializedFloat.AppendFloat(val);
    1687           0 :   SetMiscAtomOrString(serializedFloat.Equals(aString) ? nullptr : &aString);
    1688           0 :   return true;
    1689             : }
    1690             : 
    1691             : bool
    1692           0 : nsAttrValue::ParseIntMarginValue(const nsAString& aString)
    1693             : {
    1694           0 :   ResetIfSet();
    1695             : 
    1696           0 :   nsIntMargin margins;
    1697           0 :   if (!nsContentUtils::ParseIntMarginValue(aString, margins))
    1698           0 :     return false;
    1699             : 
    1700           0 :   MiscContainer* cont = EnsureEmptyMiscContainer();
    1701           0 :   cont->mValue.mIntMargin = new nsIntMargin(margins);
    1702           0 :   cont->mType = eIntMarginValue;
    1703           0 :   SetMiscAtomOrString(&aString);
    1704           0 :   return true;
    1705             : }
    1706             : 
    1707             : void
    1708           0 : nsAttrValue::LoadImage(nsIDocument* aDocument)
    1709             : {
    1710           0 :   NS_ASSERTION(Type() == eURL, "wrong type");
    1711             : 
    1712           0 :   MiscContainer* cont = GetMiscContainer();
    1713           0 :   mozilla::css::URLValue* url = cont->mValue.mURL;
    1714             : 
    1715           0 :   NS_ASSERTION(!url->mString.IsEmpty(),
    1716             :                "How did we end up with an empty string for eURL");
    1717             : 
    1718             :   mozilla::css::ImageValue* image =
    1719           0 :     new css::ImageValue(url->GetURI(), url->mString,
    1720           0 :                         do_AddRef(url->mExtraData), aDocument);
    1721             : 
    1722           0 :   NS_ADDREF(image);
    1723           0 :   cont->mValue.mImage = image;
    1724           0 :   NS_RELEASE(url);
    1725           0 :   cont->mType = eImage;
    1726           0 : }
    1727             : 
    1728             : bool
    1729           0 : nsAttrValue::ParseStyleAttribute(const nsAString& aString,
    1730             :                                  nsStyledElement* aElement)
    1731             : {
    1732           0 :   nsIDocument* ownerDoc = aElement->OwnerDoc();
    1733           0 :   nsHTMLCSSStyleSheet* sheet = ownerDoc->GetInlineStyleSheet();
    1734           0 :   nsCOMPtr<nsIURI> baseURI = aElement->GetBaseURIForStyleAttr();
    1735           0 :   nsIURI* docURI = ownerDoc->GetDocumentURI();
    1736             : 
    1737           0 :   NS_ASSERTION(aElement->NodePrincipal() == ownerDoc->NodePrincipal(),
    1738             :                "This is unexpected");
    1739             : 
    1740             :   // If the (immutable) document URI does not match the element's base URI
    1741             :   // (the common case is that they do match) do not cache the rule.  This is
    1742             :   // because the results of the CSS parser are dependent on these URIs, and we
    1743             :   // do not want to have to account for the URIs in the hash lookup.
    1744           0 :   bool cachingAllowed = sheet && baseURI == docURI;
    1745           0 :   if (cachingAllowed) {
    1746           0 :     MiscContainer* cont = sheet->LookupStyleAttr(aString);
    1747           0 :     if (cont) {
    1748             :       // Set our MiscContainer to the cached one.
    1749           0 :       NS_ADDREF(cont);
    1750           0 :       SetPtrValueAndType(cont, eOtherBase);
    1751           0 :       return true;
    1752             :     }
    1753             :   }
    1754             : 
    1755           0 :   RefPtr<DeclarationBlock> decl;
    1756           0 :   if (ownerDoc->GetStyleBackendType() == StyleBackendType::Servo) {
    1757             :     RefPtr<URLExtraData> data = new URLExtraData(baseURI, docURI,
    1758           0 :                                                  aElement->NodePrincipal());
    1759           0 :     decl = ServoDeclarationBlock::FromCssText(aString, data,
    1760             :                                               ownerDoc->GetCompatibilityMode(),
    1761           0 :                                               ownerDoc->CSSLoader());
    1762             :   } else {
    1763           0 :     css::Loader* cssLoader = ownerDoc->CSSLoader();
    1764           0 :     nsCSSParser cssParser(cssLoader);
    1765           0 :     decl = cssParser.ParseStyleAttribute(aString, docURI, baseURI,
    1766           0 :                                          aElement->NodePrincipal());
    1767             :   }
    1768           0 :   if (!decl) {
    1769           0 :     return false;
    1770             :   }
    1771           0 :   decl->SetHTMLCSSStyleSheet(sheet);
    1772           0 :   SetTo(decl.forget(), &aString);
    1773             : 
    1774           0 :   if (cachingAllowed) {
    1775           0 :     MiscContainer* cont = GetMiscContainer();
    1776           0 :     cont->Cache();
    1777             :   }
    1778             : 
    1779           0 :   return true;
    1780             : }
    1781             : 
    1782             : void
    1783         377 : nsAttrValue::SetMiscAtomOrString(const nsAString* aValue)
    1784             : {
    1785         377 :   NS_ASSERTION(GetMiscContainer(), "Must have MiscContainer!");
    1786         377 :   NS_ASSERTION(!GetMiscContainer()->mStringBits,
    1787             :                "Trying to re-set atom or string!");
    1788         377 :   if (aValue) {
    1789         368 :     uint32_t len = aValue->Length();
    1790             :     // * We're allowing eCSSDeclaration attributes to store empty
    1791             :     //   strings as it can be beneficial to store an empty style
    1792             :     //   attribute as a parsed rule.
    1793             :     // * We're allowing enumerated values because sometimes the empty
    1794             :     //   string corresponds to a particular enumerated value, especially
    1795             :     //   for enumerated values that are not limited enumerated.
    1796             :     // Add other types as needed.
    1797         368 :     NS_ASSERTION(len || Type() == eCSSDeclaration || Type() == eEnum,
    1798             :                  "Empty string?");
    1799         368 :     MiscContainer* cont = GetMiscContainer();
    1800         368 :     if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
    1801         260 :       nsCOMPtr<nsIAtom> atom = NS_AtomizeMainThread(*aValue);
    1802         130 :       if (atom) {
    1803         130 :         cont->mStringBits =
    1804         260 :           reinterpret_cast<uintptr_t>(atom.forget().take()) | eAtomBase;
    1805             :       }
    1806             :     } else {
    1807         238 :       nsStringBuffer* buf = GetStringBuffer(*aValue).take();
    1808         238 :       if (buf) {
    1809         238 :         cont->mStringBits = reinterpret_cast<uintptr_t>(buf) | eStringBase;
    1810             :       }
    1811             :     }
    1812             :   }
    1813         377 : }
    1814             : 
    1815             : void
    1816         661 : nsAttrValue::ResetMiscAtomOrString()
    1817             : {
    1818         661 :   MiscContainer* cont = GetMiscContainer();
    1819         661 :   void* ptr = MISC_STR_PTR(cont);
    1820         661 :   if (ptr) {
    1821         258 :     if (static_cast<ValueBaseType>(cont->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
    1822             :         eStringBase) {
    1823         131 :       static_cast<nsStringBuffer*>(ptr)->Release();
    1824             :     } else {
    1825         127 :       static_cast<nsIAtom*>(ptr)->Release();
    1826             :     }
    1827         258 :     cont->mStringBits = 0;
    1828             :   }
    1829         661 : }
    1830             : 
    1831             : void
    1832         190 : nsAttrValue::SetSVGType(ValueType aType, const void* aValue,
    1833             :                         const nsAString* aSerialized) {
    1834         190 :   MOZ_ASSERT(IsSVGType(aType), "Not an SVG type");
    1835             : 
    1836         190 :   MiscContainer* cont = EnsureEmptyMiscContainer();
    1837             :   // All SVG types are just pointers to classes so just setting any of them
    1838             :   // will do. We'll lose type-safety but the signature of the calling
    1839             :   // function should ensure we don't get anything unexpected, and once we
    1840             :   // stick aValue in a union we lose type information anyway.
    1841         190 :   cont->mValue.mSVGAngle = static_cast<const nsSVGAngle*>(aValue);
    1842         190 :   cont->mType = aType;
    1843         190 :   SetMiscAtomOrString(aSerialized);
    1844         190 : }
    1845             : 
    1846             : MiscContainer*
    1847        1228 : nsAttrValue::ClearMiscContainer()
    1848             : {
    1849        1228 :   MiscContainer* cont = nullptr;
    1850        1228 :   if (BaseType() == eOtherBase) {
    1851         462 :     cont = GetMiscContainer();
    1852         462 :     if (cont->IsRefCounted() && cont->mValue.mRefCount > 1) {
    1853             :       // This MiscContainer is shared, we need a new one.
    1854           0 :       NS_RELEASE(cont);
    1855             : 
    1856           0 :       cont = new MiscContainer;
    1857           0 :       SetPtrValueAndType(cont, eOtherBase);
    1858             :     }
    1859             :     else {
    1860         462 :       switch (cont->mType) {
    1861             :         case eCSSDeclaration:
    1862             :         {
    1863          10 :           MOZ_ASSERT(cont->mValue.mRefCount == 1);
    1864          10 :           cont->Release();
    1865          10 :           cont->Evict();
    1866          10 :           NS_RELEASE(cont->mValue.mCSSDeclaration);
    1867          10 :           break;
    1868             :         }
    1869             :         case eURL:
    1870             :         {
    1871           0 :           NS_RELEASE(cont->mValue.mURL);
    1872           0 :           break;
    1873             :         }
    1874             :         case eImage:
    1875             :         {
    1876           0 :           NS_RELEASE(cont->mValue.mImage);
    1877           0 :           break;
    1878             :         }
    1879             :         case eAtomArray:
    1880             :         {
    1881          63 :           delete cont->mValue.mAtomArray;
    1882          63 :           break;
    1883             :         }
    1884             :         case eIntMarginValue:
    1885             :         {
    1886           0 :           delete cont->mValue.mIntMargin;
    1887           0 :           break;
    1888             :         }
    1889             :         default:
    1890             :         {
    1891         389 :           break;
    1892             :         }
    1893             :       }
    1894             :     }
    1895         462 :     ResetMiscAtomOrString();
    1896             :   }
    1897             :   else {
    1898         766 :     ResetIfSet();
    1899             :   }
    1900             : 
    1901        1228 :   return cont;
    1902             : }
    1903             : 
    1904             : MiscContainer*
    1905         965 : nsAttrValue::EnsureEmptyMiscContainer()
    1906             : {
    1907         965 :   MiscContainer* cont = ClearMiscContainer();
    1908         965 :   if (cont) {
    1909         199 :     MOZ_ASSERT(BaseType() == eOtherBase);
    1910         199 :     ResetMiscAtomOrString();
    1911         199 :     cont = GetMiscContainer();
    1912             :   }
    1913             :   else {
    1914         766 :     cont = new MiscContainer;
    1915         766 :     SetPtrValueAndType(cont, eOtherBase);
    1916             :   }
    1917             : 
    1918         965 :   return cont;
    1919             : }
    1920             : 
    1921             : bool
    1922         360 : nsAttrValue::EnsureEmptyAtomArray()
    1923             : {
    1924         360 :   if (Type() == eAtomArray) {
    1925           0 :     ResetMiscAtomOrString();
    1926           0 :     GetAtomArrayValue()->Clear();
    1927           0 :     return true;
    1928             :   }
    1929             : 
    1930         360 :   MiscContainer* cont = EnsureEmptyMiscContainer();
    1931         360 :   cont->mValue.mAtomArray = new AtomArray;
    1932         360 :   cont->mType = eAtomArray;
    1933             : 
    1934         360 :   return true;
    1935             : }
    1936             : 
    1937             : already_AddRefed<nsStringBuffer>
    1938        2511 : nsAttrValue::GetStringBuffer(const nsAString& aValue) const
    1939             : {
    1940        2511 :   uint32_t len = aValue.Length();
    1941        2511 :   if (!len) {
    1942          24 :     return nullptr;
    1943             :   }
    1944             : 
    1945        4974 :   RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aValue);
    1946        2487 :   if (buf && (buf->StorageSize()/sizeof(char16_t) - 1) == len) {
    1947         389 :     return buf.forget();
    1948             :   }
    1949             : 
    1950        2098 :   buf = nsStringBuffer::Alloc((len + 1) * sizeof(char16_t));
    1951        2098 :   if (!buf) {
    1952           0 :     return nullptr;
    1953             :   }
    1954        2098 :   char16_t *data = static_cast<char16_t*>(buf->Data());
    1955        2098 :   CopyUnicodeTo(aValue, 0, data, len);
    1956        2098 :   data[len] = char16_t(0);
    1957        2098 :   return buf.forget();
    1958             : }
    1959             : 
    1960             : size_t
    1961         338 : nsAttrValue::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
    1962             : {
    1963         338 :   size_t n = 0;
    1964             : 
    1965         338 :   switch (BaseType()) {
    1966             :     case eStringBase:
    1967             :     {
    1968         133 :       nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr());
    1969         133 :       n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0;
    1970         133 :       break;
    1971             :     }
    1972             :     case eOtherBase:
    1973             :     {
    1974         156 :       MiscContainer* container = GetMiscContainer();
    1975         156 :       if (!container) {
    1976           0 :         break;
    1977             :       }
    1978         156 :       if (container->IsRefCounted() && container->mValue.mRefCount > 1) {
    1979             :         // We don't report this MiscContainer at all in order to avoid
    1980             :         // twice-reporting it.
    1981             :         // TODO DMD, bug 1027551 - figure out how to report this ref-counted
    1982             :         // object just once.
    1983           0 :         break;
    1984             :       }
    1985         156 :       n += aMallocSizeOf(container);
    1986             : 
    1987         156 :       void* otherPtr = MISC_STR_PTR(container);
    1988             :       // We only count the size of the object pointed by otherPtr if it's a
    1989             :       // string. When it's an atom, it's counted separatly.
    1990         312 :       if (otherPtr &&
    1991         156 :           static_cast<ValueBaseType>(container->mStringBits & NS_ATTRVALUE_BASETYPE_MASK) == eStringBase) {
    1992          42 :         nsStringBuffer* str = static_cast<nsStringBuffer*>(otherPtr);
    1993          42 :         n += str ? str->SizeOfIncludingThisIfUnshared(aMallocSizeOf) : 0;
    1994             :       }
    1995             : 
    1996         156 :       if (Type() == eCSSDeclaration && container->mValue.mCSSDeclaration) {
    1997             :         // TODO: mCSSDeclaration might be owned by another object which
    1998             :         //       would make us count them twice, bug 677493.
    1999             :         // Bug 1281964: For ServoDeclarationBlock if we do measure we'll
    2000             :         // need a way to call the Servo heap_size_of function.
    2001             :         //n += container->mCSSDeclaration->SizeOfIncludingThis(aMallocSizeOf);
    2002         156 :       } else if (Type() == eAtomArray && container->mValue.mAtomArray) {
    2003             :         // Don't measure each nsIAtom, they are measured separatly.
    2004           0 :         n += container->mValue.mAtomArray->ShallowSizeOfIncludingThis(aMallocSizeOf);
    2005             :       }
    2006         156 :       break;
    2007             :     }
    2008             :     case eAtomBase:    // Atoms are counted separately.
    2009             :     case eIntegerBase: // The value is in mBits, nothing to do.
    2010          49 :       break;
    2011             :   }
    2012             : 
    2013         338 :   return n;
    2014             : }
    2015             : 

Generated by: LCOV version 1.13