LCOV - code coverage report
Current view: directory - content/base/src - nsAttrValue.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 822 102 12.4 %
Date: 2012-06-02 Functions: 71 14 19.7 %

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

Generated by: LCOV version 1.7