LCOV - code coverage report
Current view: directory - layout/style - nsCSSParser.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 4190 171 4.1 %
Date: 2012-04-21 Functions: 205 23 11.2 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 et sw=2 tw=78: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   emk <VYV03354@nifty.ne.jp>
      25                 :  *   Daniel Glazman <glazman@netscape.com>
      26                 :  *   L. David Baron <dbaron@dbaron.org>
      27                 :  *   Boris Zbarsky <bzbarsky@mit.edu>
      28                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      29                 :  *   Christian Biesinger <cbiesinger@web.de>
      30                 :  *   Jeff Walden <jwalden+code@mit.edu>
      31                 :  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
      32                 :  *   Siraj Razick <siraj.razick@collabora.co.uk>, Collabora Ltd.
      33                 :  *
      34                 :  * Alternatively, the contents of this file may be used under the terms of
      35                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      36                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      37                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      38                 :  * of those above. If you wish to allow use of your version of this file only
      39                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      40                 :  * use your version of this file under the terms of the MPL, indicate your
      41                 :  * decision by deleting the provisions above and replace them with the notice
      42                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      43                 :  * the provisions above, a recipient may use your version of this file under
      44                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      45                 :  *
      46                 :  * ***** END LICENSE BLOCK ***** */
      47                 : 
      48                 : /* parsing of CSS stylesheets, based on a token stream from the CSS scanner */
      49                 : 
      50                 : #include "nsCSSParser.h"
      51                 : #include "nsCSSProps.h"
      52                 : #include "nsCSSKeywords.h"
      53                 : #include "nsCSSScanner.h"
      54                 : #include "mozilla/css/Loader.h"
      55                 : #include "mozilla/css/StyleRule.h"
      56                 : #include "mozilla/css/ImportRule.h"
      57                 : #include "nsCSSRules.h"
      58                 : #include "mozilla/css/NameSpaceRule.h"
      59                 : #include "nsTArray.h"
      60                 : #include "nsCSSStyleSheet.h"
      61                 : #include "mozilla/css/Declaration.h"
      62                 : #include "nsStyleConsts.h"
      63                 : #include "nsIURL.h"
      64                 : #include "nsNetUtil.h"
      65                 : #include "nsCOMPtr.h"
      66                 : #include "nsString.h"
      67                 : #include "nsReadableUtils.h"
      68                 : #include "nsUnicharUtils.h"
      69                 : #include "nsIAtom.h"
      70                 : #include "nsCOMArray.h"
      71                 : #include "nsColor.h"
      72                 : #include "nsCSSPseudoClasses.h"
      73                 : #include "nsCSSPseudoElements.h"
      74                 : #include "nsCSSAnonBoxes.h"
      75                 : #include "nsINameSpaceManager.h"
      76                 : #include "nsXMLNameSpaceMap.h"
      77                 : #include "nsThemeConstants.h"
      78                 : #include "nsContentErrors.h"
      79                 : #include "nsIMediaList.h"
      80                 : #include "mozilla/LookAndFeel.h"
      81                 : #include "nsStyleUtil.h"
      82                 : #include "nsIPrincipal.h"
      83                 : #include "prprf.h"
      84                 : #include "math.h"
      85                 : #include "nsContentUtils.h"
      86                 : #include "nsDOMError.h"
      87                 : #include "nsAutoPtr.h"
      88                 : #include "prlog.h"
      89                 : #include "CSSCalc.h"
      90                 : #include "nsMediaFeatures.h"
      91                 : #include "nsLayoutUtils.h"
      92                 : 
      93                 : #include "mozilla/Util.h"
      94                 : 
      95                 : using namespace mozilla;
      96                 : 
      97                 : // Flags for ParseVariant method
      98                 : #define VARIANT_KEYWORD         0x000001  // K
      99                 : #define VARIANT_LENGTH          0x000002  // L
     100                 : #define VARIANT_PERCENT         0x000004  // P
     101                 : #define VARIANT_COLOR           0x000008  // C eCSSUnit_Color, eCSSUnit_Ident (e.g.  "red")
     102                 : #define VARIANT_URL             0x000010  // U
     103                 : #define VARIANT_NUMBER          0x000020  // N
     104                 : #define VARIANT_INTEGER         0x000040  // I
     105                 : #define VARIANT_ANGLE           0x000080  // G
     106                 : #define VARIANT_FREQUENCY       0x000100  // F
     107                 : #define VARIANT_TIME            0x000200  // T
     108                 : #define VARIANT_STRING          0x000400  // S
     109                 : #define VARIANT_COUNTER         0x000800  //
     110                 : #define VARIANT_ATTR            0x001000  //
     111                 : #define VARIANT_IDENTIFIER      0x002000  // D
     112                 : #define VARIANT_IDENTIFIER_NO_INHERIT 0x004000 // like above, but excluding
     113                 :                                                // 'inherit' and 'initial'
     114                 : #define VARIANT_AUTO            0x010000  // A
     115                 : #define VARIANT_INHERIT         0x020000  // H eCSSUnit_Initial, eCSSUnit_Inherit
     116                 : #define VARIANT_NONE            0x040000  // O
     117                 : #define VARIANT_NORMAL          0x080000  // M
     118                 : #define VARIANT_SYSFONT         0x100000  // eCSSUnit_System_Font
     119                 : #define VARIANT_GRADIENT        0x200000  // eCSSUnit_Gradient
     120                 : #define VARIANT_TIMING_FUNCTION 0x400000  // cubic-bezier() and steps()
     121                 : #define VARIANT_ALL             0x800000  //
     122                 : #define VARIANT_IMAGE_RECT    0x01000000  // eCSSUnit_Function
     123                 : // This is an extra bit that says that a VARIANT_ANGLE allows unitless zero:
     124                 : #define VARIANT_ZERO_ANGLE    0x02000000  // unitless zero for angles
     125                 : #define VARIANT_CALC          0x04000000  // eCSSUnit_Calc
     126                 : #define VARIANT_ELEMENT       0x08000000  // eCSSUnit_Element
     127                 : #define VARIANT_POSITIVE_LENGTH 0x10000000 // Only lengths greater than 0.0
     128                 : 
     129                 : // Common combinations of variants
     130                 : #define VARIANT_AL   (VARIANT_AUTO | VARIANT_LENGTH)
     131                 : #define VARIANT_LP   (VARIANT_LENGTH | VARIANT_PERCENT)
     132                 : #define VARIANT_LN   (VARIANT_LENGTH | VARIANT_NUMBER)
     133                 : #define VARIANT_AH   (VARIANT_AUTO | VARIANT_INHERIT)
     134                 : #define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
     135                 : #define VARIANT_AHI  (VARIANT_AH | VARIANT_INTEGER)
     136                 : #define VARIANT_AHK  (VARIANT_AH | VARIANT_KEYWORD)
     137                 : #define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)
     138                 : #define VARIANT_AHL  (VARIANT_AH | VARIANT_LENGTH)
     139                 : #define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
     140                 : #define VARIANT_HK   (VARIANT_INHERIT | VARIANT_KEYWORD)
     141                 : #define VARIANT_HKF  (VARIANT_HK | VARIANT_FREQUENCY)
     142                 : #define VARIANT_HKI  (VARIANT_HK | VARIANT_INTEGER)
     143                 : #define VARIANT_HKL  (VARIANT_HK | VARIANT_LENGTH)
     144                 : #define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
     145                 : #define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)
     146                 : #define VARIANT_HL   (VARIANT_INHERIT | VARIANT_LENGTH)
     147                 : #define VARIANT_HI   (VARIANT_INHERIT | VARIANT_INTEGER)
     148                 : #define VARIANT_HLP  (VARIANT_HL | VARIANT_PERCENT)
     149                 : #define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
     150                 : #define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
     151                 : #define VARIANT_HTP  (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
     152                 : #define VARIANT_HMK  (VARIANT_HK | VARIANT_NORMAL)
     153                 : #define VARIANT_HC   (VARIANT_INHERIT | VARIANT_COLOR)
     154                 : #define VARIANT_HCK  (VARIANT_HK | VARIANT_COLOR)
     155                 : #define VARIANT_HUK  (VARIANT_HK | VARIANT_URL)
     156                 : #define VARIANT_HUO  (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
     157                 : #define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
     158                 : #define VARIANT_HPN  (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
     159                 : #define VARIANT_PN   (VARIANT_PERCENT | VARIANT_NUMBER)
     160                 : #define VARIANT_ALPN (VARIANT_AL | VARIANT_PN)
     161                 : #define VARIANT_HN   (VARIANT_INHERIT | VARIANT_NUMBER)
     162                 : #define VARIANT_HON  (VARIANT_HN | VARIANT_NONE)
     163                 : #define VARIANT_HOS  (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
     164                 : #define VARIANT_LPN  (VARIANT_LP | VARIANT_NUMBER)
     165                 : #define VARIANT_UK   (VARIANT_URL | VARIANT_KEYWORD)
     166                 : #define VARIANT_UO   (VARIANT_URL | VARIANT_NONE)
     167                 : #define VARIANT_ANGLE_OR_ZERO (VARIANT_ANGLE | VARIANT_ZERO_ANGLE)
     168                 : #define VARIANT_LPCALC (VARIANT_LENGTH | VARIANT_CALC | VARIANT_PERCENT)
     169                 : #define VARIANT_LNCALC (VARIANT_LENGTH | VARIANT_CALC | VARIANT_NUMBER)
     170                 : #define VARIANT_LPNCALC (VARIANT_LNCALC | VARIANT_PERCENT)
     171                 : #define VARIANT_IMAGE (VARIANT_URL | VARIANT_NONE | VARIANT_GRADIENT | \
     172                 :                        VARIANT_IMAGE_RECT | VARIANT_ELEMENT)
     173                 : 
     174                 : // This lives here because it depends on the above macros.
     175                 : const PRUint32
     176                 : nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
     177                 : #define CSS_PROP(name_, id_, method_, flags_, parsevariant_, kwtable_,       \
     178                 :                  stylestruct_, stylestructoffset_, animtype_)                \
     179                 :   parsevariant_,
     180                 : #include "nsCSSPropList.h"
     181                 : #undef CSS_PROP
     182                 : };
     183                 : 
     184                 : //----------------------------------------------------------------------
     185                 : 
     186                 : namespace {
     187                 : 
     188                 : // Rule processing function
     189                 : typedef void (* RuleAppendFunc) (css::Rule* aRule, void* aData);
     190                 : static void AppendRuleToArray(css::Rule* aRule, void* aArray);
     191                 : static void AppendRuleToSheet(css::Rule* aRule, void* aParser);
     192                 : 
     193                 : // Your basic top-down recursive descent style parser
     194                 : // The exposed methods and members of this class are precisely those
     195                 : // needed by nsCSSParser, far below.
     196                 : class CSSParserImpl {
     197                 : public:
     198                 :   CSSParserImpl();
     199                 :   ~CSSParserImpl();
     200                 : 
     201                 :   nsresult SetStyleSheet(nsCSSStyleSheet* aSheet);
     202                 : 
     203                 :   nsresult SetQuirkMode(bool aQuirkMode);
     204                 : 
     205                 :   nsresult SetSVGMode(bool aSVGMode);
     206                 : 
     207                 :   nsresult SetChildLoader(mozilla::css::Loader* aChildLoader);
     208                 : 
     209                 :   // Clears everything set by the above Set*() functions.
     210                 :   void Reset();
     211                 : 
     212                 :   nsresult ParseSheet(const nsAString& aInput,
     213                 :                       nsIURI*          aSheetURI,
     214                 :                       nsIURI*          aBaseURI,
     215                 :                       nsIPrincipal*    aSheetPrincipal,
     216                 :                       PRUint32         aLineNumber,
     217                 :                       bool             aAllowUnsafeRules);
     218                 : 
     219                 :   nsresult ParseStyleAttribute(const nsAString&  aAttributeValue,
     220                 :                                nsIURI*           aDocURL,
     221                 :                                nsIURI*           aBaseURL,
     222                 :                                nsIPrincipal*     aNodePrincipal,
     223                 :                                css::StyleRule**  aResult);
     224                 : 
     225                 :   nsresult ParseDeclarations(const nsAString&  aBuffer,
     226                 :                              nsIURI*           aSheetURL,
     227                 :                              nsIURI*           aBaseURL,
     228                 :                              nsIPrincipal*     aSheetPrincipal,
     229                 :                              css::Declaration* aDeclaration,
     230                 :                              bool*           aChanged);
     231                 : 
     232                 :   nsresult ParseRule(const nsAString&        aRule,
     233                 :                      nsIURI*                 aSheetURL,
     234                 :                      nsIURI*                 aBaseURL,
     235                 :                      nsIPrincipal*           aSheetPrincipal,
     236                 :                      nsCOMArray<css::Rule>&  aResult);
     237                 : 
     238                 :   nsresult ParseProperty(const nsCSSProperty aPropID,
     239                 :                          const nsAString& aPropValue,
     240                 :                          nsIURI* aSheetURL,
     241                 :                          nsIURI* aBaseURL,
     242                 :                          nsIPrincipal* aSheetPrincipal,
     243                 :                          css::Declaration* aDeclaration,
     244                 :                          bool* aChanged,
     245                 :                          bool aIsImportant);
     246                 : 
     247                 :   nsresult ParseMediaList(const nsSubstring& aBuffer,
     248                 :                           nsIURI* aURL, // for error reporting
     249                 :                           PRUint32 aLineNumber, // for error reporting
     250                 :                           nsMediaList* aMediaList,
     251                 :                           bool aHTMLMode);
     252                 : 
     253                 :   nsresult ParseColorString(const nsSubstring& aBuffer,
     254                 :                             nsIURI* aURL, // for error reporting
     255                 :                             PRUint32 aLineNumber, // for error reporting
     256                 :                             nscolor* aColor);
     257                 : 
     258                 :   nsresult ParseSelectorString(const nsSubstring& aSelectorString,
     259                 :                                nsIURI* aURL, // for error reporting
     260                 :                                PRUint32 aLineNumber, // for error reporting
     261                 :                                nsCSSSelectorList **aSelectorList);
     262                 : 
     263                 :   already_AddRefed<nsCSSKeyframeRule>
     264                 :   ParseKeyframeRule(const nsSubstring& aBuffer,
     265                 :                     nsIURI*            aURL,
     266                 :                     PRUint32           aLineNumber);
     267                 : 
     268                 :   bool ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
     269                 :                                    nsIURI* aURL, // for error reporting
     270                 :                                    PRUint32 aLineNumber, // for error reporting
     271                 :                                    InfallibleTArray<float>& aSelectorList);
     272                 : 
     273                 : protected:
     274                 :   class nsAutoParseCompoundProperty;
     275                 :   friend class nsAutoParseCompoundProperty;
     276                 : 
     277                 :   void AppendRule(css::Rule* aRule);
     278                 :   friend void AppendRuleToSheet(css::Rule*, void*); // calls AppendRule
     279                 : 
     280                 :   /**
     281                 :    * This helper class automatically calls SetParsingCompoundProperty in its
     282                 :    * constructor and takes care of resetting it to false in its destructor.
     283                 :    */
     284                 :   class nsAutoParseCompoundProperty {
     285                 :     public:
     286               0 :       nsAutoParseCompoundProperty(CSSParserImpl* aParser) : mParser(aParser)
     287                 :       {
     288               0 :         NS_ASSERTION(!aParser->IsParsingCompoundProperty(),
     289                 :                      "already parsing compound property");
     290               0 :         NS_ASSERTION(aParser, "Null parser?");
     291               0 :         aParser->SetParsingCompoundProperty(true);
     292               0 :       }
     293                 : 
     294               0 :       ~nsAutoParseCompoundProperty()
     295                 :       {
     296               0 :         mParser->SetParsingCompoundProperty(false);
     297               0 :       }
     298                 :     private:
     299                 :       CSSParserImpl* mParser;
     300                 :   };
     301                 : 
     302                 :   // the caller must hold on to aString until parsing is done
     303                 :   void InitScanner(const nsSubstring& aString, nsIURI* aSheetURI,
     304                 :                    PRUint32 aLineNumber, nsIURI* aBaseURI,
     305                 :                    nsIPrincipal* aSheetPrincipal);
     306                 :   void ReleaseScanner(void);
     307               0 :   bool IsSVGMode() const {
     308               0 :     return mScanner.IsSVGMode();
     309                 :   }
     310                 : 
     311                 :   bool GetToken(bool aSkipWS);
     312                 :   void UngetToken();
     313                 : 
     314                 :   // get the part in paretheses of the url() function, which is really a
     315                 :   // part of a token in the CSS grammar, but we're using a combination
     316                 :   // of the parser and the scanner to do it to handle the backtracking
     317                 :   // required by the error handling of the tokenization (since if we
     318                 :   // fail to scan the full token, we should fall back to tokenizing as
     319                 :   // FUNCTION ... ')').
     320                 :   // Note that this function WILL WRITE TO aURL IN SOME FAILURE CASES.
     321                 :   bool GetURLInParens(nsString& aURL);
     322                 : 
     323             110 :   void AssertInitialState() {
     324             110 :     NS_PRECONDITION(!mHTMLMediaMode, "Bad initial state");
     325             110 :     NS_PRECONDITION(!mParsingCompoundProperty, "Bad initial state");
     326             110 :   }
     327                 : 
     328                 :   bool ExpectSymbol(PRUnichar aSymbol, bool aSkipWS);
     329                 :   bool ExpectEndProperty();
     330                 :   bool CheckEndProperty();
     331                 :   nsSubstring* NextIdent();
     332                 :   void SkipUntil(PRUnichar aStopSymbol);
     333                 :   void SkipUntilOneOf(const PRUnichar* aStopSymbolChars);
     334                 :   void SkipRuleSet(bool aInsideBraces);
     335                 :   bool SkipAtRule(bool aInsideBlock);
     336                 :   bool SkipDeclaration(bool aCheckForBraces);
     337                 : 
     338                 :   void PushGroup(css::GroupRule* aRule);
     339                 :   void PopGroup();
     340                 : 
     341                 :   bool ParseRuleSet(RuleAppendFunc aAppendFunc, void* aProcessData,
     342                 :                     bool aInsideBraces = false);
     343                 :   bool ParseAtRule(RuleAppendFunc aAppendFunc, void* aProcessData,
     344                 :                    bool aInAtRule);
     345                 :   bool ParseCharsetRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     346                 :   bool ParseImportRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     347                 :   bool ParseURLOrString(nsString& aURL);
     348                 :   bool GatherMedia(nsMediaList* aMedia,
     349                 :                    bool aInAtRule);
     350                 :   bool ParseMediaQuery(bool aInAtRule, nsMediaQuery **aQuery,
     351                 :                        bool *aHitStop);
     352                 :   bool ParseMediaQueryExpression(nsMediaQuery* aQuery);
     353                 :   void ProcessImport(const nsString& aURLSpec,
     354                 :                      nsMediaList* aMedia,
     355                 :                      RuleAppendFunc aAppendFunc,
     356                 :                      void* aProcessData);
     357                 :   bool ParseGroupRule(css::GroupRule* aRule, RuleAppendFunc aAppendFunc,
     358                 :                       void* aProcessData);
     359                 :   bool ParseMediaRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     360                 :   bool ParseMozDocumentRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     361                 :   bool ParseNameSpaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     362                 :   void ProcessNameSpace(const nsString& aPrefix,
     363                 :                         const nsString& aURLSpec, RuleAppendFunc aAppendFunc,
     364                 :                         void* aProcessData);
     365                 : 
     366                 :   bool ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     367                 :   bool ParseFontDescriptor(nsCSSFontFaceRule* aRule);
     368                 :   bool ParseFontDescriptorValue(nsCSSFontDesc aDescID,
     369                 :                                 nsCSSValue& aValue);
     370                 : 
     371                 :   bool ParsePageRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     372                 :   bool ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aProcessData);
     373                 :   already_AddRefed<nsCSSKeyframeRule> ParseKeyframeRule();
     374                 :   bool ParseKeyframeSelectorList(InfallibleTArray<float>& aSelectorList);
     375                 : 
     376                 :   enum nsSelectorParsingStatus {
     377                 :     // we have parsed a selector and we saw a token that cannot be
     378                 :     // part of a selector:
     379                 :     eSelectorParsingStatus_Done,
     380                 :     // we should continue parsing the selector:
     381                 :     eSelectorParsingStatus_Continue,
     382                 :     // we saw an unexpected token or token value,
     383                 :     // or we saw end-of-file with an unfinished selector:
     384                 :     eSelectorParsingStatus_Error
     385                 :   };
     386                 :   nsSelectorParsingStatus ParseIDSelector(PRInt32&       aDataMask,
     387                 :                                           nsCSSSelector& aSelector);
     388                 : 
     389                 :   nsSelectorParsingStatus ParseClassSelector(PRInt32&       aDataMask,
     390                 :                                              nsCSSSelector& aSelector);
     391                 : 
     392                 :   // aPseudoElement and aPseudoElementArgs are the location where
     393                 :   // pseudo-elements (as opposed to pseudo-classes) are stored;
     394                 :   // pseudo-classes are stored on aSelector.  aPseudoElement and
     395                 :   // aPseudoElementArgs must be non-null iff !aIsNegated.
     396                 :   nsSelectorParsingStatus ParsePseudoSelector(PRInt32&       aDataMask,
     397                 :                                               nsCSSSelector& aSelector,
     398                 :                                               bool           aIsNegated,
     399                 :                                               nsIAtom**      aPseudoElement,
     400                 :                                               nsAtomList**   aPseudoElementArgs,
     401                 :                                               nsCSSPseudoElements::Type* aPseudoElementType);
     402                 : 
     403                 :   nsSelectorParsingStatus ParseAttributeSelector(PRInt32&       aDataMask,
     404                 :                                                  nsCSSSelector& aSelector);
     405                 : 
     406                 :   nsSelectorParsingStatus ParseTypeOrUniversalSelector(PRInt32&       aDataMask,
     407                 :                                                        nsCSSSelector& aSelector,
     408                 :                                                        bool           aIsNegated);
     409                 : 
     410                 :   nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector,
     411                 :                                                        nsCSSPseudoClasses::Type aType);
     412                 : 
     413                 :   nsSelectorParsingStatus ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector,
     414                 :                                                          nsCSSPseudoClasses::Type aType);
     415                 : 
     416                 :   nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
     417                 :                                                               nsCSSPseudoClasses::Type aType);
     418                 : 
     419                 :   nsSelectorParsingStatus ParseNegatedSimpleSelector(PRInt32&       aDataMask,
     420                 :                                                      nsCSSSelector& aSelector);
     421                 : 
     422                 :   // If aStopChar is non-zero, the selector list is done when we hit
     423                 :   // aStopChar.  Otherwise, it's done when we hit EOF.
     424                 :   bool ParseSelectorList(nsCSSSelectorList*& aListHead,
     425                 :                            PRUnichar aStopChar);
     426                 :   bool ParseSelectorGroup(nsCSSSelectorList*& aListHead);
     427                 :   bool ParseSelector(nsCSSSelectorList* aList, PRUnichar aPrevCombinator);
     428                 : 
     429                 :   css::Declaration* ParseDeclarationBlock(bool aCheckForBraces);
     430                 :   bool ParseDeclaration(css::Declaration* aDeclaration,
     431                 :                           bool aCheckForBraces,
     432                 :                           bool aMustCallValueAppended,
     433                 :                           bool* aChanged);
     434                 : 
     435                 :   bool ParseProperty(nsCSSProperty aPropID);
     436                 :   bool ParsePropertyByFunction(nsCSSProperty aPropID);
     437                 :   bool ParseSingleValueProperty(nsCSSValue& aValue,
     438                 :                                   nsCSSProperty aPropID);
     439                 : 
     440                 :   enum PriorityParsingStatus {
     441                 :     ePriority_None,
     442                 :     ePriority_Important,
     443                 :     ePriority_Error
     444                 :   };
     445                 :   PriorityParsingStatus ParsePriority();
     446                 : 
     447                 : #ifdef MOZ_XUL
     448                 :   bool ParseTreePseudoElement(nsAtomList **aPseudoElementArgs);
     449                 : #endif
     450                 : 
     451                 :   void InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties);
     452                 : 
     453                 :   // Property specific parsing routines
     454                 :   bool ParseBackground();
     455                 : 
     456                 :   struct BackgroundParseState {
     457                 :     nsCSSValue&  mColor;
     458                 :     nsCSSValueList* mImage;
     459                 :     nsCSSValuePairList* mRepeat;
     460                 :     nsCSSValueList* mAttachment;
     461                 :     nsCSSValueList* mClip;
     462                 :     nsCSSValueList* mOrigin;
     463                 :     nsCSSValueList* mPosition;
     464                 :     nsCSSValuePairList* mSize;
     465               0 :     BackgroundParseState(
     466                 :         nsCSSValue& aColor, nsCSSValueList* aImage, nsCSSValuePairList* aRepeat,
     467                 :         nsCSSValueList* aAttachment, nsCSSValueList* aClip,
     468                 :         nsCSSValueList* aOrigin, nsCSSValueList* aPosition,
     469                 :         nsCSSValuePairList* aSize) :
     470                 :         mColor(aColor), mImage(aImage), mRepeat(aRepeat),
     471                 :         mAttachment(aAttachment), mClip(aClip), mOrigin(aOrigin),
     472               0 :         mPosition(aPosition), mSize(aSize) {};
     473                 :   };
     474                 : 
     475                 :   bool ParseBackgroundItem(BackgroundParseState& aState);
     476                 : 
     477                 :   bool ParseValueList(nsCSSProperty aPropID); // a single value prop-id
     478                 :   bool ParseBackgroundRepeat();
     479                 :   bool ParseBackgroundRepeatValues(nsCSSValuePair& aValue);
     480                 :   bool ParseBackgroundPosition();
     481                 : 
     482                 :   // ParseBoxPositionValues parses the CSS 2.1 background-position syntax,
     483                 :   // which is still used by some properties. See ParseBackgroundPositionValues
     484                 :   // for the css3-background syntax.
     485                 :   bool ParseBoxPositionValues(nsCSSValuePair& aOut, bool aAcceptsInherit,
     486                 :                               bool aAllowExplicitCenter = true); // deprecated
     487                 :   bool ParseBackgroundPositionValues(nsCSSValue& aOut, bool aAcceptsInherit);
     488                 : 
     489                 :   bool ParseBackgroundSize();
     490                 :   bool ParseBackgroundSizeValues(nsCSSValuePair& aOut);
     491                 :   bool ParseBorderColor();
     492                 :   bool ParseBorderColors(nsCSSProperty aProperty);
     493                 :   void SetBorderImageInitialValues();
     494                 :   bool ParseBorderImageRepeat(bool aAcceptsInherit);
     495                 :   // If ParseBorderImageSlice returns false, aConsumedTokens indicates
     496                 :   // whether or not any tokens were consumed (in other words, was the property
     497                 :   // in error or just not present).  If ParseBorderImageSlice returns true
     498                 :   // aConsumedTokens is always true.
     499                 :   bool ParseBorderImageSlice(bool aAcceptsInherit, bool* aConsumedTokens);
     500                 :   bool ParseBorderImageWidth(bool aAcceptsInherit);
     501                 :   bool ParseBorderImageOutset(bool aAcceptsInherit);
     502                 :   bool ParseBorderImage();
     503                 :   bool ParseBorderSpacing();
     504                 :   bool ParseBorderSide(const nsCSSProperty aPropIDs[],
     505                 :                          bool aSetAllSides);
     506                 :   bool ParseDirectionalBorderSide(const nsCSSProperty aPropIDs[],
     507                 :                                     PRInt32 aSourceType);
     508                 :   bool ParseBorderStyle();
     509                 :   bool ParseBorderWidth();
     510                 : 
     511                 :   bool ParseCalc(nsCSSValue &aValue, PRInt32 aVariantMask);
     512                 :   bool ParseCalcAdditiveExpression(nsCSSValue& aValue,
     513                 :                                      PRInt32& aVariantMask);
     514                 :   bool ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
     515                 :                                            PRInt32& aVariantMask,
     516                 :                                            bool *aHadFinalWS);
     517                 :   bool ParseCalcTerm(nsCSSValue& aValue, PRInt32& aVariantMask);
     518                 :   bool RequireWhitespace();
     519                 : 
     520                 :   // for 'clip' and '-moz-image-region'
     521                 :   bool ParseRect(nsCSSProperty aPropID);
     522                 :   bool ParseColumns();
     523                 :   bool ParseContent();
     524                 :   bool ParseCounterData(nsCSSProperty aPropID);
     525                 :   bool ParseCursor();
     526                 :   bool ParseFont();
     527                 :   bool ParseFontWeight(nsCSSValue& aValue);
     528                 :   bool ParseOneFamily(nsAString& aValue);
     529                 :   bool ParseFamily(nsCSSValue& aValue);
     530                 :   bool ParseFontSrc(nsCSSValue& aValue);
     531                 :   bool ParseFontSrcFormat(InfallibleTArray<nsCSSValue>& values);
     532                 :   bool ParseFontRanges(nsCSSValue& aValue);
     533                 :   bool ParseListStyle();
     534                 :   bool ParseMargin();
     535                 :   bool ParseMarks(nsCSSValue& aValue);
     536                 :   bool ParseMozTransform();
     537                 :   bool ParseOutline();
     538                 :   bool ParseOverflow();
     539                 :   bool ParsePadding();
     540                 :   bool ParseQuotes();
     541                 :   bool ParseSize();
     542                 :   bool ParseTextDecoration();
     543                 :   bool ParseTextDecorationLine(nsCSSValue& aValue);
     544                 :   bool ParseTextOverflow(nsCSSValue& aValue);
     545                 :   bool ParseUnicodeBidi(nsCSSValue& aValue);
     546                 : 
     547                 :   bool ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow);
     548                 :   bool ParseShadowList(nsCSSProperty aProperty);
     549                 :   bool ParseTransitionProperty();
     550                 :   bool ParseTransitionTimingFunctionValues(nsCSSValue& aValue);
     551                 :   bool ParseTransitionTimingFunctionValueComponent(float& aComponent,
     552                 :                                                      char aStop,
     553                 :                                                      bool aCheckRange);
     554                 :   bool ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue);
     555                 :   enum ParseAnimationOrTransitionShorthandResult {
     556                 :     eParseAnimationOrTransitionShorthand_Values,
     557                 :     eParseAnimationOrTransitionShorthand_Inherit,
     558                 :     eParseAnimationOrTransitionShorthand_Error
     559                 :   };
     560                 :   ParseAnimationOrTransitionShorthandResult
     561                 :     ParseAnimationOrTransitionShorthand(const nsCSSProperty* aProperties,
     562                 :                                         const nsCSSValue* aInitialValues,
     563                 :                                         nsCSSValue* aValues,
     564                 :                                         size_t aNumProperties);
     565                 :   bool ParseTransition();
     566                 :   bool ParseAnimation();
     567                 : 
     568                 :   bool ParsePaint(nsCSSProperty aPropID);
     569                 :   bool ParseDasharray();
     570                 :   bool ParseMarker();
     571                 : 
     572                 :   // Reused utility parsing routines
     573                 :   void AppendValue(nsCSSProperty aPropID, const nsCSSValue& aValue);
     574                 :   bool ParseBoxProperties(const nsCSSProperty aPropIDs[]);
     575                 :   bool ParseGroupedBoxProperty(PRInt32 aVariantMask,
     576                 :                                nsCSSValue& aValue);
     577                 :   bool ParseDirectionalBoxProperty(nsCSSProperty aProperty,
     578                 :                                      PRInt32 aSourceType);
     579                 :   bool ParseBoxCornerRadius(const nsCSSProperty aPropID);
     580                 :   bool ParseBoxCornerRadii(const nsCSSProperty aPropIDs[]);
     581                 :   PRInt32 ParseChoice(nsCSSValue aValues[],
     582                 :                       const nsCSSProperty aPropIDs[], PRInt32 aNumIDs);
     583                 :   bool ParseColor(nsCSSValue& aValue);
     584                 :   bool ParseColorComponent(PRUint8& aComponent,
     585                 :                              PRInt32& aType, char aStop);
     586                 :   // ParseHSLColor parses everything starting with the opening '('
     587                 :   // up through and including the aStop char.
     588                 :   bool ParseHSLColor(nscolor& aColor, char aStop);
     589                 :   // ParseColorOpacity will enforce that the color ends with a ')'
     590                 :   // after the opacity
     591                 :   bool ParseColorOpacity(PRUint8& aOpacity);
     592                 :   bool ParseEnum(nsCSSValue& aValue, const PRInt32 aKeywordTable[]);
     593                 :   bool ParseVariant(nsCSSValue& aValue,
     594                 :                       PRInt32 aVariantMask,
     595                 :                       const PRInt32 aKeywordTable[]);
     596                 :   bool ParseNonNegativeVariant(nsCSSValue& aValue,
     597                 :                                  PRInt32 aVariantMask,
     598                 :                                  const PRInt32 aKeywordTable[]);
     599                 :   bool ParseOneOrLargerVariant(nsCSSValue& aValue,
     600                 :                                  PRInt32 aVariantMask,
     601                 :                                  const PRInt32 aKeywordTable[]);
     602                 :   bool ParseCounter(nsCSSValue& aValue);
     603                 :   bool ParseAttr(nsCSSValue& aValue);
     604                 :   bool SetValueToURL(nsCSSValue& aValue, const nsString& aURL);
     605                 :   bool TranslateDimension(nsCSSValue& aValue, PRInt32 aVariantMask,
     606                 :                             float aNumber, const nsString& aUnit);
     607                 :   bool ParseImageRect(nsCSSValue& aImage);
     608                 :   bool ParseElement(nsCSSValue& aValue);
     609                 :   bool ParseColorStop(nsCSSValueGradient* aGradient);
     610                 :   bool ParseGradient(nsCSSValue& aValue, bool aIsRadial,
     611                 :                        bool aIsRepeating);
     612                 : 
     613               0 :   void SetParsingCompoundProperty(bool aBool) {
     614               0 :     mParsingCompoundProperty = aBool;
     615               0 :   }
     616               0 :   bool IsParsingCompoundProperty(void) const {
     617               0 :     return mParsingCompoundProperty;
     618                 :   }
     619                 : 
     620                 :   /* Functions for -moz-transform Parsing */
     621                 :   bool ParseSingleTransform(nsCSSValue& aValue, bool& aIs3D);
     622                 :   bool ParseFunction(const nsString &aFunction, const PRInt32 aAllowedTypes[],
     623                 :                        PRUint16 aMinElems, PRUint16 aMaxElems,
     624                 :                        nsCSSValue &aValue);
     625                 :   bool ParseFunctionInternals(const PRInt32 aVariantMask[],
     626                 :                                 PRUint16 aMinElems,
     627                 :                                 PRUint16 aMaxElems,
     628                 :                                 InfallibleTArray<nsCSSValue>& aOutput);
     629                 : 
     630                 :   /* Functions for -moz-transform-origin/-moz-perspective-origin Parsing */
     631                 :   bool ParseMozTransformOrigin(bool aPerspective);
     632                 : 
     633                 :   /* Find and return the namespace ID associated with aPrefix.
     634                 :      If aPrefix has not been declared in an @namespace rule, returns
     635                 :      kNameSpaceID_Unknown and sets mFoundUnresolvablePrefix to true. */
     636                 :   PRInt32 GetNamespaceIdForPrefix(const nsString& aPrefix);
     637                 : 
     638                 :   /* Find the correct default namespace, and set it on aSelector. */
     639                 :   void SetDefaultNamespaceOnSelector(nsCSSSelector& aSelector);
     640                 : 
     641                 :   // Current token. The value is valid after calling GetToken and invalidated
     642                 :   // by UngetToken.
     643                 :   nsCSSToken mToken;
     644                 : 
     645                 :   // Our scanner.
     646                 :   nsCSSScanner mScanner;
     647                 : 
     648                 :   // The URI to be used as a base for relative URIs.
     649                 :   nsCOMPtr<nsIURI> mBaseURI;
     650                 : 
     651                 :   // The URI to be used as an HTTP "Referer" and for error reporting.
     652                 :   nsCOMPtr<nsIURI> mSheetURI;
     653                 : 
     654                 :   // The principal of the sheet involved
     655                 :   nsCOMPtr<nsIPrincipal> mSheetPrincipal;
     656                 : 
     657                 :   // The sheet we're parsing into
     658                 :   nsRefPtr<nsCSSStyleSheet> mSheet;
     659                 : 
     660                 :   // Used for @import rules
     661                 :   mozilla::css::Loader* mChildLoader; // not ref counted, it owns us
     662                 : 
     663                 :   // Sheet section we're in.  This is used to enforce correct ordering of the
     664                 :   // various rule types (eg the fact that a @charset rule must come before
     665                 :   // anything else).  Note that there are checks of similar things in various
     666                 :   // places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
     667                 :   enum nsCSSSection {
     668                 :     eCSSSection_Charset,
     669                 :     eCSSSection_Import,
     670                 :     eCSSSection_NameSpace,
     671                 :     eCSSSection_General
     672                 :   };
     673                 :   nsCSSSection  mSection;
     674                 : 
     675                 :   nsXMLNameSpaceMap *mNameSpaceMap;  // weak, mSheet owns it
     676                 : 
     677                 :   // After an UngetToken is done this flag is true. The next call to
     678                 :   // GetToken clears the flag.
     679                 :   bool mHavePushBack : 1;
     680                 : 
     681                 :   // True if we are in quirks mode; false in standards or almost standards mode
     682                 :   bool          mNavQuirkMode : 1;
     683                 : 
     684                 :   // True if unsafe rules should be allowed
     685                 :   bool mUnsafeRulesEnabled : 1;
     686                 : 
     687                 :   // True for parsing media lists for HTML attributes, where we have to
     688                 :   // ignore CSS comments.
     689                 :   bool mHTMLMediaMode : 1;
     690                 : 
     691                 :   // This flag is set when parsing a non-box shorthand; it's used to not apply
     692                 :   // some quirks during shorthand parsing
     693                 :   bool          mParsingCompoundProperty : 1;
     694                 : 
     695                 :   // GetNamespaceIdForPrefix will set mFoundUnresolvablePrefix to true
     696                 :   // when it encounters a prefix that is not mapped to a namespace.
     697                 :   bool          mFoundUnresolvablePrefix : 1;
     698                 : 
     699                 : #ifdef DEBUG
     700                 :   bool mScannerInited : 1;
     701                 : #endif
     702                 : 
     703                 :   // Stack of rule groups; used for @media and such.
     704                 :   InfallibleTArray<nsRefPtr<css::GroupRule> > mGroupStack;
     705                 : 
     706                 :   // During the parsing of a property (which may be a shorthand), the data
     707                 :   // are stored in |mTempData|.  (It is needed to ensure that parser
     708                 :   // errors cause the data to be ignored, and to ensure that a
     709                 :   // non-'!important' declaration does not override an '!important'
     710                 :   // one.)
     711                 :   nsCSSExpandedDataBlock mTempData;
     712                 : 
     713                 :   // All data from successfully parsed properties are placed into |mData|.
     714                 :   nsCSSExpandedDataBlock mData;
     715                 : 
     716                 : public:
     717                 :   // Used from nsCSSParser constructors and destructors
     718                 :   CSSParserImpl* mNextFree;
     719                 : };
     720                 : 
     721               0 : static void AppendRuleToArray(css::Rule* aRule, void* aArray)
     722                 : {
     723               0 :   static_cast<nsCOMArray<css::Rule>*>(aArray)->AppendObject(aRule);
     724               0 : }
     725                 : 
     726               0 : static void AppendRuleToSheet(css::Rule* aRule, void* aParser)
     727                 : {
     728               0 :   CSSParserImpl* parser = (CSSParserImpl*) aParser;
     729               0 :   parser->AppendRule(aRule);
     730               0 : }
     731                 : 
     732                 : #ifdef CSS_REPORT_PARSE_ERRORS
     733                 : 
     734                 : #define REPORT_UNEXPECTED(msg_) \
     735                 :   mScanner.ReportUnexpected(#msg_)
     736                 : 
     737                 : #define REPORT_UNEXPECTED_P(msg_, params_) \
     738                 :   mScanner.ReportUnexpectedParams(#msg_, params_)
     739                 : 
     740                 : #define REPORT_UNEXPECTED_EOF(lf_) \
     741                 :   mScanner.ReportUnexpectedEOF(#lf_)
     742                 : 
     743                 : #define REPORT_UNEXPECTED_EOF_CHAR(ch_) \
     744                 :   mScanner.ReportUnexpectedEOF(ch_)
     745                 : 
     746                 : #define REPORT_UNEXPECTED_TOKEN(msg_) \
     747                 :   mScanner.ReportUnexpectedToken(mToken, #msg_)
     748                 : 
     749                 : #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_) \
     750                 :   mScanner.ReportUnexpectedTokenParams(mToken, #msg_, \
     751                 :                                        params_, ArrayLength(params_))
     752                 : 
     753                 : 
     754                 : #define OUTPUT_ERROR() \
     755                 :   mScanner.OutputError()
     756                 : 
     757                 : #define CLEAR_ERROR() \
     758                 :   mScanner.ClearError()
     759                 : 
     760                 : #else
     761                 : 
     762                 : #define REPORT_UNEXPECTED(msg_)
     763                 : #define REPORT_UNEXPECTED_P(msg_, params_)
     764                 : #define REPORT_UNEXPECTED_EOF(lf_)
     765                 : #define REPORT_UNEXPECTED_EOF_CHAR(ch_)
     766                 : #define REPORT_UNEXPECTED_TOKEN(msg_)
     767                 : #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_)
     768                 : #define OUTPUT_ERROR()
     769                 : #define CLEAR_ERROR()
     770                 : 
     771                 : #endif
     772                 : 
     773              12 : CSSParserImpl::CSSParserImpl()
     774                 :   : mToken(),
     775                 :     mScanner(),
     776                 :     mChildLoader(nsnull),
     777                 :     mSection(eCSSSection_Charset),
     778                 :     mNameSpaceMap(nsnull),
     779                 :     mHavePushBack(false),
     780                 :     mNavQuirkMode(false),
     781                 :     mUnsafeRulesEnabled(false),
     782                 :     mHTMLMediaMode(false),
     783                 :     mParsingCompoundProperty(false),
     784                 :     mFoundUnresolvablePrefix(false)
     785                 : #ifdef DEBUG
     786                 :     , mScannerInited(false)
     787                 : #endif
     788              12 :     , mNextFree(nsnull)
     789                 : {
     790              12 : }
     791                 : 
     792              24 : CSSParserImpl::~CSSParserImpl()
     793                 : {
     794              12 :   mData.AssertInitialState();
     795              12 :   mTempData.AssertInitialState();
     796              12 : }
     797                 : 
     798                 : nsresult
     799             110 : CSSParserImpl::SetStyleSheet(nsCSSStyleSheet* aSheet)
     800                 : {
     801             110 :   if (aSheet != mSheet) {
     802                 :     // Switch to using the new sheet, if any
     803               0 :     mGroupStack.Clear();
     804               0 :     mSheet = aSheet;
     805               0 :     if (mSheet) {
     806               0 :       mNameSpaceMap = mSheet->GetNameSpaceMap();
     807                 :     } else {
     808               0 :       mNameSpaceMap = nsnull;
     809                 :     }
     810                 :   }
     811                 : 
     812             110 :   return NS_OK;
     813                 : }
     814                 : 
     815                 : nsresult
     816             220 : CSSParserImpl::SetQuirkMode(bool aQuirkMode)
     817                 : {
     818             220 :   mNavQuirkMode = aQuirkMode;
     819             220 :   return NS_OK;
     820                 : }
     821                 : 
     822                 : nsresult
     823             110 : CSSParserImpl::SetSVGMode(bool aSVGMode)
     824                 : {
     825             110 :   mScanner.SetSVGMode(aSVGMode);
     826             110 :   return NS_OK;
     827                 : }
     828                 : 
     829                 : nsresult
     830             220 : CSSParserImpl::SetChildLoader(mozilla::css::Loader* aChildLoader)
     831                 : {
     832             220 :   mChildLoader = aChildLoader;  // not ref counted, it owns us
     833             220 :   return NS_OK;
     834                 : }
     835                 : 
     836                 : void
     837             110 : CSSParserImpl::Reset()
     838                 : {
     839             110 :   NS_ASSERTION(! mScannerInited, "resetting with scanner active");
     840             110 :   SetStyleSheet(nsnull);
     841             110 :   SetQuirkMode(false);
     842             110 :   SetSVGMode(false);
     843             110 :   SetChildLoader(nsnull);
     844             110 : }
     845                 : 
     846                 : void
     847             110 : CSSParserImpl::InitScanner(const nsSubstring& aString, nsIURI* aSheetURI,
     848                 :                            PRUint32 aLineNumber, nsIURI* aBaseURI,
     849                 :                            nsIPrincipal* aSheetPrincipal)
     850                 : {
     851                 :   // Having it not own the string is OK since the caller will hold on to
     852                 :   // the stream until we're done parsing.
     853             110 :   NS_ASSERTION(! mScannerInited, "already have scanner");
     854                 : 
     855             110 :   mScanner.Init(aString, aSheetURI, aLineNumber, mSheet, mChildLoader);
     856                 : 
     857                 : #ifdef DEBUG
     858             110 :   mScannerInited = true;
     859                 : #endif
     860             110 :   mBaseURI = aBaseURI;
     861             110 :   mSheetURI = aSheetURI;
     862             110 :   mSheetPrincipal = aSheetPrincipal;
     863                 : 
     864             110 :   mHavePushBack = false;
     865             110 : }
     866                 : 
     867                 : void
     868             110 : CSSParserImpl::ReleaseScanner(void)
     869                 : {
     870             110 :   mScanner.Close();
     871                 : #ifdef DEBUG
     872             110 :   mScannerInited = false;
     873                 : #endif
     874             110 :   mBaseURI = nsnull;
     875             110 :   mSheetURI = nsnull;
     876             110 :   mSheetPrincipal = nsnull;
     877             110 : }
     878                 : 
     879                 : nsresult
     880               0 : CSSParserImpl::ParseSheet(const nsAString& aInput,
     881                 :                           nsIURI*          aSheetURI,
     882                 :                           nsIURI*          aBaseURI,
     883                 :                           nsIPrincipal*    aSheetPrincipal,
     884                 :                           PRUint32         aLineNumber,
     885                 :                           bool             aAllowUnsafeRules)
     886                 : {
     887               0 :   NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
     888                 : 
     889               0 :   NS_ASSERTION(nsnull != aBaseURI, "need base URI");
     890               0 :   NS_ASSERTION(nsnull != aSheetURI, "need sheet URI");
     891               0 :   AssertInitialState();
     892                 : 
     893               0 :   NS_PRECONDITION(mSheet, "Must have sheet to parse into");
     894               0 :   NS_ENSURE_STATE(mSheet);
     895                 : 
     896                 : #ifdef DEBUG
     897               0 :   nsIURI* uri = mSheet->GetSheetURI();
     898                 :   bool equal;
     899               0 :   NS_ASSERTION(NS_SUCCEEDED(aSheetURI->Equals(uri, &equal)) && equal,
     900                 :                "Sheet URI does not match passed URI");
     901               0 :   NS_ASSERTION(NS_SUCCEEDED(mSheet->Principal()->Equals(aSheetPrincipal,
     902                 :                                                         &equal)) &&
     903                 :                equal,
     904                 :                "Sheet principal does not match passed principal");
     905                 : #endif
     906                 : 
     907               0 :   InitScanner(aInput, aSheetURI, aLineNumber, aBaseURI, aSheetPrincipal);
     908                 : 
     909               0 :   PRInt32 ruleCount = mSheet->StyleRuleCount();
     910               0 :   if (0 < ruleCount) {
     911               0 :     css::Rule* lastRule = nsnull;
     912               0 :     mSheet->GetStyleRuleAt(ruleCount - 1, lastRule);
     913               0 :     if (lastRule) {
     914               0 :       switch (lastRule->GetType()) {
     915                 :         case css::Rule::CHARSET_RULE:
     916                 :         case css::Rule::IMPORT_RULE:
     917               0 :           mSection = eCSSSection_Import;
     918               0 :           break;
     919                 :         case css::Rule::NAMESPACE_RULE:
     920               0 :           mSection = eCSSSection_NameSpace;
     921               0 :           break;
     922                 :         default:
     923               0 :           mSection = eCSSSection_General;
     924               0 :           break;
     925                 :       }
     926               0 :       NS_RELEASE(lastRule);
     927                 :     }
     928                 :   }
     929                 :   else {
     930               0 :     mSection = eCSSSection_Charset; // sheet is empty, any rules are fair
     931                 :   }
     932                 : 
     933               0 :   mUnsafeRulesEnabled = aAllowUnsafeRules;
     934                 : 
     935               0 :   nsCSSToken* tk = &mToken;
     936               0 :   for (;;) {
     937                 :     // Get next non-whitespace token
     938               0 :     if (!GetToken(true)) {
     939               0 :       OUTPUT_ERROR();
     940                 :       break;
     941                 :     }
     942               0 :     if (eCSSToken_HTMLComment == tk->mType) {
     943               0 :       continue; // legal here only
     944                 :     }
     945               0 :     if (eCSSToken_AtKeyword == tk->mType) {
     946               0 :       ParseAtRule(AppendRuleToSheet, this, false);
     947               0 :       continue;
     948                 :     }
     949               0 :     UngetToken();
     950               0 :     if (ParseRuleSet(AppendRuleToSheet, this)) {
     951               0 :       mSection = eCSSSection_General;
     952                 :     }
     953                 :   }
     954               0 :   ReleaseScanner();
     955                 : 
     956               0 :   mUnsafeRulesEnabled = false;
     957                 : 
     958                 :   // XXX check for low level errors
     959               0 :   return NS_OK;
     960                 : }
     961                 : 
     962                 : /**
     963                 :  * Determines whether the identifier contained in the given string is a
     964                 :  * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1.
     965                 :  */
     966                 : static bool
     967               0 : NonMozillaVendorIdentifier(const nsAString& ident)
     968                 : {
     969               0 :   return (ident.First() == PRUnichar('-') &&
     970               0 :           !StringBeginsWith(ident, NS_LITERAL_STRING("-moz-"))) ||
     971               0 :          ident.First() == PRUnichar('_');
     972                 : 
     973                 : }
     974                 : 
     975                 : nsresult
     976               0 : CSSParserImpl::ParseStyleAttribute(const nsAString& aAttributeValue,
     977                 :                                    nsIURI*          aDocURI,
     978                 :                                    nsIURI*          aBaseURI,
     979                 :                                    nsIPrincipal*    aNodePrincipal,
     980                 :                                    css::StyleRule** aResult)
     981                 : {
     982               0 :   NS_PRECONDITION(aNodePrincipal, "Must have principal here!");
     983               0 :   AssertInitialState();
     984                 : 
     985               0 :   NS_ASSERTION(nsnull != aBaseURI, "need base URI");
     986                 : 
     987                 :   // XXX line number?
     988               0 :   InitScanner(aAttributeValue, aDocURI, 0, aBaseURI, aNodePrincipal);
     989                 : 
     990               0 :   mSection = eCSSSection_General;
     991                 : 
     992                 :   // In quirks mode, allow style declarations to have braces or not
     993                 :   // (bug 99554).
     994                 :   bool haveBraces;
     995               0 :   if (mNavQuirkMode && GetToken(true)) {
     996                 :     haveBraces = eCSSToken_Symbol == mToken.mType &&
     997               0 :                  '{' == mToken.mSymbol;
     998               0 :     UngetToken();
     999                 :   }
    1000                 :   else {
    1001               0 :     haveBraces = false;
    1002                 :   }
    1003                 : 
    1004               0 :   css::Declaration* declaration = ParseDeclarationBlock(haveBraces);
    1005               0 :   if (declaration) {
    1006                 :     // Create a style rule for the declaration
    1007               0 :     NS_ADDREF(*aResult = new css::StyleRule(nsnull, declaration));
    1008                 :   } else {
    1009               0 :     *aResult = nsnull;
    1010                 :   }
    1011                 : 
    1012               0 :   ReleaseScanner();
    1013                 : 
    1014                 :   // XXX check for low level errors
    1015               0 :   return NS_OK;
    1016                 : }
    1017                 : 
    1018                 : nsresult
    1019               0 : CSSParserImpl::ParseDeclarations(const nsAString&  aBuffer,
    1020                 :                                  nsIURI*           aSheetURI,
    1021                 :                                  nsIURI*           aBaseURI,
    1022                 :                                  nsIPrincipal*     aSheetPrincipal,
    1023                 :                                  css::Declaration* aDeclaration,
    1024                 :                                  bool*           aChanged)
    1025                 : {
    1026               0 :   NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
    1027               0 :   AssertInitialState();
    1028                 : 
    1029               0 :   *aChanged = false;
    1030                 : 
    1031               0 :   InitScanner(aBuffer, aSheetURI, 0, aBaseURI, aSheetPrincipal);
    1032                 : 
    1033               0 :   mSection = eCSSSection_General;
    1034                 : 
    1035               0 :   mData.AssertInitialState();
    1036               0 :   aDeclaration->ClearData();
    1037                 :   // We could check if it was already empty, but...
    1038               0 :   *aChanged = true;
    1039                 : 
    1040               0 :   for (;;) {
    1041                 :     // If we cleared the old decl, then we want to be calling
    1042                 :     // ValueAppended as we parse.
    1043               0 :     if (!ParseDeclaration(aDeclaration, false, true, aChanged)) {
    1044               0 :       if (!SkipDeclaration(false)) {
    1045                 :         break;
    1046                 :       }
    1047                 :     }
    1048                 :   }
    1049                 : 
    1050               0 :   aDeclaration->CompressFrom(&mData);
    1051               0 :   ReleaseScanner();
    1052               0 :   return NS_OK;
    1053                 : }
    1054                 : 
    1055                 : nsresult
    1056               0 : CSSParserImpl::ParseRule(const nsAString&        aRule,
    1057                 :                          nsIURI*                 aSheetURI,
    1058                 :                          nsIURI*                 aBaseURI,
    1059                 :                          nsIPrincipal*           aSheetPrincipal,
    1060                 :                          nsCOMArray<css::Rule>&  aResult)
    1061                 : {
    1062               0 :   NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
    1063               0 :   AssertInitialState();
    1064                 : 
    1065               0 :   NS_ASSERTION(nsnull != aBaseURI, "need base URI");
    1066                 : 
    1067               0 :   InitScanner(aRule, aSheetURI, 0, aBaseURI, aSheetPrincipal);
    1068                 : 
    1069               0 :   mSection = eCSSSection_Charset; // callers are responsible for rejecting invalid rules.
    1070                 : 
    1071               0 :   nsCSSToken* tk = &mToken;
    1072                 :   // Get first non-whitespace token
    1073               0 :   if (!GetToken(true)) {
    1074               0 :     REPORT_UNEXPECTED(PEParseRuleWSOnly);
    1075               0 :     OUTPUT_ERROR();
    1076               0 :   } else if (eCSSToken_AtKeyword == tk->mType) {
    1077               0 :     ParseAtRule(AppendRuleToArray, &aResult, false);
    1078                 :   }
    1079                 :   else {
    1080               0 :     UngetToken();
    1081               0 :     ParseRuleSet(AppendRuleToArray, &aResult);
    1082                 :   }
    1083               0 :   OUTPUT_ERROR();
    1084               0 :   ReleaseScanner();
    1085                 :   // XXX check for low-level errors
    1086               0 :   return NS_OK;
    1087                 : }
    1088                 : 
    1089                 : // See Bug 723197
    1090                 : #ifdef _MSC_VER
    1091                 : #pragma optimize( "", off )
    1092                 : #endif
    1093                 : nsresult
    1094               0 : CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
    1095                 :                              const nsAString& aPropValue,
    1096                 :                              nsIURI* aSheetURI,
    1097                 :                              nsIURI* aBaseURI,
    1098                 :                              nsIPrincipal* aSheetPrincipal,
    1099                 :                              css::Declaration* aDeclaration,
    1100                 :                              bool* aChanged,
    1101                 :                              bool aIsImportant)
    1102                 : {
    1103               0 :   NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
    1104               0 :   NS_PRECONDITION(aBaseURI, "need base URI");
    1105               0 :   NS_PRECONDITION(aDeclaration, "Need declaration to parse into!");
    1106               0 :   AssertInitialState();
    1107               0 :   mData.AssertInitialState();
    1108               0 :   mTempData.AssertInitialState();
    1109               0 :   aDeclaration->AssertMutable();
    1110                 : 
    1111               0 :   InitScanner(aPropValue, aSheetURI, 0, aBaseURI, aSheetPrincipal);
    1112               0 :   mSection = eCSSSection_General;
    1113                 : 
    1114               0 :   *aChanged = false;
    1115                 : 
    1116               0 :   if (eCSSProperty_UNKNOWN == aPropID) { // unknown property
    1117               0 :     NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID));
    1118                 :     const PRUnichar *params[] = {
    1119               0 :       propName.get()
    1120               0 :     };
    1121               0 :     REPORT_UNEXPECTED_P(PEUnknownProperty, params);
    1122               0 :     REPORT_UNEXPECTED(PEDeclDropped);
    1123               0 :     OUTPUT_ERROR();
    1124               0 :     ReleaseScanner();
    1125               0 :     return NS_OK;
    1126                 :   }
    1127                 : 
    1128               0 :   bool parsedOK = ParseProperty(aPropID);
    1129                 :   // We should now be at EOF
    1130               0 :   if (parsedOK && GetToken(true)) {
    1131               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);
    1132               0 :     parsedOK = false;
    1133                 :   }
    1134                 : 
    1135               0 :   if (!parsedOK) {
    1136               0 :     NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID));
    1137                 :     const PRUnichar *params[] = {
    1138               0 :       propName.get()
    1139               0 :     };
    1140               0 :     REPORT_UNEXPECTED_P(PEValueParsingError, params);
    1141               0 :     REPORT_UNEXPECTED(PEDeclDropped);
    1142               0 :     OUTPUT_ERROR();
    1143               0 :     mTempData.ClearProperty(aPropID);
    1144                 :   } else {
    1145                 : 
    1146                 :     // We know we don't need to force a ValueAppended call for the new
    1147                 :     // value.  So if we are not processing a shorthand, and there's
    1148                 :     // already a value for this property in the declaration at the
    1149                 :     // same importance level, then we can just copy our parsed value
    1150                 :     // directly into the declaration without going through the whole
    1151                 :     // expand/compress thing.
    1152               0 :     if (!aDeclaration->TryReplaceValue(aPropID, aIsImportant, mTempData,
    1153               0 :                                        aChanged)) {
    1154                 :       // Do it the slow way
    1155               0 :       aDeclaration->ExpandTo(&mData);
    1156                 :       *aChanged = mData.TransferFromBlock(mTempData, aPropID, aIsImportant,
    1157               0 :                                           true, false, aDeclaration);
    1158               0 :       aDeclaration->CompressFrom(&mData);
    1159                 :     }
    1160               0 :     CLEAR_ERROR();
    1161                 :   }
    1162                 : 
    1163               0 :   mTempData.AssertInitialState();
    1164                 : 
    1165               0 :   ReleaseScanner();
    1166               0 :   return NS_OK;
    1167                 : }
    1168                 : #ifdef _MSC_VER
    1169                 : #pragma optimize( "", on )
    1170                 : #endif
    1171                 : 
    1172                 : nsresult
    1173               0 : CSSParserImpl::ParseMediaList(const nsSubstring& aBuffer,
    1174                 :                               nsIURI* aURI, // for error reporting
    1175                 :                               PRUint32 aLineNumber, // for error reporting
    1176                 :                               nsMediaList* aMediaList,
    1177                 :                               bool aHTMLMode)
    1178                 : {
    1179                 :   // XXX Are there cases where the caller wants to keep what it already
    1180                 :   // has in case of parser error?
    1181               0 :   aMediaList->Clear();
    1182                 : 
    1183                 :   // fake base URI since media lists don't have URIs in them
    1184               0 :   InitScanner(aBuffer, aURI, aLineNumber, aURI, nsnull);
    1185                 : 
    1186               0 :   AssertInitialState();
    1187               0 :   mHTMLMediaMode = aHTMLMode;
    1188                 : 
    1189                 :     // XXXldb We need to make the scanner not skip CSS comments!  (Or
    1190                 :     // should we?)
    1191                 : 
    1192                 :   // For aHTMLMode, we used to follow the parsing rules in
    1193                 :   // http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors
    1194                 :   // which wouldn't work for media queries since they remove all but the
    1195                 :   // first word.  However, they're changed in
    1196                 :   // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2
    1197                 :   // (as of 2008-05-29) which says that the media attribute just points
    1198                 :   // to a media query.  (The main substative difference is the relative
    1199                 :   // precedence of commas and paretheses.)
    1200                 : 
    1201               0 :   GatherMedia(aMediaList, false);
    1202                 : 
    1203               0 :   CLEAR_ERROR();
    1204               0 :   ReleaseScanner();
    1205               0 :   mHTMLMediaMode = false;
    1206                 : 
    1207               0 :   return NS_OK;
    1208                 : }
    1209                 : 
    1210                 : nsresult
    1211               0 : CSSParserImpl::ParseColorString(const nsSubstring& aBuffer,
    1212                 :                                 nsIURI* aURI, // for error reporting
    1213                 :                                 PRUint32 aLineNumber, // for error reporting
    1214                 :                                 nscolor* aColor)
    1215                 : {
    1216               0 :   AssertInitialState();
    1217               0 :   InitScanner(aBuffer, aURI, aLineNumber, aURI, nsnull);
    1218                 : 
    1219               0 :   nsCSSValue value;
    1220                 :   // Parse a color, and check that there's nothing else after it.
    1221               0 :   bool colorParsed = ParseColor(value) && !GetToken(true);
    1222               0 :   OUTPUT_ERROR();
    1223               0 :   ReleaseScanner();
    1224                 : 
    1225               0 :   if (!colorParsed) {
    1226               0 :     return NS_ERROR_FAILURE;
    1227                 :   }
    1228                 : 
    1229               0 :   switch (value.GetUnit()) {
    1230                 :   case eCSSUnit_Color:
    1231               0 :     *aColor = value.GetColorValue();
    1232               0 :     return NS_OK;
    1233                 : 
    1234                 :   case eCSSUnit_Ident: {
    1235               0 :     nsDependentString id(value.GetStringBufferValue());
    1236               0 :     if (!NS_ColorNameToRGB(id, aColor)) {
    1237               0 :       return NS_ERROR_FAILURE;
    1238                 :     }
    1239               0 :     return NS_OK;
    1240                 :   }
    1241                 : 
    1242                 :   case eCSSUnit_EnumColor: {
    1243               0 :     PRInt32 val = value.GetIntValue();
    1244               0 :     if (val < 0) {
    1245                 :       // XXX - negative numbers are NS_COLOR_CURRENTCOLOR,
    1246                 :       // NS_COLOR_MOZ_HYPERLINKTEXT, etc. which we don't handle.
    1247                 :       // Should remove this limitation at some point.
    1248               0 :       return NS_ERROR_FAILURE;
    1249                 :     }
    1250                 :     nscolor rgba;
    1251               0 :     nsresult rv = LookAndFeel::GetColor(LookAndFeel::ColorID(val), &rgba);
    1252               0 :     if (NS_FAILED(rv)) {
    1253               0 :       return rv;
    1254                 :     }
    1255               0 :     *aColor = rgba;
    1256               0 :     return NS_OK;
    1257                 :   }
    1258                 : 
    1259                 :   default:
    1260               0 :     return NS_ERROR_FAILURE;
    1261                 :   }
    1262                 : }
    1263                 : 
    1264                 : nsresult
    1265             110 : CSSParserImpl::ParseSelectorString(const nsSubstring& aSelectorString,
    1266                 :                                    nsIURI* aURI, // for error reporting
    1267                 :                                    PRUint32 aLineNumber, // for error reporting
    1268                 :                                    nsCSSSelectorList **aSelectorList)
    1269                 : {
    1270             110 :   InitScanner(aSelectorString, aURI, aLineNumber, aURI, nsnull);
    1271                 : 
    1272             110 :   AssertInitialState();
    1273                 : 
    1274                 :   // This is the only place that cares about mFoundUnresolvablePrefix,
    1275                 :   // so this is the only place that bothers clearing it.
    1276             110 :   mFoundUnresolvablePrefix = false;
    1277                 : 
    1278             110 :   bool success = ParseSelectorList(*aSelectorList, PRUnichar(0));
    1279             110 :   bool prefixErr = mFoundUnresolvablePrefix;
    1280                 : 
    1281                 :   // We deliberately do not call OUTPUT_ERROR here, because all our
    1282                 :   // callers map a failure return to a JS exception, and if that JS
    1283                 :   // exception is caught, people don't want to see parser diagnostics;
    1284                 :   // see e.g. http://bugs.jquery.com/ticket/7535
    1285                 :   // It would be nice to be able to save the parser diagnostics into
    1286                 :   // the exception, so that if it _isn't_ caught we can report them
    1287                 :   // along with the usual uncaught-exception message, but we don't
    1288                 :   // have any way to do that at present; see bug 631621.
    1289             110 :   CLEAR_ERROR();
    1290             110 :   ReleaseScanner();
    1291                 : 
    1292             110 :   if (success) {
    1293             110 :     NS_ASSERTION(*aSelectorList, "Should have list!");
    1294             110 :     return NS_OK;
    1295                 :   }
    1296                 : 
    1297               0 :   NS_ASSERTION(!*aSelectorList, "Shouldn't have list!");
    1298               0 :   if (prefixErr)
    1299               0 :     return NS_ERROR_DOM_NAMESPACE_ERR;
    1300                 : 
    1301               0 :   return NS_ERROR_DOM_SYNTAX_ERR;
    1302                 : }
    1303                 : 
    1304                 : 
    1305                 : already_AddRefed<nsCSSKeyframeRule>
    1306               0 : CSSParserImpl::ParseKeyframeRule(const nsSubstring&  aBuffer,
    1307                 :                                  nsIURI*             aURI,
    1308                 :                                  PRUint32            aLineNumber)
    1309                 : {
    1310               0 :   InitScanner(aBuffer, aURI, aLineNumber, aURI, nsnull);
    1311                 : 
    1312               0 :   AssertInitialState();
    1313                 : 
    1314               0 :   nsRefPtr<nsCSSKeyframeRule> result = ParseKeyframeRule();
    1315               0 :   if (GetToken(true)) {
    1316                 :     // extra garbage at the end
    1317               0 :     result = nsnull;
    1318                 :   }
    1319                 : 
    1320               0 :   OUTPUT_ERROR();
    1321               0 :   ReleaseScanner();
    1322                 : 
    1323               0 :   return result.forget();
    1324                 : }
    1325                 : 
    1326                 : bool
    1327               0 : CSSParserImpl::ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
    1328                 :                                            nsIURI* aURI, // for error reporting
    1329                 :                                            PRUint32 aLineNumber, // for error reporting
    1330                 :                                            InfallibleTArray<float>& aSelectorList)
    1331                 : {
    1332               0 :   NS_ABORT_IF_FALSE(aSelectorList.IsEmpty(), "given list should start empty");
    1333                 : 
    1334               0 :   InitScanner(aSelectorString, aURI, aLineNumber, aURI, nsnull);
    1335                 : 
    1336               0 :   AssertInitialState();
    1337                 : 
    1338               0 :   bool success = ParseKeyframeSelectorList(aSelectorList) &&
    1339                 :                  // must consume entire input string
    1340               0 :                  !GetToken(true);
    1341                 : 
    1342               0 :   OUTPUT_ERROR();
    1343               0 :   ReleaseScanner();
    1344                 : 
    1345               0 :   if (success) {
    1346               0 :     NS_ASSERTION(!aSelectorList.IsEmpty(), "should not be empty");
    1347                 :   } else {
    1348               0 :     aSelectorList.Clear();
    1349                 :   }
    1350                 : 
    1351               0 :   return success;
    1352                 : }
    1353                 : 
    1354                 : //----------------------------------------------------------------------
    1355                 : 
    1356                 : bool
    1357            1210 : CSSParserImpl::GetToken(bool aSkipWS)
    1358                 : {
    1359             110 :   for (;;) {
    1360            1210 :     if (!mHavePushBack) {
    1361             990 :       if (!mScanner.Next(mToken)) {
    1362                 :         break;
    1363                 :       }
    1364                 :     }
    1365             770 :     mHavePushBack = false;
    1366             770 :     if (aSkipWS && (eCSSToken_WhiteSpace == mToken.mType)) {
    1367             110 :       continue;
    1368                 :     }
    1369             660 :     return true;
    1370                 :   }
    1371             440 :   return false;
    1372                 : }
    1373                 : 
    1374                 : bool
    1375               0 : CSSParserImpl::GetURLInParens(nsString& aURL)
    1376                 : {
    1377               0 :   NS_ASSERTION(!mHavePushBack, "mustn't have pushback at this point");
    1378               0 :   if (! mScanner.NextURL(mToken)) {
    1379                 :     // EOF
    1380               0 :     return false;
    1381                 :   }
    1382                 : 
    1383               0 :   aURL = mToken.mIdent;
    1384                 : 
    1385               0 :   if (eCSSToken_URL != mToken.mType) {
    1386                 :     // In the failure case (which gives a token of type
    1387                 :     // eCSSToken_Bad_URL), we do not have to match parentheses *inside*
    1388                 :     // the Bad_URL token, since this is now an invalid URL token.  But
    1389                 :     // we do need to match the closing parenthesis to match the 'url('.
    1390               0 :     NS_ABORT_IF_FALSE(mToken.mType == eCSSToken_Bad_URL,
    1391                 :                       "unexpected token type");
    1392               0 :     SkipUntil(')');
    1393               0 :     return false;
    1394                 :   }
    1395                 : 
    1396               0 :   return true;
    1397                 : }
    1398                 : 
    1399                 : void
    1400             220 : CSSParserImpl::UngetToken()
    1401                 : {
    1402             220 :   NS_PRECONDITION(!mHavePushBack, "double pushback");
    1403             220 :   mHavePushBack = true;
    1404             220 : }
    1405                 : 
    1406                 : bool
    1407             220 : CSSParserImpl::ExpectSymbol(PRUnichar aSymbol,
    1408                 :                             bool aSkipWS)
    1409                 : {
    1410             220 :   if (!GetToken(aSkipWS)) {
    1411                 :     // CSS2.1 specifies that all "open constructs" are to be closed at
    1412                 :     // EOF.  It simplifies higher layers if we claim to have found an
    1413                 :     // ), ], }, or ; if we encounter EOF while looking for one of them.
    1414                 :     // Do still issue a diagnostic, to aid debugging.
    1415             110 :     if (aSymbol == ')' || aSymbol == ']' ||
    1416                 :         aSymbol == '}' || aSymbol == ';') {
    1417               0 :       REPORT_UNEXPECTED_EOF_CHAR(aSymbol);
    1418               0 :       return true;
    1419                 :     }
    1420                 :     else
    1421             110 :       return false;
    1422                 :   }
    1423             110 :   if (mToken.IsSymbol(aSymbol)) {
    1424               0 :     return true;
    1425                 :   }
    1426             110 :   UngetToken();
    1427             110 :   return false;
    1428                 : }
    1429                 : 
    1430                 : // Checks to see if we're at the end of a property.  If an error occurs during
    1431                 : // the check, does not signal a parse error.
    1432                 : bool
    1433               0 : CSSParserImpl::CheckEndProperty()
    1434                 : {
    1435               0 :   if (!GetToken(true)) {
    1436               0 :     return true; // properties may end with eof
    1437                 :   }
    1438               0 :   if ((eCSSToken_Symbol == mToken.mType) &&
    1439                 :       ((';' == mToken.mSymbol) ||
    1440                 :        ('!' == mToken.mSymbol) ||
    1441                 :        ('}' == mToken.mSymbol))) {
    1442                 :     // XXX need to verify that ! is only followed by "important [;|}]
    1443                 :     // XXX this requires a multi-token pushback buffer
    1444               0 :     UngetToken();
    1445               0 :     return true;
    1446                 :   }
    1447               0 :   UngetToken();
    1448               0 :   return false;
    1449                 : }
    1450                 : 
    1451                 : // Checks if we're at the end of a property, raising an error if we're not.
    1452                 : bool
    1453               0 : CSSParserImpl::ExpectEndProperty()
    1454                 : {
    1455               0 :   if (CheckEndProperty())
    1456               0 :     return true;
    1457                 : 
    1458                 :   // If we're here, we read something incorrect, so we should report it.
    1459               0 :   REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);
    1460               0 :   return false;
    1461                 : }
    1462                 : 
    1463                 : // Parses the priority suffix on a property, which at present may be
    1464                 : // either '!important' or nothing.
    1465                 : CSSParserImpl::PriorityParsingStatus
    1466               0 : CSSParserImpl::ParsePriority()
    1467                 : {
    1468               0 :   if (!GetToken(true)) {
    1469               0 :     return ePriority_None; // properties may end with EOF
    1470                 :   }
    1471               0 :   if (!mToken.IsSymbol('!')) {
    1472               0 :     UngetToken();
    1473               0 :     return ePriority_None; // dunno what it is, but it's not a priority
    1474                 :   }
    1475                 : 
    1476               0 :   if (!GetToken(true)) {
    1477                 :     // EOF is not ok after !
    1478               0 :     REPORT_UNEXPECTED_EOF(PEImportantEOF);
    1479               0 :     return ePriority_Error;
    1480                 :   }
    1481                 : 
    1482               0 :   if (mToken.mType != eCSSToken_Ident ||
    1483               0 :       !mToken.mIdent.LowerCaseEqualsLiteral("important")) {
    1484               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedImportant);
    1485               0 :     UngetToken();
    1486               0 :     return ePriority_Error;
    1487                 :   }
    1488                 : 
    1489               0 :   return ePriority_Important;
    1490                 : }
    1491                 : 
    1492                 : nsSubstring*
    1493               0 : CSSParserImpl::NextIdent()
    1494                 : {
    1495                 :   // XXX Error reporting?
    1496               0 :   if (!GetToken(true)) {
    1497               0 :     return nsnull;
    1498                 :   }
    1499               0 :   if (eCSSToken_Ident != mToken.mType) {
    1500               0 :     UngetToken();
    1501               0 :     return nsnull;
    1502                 :   }
    1503               0 :   return &mToken.mIdent;
    1504                 : }
    1505                 : 
    1506                 : bool
    1507               0 : CSSParserImpl::SkipAtRule(bool aInsideBlock)
    1508                 : {
    1509               0 :   for (;;) {
    1510               0 :     if (!GetToken(true)) {
    1511               0 :       REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF);
    1512               0 :       return false;
    1513                 :     }
    1514               0 :     if (eCSSToken_Symbol == mToken.mType) {
    1515               0 :       PRUnichar symbol = mToken.mSymbol;
    1516               0 :       if (symbol == ';') {
    1517               0 :         break;
    1518                 :       }
    1519               0 :       if (aInsideBlock && symbol == '}') {
    1520                 :         // The closing } doesn't belong to us.
    1521               0 :         UngetToken();
    1522               0 :         break;
    1523                 :       }
    1524               0 :       if (symbol == '{') {
    1525               0 :         SkipUntil('}');
    1526               0 :         break;
    1527               0 :       } else if (symbol == '(') {
    1528               0 :         SkipUntil(')');
    1529               0 :       } else if (symbol == '[') {
    1530               0 :         SkipUntil(']');
    1531                 :       }
    1532               0 :     } else if (eCSSToken_Function == mToken.mType ||
    1533                 :                eCSSToken_Bad_URL == mToken.mType) {
    1534               0 :       SkipUntil(')');
    1535                 :     }
    1536                 :   }
    1537               0 :   return true;
    1538                 : }
    1539                 : 
    1540                 : bool
    1541               0 : CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc,
    1542                 :                            void* aData,
    1543                 :                            bool aInAtRule)
    1544                 : {
    1545                 : 
    1546                 :   nsCSSSection newSection;
    1547                 :   bool (CSSParserImpl::*parseFunc)(RuleAppendFunc, void*);
    1548                 : 
    1549               0 :   if ((mSection <= eCSSSection_Charset) &&
    1550               0 :       (mToken.mIdent.LowerCaseEqualsLiteral("charset"))) {
    1551               0 :     parseFunc = &CSSParserImpl::ParseCharsetRule;
    1552               0 :     newSection = eCSSSection_Import;  // only one charset allowed
    1553                 : 
    1554               0 :   } else if ((mSection <= eCSSSection_Import) &&
    1555               0 :              mToken.mIdent.LowerCaseEqualsLiteral("import")) {
    1556               0 :     parseFunc = &CSSParserImpl::ParseImportRule;
    1557               0 :     newSection = eCSSSection_Import;
    1558                 : 
    1559               0 :   } else if ((mSection <= eCSSSection_NameSpace) &&
    1560               0 :              mToken.mIdent.LowerCaseEqualsLiteral("namespace")) {
    1561               0 :     parseFunc = &CSSParserImpl::ParseNameSpaceRule;
    1562               0 :     newSection = eCSSSection_NameSpace;
    1563                 : 
    1564               0 :   } else if (mToken.mIdent.LowerCaseEqualsLiteral("media")) {
    1565               0 :     parseFunc = &CSSParserImpl::ParseMediaRule;
    1566               0 :     newSection = eCSSSection_General;
    1567                 : 
    1568               0 :   } else if (mToken.mIdent.LowerCaseEqualsLiteral("-moz-document")) {
    1569               0 :     parseFunc = &CSSParserImpl::ParseMozDocumentRule;
    1570               0 :     newSection = eCSSSection_General;
    1571                 : 
    1572               0 :   } else if (mToken.mIdent.LowerCaseEqualsLiteral("font-face")) {
    1573               0 :     parseFunc = &CSSParserImpl::ParseFontFaceRule;
    1574               0 :     newSection = eCSSSection_General;
    1575                 : 
    1576               0 :   } else if (mToken.mIdent.LowerCaseEqualsLiteral("page")) {
    1577               0 :     parseFunc = &CSSParserImpl::ParsePageRule;
    1578               0 :     newSection = eCSSSection_General;
    1579                 : 
    1580               0 :   } else if (mToken.mIdent.LowerCaseEqualsLiteral("-moz-keyframes")) {
    1581               0 :     parseFunc = &CSSParserImpl::ParseKeyframesRule;
    1582               0 :     newSection = eCSSSection_General;
    1583                 : 
    1584                 :   } else {
    1585               0 :     if (!NonMozillaVendorIdentifier(mToken.mIdent)) {
    1586               0 :       REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule);
    1587               0 :       OUTPUT_ERROR();
    1588                 :     }
    1589                 :     // Skip over unsupported at rule, don't advance section
    1590               0 :     return SkipAtRule(aInAtRule);
    1591                 :   }
    1592                 : 
    1593                 :   // Inside of @-rules, only the rules that can occur anywhere
    1594                 :   // are allowed.
    1595               0 :   bool unnestable = aInAtRule && newSection != eCSSSection_General;
    1596               0 :   if (unnestable) {
    1597               0 :     REPORT_UNEXPECTED_TOKEN(PEGroupRuleNestedAtRule);
    1598                 :   }
    1599                 :   
    1600               0 :   if (unnestable || !(this->*parseFunc)(aAppendFunc, aData)) {
    1601                 :     // Skip over invalid at rule, don't advance section
    1602               0 :     OUTPUT_ERROR();
    1603               0 :     return SkipAtRule(aInAtRule);
    1604                 :   }
    1605                 : 
    1606                 :   // Nested @-rules don't affect the top-level rule chain requirement
    1607               0 :   if (!aInAtRule) {
    1608               0 :     mSection = newSection;
    1609                 :   }
    1610                 :   
    1611               0 :   return true;
    1612                 : }
    1613                 : 
    1614                 : bool
    1615               0 : CSSParserImpl::ParseCharsetRule(RuleAppendFunc aAppendFunc,
    1616                 :                                 void* aData)
    1617                 : {
    1618               0 :   if (!GetToken(true)) {
    1619               0 :     REPORT_UNEXPECTED_EOF(PECharsetRuleEOF);
    1620               0 :     return false;
    1621                 :   }
    1622                 : 
    1623               0 :   if (eCSSToken_String != mToken.mType) {
    1624               0 :     UngetToken();
    1625               0 :     REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString);
    1626               0 :     return false;
    1627                 :   }
    1628                 : 
    1629               0 :   nsAutoString charset = mToken.mIdent;
    1630                 : 
    1631               0 :   if (!ExpectSymbol(';', true)) {
    1632               0 :     return false;
    1633                 :   }
    1634                 : 
    1635               0 :   nsRefPtr<css::CharsetRule> rule = new css::CharsetRule(charset);
    1636               0 :   (*aAppendFunc)(rule, aData);
    1637                 : 
    1638               0 :   return true;
    1639                 : }
    1640                 : 
    1641                 : bool
    1642               0 : CSSParserImpl::ParseURLOrString(nsString& aURL)
    1643                 : {
    1644               0 :   if (!GetToken(true)) {
    1645               0 :     return false;
    1646                 :   }
    1647               0 :   if (eCSSToken_String == mToken.mType || eCSSToken_URL == mToken.mType) {
    1648               0 :     aURL = mToken.mIdent;
    1649               0 :     return true;
    1650                 :   }
    1651               0 :   UngetToken();
    1652               0 :   return false;
    1653                 : }
    1654                 : 
    1655                 : bool
    1656               0 : CSSParserImpl::ParseMediaQuery(bool aInAtRule,
    1657                 :                                nsMediaQuery **aQuery,
    1658                 :                                bool *aHitStop)
    1659                 : {
    1660               0 :   *aQuery = nsnull;
    1661               0 :   *aHitStop = false;
    1662                 : 
    1663                 :   // "If the comma-separated list is the empty list it is assumed to
    1664                 :   // specify the media query 'all'."  (css3-mediaqueries, section
    1665                 :   // "Media Queries")
    1666               0 :   if (!GetToken(true)) {
    1667               0 :     *aHitStop = true;
    1668                 :     // expected termination by EOF
    1669               0 :     if (!aInAtRule)
    1670               0 :       return true;
    1671                 : 
    1672                 :     // unexpected termination by EOF
    1673               0 :     REPORT_UNEXPECTED_EOF(PEGatherMediaEOF);
    1674               0 :     return true;
    1675                 :   }
    1676                 : 
    1677               0 :   if (eCSSToken_Symbol == mToken.mType && aInAtRule &&
    1678                 :       (mToken.mSymbol == ';' || mToken.mSymbol == '{' || mToken.mSymbol == '}' )) {
    1679               0 :     *aHitStop = true;
    1680               0 :     UngetToken();
    1681               0 :     return true;
    1682                 :   }
    1683               0 :   UngetToken();
    1684                 : 
    1685               0 :   nsMediaQuery* query = new nsMediaQuery;
    1686               0 :   *aQuery = query;
    1687                 : 
    1688               0 :   if (ExpectSymbol('(', true)) {
    1689                 :     // we got an expression without a media type
    1690               0 :     UngetToken(); // so ParseMediaQueryExpression can handle it
    1691               0 :     query->SetType(nsGkAtoms::all);
    1692               0 :     query->SetTypeOmitted();
    1693                 :     // Just parse the first expression here.
    1694               0 :     if (!ParseMediaQueryExpression(query)) {
    1695               0 :       OUTPUT_ERROR();
    1696               0 :       query->SetHadUnknownExpression();
    1697                 :     }
    1698                 :   } else {
    1699               0 :     nsCOMPtr<nsIAtom> mediaType;
    1700               0 :     bool gotNotOrOnly = false;
    1701               0 :     for (;;) {
    1702               0 :       if (!GetToken(true)) {
    1703               0 :         REPORT_UNEXPECTED_EOF(PEGatherMediaEOF);
    1704               0 :         return false;
    1705                 :       }
    1706               0 :       if (eCSSToken_Ident != mToken.mType) {
    1707               0 :         REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent);
    1708               0 :         UngetToken();
    1709               0 :         return false;
    1710                 :       }
    1711                 :       // case insensitive from CSS - must be lower cased
    1712               0 :       nsContentUtils::ASCIIToLower(mToken.mIdent);
    1713               0 :       mediaType = do_GetAtom(mToken.mIdent);
    1714               0 :       if (!mediaType) {
    1715               0 :         NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
    1716                 :       }
    1717               0 :       if (gotNotOrOnly ||
    1718               0 :           (mediaType != nsGkAtoms::_not && mediaType != nsGkAtoms::only))
    1719                 :         break;
    1720               0 :       gotNotOrOnly = true;
    1721               0 :       if (mediaType == nsGkAtoms::_not)
    1722               0 :         query->SetNegated();
    1723                 :       else
    1724               0 :         query->SetHasOnly();
    1725                 :     }
    1726               0 :     query->SetType(mediaType);
    1727                 :   }
    1728                 : 
    1729               0 :   for (;;) {
    1730               0 :     if (!GetToken(true)) {
    1731               0 :       *aHitStop = true;
    1732                 :       // expected termination by EOF
    1733               0 :       if (!aInAtRule)
    1734               0 :         break;
    1735                 : 
    1736                 :       // unexpected termination by EOF
    1737               0 :       REPORT_UNEXPECTED_EOF(PEGatherMediaEOF);
    1738               0 :       break;
    1739                 :     }
    1740                 : 
    1741               0 :     if (eCSSToken_Symbol == mToken.mType && aInAtRule &&
    1742                 :         (mToken.mSymbol == ';' || mToken.mSymbol == '{' || mToken.mSymbol == '}')) {
    1743               0 :       *aHitStop = true;
    1744               0 :       UngetToken();
    1745               0 :       break;
    1746                 :     }
    1747               0 :     if (eCSSToken_Symbol == mToken.mType && mToken.mSymbol == ',') {
    1748                 :       // Done with the expressions for this query
    1749               0 :       break;
    1750                 :     }
    1751               0 :     if (eCSSToken_Ident != mToken.mType ||
    1752               0 :         !mToken.mIdent.LowerCaseEqualsLiteral("and")) {
    1753               0 :       REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma);
    1754               0 :       UngetToken();
    1755               0 :       return false;
    1756                 :     }
    1757               0 :     if (!ParseMediaQueryExpression(query)) {
    1758               0 :       OUTPUT_ERROR();
    1759               0 :       query->SetHadUnknownExpression();
    1760                 :     }
    1761                 :   }
    1762               0 :   return true;
    1763                 : }
    1764                 : 
    1765                 : // Returns false only when there is a low-level error in the scanner
    1766                 : // (out-of-memory).
    1767                 : bool
    1768               0 : CSSParserImpl::GatherMedia(nsMediaList* aMedia,
    1769                 :                            bool aInAtRule)
    1770                 : {
    1771               0 :   for (;;) {
    1772               0 :     nsAutoPtr<nsMediaQuery> query;
    1773                 :     bool hitStop;
    1774               0 :     if (!ParseMediaQuery(aInAtRule, getter_Transfers(query),
    1775               0 :                          &hitStop)) {
    1776               0 :       NS_ASSERTION(!hitStop, "should return true when hit stop");
    1777               0 :       OUTPUT_ERROR();
    1778               0 :       if (query) {
    1779               0 :         query->SetHadUnknownExpression();
    1780                 :       }
    1781               0 :       if (aInAtRule) {
    1782                 :         const PRUnichar stopChars[] =
    1783               0 :           { PRUnichar(','), PRUnichar('{'), PRUnichar(';'), PRUnichar('}'), PRUnichar(0) };
    1784               0 :         SkipUntilOneOf(stopChars);
    1785                 :       } else {
    1786               0 :         SkipUntil(',');
    1787                 :       }
    1788                 :       // Rely on SkipUntilOneOf leaving mToken around as the last token read.
    1789               0 :       if (mToken.mType == eCSSToken_Symbol && aInAtRule &&
    1790                 :           (mToken.mSymbol == '{' || mToken.mSymbol == ';'  || mToken.mSymbol == '}')) {
    1791               0 :         UngetToken();
    1792               0 :         hitStop = true;
    1793                 :       }
    1794                 :     }
    1795               0 :     if (query) {
    1796               0 :       aMedia->AppendQuery(query);
    1797                 :     }
    1798               0 :     if (hitStop) {
    1799                 :       break;
    1800                 :     }
    1801                 :   }
    1802               0 :   return true;
    1803                 : }
    1804                 : 
    1805                 : bool
    1806               0 : CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery)
    1807                 : {
    1808               0 :   if (!ExpectSymbol('(', true)) {
    1809               0 :     REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart);
    1810               0 :     return false;
    1811                 :   }
    1812               0 :   if (! GetToken(true)) {
    1813               0 :     REPORT_UNEXPECTED_EOF(PEMQExpressionEOF);
    1814               0 :     return false;
    1815                 :   }
    1816               0 :   if (eCSSToken_Ident != mToken.mType) {
    1817               0 :     REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName);
    1818               0 :     UngetToken();
    1819               0 :     SkipUntil(')');
    1820               0 :     return false;
    1821                 :   }
    1822                 : 
    1823               0 :   nsMediaExpression *expr = aQuery->NewExpression();
    1824                 : 
    1825                 :   // case insensitive from CSS - must be lower cased
    1826               0 :   nsContentUtils::ASCIIToLower(mToken.mIdent);
    1827                 :   const PRUnichar *featureString;
    1828               0 :   if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("min-"))) {
    1829               0 :     expr->mRange = nsMediaExpression::eMin;
    1830               0 :     featureString = mToken.mIdent.get() + 4;
    1831               0 :   } else if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("max-"))) {
    1832               0 :     expr->mRange = nsMediaExpression::eMax;
    1833               0 :     featureString = mToken.mIdent.get() + 4;
    1834                 :   } else {
    1835               0 :     expr->mRange = nsMediaExpression::eEqual;
    1836               0 :     featureString = mToken.mIdent.get();
    1837                 :   }
    1838                 : 
    1839               0 :   nsCOMPtr<nsIAtom> mediaFeatureAtom = do_GetAtom(featureString);
    1840               0 :   if (!mediaFeatureAtom) {
    1841               0 :     NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
    1842                 :   }
    1843               0 :   const nsMediaFeature *feature = nsMediaFeatures::features;
    1844               0 :   for (; feature->mName; ++feature) {
    1845               0 :     if (*(feature->mName) == mediaFeatureAtom) {
    1846               0 :       break;
    1847                 :     }
    1848                 :   }
    1849               0 :   if (!feature->mName ||
    1850                 :       (expr->mRange != nsMediaExpression::eEqual &&
    1851                 :        feature->mRangeType != nsMediaFeature::eMinMaxAllowed)) {
    1852               0 :     REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName);
    1853               0 :     SkipUntil(')');
    1854               0 :     return false;
    1855                 :   }
    1856               0 :   expr->mFeature = feature;
    1857                 : 
    1858               0 :   if (!GetToken(true) || mToken.IsSymbol(')')) {
    1859                 :     // Query expressions for any feature can be given without a value.
    1860                 :     // However, min/max prefixes are not allowed.
    1861               0 :     if (expr->mRange != nsMediaExpression::eEqual) {
    1862               0 :       REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue);
    1863               0 :       return false;
    1864                 :     }
    1865               0 :     expr->mValue.Reset();
    1866               0 :     return true;
    1867                 :   }
    1868                 : 
    1869               0 :   if (!mToken.IsSymbol(':')) {
    1870               0 :     REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd);
    1871               0 :     UngetToken();
    1872               0 :     SkipUntil(')');
    1873               0 :     return false;
    1874                 :   }
    1875                 : 
    1876                 :   bool rv;
    1877               0 :   switch (feature->mValueType) {
    1878                 :     case nsMediaFeature::eLength:
    1879               0 :       rv = ParseNonNegativeVariant(expr->mValue, VARIANT_LENGTH, nsnull);
    1880               0 :       break;
    1881                 :     case nsMediaFeature::eInteger:
    1882                 :     case nsMediaFeature::eBoolInteger:
    1883               0 :       rv = ParseNonNegativeVariant(expr->mValue, VARIANT_INTEGER, nsnull);
    1884                 :       // Enforce extra restrictions for eBoolInteger
    1885               0 :       if (rv &&
    1886                 :           feature->mValueType == nsMediaFeature::eBoolInteger &&
    1887               0 :           expr->mValue.GetIntValue() > 1)
    1888               0 :         rv = false;
    1889               0 :       break;
    1890                 :     case nsMediaFeature::eFloat:
    1891               0 :       rv = ParseNonNegativeVariant(expr->mValue, VARIANT_NUMBER, nsnull);
    1892               0 :       break;
    1893                 :     case nsMediaFeature::eIntRatio:
    1894                 :       {
    1895                 :         // Two integers separated by '/', with optional whitespace on
    1896                 :         // either side of the '/'.
    1897               0 :         nsRefPtr<nsCSSValue::Array> a = nsCSSValue::Array::Create(2);
    1898               0 :         expr->mValue.SetArrayValue(a, eCSSUnit_Array);
    1899                 :         // We don't bother with ParseNonNegativeVariant since we have to
    1900                 :         // check for != 0 as well; no need to worry about the UngetToken
    1901                 :         // since we're throwing out up to the next ')' anyway.
    1902               0 :         rv = ParseVariant(a->Item(0), VARIANT_INTEGER, nsnull) &&
    1903               0 :              a->Item(0).GetIntValue() > 0 &&
    1904               0 :              ExpectSymbol('/', true) &&
    1905               0 :              ParseVariant(a->Item(1), VARIANT_INTEGER, nsnull) &&
    1906               0 :              a->Item(1).GetIntValue() > 0;
    1907                 :       }
    1908               0 :       break;
    1909                 :     case nsMediaFeature::eResolution:
    1910               0 :       rv = GetToken(true);
    1911               0 :       if (!rv)
    1912               0 :         break;
    1913               0 :       rv = mToken.mType == eCSSToken_Dimension && mToken.mNumber > 0.0f;
    1914               0 :       if (!rv) {
    1915               0 :         UngetToken();
    1916               0 :         break;
    1917                 :       }
    1918                 :       // No worries about whether unitless zero is allowed, since the
    1919                 :       // value must be positive (and we checked that above).
    1920               0 :       NS_ASSERTION(!mToken.mIdent.IsEmpty(), "unit lied");
    1921               0 :       if (mToken.mIdent.LowerCaseEqualsLiteral("dpi")) {
    1922               0 :         expr->mValue.SetFloatValue(mToken.mNumber, eCSSUnit_Inch);
    1923               0 :       } else if (mToken.mIdent.LowerCaseEqualsLiteral("dpcm")) {
    1924               0 :         expr->mValue.SetFloatValue(mToken.mNumber, eCSSUnit_Centimeter);
    1925                 :       } else {
    1926               0 :         rv = false;
    1927                 :       }
    1928               0 :       break;
    1929                 :     case nsMediaFeature::eEnumerated:
    1930                 :       rv = ParseVariant(expr->mValue, VARIANT_KEYWORD,
    1931               0 :                         feature->mData.mKeywordTable);
    1932               0 :       break;
    1933                 :     case nsMediaFeature::eIdent:
    1934               0 :       rv = ParseVariant(expr->mValue, VARIANT_IDENTIFIER, nsnull);
    1935               0 :       break;
    1936                 :   }
    1937               0 :   if (!rv || !ExpectSymbol(')', true)) {
    1938               0 :     REPORT_UNEXPECTED(PEMQExpectedFeatureValue);
    1939               0 :     SkipUntil(')');
    1940               0 :     return false;
    1941                 :   }
    1942                 : 
    1943               0 :   return true;
    1944                 : }
    1945                 : 
    1946                 : // Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"
    1947                 : bool
    1948               0 : CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc, void* aData)
    1949                 : {
    1950               0 :   nsRefPtr<nsMediaList> media = new nsMediaList();
    1951                 : 
    1952               0 :   nsAutoString url;
    1953               0 :   if (!ParseURLOrString(url)) {
    1954               0 :     REPORT_UNEXPECTED_TOKEN(PEImportNotURI);
    1955               0 :     return false;
    1956                 :   }
    1957                 : 
    1958               0 :   if (!ExpectSymbol(';', true)) {
    1959               0 :     if (!GatherMedia(media, true) ||
    1960               0 :         !ExpectSymbol(';', true)) {
    1961               0 :       REPORT_UNEXPECTED_TOKEN(PEImportUnexpected);
    1962                 :       // don't advance section, simply ignore invalid @import
    1963               0 :       return false;
    1964                 :     }
    1965                 : 
    1966                 :     // Safe to assert this, since we ensured that there is something
    1967                 :     // other than the ';' coming after the @import's url() token.
    1968               0 :     NS_ASSERTION(media->Count() != 0, "media list must be nonempty");
    1969                 :   }
    1970                 : 
    1971               0 :   ProcessImport(url, media, aAppendFunc, aData);
    1972               0 :   return true;
    1973                 : }
    1974                 : 
    1975                 : 
    1976                 : void
    1977               0 : CSSParserImpl::ProcessImport(const nsString& aURLSpec,
    1978                 :                              nsMediaList* aMedia,
    1979                 :                              RuleAppendFunc aAppendFunc,
    1980                 :                              void* aData)
    1981                 : {
    1982               0 :   nsRefPtr<css::ImportRule> rule = new css::ImportRule(aMedia, aURLSpec);
    1983               0 :   (*aAppendFunc)(rule, aData);
    1984                 : 
    1985                 :   // Diagnose bad URIs even if we don't have a child loader.
    1986               0 :   nsCOMPtr<nsIURI> url;
    1987                 :   // Charset will be deduced from mBaseURI, which is more or less correct.
    1988               0 :   nsresult rv = NS_NewURI(getter_AddRefs(url), aURLSpec, nsnull, mBaseURI);
    1989                 : 
    1990               0 :   if (NS_FAILED(rv)) {
    1991               0 :     if (rv == NS_ERROR_MALFORMED_URI) {
    1992                 :       // import url is bad
    1993                 :       const PRUnichar *params[] = {
    1994               0 :         aURLSpec.get()
    1995               0 :       };
    1996               0 :       REPORT_UNEXPECTED_P(PEImportBadURI, params);
    1997               0 :       OUTPUT_ERROR();
    1998                 :     }
    1999                 :     return;
    2000                 :   }
    2001                 : 
    2002               0 :   if (mChildLoader) {
    2003               0 :     mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule);
    2004                 :   }
    2005                 : }
    2006                 : 
    2007                 : // Parse the {} part of an @media or @-moz-document rule.
    2008                 : bool
    2009               0 : CSSParserImpl::ParseGroupRule(css::GroupRule* aRule,
    2010                 :                               RuleAppendFunc aAppendFunc,
    2011                 :                               void* aData)
    2012                 : {
    2013                 :   // XXXbz this could use better error reporting throughout the method
    2014               0 :   if (!ExpectSymbol('{', true)) {
    2015               0 :     return false;
    2016                 :   }
    2017                 : 
    2018                 :   // push rule on stack, loop over children
    2019               0 :   PushGroup(aRule);
    2020               0 :   nsCSSSection holdSection = mSection;
    2021               0 :   mSection = eCSSSection_General;
    2022                 : 
    2023               0 :   for (;;) {
    2024                 :     // Get next non-whitespace token
    2025               0 :     if (! GetToken(true)) {
    2026               0 :       REPORT_UNEXPECTED_EOF(PEGroupRuleEOF);
    2027               0 :       break;
    2028                 :     }
    2029               0 :     if (mToken.IsSymbol('}')) { // done!
    2030               0 :       UngetToken();
    2031               0 :       break;
    2032                 :     }
    2033               0 :     if (eCSSToken_AtKeyword == mToken.mType) {
    2034                 :       // Parse for nested rules
    2035               0 :       ParseAtRule(aAppendFunc, aData, true);
    2036               0 :       continue;
    2037                 :     }
    2038               0 :     UngetToken();
    2039               0 :     ParseRuleSet(AppendRuleToSheet, this, true);
    2040                 :   }
    2041               0 :   PopGroup();
    2042                 : 
    2043               0 :   if (!ExpectSymbol('}', true)) {
    2044               0 :     mSection = holdSection;
    2045               0 :     return false;
    2046                 :   }
    2047               0 :   (*aAppendFunc)(aRule, aData);
    2048               0 :   return true;
    2049                 : }
    2050                 : 
    2051                 : // Parse a CSS2 media rule: "@media medium [, medium] { ... }"
    2052                 : bool
    2053               0 : CSSParserImpl::ParseMediaRule(RuleAppendFunc aAppendFunc, void* aData)
    2054                 : {
    2055               0 :   nsRefPtr<nsMediaList> media = new nsMediaList();
    2056                 : 
    2057               0 :   if (GatherMedia(media, true)) {
    2058                 :     // XXXbz this could use better error reporting throughout the method
    2059               0 :     nsRefPtr<css::MediaRule> rule = new css::MediaRule();
    2060                 :     // Append first, so when we do SetMedia() the rule
    2061                 :     // knows what its stylesheet is.
    2062               0 :     if (ParseGroupRule(rule, aAppendFunc, aData)) {
    2063               0 :       rule->SetMedia(media);
    2064               0 :       return true;
    2065                 :     }
    2066                 :   }
    2067                 : 
    2068               0 :   return false;
    2069                 : }
    2070                 : 
    2071                 : // Parse a @-moz-document rule.  This is like an @media rule, but instead
    2072                 : // of a medium it has a nonempty list of items where each item is either
    2073                 : // url(), url-prefix(), or domain().
    2074                 : bool
    2075               0 : CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc, void* aData)
    2076                 : {
    2077               0 :   css::DocumentRule::URL *urls = nsnull;
    2078               0 :   css::DocumentRule::URL **next = &urls;
    2079               0 :   do {
    2080               0 :     if (!GetToken(true)) {
    2081               0 :       REPORT_UNEXPECTED_EOF(PEMozDocRuleEOF);
    2082               0 :       delete urls;
    2083               0 :       return false;
    2084                 :     }
    2085                 :         
    2086               0 :     if (!(eCSSToken_URL == mToken.mType ||
    2087                 :           (eCSSToken_Function == mToken.mType &&
    2088               0 :            (mToken.mIdent.LowerCaseEqualsLiteral("url-prefix") ||
    2089               0 :             mToken.mIdent.LowerCaseEqualsLiteral("domain") ||
    2090               0 :             mToken.mIdent.LowerCaseEqualsLiteral("regexp"))))) {
    2091               0 :       REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc);
    2092               0 :       UngetToken();
    2093               0 :       delete urls;
    2094               0 :       return false;
    2095                 :     }
    2096               0 :     css::DocumentRule::URL *cur = *next = new css::DocumentRule::URL;
    2097               0 :     next = &cur->next;
    2098               0 :     if (mToken.mType == eCSSToken_URL) {
    2099               0 :       cur->func = css::DocumentRule::eURL;
    2100               0 :       CopyUTF16toUTF8(mToken.mIdent, cur->url);
    2101               0 :     } else if (mToken.mIdent.LowerCaseEqualsLiteral("regexp")) {
    2102                 :       // regexp() is different from url-prefix() and domain() (but
    2103                 :       // probably the way they *should* have been* in that it requires a
    2104                 :       // string argument, and doesn't try to behave like url().
    2105               0 :       cur->func = css::DocumentRule::eRegExp;
    2106               0 :       GetToken(true);
    2107                 :       // copy before we know it's valid (but before ExpectSymbol changes
    2108                 :       // mToken.mIdent)
    2109               0 :       CopyUTF16toUTF8(mToken.mIdent, cur->url);
    2110               0 :       if (eCSSToken_String != mToken.mType || !ExpectSymbol(')', true)) {
    2111               0 :         REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotString);
    2112               0 :         SkipUntil(')');
    2113               0 :         delete urls;
    2114               0 :         return false;
    2115                 :       }
    2116                 :     } else {
    2117               0 :       if (mToken.mIdent.LowerCaseEqualsLiteral("url-prefix")) {
    2118               0 :         cur->func = css::DocumentRule::eURLPrefix;
    2119               0 :       } else if (mToken.mIdent.LowerCaseEqualsLiteral("domain")) {
    2120               0 :         cur->func = css::DocumentRule::eDomain;
    2121                 :       }
    2122                 : 
    2123               0 :       nsAutoString url;
    2124               0 :       if (!GetURLInParens(url)) {
    2125               0 :         REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI);
    2126               0 :         delete urls;
    2127               0 :         return false;
    2128                 :       }
    2129                 : 
    2130                 :       // We could try to make the URL (as long as it's not domain())
    2131                 :       // canonical and absolute with NS_NewURI and GetSpec, but I'm
    2132                 :       // inclined to think we shouldn't.
    2133               0 :       CopyUTF16toUTF8(url, cur->url);
    2134                 :     }
    2135                 :   } while (ExpectSymbol(',', true));
    2136                 : 
    2137               0 :   nsRefPtr<css::DocumentRule> rule = new css::DocumentRule();
    2138               0 :   rule->SetURLs(urls);
    2139                 : 
    2140               0 :   return ParseGroupRule(rule, aAppendFunc, aData);
    2141                 : }
    2142                 : 
    2143                 : // Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"
    2144                 : bool
    2145               0 : CSSParserImpl::ParseNameSpaceRule(RuleAppendFunc aAppendFunc, void* aData)
    2146                 : {
    2147               0 :   if (!GetToken(true)) {
    2148               0 :     REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF);
    2149               0 :     return false;
    2150                 :   }
    2151                 : 
    2152               0 :   nsAutoString  prefix;
    2153               0 :   nsAutoString  url;
    2154                 : 
    2155               0 :   if (eCSSToken_Ident == mToken.mType) {
    2156               0 :     prefix = mToken.mIdent;
    2157                 :     // user-specified identifiers are case-sensitive (bug 416106)
    2158                 :   } else {
    2159               0 :     UngetToken();
    2160                 :   }
    2161                 : 
    2162               0 :   if (!ParseURLOrString(url) || !ExpectSymbol(';', true)) {
    2163               0 :     if (mHavePushBack) {
    2164               0 :       REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected);
    2165                 :     } else {
    2166               0 :       REPORT_UNEXPECTED_EOF(PEAtNSURIEOF);
    2167                 :     }
    2168               0 :     return false;
    2169                 :   }
    2170                 : 
    2171               0 :   ProcessNameSpace(prefix, url, aAppendFunc, aData);
    2172               0 :   return true;
    2173                 : }
    2174                 : 
    2175                 : void
    2176               0 : CSSParserImpl::ProcessNameSpace(const nsString& aPrefix,
    2177                 :                                 const nsString& aURLSpec,
    2178                 :                                 RuleAppendFunc aAppendFunc,
    2179                 :                                 void* aData)
    2180                 : {
    2181               0 :   nsCOMPtr<nsIAtom> prefix;
    2182                 : 
    2183               0 :   if (!aPrefix.IsEmpty()) {
    2184               0 :     prefix = do_GetAtom(aPrefix);
    2185               0 :     if (!prefix) {
    2186               0 :       NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
    2187                 :     }
    2188                 :   }
    2189                 : 
    2190               0 :   nsRefPtr<css::NameSpaceRule> rule = new css::NameSpaceRule(prefix, aURLSpec);
    2191               0 :   (*aAppendFunc)(rule, aData);
    2192                 : 
    2193                 :   // If this was the first namespace rule encountered, it will trigger
    2194                 :   // creation of a namespace map.
    2195               0 :   if (!mNameSpaceMap) {
    2196               0 :     mNameSpaceMap = mSheet->GetNameSpaceMap();
    2197                 :   }
    2198               0 : }
    2199                 : 
    2200                 : // font-face-rule: '@font-face' '{' font-description '}'
    2201                 : // font-description: font-descriptor+
    2202                 : bool
    2203               0 : CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aData)
    2204                 : {
    2205               0 :   if (!ExpectSymbol('{', true)) {
    2206               0 :     REPORT_UNEXPECTED_TOKEN(PEBadFontBlockStart);
    2207               0 :     return false;
    2208                 :   }
    2209                 : 
    2210               0 :   nsRefPtr<nsCSSFontFaceRule> rule(new nsCSSFontFaceRule());
    2211                 : 
    2212               0 :   for (;;) {
    2213               0 :     if (!GetToken(true)) {
    2214               0 :       REPORT_UNEXPECTED_EOF(PEFontFaceEOF);
    2215               0 :       break;
    2216                 :     }
    2217               0 :     if (mToken.IsSymbol('}')) { // done!
    2218               0 :       UngetToken();
    2219               0 :       break;
    2220                 :     }
    2221                 : 
    2222                 :     // ignore extra semicolons
    2223               0 :     if (mToken.IsSymbol(';'))
    2224               0 :       continue;
    2225                 : 
    2226               0 :     if (!ParseFontDescriptor(rule)) {
    2227               0 :       REPORT_UNEXPECTED(PEDeclSkipped);
    2228               0 :       OUTPUT_ERROR();
    2229               0 :       if (!SkipDeclaration(true))
    2230               0 :         break;
    2231                 :     }
    2232                 :   }
    2233               0 :   if (!ExpectSymbol('}', true)) {
    2234               0 :     REPORT_UNEXPECTED_TOKEN(PEBadFontBlockEnd);
    2235               0 :     return false;
    2236                 :   }
    2237               0 :   (*aAppendFunc)(rule, aData);
    2238               0 :   return true;
    2239                 : }
    2240                 : 
    2241                 : // font-descriptor: font-family-desc
    2242                 : //                | font-style-desc
    2243                 : //                | font-weight-desc
    2244                 : //                | font-stretch-desc
    2245                 : //                | font-src-desc
    2246                 : //                | unicode-range-desc
    2247                 : //
    2248                 : // All font-*-desc productions follow the pattern
    2249                 : //    IDENT ':' value ';'
    2250                 : //
    2251                 : // On entry to this function, mToken is the IDENT.
    2252                 : 
    2253                 : bool
    2254               0 : CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule* aRule)
    2255                 : {
    2256               0 :   if (eCSSToken_Ident != mToken.mType) {
    2257               0 :     REPORT_UNEXPECTED_TOKEN(PEFontDescExpected);
    2258               0 :     return false;
    2259                 :   }
    2260                 : 
    2261               0 :   nsString descName = mToken.mIdent;
    2262               0 :   if (!ExpectSymbol(':', true)) {
    2263               0 :     REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);
    2264               0 :     OUTPUT_ERROR();
    2265               0 :     return false;
    2266                 :   }
    2267                 : 
    2268               0 :   nsCSSFontDesc descID = nsCSSProps::LookupFontDesc(descName);
    2269               0 :   nsCSSValue value;
    2270                 : 
    2271               0 :   if (descID == eCSSFontDesc_UNKNOWN) {
    2272               0 :     if (NonMozillaVendorIdentifier(descName)) {
    2273                 :       // silently skip other vendors' extensions
    2274               0 :       SkipDeclaration(true);
    2275               0 :       return true;
    2276                 :     } else {
    2277                 :       const PRUnichar *params[] = {
    2278               0 :         descName.get()
    2279               0 :       };
    2280               0 :       REPORT_UNEXPECTED_P(PEUnknownFontDesc, params);
    2281               0 :       return false;
    2282                 :     }
    2283                 :   }
    2284                 : 
    2285               0 :   if (!ParseFontDescriptorValue(descID, value)) {
    2286                 :     const PRUnichar *params[] = {
    2287               0 :       descName.get()
    2288               0 :     };
    2289               0 :     REPORT_UNEXPECTED_P(PEValueParsingError, params);
    2290               0 :     return false;
    2291                 :   }
    2292                 : 
    2293               0 :   if (!ExpectEndProperty())
    2294               0 :     return false;
    2295                 : 
    2296               0 :   aRule->SetDesc(descID, value);
    2297               0 :   return true;
    2298                 : }
    2299                 : 
    2300                 : 
    2301                 : bool
    2302               0 : CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc, void* aData)
    2303                 : {
    2304                 :   // XXX not yet implemented
    2305               0 :   return false;
    2306                 : }
    2307                 : 
    2308                 : bool
    2309               0 : CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData)
    2310                 : {
    2311               0 :   if (!GetToken(true)) {
    2312               0 :     REPORT_UNEXPECTED_EOF(PEKeyframeNameEOF);
    2313               0 :     return false;
    2314                 :   }
    2315                 : 
    2316               0 :   if (mToken.mType != eCSSToken_Ident) {
    2317               0 :     REPORT_UNEXPECTED_TOKEN(PEKeyframeBadName);
    2318               0 :     UngetToken();
    2319               0 :     return false;
    2320                 :   }
    2321               0 :   nsString name(mToken.mIdent);
    2322                 : 
    2323               0 :   if (!ExpectSymbol('{', true)) {
    2324               0 :     REPORT_UNEXPECTED_TOKEN(PEKeyframeBrace);
    2325               0 :     return false;
    2326                 :   }
    2327                 : 
    2328               0 :   nsRefPtr<nsCSSKeyframesRule> rule = new nsCSSKeyframesRule(name);
    2329                 : 
    2330               0 :   while (!ExpectSymbol('}', true)) {
    2331               0 :     nsRefPtr<nsCSSKeyframeRule> kid = ParseKeyframeRule();
    2332               0 :     if (kid) {
    2333               0 :       rule->AppendStyleRule(kid);
    2334                 :     } else {
    2335               0 :       OUTPUT_ERROR();
    2336               0 :       SkipRuleSet(true);
    2337                 :     }
    2338                 :   }
    2339                 : 
    2340               0 :   (*aAppendFunc)(rule, aData);
    2341               0 :   return true;
    2342                 : }
    2343                 : 
    2344                 : already_AddRefed<nsCSSKeyframeRule>
    2345               0 : CSSParserImpl::ParseKeyframeRule()
    2346                 : {
    2347               0 :   InfallibleTArray<float> selectorList;
    2348               0 :   if (!ParseKeyframeSelectorList(selectorList)) {
    2349               0 :     REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored);
    2350               0 :     return nsnull;
    2351                 :   }
    2352                 : 
    2353               0 :   nsAutoPtr<css::Declaration> declaration(ParseDeclarationBlock(true));
    2354               0 :   if (!declaration) {
    2355               0 :     REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored);
    2356               0 :     return nsnull;
    2357                 :   }
    2358                 : 
    2359                 :   // Takes ownership of declaration, and steals contents of selectorList.
    2360                 :   nsRefPtr<nsCSSKeyframeRule> rule =
    2361               0 :     new nsCSSKeyframeRule(selectorList, declaration);
    2362                 : 
    2363               0 :   return rule.forget();
    2364                 : }
    2365                 : 
    2366                 : bool
    2367               0 : CSSParserImpl::ParseKeyframeSelectorList(InfallibleTArray<float>& aSelectorList)
    2368                 : {
    2369               0 :   for (;;) {
    2370               0 :     if (!GetToken(true)) {
    2371                 :       // The first time through the loop, this means we got an empty
    2372                 :       // list.  Otherwise, it means we have a trailing comma.
    2373               0 :       return false;
    2374                 :     }
    2375                 :     float value;
    2376               0 :     switch (mToken.mType) {
    2377                 :       case eCSSToken_Percentage:
    2378               0 :         value = mToken.mNumber;
    2379               0 :         break;
    2380                 :       case eCSSToken_Ident:
    2381               0 :         if (mToken.mIdent.LowerCaseEqualsLiteral("from")) {
    2382               0 :           value = 0.0f;
    2383               0 :           break;
    2384                 :         }
    2385               0 :         if (mToken.mIdent.LowerCaseEqualsLiteral("to")) {
    2386               0 :           value = 1.0f;
    2387               0 :           break;
    2388                 :         }
    2389                 :         // fall through
    2390                 :       default:
    2391               0 :         UngetToken();
    2392                 :         // The first time through the loop, this means we got an empty
    2393                 :         // list.  Otherwise, it means we have a trailing comma.
    2394               0 :         return false;
    2395                 :     }
    2396               0 :     aSelectorList.AppendElement(value);
    2397               0 :     if (!ExpectSymbol(',', true)) {
    2398               0 :       return true;
    2399                 :     }
    2400                 :   }
    2401                 : }
    2402                 : 
    2403                 : void
    2404               0 : CSSParserImpl::SkipUntil(PRUnichar aStopSymbol)
    2405                 : {
    2406               0 :   nsCSSToken* tk = &mToken;
    2407               0 :   nsAutoTArray<PRUnichar, 16> stack;
    2408               0 :   stack.AppendElement(aStopSymbol);
    2409               0 :   for (;;) {
    2410               0 :     if (!GetToken(true)) {
    2411               0 :       break;
    2412                 :     }
    2413               0 :     if (eCSSToken_Symbol == tk->mType) {
    2414               0 :       PRUnichar symbol = tk->mSymbol;
    2415               0 :       PRUint32 stackTopIndex = stack.Length() - 1;
    2416               0 :       if (symbol == stack.ElementAt(stackTopIndex)) {
    2417               0 :         stack.RemoveElementAt(stackTopIndex);
    2418               0 :         if (stackTopIndex == 0) {
    2419               0 :           break;
    2420                 :         }
    2421                 : 
    2422                 :       // Just handle out-of-memory by parsing incorrectly.  It's
    2423                 :       // highly unlikely we're dealing with a legitimate style sheet
    2424                 :       // anyway.
    2425               0 :       } else if ('{' == symbol) {
    2426               0 :         stack.AppendElement('}');
    2427               0 :       } else if ('[' == symbol) {
    2428               0 :         stack.AppendElement(']');
    2429               0 :       } else if ('(' == symbol) {
    2430               0 :         stack.AppendElement(')');
    2431                 :       }
    2432               0 :     } else if (eCSSToken_Function == tk->mType ||
    2433                 :                eCSSToken_Bad_URL == tk->mType) {
    2434               0 :       stack.AppendElement(')');
    2435                 :     }
    2436                 :   }
    2437               0 : }
    2438                 : 
    2439                 : void
    2440               0 : CSSParserImpl::SkipUntilOneOf(const PRUnichar* aStopSymbolChars)
    2441                 : {
    2442               0 :   nsCSSToken* tk = &mToken;
    2443               0 :   nsDependentString stopSymbolChars(aStopSymbolChars);
    2444               0 :   for (;;) {
    2445               0 :     if (!GetToken(true)) {
    2446               0 :       break;
    2447                 :     }
    2448               0 :     if (eCSSToken_Symbol == tk->mType) {
    2449               0 :       PRUnichar symbol = tk->mSymbol;
    2450               0 :       if (stopSymbolChars.FindChar(symbol) != -1) {
    2451               0 :         break;
    2452               0 :       } else if ('{' == symbol) {
    2453               0 :         SkipUntil('}');
    2454               0 :       } else if ('[' == symbol) {
    2455               0 :         SkipUntil(']');
    2456               0 :       } else if ('(' == symbol) {
    2457               0 :         SkipUntil(')');
    2458                 :       }
    2459               0 :     } else if (eCSSToken_Function == tk->mType ||
    2460                 :                eCSSToken_Bad_URL == tk->mType) {
    2461               0 :       SkipUntil(')');
    2462                 :     }
    2463                 :   }
    2464               0 : }
    2465                 : 
    2466                 : bool
    2467               0 : CSSParserImpl::SkipDeclaration(bool aCheckForBraces)
    2468                 : {
    2469               0 :   nsCSSToken* tk = &mToken;
    2470               0 :   for (;;) {
    2471               0 :     if (!GetToken(true)) {
    2472               0 :       if (aCheckForBraces) {
    2473               0 :         REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF);
    2474                 :       }
    2475               0 :       return false;
    2476                 :     }
    2477               0 :     if (eCSSToken_Symbol == tk->mType) {
    2478               0 :       PRUnichar symbol = tk->mSymbol;
    2479               0 :       if (';' == symbol) {
    2480               0 :         break;
    2481                 :       }
    2482               0 :       if (aCheckForBraces) {
    2483               0 :         if ('}' == symbol) {
    2484               0 :           UngetToken();
    2485               0 :           break;
    2486                 :         }
    2487                 :       }
    2488               0 :       if ('{' == symbol) {
    2489               0 :         SkipUntil('}');
    2490               0 :       } else if ('(' == symbol) {
    2491               0 :         SkipUntil(')');
    2492               0 :       } else if ('[' == symbol) {
    2493               0 :         SkipUntil(']');
    2494                 :       }
    2495               0 :     } else if (eCSSToken_Function == tk->mType ||
    2496                 :                eCSSToken_Bad_URL == tk->mType) {
    2497               0 :       SkipUntil(')');
    2498                 :     }
    2499                 :   }
    2500               0 :   return true;
    2501                 : }
    2502                 : 
    2503                 : void
    2504               0 : CSSParserImpl::SkipRuleSet(bool aInsideBraces)
    2505                 : {
    2506               0 :   nsCSSToken* tk = &mToken;
    2507               0 :   for (;;) {
    2508               0 :     if (!GetToken(true)) {
    2509               0 :       REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF);
    2510               0 :       break;
    2511                 :     }
    2512               0 :     if (eCSSToken_Symbol == tk->mType) {
    2513               0 :       PRUnichar symbol = tk->mSymbol;
    2514               0 :       if ('}' == symbol && aInsideBraces) {
    2515                 :         // leave block closer for higher-level grammar to consume
    2516               0 :         UngetToken();
    2517               0 :         break;
    2518               0 :       } else if ('{' == symbol) {
    2519               0 :         SkipUntil('}');
    2520               0 :         break;
    2521               0 :       } else if ('(' == symbol) {
    2522               0 :         SkipUntil(')');
    2523               0 :       } else if ('[' == symbol) {
    2524               0 :         SkipUntil(']');
    2525                 :       }
    2526               0 :     } else if (eCSSToken_Function == tk->mType ||
    2527                 :                eCSSToken_Bad_URL == tk->mType) {
    2528               0 :       SkipUntil(')');
    2529                 :     }
    2530                 :   }
    2531               0 : }
    2532                 : 
    2533                 : void
    2534               0 : CSSParserImpl::PushGroup(css::GroupRule* aRule)
    2535                 : {
    2536               0 :   mGroupStack.AppendElement(aRule);
    2537               0 : }
    2538                 : 
    2539                 : void
    2540               0 : CSSParserImpl::PopGroup()
    2541                 : {
    2542               0 :   PRUint32 count = mGroupStack.Length();
    2543               0 :   if (0 < count) {
    2544               0 :     mGroupStack.RemoveElementAt(count - 1);
    2545                 :   }
    2546               0 : }
    2547                 : 
    2548                 : void
    2549               0 : CSSParserImpl::AppendRule(css::Rule* aRule)
    2550                 : {
    2551               0 :   PRUint32 count = mGroupStack.Length();
    2552               0 :   if (0 < count) {
    2553               0 :     mGroupStack[count - 1]->AppendStyleRule(aRule);
    2554                 :   }
    2555                 :   else {
    2556               0 :     mSheet->AppendStyleRule(aRule);
    2557                 :   }
    2558               0 : }
    2559                 : 
    2560                 : bool
    2561               0 : CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData,
    2562                 :                             bool aInsideBraces)
    2563                 : {
    2564                 :   // First get the list of selectors for the rule
    2565               0 :   nsCSSSelectorList* slist = nsnull;
    2566               0 :   PRUint32 linenum = mScanner.GetLineNumber();
    2567               0 :   if (! ParseSelectorList(slist, PRUnichar('{'))) {
    2568               0 :     REPORT_UNEXPECTED(PEBadSelectorRSIgnored);
    2569               0 :     OUTPUT_ERROR();
    2570               0 :     SkipRuleSet(aInsideBraces);
    2571               0 :     return false;
    2572                 :   }
    2573               0 :   NS_ASSERTION(nsnull != slist, "null selector list");
    2574               0 :   CLEAR_ERROR();
    2575                 : 
    2576                 :   // Next parse the declaration block
    2577               0 :   css::Declaration* declaration = ParseDeclarationBlock(true);
    2578               0 :   if (nsnull == declaration) {
    2579               0 :     delete slist;
    2580               0 :     return false;
    2581                 :   }
    2582                 : 
    2583                 : #if 0
    2584                 :   slist->Dump();
    2585                 :   fputs("{\n", stdout);
    2586                 :   declaration->List();
    2587                 :   fputs("}\n", stdout);
    2588                 : #endif
    2589                 : 
    2590                 :   // Translate the selector list and declaration block into style data
    2591                 : 
    2592               0 :   nsRefPtr<css::StyleRule> rule = new css::StyleRule(slist, declaration);
    2593               0 :   rule->SetLineNumber(linenum);
    2594               0 :   (*aAppendFunc)(rule, aData);
    2595                 : 
    2596               0 :   return true;
    2597                 : }
    2598                 : 
    2599                 : bool
    2600             110 : CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead,
    2601                 :                                  PRUnichar aStopChar)
    2602                 : {
    2603             110 :   nsCSSSelectorList* list = nsnull;
    2604             110 :   if (! ParseSelectorGroup(list)) {
    2605                 :     // must have at least one selector group
    2606               0 :     aListHead = nsnull;
    2607               0 :     return false;
    2608                 :   }
    2609             110 :   NS_ASSERTION(nsnull != list, "no selector list");
    2610             110 :   aListHead = list;
    2611                 : 
    2612                 :   // After that there must either be a "," or a "{" (the latter if
    2613                 :   // StopChar is nonzero)
    2614             110 :   nsCSSToken* tk = &mToken;
    2615               0 :   for (;;) {
    2616             110 :     if (! GetToken(true)) {
    2617             110 :       if (aStopChar == PRUnichar(0)) {
    2618             110 :         return true;
    2619                 :       }
    2620                 : 
    2621               0 :       REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF);
    2622               0 :       break;
    2623                 :     }
    2624                 : 
    2625               0 :     if (eCSSToken_Symbol == tk->mType) {
    2626               0 :       if (',' == tk->mSymbol) {
    2627               0 :         nsCSSSelectorList* newList = nsnull;
    2628                 :         // Another selector group must follow
    2629               0 :         if (! ParseSelectorGroup(newList)) {
    2630               0 :           break;
    2631                 :         }
    2632                 :         // add new list to the end of the selector list
    2633               0 :         list->mNext = newList;
    2634               0 :         list = newList;
    2635               0 :         continue;
    2636               0 :       } else if (aStopChar == tk->mSymbol && aStopChar != PRUnichar(0)) {
    2637               0 :         UngetToken();
    2638               0 :         return true;
    2639                 :       }
    2640                 :     }
    2641               0 :     REPORT_UNEXPECTED_TOKEN(PESelectorListExtra);
    2642               0 :     UngetToken();
    2643               0 :     break;
    2644                 :   }
    2645                 : 
    2646               0 :   delete aListHead;
    2647               0 :   aListHead = nsnull;
    2648               0 :   return false;
    2649                 : }
    2650                 : 
    2651               0 : static bool IsUniversalSelector(const nsCSSSelector& aSelector)
    2652                 : {
    2653                 :   return bool((aSelector.mNameSpace == kNameSpaceID_Unknown) &&
    2654               0 :                 (aSelector.mLowercaseTag == nsnull) &&
    2655                 :                 (aSelector.mIDList == nsnull) &&
    2656                 :                 (aSelector.mClassList == nsnull) &&
    2657                 :                 (aSelector.mAttrList == nsnull) &&
    2658                 :                 (aSelector.mNegations == nsnull) &&
    2659               0 :                 (aSelector.mPseudoClassList == nsnull));
    2660                 : }
    2661                 : 
    2662                 : bool
    2663             110 : CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList)
    2664                 : {
    2665             110 :   PRUnichar combinator = 0;
    2666             220 :   nsAutoPtr<nsCSSSelectorList> list(new nsCSSSelectorList());
    2667                 : 
    2668             110 :   for (;;) {
    2669             220 :     if (!ParseSelector(list, combinator)) {
    2670               0 :       return false;
    2671                 :     }
    2672                 : 
    2673                 :     // Look for a combinator.
    2674             220 :     if (!GetToken(false)) {
    2675             110 :       break; // EOF ok here
    2676                 :     }
    2677                 : 
    2678             110 :     combinator = PRUnichar(0);
    2679             110 :     if (mToken.mType == eCSSToken_WhiteSpace) {
    2680             110 :       if (!GetToken(true)) {
    2681               0 :         break; // EOF ok here
    2682                 :       }
    2683             110 :       combinator = PRUnichar(' ');
    2684                 :     }
    2685                 : 
    2686             110 :     if (mToken.mType != eCSSToken_Symbol) {
    2687               0 :       UngetToken(); // not a combinator
    2688                 :     } else {
    2689             110 :       PRUnichar symbol = mToken.mSymbol;
    2690             110 :       if (symbol == '+' || symbol == '>' || symbol == '~') {
    2691             110 :         combinator = mToken.mSymbol;
    2692                 :       } else {
    2693               0 :         UngetToken(); // not a combinator
    2694               0 :         if (symbol == ',' || symbol == '{' || symbol == ')') {
    2695               0 :           break; // end of selector group
    2696                 :         }
    2697                 :       }
    2698                 :     }
    2699                 : 
    2700             110 :     if (!combinator) {
    2701               0 :       REPORT_UNEXPECTED_TOKEN(PESelectorListExtra);
    2702               0 :       return false;
    2703                 :     }
    2704                 :   }
    2705                 : 
    2706             110 :   aList = list.forget();
    2707             110 :   return true;
    2708                 : }
    2709                 : 
    2710                 : #define SEL_MASK_NSPACE   0x01
    2711                 : #define SEL_MASK_ELEM     0x02
    2712                 : #define SEL_MASK_ID       0x04
    2713                 : #define SEL_MASK_CLASS    0x08
    2714                 : #define SEL_MASK_ATTRIB   0x10
    2715                 : #define SEL_MASK_PCLASS   0x20
    2716                 : #define SEL_MASK_PELEM    0x40
    2717                 : 
    2718                 : //
    2719                 : // Parses an ID selector #name
    2720                 : //
    2721                 : CSSParserImpl::nsSelectorParsingStatus
    2722               0 : CSSParserImpl::ParseIDSelector(PRInt32&       aDataMask,
    2723                 :                                nsCSSSelector& aSelector)
    2724                 : {
    2725               0 :   NS_ASSERTION(!mToken.mIdent.IsEmpty(),
    2726                 :                "Empty mIdent in eCSSToken_ID token?");
    2727               0 :   aDataMask |= SEL_MASK_ID;
    2728               0 :   aSelector.AddID(mToken.mIdent);
    2729               0 :   return eSelectorParsingStatus_Continue;
    2730                 : }
    2731                 : 
    2732                 : //
    2733                 : // Parses a class selector .name
    2734                 : //
    2735                 : CSSParserImpl::nsSelectorParsingStatus
    2736               0 : CSSParserImpl::ParseClassSelector(PRInt32&       aDataMask,
    2737                 :                                   nsCSSSelector& aSelector)
    2738                 : {
    2739               0 :   if (! GetToken(false)) { // get ident
    2740               0 :     REPORT_UNEXPECTED_EOF(PEClassSelEOF);
    2741               0 :     return eSelectorParsingStatus_Error;
    2742                 :   }
    2743               0 :   if (eCSSToken_Ident != mToken.mType) {  // malformed selector
    2744               0 :     REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent);
    2745               0 :     UngetToken();
    2746               0 :     return eSelectorParsingStatus_Error;
    2747                 :   }
    2748               0 :   aDataMask |= SEL_MASK_CLASS;
    2749                 : 
    2750               0 :   aSelector.AddClass(mToken.mIdent);
    2751                 : 
    2752               0 :   return eSelectorParsingStatus_Continue;
    2753                 : }
    2754                 : 
    2755                 : //
    2756                 : // Parse a type element selector or a universal selector
    2757                 : // namespace|type or namespace|* or *|* or *
    2758                 : //
    2759                 : CSSParserImpl::nsSelectorParsingStatus
    2760             220 : CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32&       aDataMask,
    2761                 :                                             nsCSSSelector& aSelector,
    2762                 :                                             bool           aIsNegated)
    2763                 : {
    2764             440 :   nsAutoString buffer;
    2765             220 :   if (mToken.IsSymbol('*')) {  // universal element selector, or universal namespace
    2766               0 :     if (ExpectSymbol('|', false)) {  // was namespace
    2767               0 :       aDataMask |= SEL_MASK_NSPACE;
    2768               0 :       aSelector.SetNameSpace(kNameSpaceID_Unknown); // namespace wildcard
    2769                 : 
    2770               0 :       if (! GetToken(false)) {
    2771               0 :         REPORT_UNEXPECTED_EOF(PETypeSelEOF);
    2772               0 :         return eSelectorParsingStatus_Error;
    2773                 :       }
    2774               0 :       if (eCSSToken_Ident == mToken.mType) {  // element name
    2775               0 :         aDataMask |= SEL_MASK_ELEM;
    2776                 : 
    2777               0 :         aSelector.SetTag(mToken.mIdent);
    2778                 :       }
    2779               0 :       else if (mToken.IsSymbol('*')) {  // universal selector
    2780               0 :         aDataMask |= SEL_MASK_ELEM;
    2781                 :         // don't set tag
    2782                 :       }
    2783                 :       else {
    2784               0 :         REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
    2785               0 :         UngetToken();
    2786               0 :         return eSelectorParsingStatus_Error;
    2787                 :       }
    2788                 :     }
    2789                 :     else {  // was universal element selector
    2790               0 :       SetDefaultNamespaceOnSelector(aSelector);
    2791               0 :       aDataMask |= SEL_MASK_ELEM;
    2792                 :       // don't set any tag in the selector
    2793                 :     }
    2794               0 :     if (! GetToken(false)) {   // premature eof is ok (here!)
    2795               0 :       return eSelectorParsingStatus_Done;
    2796                 :     }
    2797                 :   }
    2798             220 :   else if (eCSSToken_Ident == mToken.mType) {    // element name or namespace name
    2799             220 :     buffer = mToken.mIdent; // hang on to ident
    2800                 : 
    2801             220 :     if (ExpectSymbol('|', false)) {  // was namespace
    2802               0 :       aDataMask |= SEL_MASK_NSPACE;
    2803               0 :       PRInt32 nameSpaceID = GetNamespaceIdForPrefix(buffer);
    2804               0 :       if (nameSpaceID == kNameSpaceID_Unknown) {
    2805               0 :         return eSelectorParsingStatus_Error;
    2806                 :       }
    2807               0 :       aSelector.SetNameSpace(nameSpaceID);
    2808                 : 
    2809               0 :       if (! GetToken(false)) {
    2810               0 :         REPORT_UNEXPECTED_EOF(PETypeSelEOF);
    2811               0 :         return eSelectorParsingStatus_Error;
    2812                 :       }
    2813               0 :       if (eCSSToken_Ident == mToken.mType) {  // element name
    2814               0 :         aDataMask |= SEL_MASK_ELEM;
    2815               0 :         aSelector.SetTag(mToken.mIdent);
    2816                 :       }
    2817               0 :       else if (mToken.IsSymbol('*')) {  // universal selector
    2818               0 :         aDataMask |= SEL_MASK_ELEM;
    2819                 :         // don't set tag
    2820                 :       }
    2821                 :       else {
    2822               0 :         REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
    2823               0 :         UngetToken();
    2824               0 :         return eSelectorParsingStatus_Error;
    2825                 :       }
    2826                 :     }
    2827                 :     else {  // was element name
    2828             220 :       SetDefaultNamespaceOnSelector(aSelector);
    2829             220 :       aSelector.SetTag(buffer);
    2830                 : 
    2831             220 :       aDataMask |= SEL_MASK_ELEM;
    2832                 :     }
    2833             220 :     if (! GetToken(false)) {   // premature eof is ok (here!)
    2834             110 :       return eSelectorParsingStatus_Done;
    2835                 :     }
    2836                 :   }
    2837               0 :   else if (mToken.IsSymbol('|')) {  // No namespace
    2838               0 :     aDataMask |= SEL_MASK_NSPACE;
    2839               0 :     aSelector.SetNameSpace(kNameSpaceID_None);  // explicit NO namespace
    2840                 : 
    2841                 :     // get mandatory tag
    2842               0 :     if (! GetToken(false)) {
    2843               0 :       REPORT_UNEXPECTED_EOF(PETypeSelEOF);
    2844               0 :       return eSelectorParsingStatus_Error;
    2845                 :     }
    2846               0 :     if (eCSSToken_Ident == mToken.mType) {  // element name
    2847               0 :       aDataMask |= SEL_MASK_ELEM;
    2848               0 :       aSelector.SetTag(mToken.mIdent);
    2849                 :     }
    2850               0 :     else if (mToken.IsSymbol('*')) {  // universal selector
    2851               0 :       aDataMask |= SEL_MASK_ELEM;
    2852                 :       // don't set tag
    2853                 :     }
    2854                 :     else {
    2855               0 :       REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
    2856               0 :       UngetToken();
    2857               0 :       return eSelectorParsingStatus_Error;
    2858                 :     }
    2859               0 :     if (! GetToken(false)) {   // premature eof is ok (here!)
    2860               0 :       return eSelectorParsingStatus_Done;
    2861                 :     }
    2862                 :   }
    2863                 :   else {
    2864               0 :     SetDefaultNamespaceOnSelector(aSelector);
    2865                 :   }
    2866                 : 
    2867             110 :   if (aIsNegated) {
    2868                 :     // restore last token read in case of a negated type selector
    2869               0 :     UngetToken();
    2870                 :   }
    2871             110 :   return eSelectorParsingStatus_Continue;
    2872                 : }
    2873                 : 
    2874                 : //
    2875                 : // Parse attribute selectors [attr], [attr=value], [attr|=value],
    2876                 : // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
    2877                 : //
    2878                 : CSSParserImpl::nsSelectorParsingStatus
    2879               0 : CSSParserImpl::ParseAttributeSelector(PRInt32&       aDataMask,
    2880                 :                                       nsCSSSelector& aSelector)
    2881                 : {
    2882               0 :   if (! GetToken(true)) { // premature EOF
    2883               0 :     REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
    2884               0 :     return eSelectorParsingStatus_Error;
    2885                 :   }
    2886                 : 
    2887               0 :   PRInt32 nameSpaceID = kNameSpaceID_None;
    2888               0 :   nsAutoString  attr;
    2889               0 :   if (mToken.IsSymbol('*')) { // wildcard namespace
    2890               0 :     nameSpaceID = kNameSpaceID_Unknown;
    2891               0 :     if (ExpectSymbol('|', false)) {
    2892               0 :       if (! GetToken(false)) { // premature EOF
    2893               0 :         REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
    2894               0 :         return eSelectorParsingStatus_Error;
    2895                 :       }
    2896               0 :       if (eCSSToken_Ident == mToken.mType) { // attr name
    2897               0 :         attr = mToken.mIdent;
    2898                 :       }
    2899                 :       else {
    2900               0 :         REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
    2901               0 :         UngetToken();
    2902               0 :         return eSelectorParsingStatus_Error;
    2903                 :        }
    2904                 :     }
    2905                 :     else {
    2906               0 :       REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar);
    2907               0 :       return eSelectorParsingStatus_Error;
    2908                 :     }
    2909                 :   }
    2910               0 :   else if (mToken.IsSymbol('|')) { // NO namespace
    2911               0 :     if (! GetToken(false)) { // premature EOF
    2912               0 :       REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
    2913               0 :       return eSelectorParsingStatus_Error;
    2914                 :     }
    2915               0 :     if (eCSSToken_Ident == mToken.mType) { // attr name
    2916               0 :       attr = mToken.mIdent;
    2917                 :     }
    2918                 :     else {
    2919               0 :       REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
    2920               0 :       UngetToken();
    2921               0 :       return eSelectorParsingStatus_Error;
    2922                 :     }
    2923                 :   }
    2924               0 :   else if (eCSSToken_Ident == mToken.mType) { // attr name or namespace
    2925               0 :     attr = mToken.mIdent; // hang on to it
    2926               0 :     if (ExpectSymbol('|', false)) {  // was a namespace
    2927               0 :       nameSpaceID = GetNamespaceIdForPrefix(attr);
    2928               0 :       if (nameSpaceID == kNameSpaceID_Unknown) {
    2929               0 :         return eSelectorParsingStatus_Error;
    2930                 :       }
    2931               0 :       if (! GetToken(false)) { // premature EOF
    2932               0 :         REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
    2933               0 :         return eSelectorParsingStatus_Error;
    2934                 :       }
    2935               0 :       if (eCSSToken_Ident == mToken.mType) { // attr name
    2936               0 :         attr = mToken.mIdent;
    2937                 :       }
    2938                 :       else {
    2939               0 :         REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
    2940               0 :         UngetToken();
    2941               0 :         return eSelectorParsingStatus_Error;
    2942                 :       }
    2943                 :     }
    2944                 :   }
    2945                 :   else {  // malformed
    2946               0 :     REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected);
    2947               0 :     UngetToken();
    2948               0 :     return eSelectorParsingStatus_Error;
    2949                 :   }
    2950                 : 
    2951               0 :   if (! GetToken(true)) { // premature EOF
    2952               0 :     REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF);
    2953               0 :     return eSelectorParsingStatus_Error;
    2954                 :   }
    2955               0 :   if ((eCSSToken_Symbol == mToken.mType) ||
    2956                 :       (eCSSToken_Includes == mToken.mType) ||
    2957                 :       (eCSSToken_Dashmatch == mToken.mType) ||
    2958                 :       (eCSSToken_Beginsmatch == mToken.mType) ||
    2959                 :       (eCSSToken_Endsmatch == mToken.mType) ||
    2960                 :       (eCSSToken_Containsmatch == mToken.mType)) {
    2961                 :     PRUint8 func;
    2962               0 :     if (eCSSToken_Includes == mToken.mType) {
    2963               0 :       func = NS_ATTR_FUNC_INCLUDES;
    2964                 :     }
    2965               0 :     else if (eCSSToken_Dashmatch == mToken.mType) {
    2966               0 :       func = NS_ATTR_FUNC_DASHMATCH;
    2967                 :     }
    2968               0 :     else if (eCSSToken_Beginsmatch == mToken.mType) {
    2969               0 :       func = NS_ATTR_FUNC_BEGINSMATCH;
    2970                 :     }
    2971               0 :     else if (eCSSToken_Endsmatch == mToken.mType) {
    2972               0 :       func = NS_ATTR_FUNC_ENDSMATCH;
    2973                 :     }
    2974               0 :     else if (eCSSToken_Containsmatch == mToken.mType) {
    2975               0 :       func = NS_ATTR_FUNC_CONTAINSMATCH;
    2976                 :     }
    2977               0 :     else if (']' == mToken.mSymbol) {
    2978               0 :       aDataMask |= SEL_MASK_ATTRIB;
    2979               0 :       aSelector.AddAttribute(nameSpaceID, attr);
    2980               0 :       func = NS_ATTR_FUNC_SET;
    2981                 :     }
    2982               0 :     else if ('=' == mToken.mSymbol) {
    2983               0 :       func = NS_ATTR_FUNC_EQUALS;
    2984                 :     }
    2985                 :     else {
    2986               0 :       REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);
    2987               0 :       UngetToken(); // bad function
    2988               0 :       return eSelectorParsingStatus_Error;
    2989                 :     }
    2990               0 :     if (NS_ATTR_FUNC_SET != func) { // get value
    2991               0 :       if (! GetToken(true)) { // premature EOF
    2992               0 :         REPORT_UNEXPECTED_EOF(PEAttSelValueEOF);
    2993               0 :         return eSelectorParsingStatus_Error;
    2994                 :       }
    2995               0 :       if ((eCSSToken_Ident == mToken.mType) || (eCSSToken_String == mToken.mType)) {
    2996               0 :         nsAutoString  value(mToken.mIdent);
    2997               0 :         if (! GetToken(true)) { // premature EOF
    2998               0 :           REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF);
    2999               0 :           return eSelectorParsingStatus_Error;
    3000                 :         }
    3001               0 :         if (mToken.IsSymbol(']')) {
    3002               0 :           bool isCaseSensitive = true;
    3003                 : 
    3004                 :           // For cases when this style sheet is applied to an HTML
    3005                 :           // element in an HTML document, and the attribute selector is
    3006                 :           // for a non-namespaced attribute, then check to see if it's
    3007                 :           // one of the known attributes whose VALUE is
    3008                 :           // case-insensitive.
    3009               0 :           if (nameSpaceID == kNameSpaceID_None) {
    3010                 :             static const char* caseInsensitiveHTMLAttribute[] = {
    3011                 :               // list based on http://www.w3.org/TR/html4/
    3012                 :               "lang",
    3013                 :               "dir",
    3014                 :               "http-equiv",
    3015                 :               "text",
    3016                 :               "link",
    3017                 :               "vlink",
    3018                 :               "alink",
    3019                 :               "compact",
    3020                 :               "align",
    3021                 :               "frame",
    3022                 :               "rules",
    3023                 :               "valign",
    3024                 :               "scope",
    3025                 :               "axis",
    3026                 :               "nowrap",
    3027                 :               "hreflang",
    3028                 :               "rel",
    3029                 :               "rev",
    3030                 :               "charset",
    3031                 :               "codetype",
    3032                 :               "declare",
    3033                 :               "valuetype",
    3034                 :               "shape",
    3035                 :               "nohref",
    3036                 :               "media",
    3037                 :               "bgcolor",
    3038                 :               "clear",
    3039                 :               "color",
    3040                 :               "face",
    3041                 :               "noshade",
    3042                 :               "noresize",
    3043                 :               "scrolling",
    3044                 :               "target",
    3045                 :               "method",
    3046                 :               "enctype",
    3047                 :               "accept-charset",
    3048                 :               "accept",
    3049                 :               "checked",
    3050                 :               "multiple",
    3051                 :               "selected",
    3052                 :               "disabled",
    3053                 :               "readonly",
    3054                 :               "language",
    3055                 :               "defer",
    3056                 :               "type",
    3057                 :               // additional attributes not in HTML4
    3058                 :               "direction", // marquee
    3059                 :               nsnull
    3060                 :             };
    3061               0 :             short i = 0;
    3062                 :             const char* htmlAttr;
    3063               0 :             while ((htmlAttr = caseInsensitiveHTMLAttribute[i++])) {
    3064               0 :               if (attr.LowerCaseEqualsASCII(htmlAttr)) {
    3065               0 :                 isCaseSensitive = false;
    3066               0 :                 break;
    3067                 :               }
    3068                 :             }
    3069                 :           }
    3070               0 :           aDataMask |= SEL_MASK_ATTRIB;
    3071               0 :           aSelector.AddAttribute(nameSpaceID, attr, func, value, isCaseSensitive);
    3072                 :         }
    3073                 :         else {
    3074               0 :           REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose);
    3075               0 :           UngetToken();
    3076               0 :           return eSelectorParsingStatus_Error;
    3077                 :         }
    3078                 :       }
    3079                 :       else {
    3080               0 :         REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue);
    3081               0 :         UngetToken();
    3082               0 :         return eSelectorParsingStatus_Error;
    3083                 :       }
    3084                 :     }
    3085                 :   }
    3086                 :   else {
    3087               0 :     REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);
    3088               0 :     UngetToken(); // bad dog, no biscut!
    3089               0 :     return eSelectorParsingStatus_Error;
    3090                 :    }
    3091               0 :    return eSelectorParsingStatus_Continue;
    3092                 : }
    3093                 : 
    3094                 : //
    3095                 : // Parse pseudo-classes and pseudo-elements
    3096                 : //
    3097                 : CSSParserImpl::nsSelectorParsingStatus
    3098               0 : CSSParserImpl::ParsePseudoSelector(PRInt32&       aDataMask,
    3099                 :                                    nsCSSSelector& aSelector,
    3100                 :                                    bool           aIsNegated,
    3101                 :                                    nsIAtom**      aPseudoElement,
    3102                 :                                    nsAtomList**   aPseudoElementArgs,
    3103                 :                                    nsCSSPseudoElements::Type* aPseudoElementType)
    3104                 : {
    3105               0 :   NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs),
    3106                 :                "expected location to store pseudo element");
    3107               0 :   NS_ASSERTION(!aIsNegated || (!aPseudoElement && !aPseudoElementArgs),
    3108                 :                "negated selectors shouldn't have a place to store "
    3109                 :                "pseudo elements");
    3110               0 :   if (! GetToken(false)) { // premature eof
    3111               0 :     REPORT_UNEXPECTED_EOF(PEPseudoSelEOF);
    3112               0 :     return eSelectorParsingStatus_Error;
    3113                 :   }
    3114                 : 
    3115                 :   // First, find out whether we are parsing a CSS3 pseudo-element
    3116               0 :   bool parsingPseudoElement = false;
    3117               0 :   if (mToken.IsSymbol(':')) {
    3118               0 :     parsingPseudoElement = true;
    3119               0 :     if (! GetToken(false)) { // premature eof
    3120               0 :       REPORT_UNEXPECTED_EOF(PEPseudoSelEOF);
    3121               0 :       return eSelectorParsingStatus_Error;
    3122                 :     }
    3123                 :   }
    3124                 : 
    3125                 :   // Do some sanity-checking on the token
    3126               0 :   if (eCSSToken_Ident != mToken.mType && eCSSToken_Function != mToken.mType) {
    3127                 :     // malformed selector
    3128               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName);
    3129               0 :     UngetToken();
    3130               0 :     return eSelectorParsingStatus_Error;
    3131                 :   }
    3132                 : 
    3133                 :   // OK, now we know we have an mIdent.  Atomize it.  All the atoms, for
    3134                 :   // pseudo-classes as well as pseudo-elements, start with a single ':'.
    3135               0 :   nsAutoString buffer;
    3136               0 :   buffer.Append(PRUnichar(':'));
    3137               0 :   buffer.Append(mToken.mIdent);
    3138               0 :   nsContentUtils::ASCIIToLower(buffer);
    3139               0 :   nsCOMPtr<nsIAtom> pseudo = do_GetAtom(buffer);
    3140               0 :   if (!pseudo) {
    3141               0 :     NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
    3142                 :   }
    3143                 : 
    3144                 :   // stash away some info about this pseudo so we only have to get it once.
    3145               0 :   bool isTreePseudo = false;
    3146                 :   nsCSSPseudoElements::Type pseudoElementType =
    3147               0 :     nsCSSPseudoElements::GetPseudoType(pseudo);
    3148                 : #ifdef MOZ_XUL
    3149               0 :   isTreePseudo = (pseudoElementType == nsCSSPseudoElements::ePseudo_XULTree);
    3150                 :   // If a tree pseudo-element is using the function syntax, it will
    3151                 :   // get isTree set here and will pass the check below that only
    3152                 :   // allows functions if they are in our list of things allowed to be
    3153                 :   // functions.  If it is _not_ using the function syntax, isTree will
    3154                 :   // be false, and it will still pass that check.  So the tree
    3155                 :   // pseudo-elements are allowed to be either functions or not, as
    3156                 :   // desired.
    3157               0 :   bool isTree = (eCSSToken_Function == mToken.mType) && isTreePseudo;
    3158                 : #endif
    3159                 :   bool isPseudoElement =
    3160               0 :     (pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount);
    3161                 :   // anonymous boxes are only allowed if they're the tree boxes or we have
    3162                 :   // enabled unsafe rules
    3163                 :   bool isAnonBox = isTreePseudo ||
    3164                 :     (pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox &&
    3165               0 :      mUnsafeRulesEnabled);
    3166                 :   nsCSSPseudoClasses::Type pseudoClassType =
    3167               0 :     nsCSSPseudoClasses::GetPseudoType(pseudo);
    3168                 :   bool isPseudoClass =
    3169               0 :     (pseudoClassType != nsCSSPseudoClasses::ePseudoClass_NotPseudoClass);
    3170                 : 
    3171               0 :   NS_ASSERTION(!isPseudoClass ||
    3172                 :                pseudoElementType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
    3173                 :                "Why is this atom both a pseudo-class and a pseudo-element?");
    3174               0 :   NS_ASSERTION(isPseudoClass + isPseudoElement + isAnonBox <= 1,
    3175                 :                "Shouldn't be more than one of these");
    3176                 : 
    3177               0 :   if (!isPseudoClass && !isPseudoElement && !isAnonBox) {
    3178                 :     // Not a pseudo-class, not a pseudo-element.... forget it
    3179               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown);
    3180               0 :     UngetToken();
    3181               0 :     return eSelectorParsingStatus_Error;
    3182                 :   }
    3183                 : 
    3184                 :   // If it's a function token, it better be on our "ok" list, and if the name
    3185                 :   // is that of a function pseudo it better be a function token
    3186               0 :   if ((eCSSToken_Function == mToken.mType) !=
    3187                 :       (
    3188                 : #ifdef MOZ_XUL
    3189                 :        isTree ||
    3190                 : #endif
    3191                 :        nsCSSPseudoClasses::ePseudoClass_notPseudo == pseudoClassType ||
    3192               0 :        nsCSSPseudoClasses::HasStringArg(pseudoClassType) ||
    3193               0 :        nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) ||
    3194               0 :        nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType))) {
    3195                 :     // There are no other function pseudos
    3196               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc);
    3197               0 :     UngetToken();
    3198               0 :     return eSelectorParsingStatus_Error;
    3199                 :   }
    3200                 : 
    3201                 :   // If it starts with "::", it better be a pseudo-element
    3202               0 :   if (parsingPseudoElement &&
    3203               0 :       !isPseudoElement &&
    3204               0 :       !isAnonBox) {
    3205               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE);
    3206               0 :     UngetToken();
    3207               0 :     return eSelectorParsingStatus_Error;
    3208                 :   }
    3209                 : 
    3210               0 :   if (!parsingPseudoElement &&
    3211                 :       nsCSSPseudoClasses::ePseudoClass_notPseudo == pseudoClassType) {
    3212               0 :     if (aIsNegated) { // :not() can't be itself negated
    3213               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);
    3214               0 :       UngetToken();
    3215               0 :       return eSelectorParsingStatus_Error;
    3216                 :     }
    3217                 :     // CSS 3 Negation pseudo-class takes one simple selector as argument
    3218                 :     nsSelectorParsingStatus parsingStatus =
    3219               0 :       ParseNegatedSimpleSelector(aDataMask, aSelector);
    3220               0 :     if (eSelectorParsingStatus_Continue != parsingStatus) {
    3221               0 :       return parsingStatus;
    3222               0 :     }
    3223                 :   }
    3224               0 :   else if (!parsingPseudoElement && isPseudoClass) {
    3225               0 :     aDataMask |= SEL_MASK_PCLASS;
    3226               0 :     if (eCSSToken_Function == mToken.mType) {
    3227                 :       nsSelectorParsingStatus parsingStatus;
    3228               0 :       if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) {
    3229                 :         parsingStatus =
    3230               0 :           ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
    3231                 :       }
    3232               0 :       else if (nsCSSPseudoClasses::HasNthPairArg(pseudoClassType)) {
    3233                 :         parsingStatus =
    3234               0 :           ParsePseudoClassWithNthPairArg(aSelector, pseudoClassType);
    3235                 :       }
    3236                 :       else {
    3237               0 :         NS_ABORT_IF_FALSE(nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType),
    3238                 :                           "unexpected pseudo with function token");
    3239                 :         parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector,
    3240               0 :                                                             pseudoClassType);
    3241                 :       }
    3242               0 :       if (eSelectorParsingStatus_Continue != parsingStatus) {
    3243               0 :         if (eSelectorParsingStatus_Error == parsingStatus) {
    3244               0 :           SkipUntil(')');
    3245                 :         }
    3246               0 :         return parsingStatus;
    3247                 :       }
    3248                 :     }
    3249                 :     else {
    3250               0 :       aSelector.AddPseudoClass(pseudoClassType);
    3251               0 :     }
    3252                 :   }
    3253               0 :   else if (isPseudoElement || isAnonBox) {
    3254                 :     // Pseudo-element.  Make some more sanity checks.
    3255                 : 
    3256               0 :     if (aIsNegated) { // pseudo-elements can't be negated
    3257               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot);
    3258               0 :       UngetToken();
    3259               0 :       return eSelectorParsingStatus_Error;
    3260                 :     }
    3261                 :     // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
    3262                 :     // to have a single ':' on them.  Others (CSS3+ pseudo-elements and
    3263                 :     // various -moz-* pseudo-elements) must have |parsingPseudoElement|
    3264                 :     // set.
    3265               0 :     if (!parsingPseudoElement &&
    3266               0 :         !nsCSSPseudoElements::IsCSS2PseudoElement(pseudo)
    3267                 : #ifdef MOZ_XUL
    3268               0 :         && !isTreePseudo
    3269                 : #endif
    3270                 :         ) {
    3271               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly);
    3272               0 :       UngetToken();
    3273               0 :       return eSelectorParsingStatus_Error;
    3274                 :     }
    3275                 : 
    3276               0 :     if (0 == (aDataMask & SEL_MASK_PELEM)) {
    3277               0 :       aDataMask |= SEL_MASK_PELEM;
    3278               0 :       NS_ADDREF(*aPseudoElement = pseudo);
    3279               0 :       *aPseudoElementType = pseudoElementType;
    3280                 : 
    3281                 : #ifdef MOZ_XUL
    3282               0 :       if (isTree) {
    3283                 :         // We have encountered a pseudoelement of the form
    3284                 :         // -moz-tree-xxxx(a,b,c).  We parse (a,b,c) and add each
    3285                 :         // item in the list to the pseudoclass list.  They will be pulled
    3286                 :         // from the list later along with the pseudo-element.
    3287               0 :         if (!ParseTreePseudoElement(aPseudoElementArgs)) {
    3288               0 :           return eSelectorParsingStatus_Error;
    3289                 :         }
    3290                 :       }
    3291                 : #endif
    3292                 : 
    3293                 :       // the next *non*whitespace token must be '{' or ',' or EOF
    3294               0 :       if (!GetToken(true)) { // premature eof is ok (here!)
    3295               0 :         return eSelectorParsingStatus_Done;
    3296                 :       }
    3297               0 :       if ((mToken.IsSymbol('{') || mToken.IsSymbol(','))) {
    3298               0 :         UngetToken();
    3299               0 :         return eSelectorParsingStatus_Done;
    3300                 :       }
    3301               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing);
    3302               0 :       UngetToken();
    3303               0 :       return eSelectorParsingStatus_Error;
    3304                 :     }
    3305                 :     else {  // multiple pseudo elements, not legal
    3306               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE);
    3307               0 :       UngetToken();
    3308               0 :       return eSelectorParsingStatus_Error;
    3309                 :     }
    3310                 :   }
    3311                 : #ifdef DEBUG
    3312                 :   else {
    3313                 :     // We should never end up here.  Indeed, if we ended up here, we know (from
    3314                 :     // the current if/else cascade) that !isPseudoElement and !isAnonBox.  But
    3315                 :     // then due to our earlier check we know that isPseudoClass.  Since we
    3316                 :     // didn't fall into the isPseudoClass case in this cascade, we must have
    3317                 :     // parsingPseudoElement.  But we've already checked the
    3318                 :     // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if
    3319                 :     // it's happened.
    3320               0 :     NS_NOTREACHED("How did this happen?");
    3321                 :   }
    3322                 : #endif
    3323               0 :   return eSelectorParsingStatus_Continue;
    3324                 : }
    3325                 : 
    3326                 : //
    3327                 : // Parse the argument of a negation pseudo-class :not()
    3328                 : //
    3329                 : CSSParserImpl::nsSelectorParsingStatus
    3330               0 : CSSParserImpl::ParseNegatedSimpleSelector(PRInt32&       aDataMask,
    3331                 :                                           nsCSSSelector& aSelector)
    3332                 : {
    3333               0 :   if (! GetToken(true)) { // premature eof
    3334               0 :     REPORT_UNEXPECTED_EOF(PENegationEOF);
    3335               0 :     return eSelectorParsingStatus_Error;
    3336                 :   }
    3337                 : 
    3338               0 :   if (mToken.IsSymbol(')')) {
    3339               0 :     REPORT_UNEXPECTED_TOKEN(PENegationBadArg);
    3340               0 :     return eSelectorParsingStatus_Error;
    3341                 :   }
    3342                 : 
    3343                 :   // Create a new nsCSSSelector and add it to the end of
    3344                 :   // aSelector.mNegations.
    3345                 :   // Given the current parsing rules, every selector in mNegations
    3346                 :   // contains only one simple selector (css3 definition) within it.
    3347                 :   // This could easily change in future versions of CSS, and the only
    3348                 :   // thing we need to change to support that is this parsing code and the
    3349                 :   // serialization code for nsCSSSelector.
    3350               0 :   nsCSSSelector *newSel = new nsCSSSelector();
    3351               0 :   nsCSSSelector* negations = &aSelector;
    3352               0 :   while (negations->mNegations) {
    3353               0 :     negations = negations->mNegations;
    3354                 :   }
    3355               0 :   negations->mNegations = newSel;
    3356                 : 
    3357                 :   nsSelectorParsingStatus parsingStatus;
    3358               0 :   if (eCSSToken_ID == mToken.mType) { // #id
    3359               0 :     parsingStatus = ParseIDSelector(aDataMask, *newSel);
    3360                 :   }
    3361               0 :   else if (mToken.IsSymbol('.')) {    // .class
    3362               0 :     parsingStatus = ParseClassSelector(aDataMask, *newSel);
    3363                 :   }
    3364               0 :   else if (mToken.IsSymbol(':')) {    // :pseudo
    3365                 :     parsingStatus = ParsePseudoSelector(aDataMask, *newSel, true,
    3366               0 :                                         nsnull, nsnull, nsnull);
    3367                 :   }
    3368               0 :   else if (mToken.IsSymbol('[')) {    // [attribute
    3369               0 :     parsingStatus = ParseAttributeSelector(aDataMask, *newSel);
    3370               0 :     if (eSelectorParsingStatus_Error == parsingStatus) {
    3371                 :       // Skip forward to the matching ']'
    3372               0 :       SkipUntil(']');
    3373                 :     }
    3374                 :   }
    3375                 :   else {
    3376                 :     // then it should be a type element or universal selector
    3377               0 :     parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, true);
    3378                 :   }
    3379               0 :   if (eSelectorParsingStatus_Error == parsingStatus) {
    3380               0 :     REPORT_UNEXPECTED_TOKEN(PENegationBadInner);
    3381               0 :     SkipUntil(')');
    3382               0 :     return parsingStatus;
    3383                 :   }
    3384                 :   // close the parenthesis
    3385               0 :   if (!ExpectSymbol(')', true)) {
    3386               0 :     REPORT_UNEXPECTED_TOKEN(PENegationNoClose);
    3387               0 :     SkipUntil(')');
    3388               0 :     return eSelectorParsingStatus_Error;
    3389                 :   }
    3390                 : 
    3391               0 :   NS_ASSERTION(newSel->mNameSpace == kNameSpaceID_Unknown ||
    3392                 :                (!newSel->mIDList && !newSel->mClassList &&
    3393                 :                 !newSel->mPseudoClassList && !newSel->mAttrList),
    3394                 :                "Need to fix the serialization code to deal with this");
    3395                 : 
    3396               0 :   return eSelectorParsingStatus_Continue;
    3397                 : }
    3398                 : 
    3399                 : //
    3400                 : // Parse the argument of a pseudo-class that has an ident arg
    3401                 : //
    3402                 : CSSParserImpl::nsSelectorParsingStatus
    3403               0 : CSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector,
    3404                 :                                             nsCSSPseudoClasses::Type aType)
    3405                 : {
    3406               0 :   if (! GetToken(true)) { // premature eof
    3407               0 :     REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);
    3408               0 :     return eSelectorParsingStatus_Error;
    3409                 :   }
    3410                 :   // We expect an identifier with a language abbreviation
    3411               0 :   if (eCSSToken_Ident != mToken.mType) {
    3412               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent);
    3413               0 :     UngetToken();
    3414               0 :     return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3415                 :   }
    3416                 : 
    3417                 :   // -moz-locale-dir can only have values of 'ltr' or 'rtl'.
    3418               0 :   if (aType == nsCSSPseudoClasses::ePseudoClass_mozLocaleDir) {
    3419               0 :     if (!mToken.mIdent.EqualsLiteral("ltr") &&
    3420               0 :         !mToken.mIdent.EqualsLiteral("rtl")) {
    3421               0 :       return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3422                 :     }
    3423                 :   }
    3424                 : 
    3425                 :   // Add the pseudo with the language parameter
    3426               0 :   aSelector.AddPseudoClass(aType, mToken.mIdent.get());
    3427                 : 
    3428                 :   // close the parenthesis
    3429               0 :   if (!ExpectSymbol(')', true)) {
    3430               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);
    3431               0 :     return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3432                 :   }
    3433                 : 
    3434               0 :   return eSelectorParsingStatus_Continue;
    3435                 : }
    3436                 : 
    3437                 : CSSParserImpl::nsSelectorParsingStatus
    3438               0 : CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector,
    3439                 :                                               nsCSSPseudoClasses::Type aType)
    3440                 : {
    3441               0 :   PRInt32 numbers[2] = { 0, 0 };
    3442               0 :   bool lookForB = true;
    3443                 : 
    3444                 :   // Follow the whitespace rules as proposed in
    3445                 :   // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
    3446                 : 
    3447               0 :   if (! GetToken(true)) {
    3448               0 :     REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);
    3449               0 :     return eSelectorParsingStatus_Error;
    3450                 :   }
    3451                 : 
    3452               0 :   if (eCSSToken_Ident == mToken.mType || eCSSToken_Dimension == mToken.mType) {
    3453                 :     // The CSS tokenization doesn't handle :nth-child() containing - well:
    3454                 :     //   2n-1 is a dimension
    3455                 :     //   n-1 is an identifier
    3456                 :     // The easiest way to deal with that is to push everything from the
    3457                 :     // minus on back onto the scanner's pushback buffer.
    3458               0 :     PRUint32 truncAt = 0;
    3459               0 :     if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("n-"))) {
    3460               0 :       truncAt = 1;
    3461               0 :     } else if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("-n-"))) {
    3462               0 :       truncAt = 2;
    3463                 :     }
    3464               0 :     if (truncAt != 0) {
    3465               0 :       for (PRUint32 i = mToken.mIdent.Length() - 1; i >= truncAt; --i) {
    3466               0 :         mScanner.Pushback(mToken.mIdent[i]);
    3467                 :       }
    3468               0 :       mToken.mIdent.Truncate(truncAt);
    3469                 :     }
    3470                 :   }
    3471                 : 
    3472               0 :   if (eCSSToken_Ident == mToken.mType) {
    3473               0 :     if (mToken.mIdent.LowerCaseEqualsLiteral("odd")) {
    3474               0 :       numbers[0] = 2;
    3475               0 :       numbers[1] = 1;
    3476               0 :       lookForB = false;
    3477                 :     }
    3478               0 :     else if (mToken.mIdent.LowerCaseEqualsLiteral("even")) {
    3479               0 :       numbers[0] = 2;
    3480               0 :       numbers[1] = 0;
    3481               0 :       lookForB = false;
    3482                 :     }
    3483               0 :     else if (mToken.mIdent.LowerCaseEqualsLiteral("n")) {
    3484               0 :       numbers[0] = 1;
    3485                 :     }
    3486               0 :     else if (mToken.mIdent.LowerCaseEqualsLiteral("-n")) {
    3487               0 :       numbers[0] = -1;
    3488                 :     }
    3489                 :     else {
    3490               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);
    3491               0 :       return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3492                 :     }
    3493                 :   }
    3494               0 :   else if (eCSSToken_Number == mToken.mType) {
    3495               0 :     if (!mToken.mIntegerValid) {
    3496               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);
    3497               0 :       return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3498                 :     }
    3499               0 :     numbers[1] = mToken.mInteger;
    3500               0 :     lookForB = false;
    3501                 :   }
    3502               0 :   else if (eCSSToken_Dimension == mToken.mType) {
    3503               0 :     if (!mToken.mIntegerValid || !mToken.mIdent.LowerCaseEqualsLiteral("n")) {
    3504               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);
    3505               0 :       return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3506                 :     }
    3507               0 :     numbers[0] = mToken.mInteger;
    3508                 :   }
    3509                 :   // XXX If it's a ')', is that valid?  (as 0n+0)
    3510                 :   else {
    3511               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);
    3512               0 :     UngetToken();
    3513               0 :     return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3514                 :   }
    3515                 : 
    3516               0 :   if (! GetToken(true)) {
    3517               0 :     REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);
    3518               0 :     return eSelectorParsingStatus_Error;
    3519                 :   }
    3520               0 :   if (lookForB && !mToken.IsSymbol(')')) {
    3521                 :     // The '+' or '-' sign can optionally be separated by whitespace.
    3522                 :     // If it is separated by whitespace from what follows it, it appears
    3523                 :     // as a separate token rather than part of the number token.
    3524               0 :     bool haveSign = false;
    3525               0 :     PRInt32 sign = 1;
    3526               0 :     if (mToken.IsSymbol('+') || mToken.IsSymbol('-')) {
    3527               0 :       haveSign = true;
    3528               0 :       if (mToken.IsSymbol('-')) {
    3529               0 :         sign = -1;
    3530                 :       }
    3531               0 :       if (! GetToken(true)) {
    3532               0 :         REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);
    3533               0 :         return eSelectorParsingStatus_Error;
    3534                 :       }
    3535                 :     }
    3536               0 :     if (eCSSToken_Number != mToken.mType ||
    3537               0 :         !mToken.mIntegerValid || mToken.mHasSign == haveSign) {
    3538               0 :       REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth);
    3539               0 :       return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3540                 :     }
    3541               0 :     numbers[1] = mToken.mInteger * sign;
    3542               0 :     if (! GetToken(true)) {
    3543               0 :       REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF);
    3544               0 :       return eSelectorParsingStatus_Error;
    3545                 :     }
    3546                 :   }
    3547               0 :   if (!mToken.IsSymbol(')')) {
    3548               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);
    3549               0 :     return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3550                 :   }
    3551               0 :   aSelector.AddPseudoClass(aType, numbers);
    3552               0 :   return eSelectorParsingStatus_Continue;
    3553                 : }
    3554                 : 
    3555                 : //
    3556                 : // Parse the argument of a pseudo-class that has a selector list argument.
    3557                 : // Such selector lists cannot contain combinators, but can contain
    3558                 : // anything that goes between a pair of combinators.
    3559                 : //
    3560                 : CSSParserImpl::nsSelectorParsingStatus
    3561               0 : CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
    3562                 :                                                    nsCSSPseudoClasses::Type aType)
    3563                 : {
    3564               0 :   nsAutoPtr<nsCSSSelectorList> slist;
    3565               0 :   if (! ParseSelectorList(*getter_Transfers(slist), PRUnichar(')'))) {
    3566               0 :     return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3567                 :   }
    3568                 : 
    3569                 :   // Check that none of the selectors in the list have combinators or
    3570                 :   // pseudo-elements.
    3571               0 :   for (nsCSSSelectorList *l = slist; l; l = l->mNext) {
    3572               0 :     nsCSSSelector *s = l->mSelectors;
    3573               0 :     if (s->mNext || s->IsPseudoElement()) {
    3574               0 :       return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3575                 :     }
    3576                 :   }
    3577                 : 
    3578                 :   // Add the pseudo with the selector list parameter
    3579               0 :   aSelector.AddPseudoClass(aType, slist.forget());
    3580                 : 
    3581                 :   // close the parenthesis
    3582               0 :   if (!ExpectSymbol(')', true)) {
    3583               0 :     REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);
    3584               0 :     return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
    3585                 :   }
    3586                 : 
    3587               0 :   return eSelectorParsingStatus_Continue;
    3588                 : }
    3589                 : 
    3590                 : 
    3591                 : /**
    3592                 :  * This is the format for selectors:
    3593                 :  * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
    3594                 :  */
    3595                 : bool
    3596             220 : CSSParserImpl::ParseSelector(nsCSSSelectorList* aList,
    3597                 :                              PRUnichar aPrevCombinator)
    3598                 : {
    3599             220 :   if (! GetToken(true)) {
    3600               0 :     REPORT_UNEXPECTED_EOF(PESelectorEOF);
    3601               0 :     return false;
    3602                 :   }
    3603                 : 
    3604             220 :   nsCSSSelector* selector = aList->AddSelector(aPrevCombinator);
    3605             440 :   nsCOMPtr<nsIAtom> pseudoElement;
    3606             440 :   nsAutoPtr<nsAtomList> pseudoElementArgs;
    3607                 :   nsCSSPseudoElements::Type pseudoElementType =
    3608             220 :     nsCSSPseudoElements::ePseudo_NotPseudoElement;
    3609                 : 
    3610             220 :   PRInt32 dataMask = 0;
    3611                 :   nsSelectorParsingStatus parsingStatus =
    3612             220 :     ParseTypeOrUniversalSelector(dataMask, *selector, false);
    3613                 : 
    3614             220 :   while (parsingStatus == eSelectorParsingStatus_Continue) {
    3615             110 :     if (eCSSToken_ID == mToken.mType) { // #id
    3616               0 :       parsingStatus = ParseIDSelector(dataMask, *selector);
    3617                 :     }
    3618             110 :     else if (mToken.IsSymbol('.')) {    // .class
    3619               0 :       parsingStatus = ParseClassSelector(dataMask, *selector);
    3620                 :     }
    3621             110 :     else if (mToken.IsSymbol(':')) {    // :pseudo
    3622                 :       parsingStatus = ParsePseudoSelector(dataMask, *selector, false,
    3623               0 :                                           getter_AddRefs(pseudoElement),
    3624                 :                                           getter_Transfers(pseudoElementArgs),
    3625               0 :                                           &pseudoElementType);
    3626                 :     }
    3627             110 :     else if (mToken.IsSymbol('[')) {    // [attribute
    3628               0 :       parsingStatus = ParseAttributeSelector(dataMask, *selector);
    3629               0 :       if (eSelectorParsingStatus_Error == parsingStatus) {
    3630               0 :         SkipUntil(']');
    3631                 :       }
    3632                 :     }
    3633                 :     else {  // not a selector token, we're done
    3634             110 :       parsingStatus = eSelectorParsingStatus_Done;
    3635             110 :       UngetToken();
    3636             110 :       break;
    3637                 :     }
    3638                 : 
    3639               0 :     if (parsingStatus != eSelectorParsingStatus_Continue) {
    3640               0 :       break;
    3641                 :     }
    3642                 : 
    3643               0 :     if (! GetToken(false)) { // premature eof is ok (here!)
    3644               0 :       parsingStatus = eSelectorParsingStatus_Done;
    3645               0 :       break;
    3646                 :     }
    3647                 :   }
    3648                 : 
    3649             220 :   if (parsingStatus == eSelectorParsingStatus_Error) {
    3650               0 :     return false;
    3651                 :   }
    3652                 : 
    3653             220 :   if (!dataMask) {
    3654               0 :     if (selector->mNext) {
    3655               0 :       REPORT_UNEXPECTED(PESelectorGroupExtraCombinator);
    3656                 :     } else {
    3657               0 :       REPORT_UNEXPECTED(PESelectorGroupNoSelector);
    3658                 :     }
    3659               0 :     return false;
    3660                 :   }
    3661                 : 
    3662             220 :   if (pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox) {
    3663                 :     // We got an anonymous box pseudo-element; it must be the only
    3664                 :     // thing in this selector group.
    3665               0 :     if (selector->mNext || !IsUniversalSelector(*selector)) {
    3666               0 :       REPORT_UNEXPECTED(PEAnonBoxNotAlone);
    3667               0 :       return false;
    3668                 :     }
    3669                 : 
    3670                 :     // Rewrite the current selector as this pseudo-element.
    3671                 :     // It does not contribute to selector weight.
    3672               0 :     selector->mLowercaseTag.swap(pseudoElement);
    3673               0 :     selector->mClassList = pseudoElementArgs.forget();
    3674               0 :     selector->SetPseudoType(pseudoElementType);
    3675               0 :     return true;
    3676                 :   }
    3677                 : 
    3678             220 :   aList->mWeight += selector->CalcWeight();
    3679                 : 
    3680                 :   // Pseudo-elements other than anonymous boxes are represented as
    3681                 :   // direct children ('>' combinator) of the rest of the selector.
    3682             220 :   if (pseudoElement) {
    3683               0 :     selector = aList->AddSelector('>');
    3684                 : 
    3685               0 :     selector->mLowercaseTag.swap(pseudoElement);
    3686               0 :     selector->mClassList = pseudoElementArgs.forget();
    3687               0 :     selector->SetPseudoType(pseudoElementType);
    3688                 :   }
    3689                 : 
    3690             220 :   return true;
    3691                 : }
    3692                 : 
    3693                 : css::Declaration*
    3694               0 : CSSParserImpl::ParseDeclarationBlock(bool aCheckForBraces)
    3695                 : {
    3696               0 :   if (aCheckForBraces) {
    3697               0 :     if (!ExpectSymbol('{', true)) {
    3698               0 :       REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart);
    3699               0 :       OUTPUT_ERROR();
    3700               0 :       return nsnull;
    3701                 :     }
    3702                 :   }
    3703               0 :   css::Declaration* declaration = new css::Declaration();
    3704               0 :   mData.AssertInitialState();
    3705               0 :   if (declaration) {
    3706               0 :     for (;;) {
    3707                 :       bool changed;
    3708               0 :       if (!ParseDeclaration(declaration, aCheckForBraces,
    3709               0 :                             true, &changed)) {
    3710               0 :         if (!SkipDeclaration(aCheckForBraces)) {
    3711               0 :           break;
    3712                 :         }
    3713               0 :         if (aCheckForBraces) {
    3714               0 :           if (ExpectSymbol('}', true)) {
    3715               0 :             break;
    3716                 :           }
    3717                 :         }
    3718                 :         // Since the skipped declaration didn't end the block we parse
    3719                 :         // the next declaration.
    3720                 :       }
    3721                 :     }
    3722               0 :     declaration->CompressFrom(&mData);
    3723                 :   }
    3724               0 :   return declaration;
    3725                 : }
    3726                 : 
    3727                 : // The types to pass to ParseColorComponent.  These correspond to the
    3728                 : // various datatypes that can go within rgb().
    3729                 : #define COLOR_TYPE_UNKNOWN 0
    3730                 : #define COLOR_TYPE_INTEGERS 1
    3731                 : #define COLOR_TYPE_PERCENTAGES 2
    3732                 : 
    3733                 : bool
    3734               0 : CSSParserImpl::ParseColor(nsCSSValue& aValue)
    3735                 : {
    3736               0 :   if (!GetToken(true)) {
    3737               0 :     REPORT_UNEXPECTED_EOF(PEColorEOF);
    3738               0 :     return false;
    3739                 :   }
    3740                 : 
    3741               0 :   nsCSSToken* tk = &mToken;
    3742                 :   nscolor rgba;
    3743               0 :   switch (tk->mType) {
    3744                 :     case eCSSToken_ID:
    3745                 :     case eCSSToken_Ref:
    3746                 :       // #xxyyzz
    3747               0 :       if (NS_HexToRGB(tk->mIdent, &rgba)) {
    3748               0 :         aValue.SetColorValue(rgba);
    3749               0 :         return true;
    3750                 :       }
    3751               0 :       break;
    3752                 : 
    3753                 :     case eCSSToken_Ident:
    3754               0 :       if (NS_ColorNameToRGB(tk->mIdent, &rgba)) {
    3755               0 :         aValue.SetStringValue(tk->mIdent, eCSSUnit_Ident);
    3756               0 :         return true;
    3757                 :       }
    3758                 :       else {
    3759               0 :         nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(tk->mIdent);
    3760               0 :         if (eCSSKeyword_UNKNOWN < keyword) { // known keyword
    3761                 :           PRInt32 value;
    3762               0 :           if (nsCSSProps::FindKeyword(keyword, nsCSSProps::kColorKTable, value)) {
    3763               0 :             aValue.SetIntValue(value, eCSSUnit_EnumColor);
    3764               0 :             return true;
    3765                 :           }
    3766                 :         }
    3767                 :       }
    3768               0 :       break;
    3769                 :     case eCSSToken_Function:
    3770               0 :       if (mToken.mIdent.LowerCaseEqualsLiteral("rgb")) {
    3771                 :         // rgb ( component , component , component )
    3772                 :         PRUint8 r, g, b;
    3773               0 :         PRInt32 type = COLOR_TYPE_UNKNOWN;
    3774               0 :         if (ParseColorComponent(r, type, ',') &&
    3775               0 :             ParseColorComponent(g, type, ',') &&
    3776               0 :             ParseColorComponent(b, type, ')')) {
    3777               0 :           aValue.SetColorValue(NS_RGB(r,g,b));
    3778               0 :           return true;
    3779                 :         }
    3780               0 :         SkipUntil(')');
    3781               0 :         return false;
    3782                 :       }
    3783               0 :       else if (mToken.mIdent.LowerCaseEqualsLiteral("-moz-rgba") ||
    3784               0 :                mToken.mIdent.LowerCaseEqualsLiteral("rgba")) {
    3785                 :         // rgba ( component , component , component , opacity )
    3786                 :         PRUint8 r, g, b, a;
    3787               0 :         PRInt32 type = COLOR_TYPE_UNKNOWN;
    3788               0 :         if (ParseColorComponent(r, type, ',') &&
    3789               0 :             ParseColorComponent(g, type, ',') &&
    3790               0 :             ParseColorComponent(b, type, ',') &&
    3791               0 :             ParseColorOpacity(a)) {
    3792               0 :           aValue.SetColorValue(NS_RGBA(r, g, b, a));
    3793               0 :           return true;
    3794                 :         }
    3795               0 :         SkipUntil(')');
    3796               0 :         return false;
    3797                 :       }
    3798               0 :       else if (mToken.mIdent.LowerCaseEqualsLiteral("hsl")) {
    3799                 :         // hsl ( hue , saturation , lightness )
    3800                 :         // "hue" is a number, "saturation" and "lightness" are percentages.
    3801               0 :         if (ParseHSLColor(rgba, ')')) {
    3802               0 :           aValue.SetColorValue(rgba);
    3803               0 :           return true;
    3804                 :         }
    3805               0 :         SkipUntil(')');
    3806               0 :         return false;
    3807                 :       }
    3808               0 :       else if (mToken.mIdent.LowerCaseEqualsLiteral("-moz-hsla") ||
    3809               0 :                mToken.mIdent.LowerCaseEqualsLiteral("hsla")) {
    3810                 :         // hsla ( hue , saturation , lightness , opacity )
    3811                 :         // "hue" is a number, "saturation" and "lightness" are percentages,
    3812                 :         // "opacity" is a number.
    3813                 :         PRUint8 a;
    3814               0 :         if (ParseHSLColor(rgba, ',') &&
    3815               0 :             ParseColorOpacity(a)) {
    3816                 :           aValue.SetColorValue(NS_RGBA(NS_GET_R(rgba), NS_GET_G(rgba),
    3817               0 :                                        NS_GET_B(rgba), a));
    3818               0 :           return true;
    3819                 :         }
    3820               0 :         SkipUntil(')');
    3821               0 :         return false;
    3822                 :       }
    3823               0 :       break;
    3824                 :     default:
    3825               0 :       break;
    3826                 :   }
    3827                 : 
    3828                 :   // try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)
    3829               0 :   if (mNavQuirkMode && !IsParsingCompoundProperty()) {
    3830                 :     // - If the string starts with 'a-f', the nsCSSScanner builds the
    3831                 :     //   token as a eCSSToken_Ident and we can parse the string as a
    3832                 :     //   'xxyyzz' RGB color.
    3833                 :     // - If it only contains '0-9' digits, the token is a
    3834                 :     //   eCSSToken_Number and it must be converted back to a 6
    3835                 :     //   characters string to be parsed as a RGB color.
    3836                 :     // - If it starts with '0-9' and contains any 'a-f', the token is a
    3837                 :     //   eCSSToken_Dimension, the mNumber part must be converted back to
    3838                 :     //   a string and the mIdent part must be appended to that string so
    3839                 :     //   that the resulting string has 6 characters.
    3840                 :     // Note: This is a hack for Nav compatibility.  Do not attempt to
    3841                 :     // simplify it by hacking into the ncCSSScanner.  This would be very
    3842                 :     // bad.
    3843               0 :     nsAutoString str;
    3844                 :     char buffer[20];
    3845               0 :     switch (tk->mType) {
    3846                 :       case eCSSToken_Ident:
    3847               0 :         str.Assign(tk->mIdent);
    3848               0 :         break;
    3849                 : 
    3850                 :       case eCSSToken_Number:
    3851               0 :         if (tk->mIntegerValid) {
    3852               0 :           PR_snprintf(buffer, sizeof(buffer), "%06d", tk->mInteger);
    3853               0 :           str.AssignWithConversion(buffer);
    3854                 :         }
    3855               0 :         break;
    3856                 : 
    3857                 :       case eCSSToken_Dimension:
    3858               0 :         if (tk->mIdent.Length() <= 6) {
    3859               0 :           PR_snprintf(buffer, sizeof(buffer), "%06.0f", tk->mNumber);
    3860               0 :           nsAutoString temp;
    3861               0 :           temp.AssignWithConversion(buffer);
    3862               0 :           temp.Right(str, 6 - tk->mIdent.Length());
    3863               0 :           str.Append(tk->mIdent);
    3864                 :         }
    3865               0 :         break;
    3866                 :       default:
    3867                 :         // There is a whole bunch of cases that are
    3868                 :         // not handled by this switch.  Ignore them.
    3869               0 :         break;
    3870                 :     }
    3871               0 :     if (NS_HexToRGB(str, &rgba)) {
    3872               0 :       aValue.SetColorValue(rgba);
    3873               0 :       return true;
    3874                 :     }
    3875                 :   }
    3876                 : 
    3877                 :   // It's not a color
    3878               0 :   REPORT_UNEXPECTED_TOKEN(PEColorNotColor);
    3879               0 :   UngetToken();
    3880               0 :   return false;
    3881                 : }
    3882                 : 
    3883                 : // aType will be set if we have already parsed other color components
    3884                 : // in this color spec
    3885                 : bool
    3886               0 : CSSParserImpl::ParseColorComponent(PRUint8& aComponent,
    3887                 :                                    PRInt32& aType,
    3888                 :                                    char aStop)
    3889                 : {
    3890               0 :   if (!GetToken(true)) {
    3891               0 :     REPORT_UNEXPECTED_EOF(PEColorComponentEOF);
    3892               0 :     return false;
    3893                 :   }
    3894                 :   float value;
    3895               0 :   nsCSSToken* tk = &mToken;
    3896               0 :   switch (tk->mType) {
    3897                 :   case eCSSToken_Number:
    3898               0 :     switch (aType) {
    3899                 :       case COLOR_TYPE_UNKNOWN:
    3900               0 :         aType = COLOR_TYPE_INTEGERS;
    3901               0 :         break;
    3902                 :       case COLOR_TYPE_INTEGERS:
    3903               0 :         break;
    3904                 :       case COLOR_TYPE_PERCENTAGES:
    3905               0 :         REPORT_UNEXPECTED_TOKEN(PEExpectedPercent);
    3906               0 :         UngetToken();
    3907               0 :         return false;
    3908                 :       default:
    3909               0 :         NS_NOTREACHED("Someone forgot to add the new color component type in here");
    3910                 :     }
    3911                 : 
    3912               0 :     if (!mToken.mIntegerValid) {
    3913               0 :       REPORT_UNEXPECTED_TOKEN(PEExpectedInt);
    3914               0 :       UngetToken();
    3915               0 :       return false;
    3916                 :     }
    3917               0 :     value = tk->mNumber;
    3918               0 :     break;
    3919                 :   case eCSSToken_Percentage:
    3920               0 :     switch (aType) {
    3921                 :       case COLOR_TYPE_UNKNOWN:
    3922               0 :         aType = COLOR_TYPE_PERCENTAGES;
    3923               0 :         break;
    3924                 :       case COLOR_TYPE_INTEGERS:
    3925               0 :         REPORT_UNEXPECTED_TOKEN(PEExpectedInt);
    3926               0 :         UngetToken();
    3927               0 :         return false;
    3928                 :       case COLOR_TYPE_PERCENTAGES:
    3929               0 :         break;
    3930                 :       default:
    3931               0 :         NS_NOTREACHED("Someone forgot to add the new color component type in here");
    3932                 :     }
    3933               0 :     value = tk->mNumber * 255.0f;
    3934               0 :     break;
    3935                 :   default:
    3936               0 :     REPORT_UNEXPECTED_TOKEN(PEColorBadRGBContents);
    3937               0 :     UngetToken();
    3938               0 :     return false;
    3939                 :   }
    3940               0 :   if (ExpectSymbol(aStop, true)) {
    3941               0 :     if (value < 0.0f) value = 0.0f;
    3942               0 :     if (value > 255.0f) value = 255.0f;
    3943               0 :     aComponent = NSToIntRound(value);
    3944               0 :     return true;
    3945                 :   }
    3946               0 :   const PRUnichar stopString[] = { PRUnichar(aStop), PRUnichar(0) };
    3947                 :   const PRUnichar *params[] = {
    3948                 :     nsnull,
    3949                 :     stopString
    3950               0 :   };
    3951               0 :   REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm, params);
    3952               0 :   return false;
    3953                 : }
    3954                 : 
    3955                 : 
    3956                 : bool
    3957               0 : CSSParserImpl::ParseHSLColor(nscolor& aColor,
    3958                 :                              char aStop)
    3959                 : {
    3960                 :   float h, s, l;
    3961                 : 
    3962                 :   // Get the hue
    3963               0 :   if (!GetToken(true)) {
    3964               0 :     REPORT_UNEXPECTED_EOF(PEColorHueEOF);
    3965               0 :     return false;
    3966                 :   }
    3967               0 :   if (mToken.mType != eCSSToken_Number) {
    3968               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedNumber);
    3969               0 :     UngetToken();
    3970               0 :     return false;
    3971                 :   }
    3972               0 :   h = mToken.mNumber;
    3973               0 :   h /= 360.0f;
    3974                 :   // hue values are wraparound
    3975               0 :   h = h - floor(h);
    3976                 : 
    3977               0 :   if (!ExpectSymbol(',', true)) {
    3978               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedComma);
    3979               0 :     return false;
    3980                 :   }
    3981                 : 
    3982                 :   // Get the saturation
    3983               0 :   if (!GetToken(true)) {
    3984               0 :     REPORT_UNEXPECTED_EOF(PEColorSaturationEOF);
    3985               0 :     return false;
    3986                 :   }
    3987               0 :   if (mToken.mType != eCSSToken_Percentage) {
    3988               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedPercent);
    3989               0 :     UngetToken();
    3990               0 :     return false;
    3991                 :   }
    3992               0 :   s = mToken.mNumber;
    3993               0 :   if (s < 0.0f) s = 0.0f;
    3994               0 :   if (s > 1.0f) s = 1.0f;
    3995                 : 
    3996               0 :   if (!ExpectSymbol(',', true)) {
    3997               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedComma);
    3998               0 :     return false;
    3999                 :   }
    4000                 : 
    4001                 :   // Get the lightness
    4002               0 :   if (!GetToken(true)) {
    4003               0 :     REPORT_UNEXPECTED_EOF(PEColorLightnessEOF);
    4004               0 :     return false;
    4005                 :   }
    4006               0 :   if (mToken.mType != eCSSToken_Percentage) {
    4007               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedPercent);
    4008               0 :     UngetToken();
    4009               0 :     return false;
    4010                 :   }
    4011               0 :   l = mToken.mNumber;
    4012               0 :   if (l < 0.0f) l = 0.0f;
    4013               0 :   if (l > 1.0f) l = 1.0f;
    4014                 : 
    4015               0 :   if (ExpectSymbol(aStop, true)) {
    4016               0 :     aColor = NS_HSL2RGB(h, s, l);
    4017               0 :     return true;
    4018                 :   }
    4019                 : 
    4020               0 :   const PRUnichar stopString[] = { PRUnichar(aStop), PRUnichar(0) };
    4021                 :   const PRUnichar *params[] = {
    4022                 :     nsnull,
    4023                 :     stopString
    4024               0 :   };
    4025               0 :   REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm, params);
    4026               0 :   return false;
    4027                 : }
    4028                 : 
    4029                 : 
    4030                 : bool
    4031               0 : CSSParserImpl::ParseColorOpacity(PRUint8& aOpacity)
    4032                 : {
    4033               0 :   if (!GetToken(true)) {
    4034               0 :     REPORT_UNEXPECTED_EOF(PEColorOpacityEOF);
    4035               0 :     return false;
    4036                 :   }
    4037                 : 
    4038               0 :   if (mToken.mType != eCSSToken_Number) {
    4039               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedNumber);
    4040               0 :     UngetToken();
    4041               0 :     return false;
    4042                 :   }
    4043                 : 
    4044               0 :   if (mToken.mNumber < 0.0f) {
    4045               0 :     mToken.mNumber = 0.0f;
    4046               0 :   } else if (mToken.mNumber > 1.0f) {
    4047               0 :     mToken.mNumber = 1.0f;
    4048                 :   }
    4049                 : 
    4050               0 :   PRUint8 value = nsStyleUtil::FloatToColorComponent(mToken.mNumber);
    4051                 :   // Need to compare to something slightly larger
    4052                 :   // than 0.5 due to floating point inaccuracies.
    4053               0 :   NS_ASSERTION(fabs(255.0f*mToken.mNumber - value) <= 0.51f,
    4054                 :                "FloatToColorComponent did something weird");
    4055                 : 
    4056               0 :   if (!ExpectSymbol(')', true)) {
    4057               0 :     REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen);
    4058               0 :     return false;
    4059                 :   }
    4060                 : 
    4061               0 :   aOpacity = value;
    4062                 : 
    4063               0 :   return true;
    4064                 : }
    4065                 : 
    4066                 : #ifdef MOZ_XUL
    4067                 : bool
    4068               0 : CSSParserImpl::ParseTreePseudoElement(nsAtomList **aPseudoElementArgs)
    4069                 : {
    4070                 :   // The argument to a tree pseudo-element is a sequence of identifiers
    4071                 :   // that are either space- or comma-separated.  (Was the intent to
    4072                 :   // allow only comma-separated?  That's not what was done.)
    4073               0 :   nsCSSSelector fakeSelector; // so we can reuse AddPseudoClass
    4074                 : 
    4075               0 :   while (!ExpectSymbol(')', true)) {
    4076               0 :     if (!GetToken(true)) {
    4077               0 :       return false;
    4078                 :     }
    4079               0 :     if (eCSSToken_Ident == mToken.mType) {
    4080               0 :       fakeSelector.AddClass(mToken.mIdent);
    4081                 :     }
    4082               0 :     else if (!mToken.IsSymbol(',')) {
    4083               0 :       UngetToken();
    4084               0 :       SkipUntil(')');
    4085               0 :       return false;
    4086                 :     }
    4087                 :   }
    4088               0 :   *aPseudoElementArgs = fakeSelector.mClassList;
    4089               0 :   fakeSelector.mClassList = nsnull;
    4090               0 :   return true;
    4091                 : }
    4092                 : #endif
    4093                 : 
    4094                 : //----------------------------------------------------------------------
    4095                 : 
    4096                 : bool
    4097               0 : CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
    4098                 :                                 bool aCheckForBraces,
    4099                 :                                 bool aMustCallValueAppended,
    4100                 :                                 bool* aChanged)
    4101                 : {
    4102               0 :   mTempData.AssertInitialState();
    4103                 : 
    4104                 :   // Get property name
    4105               0 :   nsCSSToken* tk = &mToken;
    4106               0 :   nsAutoString propertyName;
    4107               0 :   for (;;) {
    4108               0 :     if (!GetToken(true)) {
    4109               0 :       if (aCheckForBraces) {
    4110               0 :         REPORT_UNEXPECTED_EOF(PEDeclEndEOF);
    4111                 :       }
    4112               0 :       return false;
    4113                 :     }
    4114               0 :     if (eCSSToken_Ident == tk->mType) {
    4115               0 :       propertyName = tk->mIdent;
    4116                 :       // grab the ident before the ExpectSymbol trashes the token
    4117               0 :       if (!ExpectSymbol(':', true)) {
    4118               0 :         REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon);
    4119               0 :         REPORT_UNEXPECTED(PEDeclDropped);
    4120               0 :         OUTPUT_ERROR();
    4121               0 :         return false;
    4122                 :       }
    4123                 :       break;
    4124                 :     }
    4125               0 :     if (tk->IsSymbol(';')) {
    4126                 :       // dangling semicolons are skipped
    4127               0 :       continue;
    4128                 :     }
    4129                 : 
    4130               0 :     if (!tk->IsSymbol('}')) {
    4131               0 :       REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected);
    4132               0 :       REPORT_UNEXPECTED(PEDeclSkipped);
    4133               0 :       OUTPUT_ERROR();
    4134                 :     }
    4135                 :     // Not a declaration...
    4136               0 :     UngetToken();
    4137               0 :     return false;
    4138                 :   }
    4139                 : 
    4140                 :   // Map property name to its ID and then parse the property
    4141               0 :   nsCSSProperty propID = nsCSSProps::LookupProperty(propertyName);
    4142               0 :   if (eCSSProperty_UNKNOWN == propID) { // unknown property
    4143               0 :     if (!NonMozillaVendorIdentifier(propertyName)) {
    4144                 :       const PRUnichar *params[] = {
    4145               0 :         propertyName.get()
    4146               0 :       };
    4147               0 :       REPORT_UNEXPECTED_P(PEUnknownProperty, params);
    4148               0 :       REPORT_UNEXPECTED(PEDeclDropped);
    4149               0 :       OUTPUT_ERROR();
    4150                 :     }
    4151                 : 
    4152               0 :     return false;
    4153                 :   }
    4154               0 :   if (! ParseProperty(propID)) {
    4155                 :     // XXX Much better to put stuff in the value parsers instead...
    4156                 :     const PRUnichar *params[] = {
    4157               0 :       propertyName.get()
    4158               0 :     };
    4159               0 :     REPORT_UNEXPECTED_P(PEValueParsingError, params);
    4160               0 :     REPORT_UNEXPECTED(PEDeclDropped);
    4161               0 :     OUTPUT_ERROR();
    4162               0 :     mTempData.ClearProperty(propID);
    4163               0 :     mTempData.AssertInitialState();
    4164               0 :     return false;
    4165                 :   }
    4166               0 :   CLEAR_ERROR();
    4167                 : 
    4168                 :   // Look for "!important".
    4169               0 :   PriorityParsingStatus status = ParsePriority();
    4170                 : 
    4171                 :   // Look for a semicolon or close brace.
    4172               0 :   if (status != ePriority_Error) {
    4173               0 :     if (!GetToken(true)) {
    4174                 :       // EOF is always ok
    4175               0 :     } else if (mToken.IsSymbol(';')) {
    4176                 :       // semicolon is always ok
    4177               0 :     } else if (mToken.IsSymbol('}')) {
    4178                 :       // brace is ok if aCheckForBraces, but don't eat it
    4179               0 :       UngetToken();
    4180               0 :       if (!aCheckForBraces) {
    4181               0 :         status = ePriority_Error;
    4182                 :       }
    4183                 :     } else {
    4184               0 :       UngetToken();
    4185               0 :       status = ePriority_Error;
    4186                 :     }
    4187                 :   }
    4188                 : 
    4189               0 :   if (status == ePriority_Error) {
    4190               0 :     if (aCheckForBraces) {
    4191               0 :       REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2);
    4192                 :     } else {
    4193               0 :       REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd);
    4194                 :     }
    4195               0 :     REPORT_UNEXPECTED(PEDeclDropped);
    4196               0 :     OUTPUT_ERROR();
    4197               0 :     mTempData.ClearProperty(propID);
    4198               0 :     mTempData.AssertInitialState();
    4199               0 :     return false;
    4200                 :   }
    4201                 : 
    4202                 :   *aChanged |= mData.TransferFromBlock(mTempData, propID,
    4203                 :                                        status == ePriority_Important,
    4204                 :                                        false, aMustCallValueAppended,
    4205               0 :                                        aDeclaration);
    4206               0 :   return true;
    4207                 : }
    4208                 : 
    4209                 : static const nsCSSProperty kBorderTopIDs[] = {
    4210                 :   eCSSProperty_border_top_width,
    4211                 :   eCSSProperty_border_top_style,
    4212                 :   eCSSProperty_border_top_color
    4213                 : };
    4214                 : static const nsCSSProperty kBorderRightIDs[] = {
    4215                 :   eCSSProperty_border_right_width_value,
    4216                 :   eCSSProperty_border_right_style_value,
    4217                 :   eCSSProperty_border_right_color_value,
    4218                 :   eCSSProperty_border_right_width,
    4219                 :   eCSSProperty_border_right_style,
    4220                 :   eCSSProperty_border_right_color
    4221                 : };
    4222                 : static const nsCSSProperty kBorderBottomIDs[] = {
    4223                 :   eCSSProperty_border_bottom_width,
    4224                 :   eCSSProperty_border_bottom_style,
    4225                 :   eCSSProperty_border_bottom_color
    4226                 : };
    4227                 : static const nsCSSProperty kBorderLeftIDs[] = {
    4228                 :   eCSSProperty_border_left_width_value,
    4229                 :   eCSSProperty_border_left_style_value,
    4230                 :   eCSSProperty_border_left_color_value,
    4231                 :   eCSSProperty_border_left_width,
    4232                 :   eCSSProperty_border_left_style,
    4233                 :   eCSSProperty_border_left_color
    4234                 : };
    4235                 : static const nsCSSProperty kBorderStartIDs[] = {
    4236                 :   eCSSProperty_border_start_width_value,
    4237                 :   eCSSProperty_border_start_style_value,
    4238                 :   eCSSProperty_border_start_color_value,
    4239                 :   eCSSProperty_border_start_width,
    4240                 :   eCSSProperty_border_start_style,
    4241                 :   eCSSProperty_border_start_color
    4242                 : };
    4243                 : static const nsCSSProperty kBorderEndIDs[] = {
    4244                 :   eCSSProperty_border_end_width_value,
    4245                 :   eCSSProperty_border_end_style_value,
    4246                 :   eCSSProperty_border_end_color_value,
    4247                 :   eCSSProperty_border_end_width,
    4248                 :   eCSSProperty_border_end_style,
    4249                 :   eCSSProperty_border_end_color
    4250                 : };
    4251                 : static const nsCSSProperty kColumnRuleIDs[] = {
    4252                 :   eCSSProperty__moz_column_rule_width,
    4253                 :   eCSSProperty__moz_column_rule_style,
    4254                 :   eCSSProperty__moz_column_rule_color
    4255                 : };
    4256                 : 
    4257                 : bool
    4258               0 : CSSParserImpl::ParseEnum(nsCSSValue& aValue,
    4259                 :                          const PRInt32 aKeywordTable[])
    4260                 : {
    4261               0 :   nsSubstring* ident = NextIdent();
    4262               0 :   if (nsnull == ident) {
    4263               0 :     return false;
    4264                 :   }
    4265               0 :   nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(*ident);
    4266               0 :   if (eCSSKeyword_UNKNOWN < keyword) {
    4267                 :     PRInt32 value;
    4268               0 :     if (nsCSSProps::FindKeyword(keyword, aKeywordTable, value)) {
    4269               0 :       aValue.SetIntValue(value, eCSSUnit_Enumerated);
    4270               0 :       return true;
    4271                 :     }
    4272                 :   }
    4273                 : 
    4274                 :   // Put the unknown identifier back and return
    4275               0 :   UngetToken();
    4276               0 :   return false;
    4277                 : }
    4278                 : 
    4279                 : 
    4280                 : struct UnitInfo {
    4281                 :   char name[6];  // needs to be long enough for the longest unit, with
    4282                 :                  // terminating null.
    4283                 :   PRUint32 length;
    4284                 :   nsCSSUnit unit;
    4285                 :   PRInt32 type;
    4286                 : };
    4287                 : 
    4288                 : #define STR_WITH_LEN(_str) \
    4289                 :   _str, sizeof(_str) - 1
    4290                 : 
    4291                 : const UnitInfo UnitData[] = {
    4292                 :   { STR_WITH_LEN("px"), eCSSUnit_Pixel, VARIANT_LENGTH },
    4293                 :   { STR_WITH_LEN("em"), eCSSUnit_EM, VARIANT_LENGTH },
    4294                 :   { STR_WITH_LEN("ex"), eCSSUnit_XHeight, VARIANT_LENGTH },
    4295                 :   { STR_WITH_LEN("pt"), eCSSUnit_Point, VARIANT_LENGTH },
    4296                 :   { STR_WITH_LEN("in"), eCSSUnit_Inch, VARIANT_LENGTH },
    4297                 :   { STR_WITH_LEN("cm"), eCSSUnit_Centimeter, VARIANT_LENGTH },
    4298                 :   { STR_WITH_LEN("ch"), eCSSUnit_Char, VARIANT_LENGTH },
    4299                 :   { STR_WITH_LEN("rem"), eCSSUnit_RootEM, VARIANT_LENGTH },
    4300                 :   { STR_WITH_LEN("mm"), eCSSUnit_Millimeter, VARIANT_LENGTH },
    4301                 :   { STR_WITH_LEN("mozmm"), eCSSUnit_PhysicalMillimeter, VARIANT_LENGTH },
    4302                 :   { STR_WITH_LEN("pc"), eCSSUnit_Pica, VARIANT_LENGTH },
    4303                 :   { STR_WITH_LEN("deg"), eCSSUnit_Degree, VARIANT_ANGLE },
    4304                 :   { STR_WITH_LEN("grad"), eCSSUnit_Grad, VARIANT_ANGLE },
    4305                 :   { STR_WITH_LEN("rad"), eCSSUnit_Radian, VARIANT_ANGLE },
    4306                 :   { STR_WITH_LEN("turn"), eCSSUnit_Turn, VARIANT_ANGLE },
    4307                 :   { STR_WITH_LEN("hz"), eCSSUnit_Hertz, VARIANT_FREQUENCY },
    4308                 :   { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz, VARIANT_FREQUENCY },
    4309                 :   { STR_WITH_LEN("s"), eCSSUnit_Seconds, VARIANT_TIME },
    4310                 :   { STR_WITH_LEN("ms"), eCSSUnit_Milliseconds, VARIANT_TIME }
    4311                 : };
    4312                 : 
    4313                 : #undef STR_WITH_LEN
    4314                 : 
    4315                 : bool
    4316               0 : CSSParserImpl::TranslateDimension(nsCSSValue& aValue,
    4317                 :                                   PRInt32 aVariantMask,
    4318                 :                                   float aNumber,
    4319                 :                                   const nsString& aUnit)
    4320                 : {
    4321                 :   nsCSSUnit units;
    4322               0 :   PRInt32   type = 0;
    4323               0 :   if (!aUnit.IsEmpty()) {
    4324                 :     PRUint32 i;
    4325               0 :     for (i = 0; i < ArrayLength(UnitData); ++i) {
    4326               0 :       if (aUnit.LowerCaseEqualsASCII(UnitData[i].name,
    4327               0 :                                      UnitData[i].length)) {
    4328               0 :         units = UnitData[i].unit;
    4329               0 :         type = UnitData[i].type;
    4330               0 :         break;
    4331                 :       }
    4332                 :     }
    4333                 : 
    4334               0 :     if (i == ArrayLength(UnitData)) {
    4335                 :       // Unknown unit
    4336               0 :       return false;
    4337                 :     }
    4338                 :   } else {
    4339                 :     // Must be a zero number...
    4340               0 :     NS_ASSERTION(0 == aNumber, "numbers without units must be 0");
    4341               0 :     if ((VARIANT_LENGTH & aVariantMask) != 0) {
    4342               0 :       units = eCSSUnit_Pixel;
    4343               0 :       type = VARIANT_LENGTH;
    4344                 :     }
    4345               0 :     else if ((VARIANT_ANGLE & aVariantMask) != 0) {
    4346               0 :       NS_ASSERTION(aVariantMask & VARIANT_ZERO_ANGLE,
    4347                 :                    "must have allowed zero angle");
    4348               0 :       units = eCSSUnit_Degree;
    4349               0 :       type = VARIANT_ANGLE;
    4350                 :     }
    4351                 :     else {
    4352               0 :       NS_ERROR("Variant mask does not include dimension; why were we called?");
    4353               0 :       return false;
    4354                 :     }
    4355                 :   }
    4356               0 :   if ((type & aVariantMask) != 0) {
    4357               0 :     aValue.SetFloatValue(aNumber, units);
    4358               0 :     return true;
    4359                 :   }
    4360               0 :   return false;
    4361                 : }
    4362                 : 
    4363                 : // Note that this does include VARIANT_CALC, which is numeric.  This is
    4364                 : // because calc() parsing, as proposed, drops range restrictions inside
    4365                 : // the calc() expression and clamps the result of the calculation to the
    4366                 : // range.
    4367                 : #define VARIANT_ALL_NONNUMERIC \
    4368                 :   VARIANT_KEYWORD | \
    4369                 :   VARIANT_COLOR | \
    4370                 :   VARIANT_URL | \
    4371                 :   VARIANT_STRING | \
    4372                 :   VARIANT_COUNTER | \
    4373                 :   VARIANT_ATTR | \
    4374                 :   VARIANT_IDENTIFIER | \
    4375                 :   VARIANT_IDENTIFIER_NO_INHERIT | \
    4376                 :   VARIANT_AUTO | \
    4377                 :   VARIANT_INHERIT | \
    4378                 :   VARIANT_NONE | \
    4379                 :   VARIANT_NORMAL | \
    4380                 :   VARIANT_SYSFONT | \
    4381                 :   VARIANT_GRADIENT | \
    4382                 :   VARIANT_TIMING_FUNCTION | \
    4383                 :   VARIANT_ALL | \
    4384                 :   VARIANT_CALC
    4385                 : 
    4386                 : // Note that callers passing VARIANT_CALC in aVariantMask will get
    4387                 : // full-range parsing inside the calc() expression, and the code that
    4388                 : // computes the calc will be required to clamp the resulting value to an
    4389                 : // appropriate range.
    4390                 : bool
    4391               0 : CSSParserImpl::ParseNonNegativeVariant(nsCSSValue& aValue,
    4392                 :                                        PRInt32 aVariantMask,
    4393                 :                                        const PRInt32 aKeywordTable[])
    4394                 : {
    4395                 :   // The variant mask must only contain non-numeric variants or the ones
    4396                 :   // that we specifically handle.
    4397               0 :   NS_ABORT_IF_FALSE((aVariantMask & ~(VARIANT_ALL_NONNUMERIC |
    4398                 :                                       VARIANT_NUMBER |
    4399                 :                                       VARIANT_LENGTH |
    4400                 :                                       VARIANT_PERCENT |
    4401                 :                                       VARIANT_INTEGER)) == 0,
    4402                 :                     "need to update code below to handle additional variants");
    4403                 : 
    4404               0 :   if (ParseVariant(aValue, aVariantMask, aKeywordTable)) {
    4405               0 :     if (eCSSUnit_Number == aValue.GetUnit() ||
    4406               0 :         aValue.IsLengthUnit()){
    4407               0 :       if (aValue.GetFloatValue() < 0) {
    4408               0 :         UngetToken();
    4409               0 :         return false;
    4410                 :       }
    4411                 :     }
    4412               0 :     else if (aValue.GetUnit() == eCSSUnit_Percent) {
    4413               0 :       if (aValue.GetPercentValue() < 0) {
    4414               0 :         UngetToken();
    4415               0 :         return false;
    4416                 :       }
    4417               0 :     } else if (aValue.GetUnit() == eCSSUnit_Integer) {
    4418               0 :       if (aValue.GetIntValue() < 0) {
    4419               0 :         UngetToken();
    4420               0 :         return false;
    4421                 :       }
    4422                 :     }
    4423               0 :     return true;
    4424                 :   }
    4425               0 :   return false;
    4426                 : }
    4427                 : 
    4428                 : // Note that callers passing VARIANT_CALC in aVariantMask will get
    4429                 : // full-range parsing inside the calc() expression, and the code that
    4430                 : // computes the calc will be required to clamp the resulting value to an
    4431                 : // appropriate range.
    4432                 : bool
    4433               0 : CSSParserImpl::ParseOneOrLargerVariant(nsCSSValue& aValue,
    4434                 :                                        PRInt32 aVariantMask,
    4435                 :                                        const PRInt32 aKeywordTable[])
    4436                 : {
    4437                 :   // The variant mask must only contain non-numeric variants or the ones
    4438                 :   // that we specifically handle.
    4439               0 :   NS_ABORT_IF_FALSE((aVariantMask & ~(VARIANT_ALL_NONNUMERIC |
    4440                 :                                       VARIANT_NUMBER |
    4441                 :                                       VARIANT_INTEGER)) == 0,
    4442                 :                     "need to update code below to handle additional variants");
    4443                 : 
    4444               0 :   if (ParseVariant(aValue, aVariantMask, aKeywordTable)) {
    4445               0 :     if (aValue.GetUnit() == eCSSUnit_Integer) {
    4446               0 :       if (aValue.GetIntValue() < 1) {
    4447               0 :         UngetToken();
    4448               0 :         return false;
    4449                 :       }
    4450               0 :     } else if (eCSSUnit_Number == aValue.GetUnit()) {
    4451               0 :       if (aValue.GetFloatValue() < 1.0f) {
    4452               0 :         UngetToken();
    4453               0 :         return false;
    4454                 :       }
    4455                 :     }
    4456               0 :     return true;
    4457                 :   }
    4458               0 :   return false;
    4459                 : }
    4460                 : 
    4461                 : // Assigns to aValue iff it returns true.
    4462                 : bool
    4463               0 : CSSParserImpl::ParseVariant(nsCSSValue& aValue,
    4464                 :                             PRInt32 aVariantMask,
    4465                 :                             const PRInt32 aKeywordTable[])
    4466                 : {
    4467               0 :   NS_ASSERTION(IsParsingCompoundProperty() ||
    4468                 :                ((~aVariantMask) & (VARIANT_LENGTH|VARIANT_COLOR)),
    4469                 :                "cannot distinguish lengths and colors in quirks mode");
    4470               0 :   NS_ABORT_IF_FALSE(!(aVariantMask & VARIANT_IDENTIFIER) ||
    4471                 :                     !(aVariantMask & VARIANT_IDENTIFIER_NO_INHERIT),
    4472                 :                     "must not set both VARIANT_IDENTIFIER and "
    4473                 :                     "VARIANT_IDENTIFIER_NO_INHERIT");
    4474                 : 
    4475               0 :   if (!GetToken(true)) {
    4476               0 :     return false;
    4477                 :   }
    4478               0 :   nsCSSToken* tk = &mToken;
    4479               0 :   if (((aVariantMask & (VARIANT_AHK | VARIANT_NORMAL | VARIANT_NONE | VARIANT_ALL)) != 0) &&
    4480                 :       (eCSSToken_Ident == tk->mType)) {
    4481               0 :     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(tk->mIdent);
    4482               0 :     if (eCSSKeyword_UNKNOWN < keyword) { // known keyword
    4483               0 :       if ((aVariantMask & VARIANT_AUTO) != 0) {
    4484               0 :         if (eCSSKeyword_auto == keyword) {
    4485               0 :           aValue.SetAutoValue();
    4486               0 :           return true;
    4487                 :         }
    4488                 :       }
    4489               0 :       if ((aVariantMask & VARIANT_INHERIT) != 0) {
    4490                 :         // XXX Should we check IsParsingCompoundProperty, or do all
    4491                 :         // callers handle it?  (Not all callers set it, though, since
    4492                 :         // they want the quirks that are disabled by setting it.)
    4493               0 :         if (eCSSKeyword_inherit == keyword) {
    4494               0 :           aValue.SetInheritValue();
    4495               0 :           return true;
    4496                 :         }
    4497               0 :         else if (eCSSKeyword__moz_initial == keyword) { // anything that can inherit can also take an initial val.
    4498               0 :           aValue.SetInitialValue();
    4499               0 :           return true;
    4500                 :         }
    4501                 :       }
    4502               0 :       if ((aVariantMask & VARIANT_NONE) != 0) {
    4503               0 :         if (eCSSKeyword_none == keyword) {
    4504               0 :           aValue.SetNoneValue();
    4505               0 :           return true;
    4506                 :         }
    4507                 :       }
    4508               0 :       if ((aVariantMask & VARIANT_ALL) != 0) {
    4509               0 :         if (eCSSKeyword_all == keyword) {
    4510               0 :           aValue.SetAllValue();
    4511               0 :           return true;
    4512                 :         }
    4513                 :       }
    4514               0 :       if ((aVariantMask & VARIANT_NORMAL) != 0) {
    4515               0 :         if (eCSSKeyword_normal == keyword) {
    4516               0 :           aValue.SetNormalValue();
    4517               0 :           return true;
    4518                 :         }
    4519                 :       }
    4520               0 :       if ((aVariantMask & VARIANT_SYSFONT) != 0) {
    4521               0 :         if (eCSSKeyword__moz_use_system_font == keyword &&
    4522               0 :             !IsParsingCompoundProperty()) {
    4523               0 :           aValue.SetSystemFontValue();
    4524               0 :           return true;
    4525                 :         }
    4526                 :       }
    4527               0 :       if ((aVariantMask & VARIANT_KEYWORD) != 0) {
    4528                 :         PRInt32 value;
    4529               0 :         if (nsCSSProps::FindKeyword(keyword, aKeywordTable, value)) {
    4530               0 :           aValue.SetIntValue(value, eCSSUnit_Enumerated);
    4531               0 :           return true;
    4532                 :         }
    4533                 :       }
    4534                 :     }
    4535                 :   }
    4536                 :   // Check VARIANT_NUMBER and VARIANT_INTEGER before VARIANT_LENGTH or
    4537                 :   // VARIANT_ZERO_ANGLE.
    4538               0 :   if (((aVariantMask & VARIANT_NUMBER) != 0) &&
    4539                 :       (eCSSToken_Number == tk->mType)) {
    4540               0 :     aValue.SetFloatValue(tk->mNumber, eCSSUnit_Number);
    4541               0 :     return true;
    4542                 :   }
    4543               0 :   if (((aVariantMask & VARIANT_INTEGER) != 0) &&
    4544                 :       (eCSSToken_Number == tk->mType) && tk->mIntegerValid) {
    4545               0 :     aValue.SetIntValue(tk->mInteger, eCSSUnit_Integer);
    4546               0 :     return true;
    4547                 :   }
    4548               0 :   if (((aVariantMask & (VARIANT_LENGTH | VARIANT_ANGLE |
    4549                 :                         VARIANT_FREQUENCY | VARIANT_TIME)) != 0 &&
    4550                 :        eCSSToken_Dimension == tk->mType) ||
    4551                 :       ((aVariantMask & (VARIANT_LENGTH | VARIANT_ZERO_ANGLE)) != 0 &&
    4552                 :        eCSSToken_Number == tk->mType &&
    4553                 :        tk->mNumber == 0.0f)) {
    4554               0 :     if ((aVariantMask & VARIANT_POSITIVE_LENGTH) != 0 && 
    4555                 :         tk->mNumber <= 0.0) {
    4556               0 :         UngetToken();
    4557               0 :         return false;
    4558                 :     }
    4559               0 :     if (TranslateDimension(aValue, aVariantMask, tk->mNumber, tk->mIdent)) {
    4560               0 :       return true;
    4561                 :     }
    4562                 :     // Put the token back; we didn't parse it, so we shouldn't consume it
    4563               0 :     UngetToken();
    4564               0 :     return false;
    4565                 :   }
    4566               0 :   if (((aVariantMask & VARIANT_PERCENT) != 0) &&
    4567                 :       (eCSSToken_Percentage == tk->mType)) {
    4568               0 :     aValue.SetPercentValue(tk->mNumber);
    4569               0 :     return true;
    4570                 :   }
    4571               0 :   if (mNavQuirkMode && !IsParsingCompoundProperty()) { // NONSTANDARD: Nav interprets unitless numbers as px
    4572               0 :     if (((aVariantMask & VARIANT_LENGTH) != 0) &&
    4573                 :         (eCSSToken_Number == tk->mType)) {
    4574               0 :       aValue.SetFloatValue(tk->mNumber, eCSSUnit_Pixel);
    4575               0 :       return true;
    4576                 :     }
    4577                 :   }
    4578                 : 
    4579               0 :   if (IsSVGMode() && !IsParsingCompoundProperty()) {
    4580                 :     // STANDARD: SVG Spec states that lengths and coordinates can be unitless
    4581                 :     // in which case they default to user-units (1 px = 1 user unit)
    4582               0 :     if (((aVariantMask & VARIANT_LENGTH) != 0) &&
    4583                 :         (eCSSToken_Number == tk->mType)) {
    4584               0 :       aValue.SetFloatValue(tk->mNumber, eCSSUnit_Pixel);
    4585               0 :       return true;
    4586                 :     }
    4587                 :   }
    4588                 : 
    4589               0 :   if (((aVariantMask & VARIANT_URL) != 0) &&
    4590                 :       eCSSToken_URL == tk->mType) {
    4591               0 :     SetValueToURL(aValue, tk->mIdent);
    4592               0 :     return true;
    4593                 :   }
    4594               0 :   if ((aVariantMask & VARIANT_GRADIENT) != 0 &&
    4595                 :       eCSSToken_Function == tk->mType) {
    4596                 :     // a generated gradient
    4597               0 :     if (tk->mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient"))
    4598               0 :       return ParseGradient(aValue, false, false);
    4599                 : 
    4600               0 :     if (tk->mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient"))
    4601               0 :       return ParseGradient(aValue, true, false);
    4602                 : 
    4603               0 :     if (tk->mIdent.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient"))
    4604               0 :       return ParseGradient(aValue, false, true);
    4605                 : 
    4606               0 :     if (tk->mIdent.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient"))
    4607               0 :       return ParseGradient(aValue, true, true);
    4608                 :   }
    4609               0 :   if ((aVariantMask & VARIANT_IMAGE_RECT) != 0 &&
    4610                 :       eCSSToken_Function == tk->mType &&
    4611               0 :       tk->mIdent.LowerCaseEqualsLiteral("-moz-image-rect")) {
    4612               0 :     return ParseImageRect(aValue);
    4613                 :   }
    4614               0 :   if ((aVariantMask & VARIANT_ELEMENT) != 0 &&
    4615                 :       eCSSToken_Function == tk->mType &&
    4616               0 :       tk->mIdent.LowerCaseEqualsLiteral("-moz-element")) {
    4617               0 :     return ParseElement(aValue);
    4618                 :   }
    4619               0 :   if ((aVariantMask & VARIANT_COLOR) != 0) {
    4620               0 :     if ((mNavQuirkMode && !IsParsingCompoundProperty()) || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
    4621                 :         (eCSSToken_ID == tk->mType) ||
    4622                 :         (eCSSToken_Ref == tk->mType) ||
    4623                 :         (eCSSToken_Ident == tk->mType) ||
    4624                 :         ((eCSSToken_Function == tk->mType) &&
    4625               0 :          (tk->mIdent.LowerCaseEqualsLiteral("rgb") ||
    4626               0 :           tk->mIdent.LowerCaseEqualsLiteral("hsl") ||
    4627               0 :           tk->mIdent.LowerCaseEqualsLiteral("-moz-rgba") ||
    4628               0 :           tk->mIdent.LowerCaseEqualsLiteral("-moz-hsla") ||
    4629               0 :           tk->mIdent.LowerCaseEqualsLiteral("rgba") ||
    4630               0 :           tk->mIdent.LowerCaseEqualsLiteral("hsla"))))
    4631                 :     {
    4632                 :       // Put token back so that parse color can get it
    4633               0 :       UngetToken();
    4634               0 :       if (ParseColor(aValue)) {
    4635               0 :         return true;
    4636                 :       }
    4637               0 :       return false;
    4638                 :     }
    4639                 :   }
    4640               0 :   if (((aVariantMask & VARIANT_STRING) != 0) &&
    4641                 :       (eCSSToken_String == tk->mType)) {
    4642               0 :     nsAutoString  buffer;
    4643               0 :     buffer.Append(tk->mIdent);
    4644               0 :     aValue.SetStringValue(buffer, eCSSUnit_String);
    4645               0 :     return true;
    4646                 :   }
    4647               0 :   if (((aVariantMask &
    4648                 :         (VARIANT_IDENTIFIER | VARIANT_IDENTIFIER_NO_INHERIT)) != 0) &&
    4649                 :       (eCSSToken_Ident == tk->mType) &&
    4650                 :       ((aVariantMask & VARIANT_IDENTIFIER) != 0 ||
    4651               0 :        !(tk->mIdent.LowerCaseEqualsLiteral("inherit") ||
    4652               0 :          tk->mIdent.LowerCaseEqualsLiteral("initial")))) {
    4653               0 :     aValue.SetStringValue(tk->mIdent, eCSSUnit_Ident);
    4654               0 :     return true;
    4655                 :   }
    4656               0 :   if (((aVariantMask & VARIANT_COUNTER) != 0) &&
    4657                 :       (eCSSToken_Function == tk->mType) &&
    4658               0 :       (tk->mIdent.LowerCaseEqualsLiteral("counter") ||
    4659               0 :        tk->mIdent.LowerCaseEqualsLiteral("counters"))) {
    4660               0 :     return ParseCounter(aValue);
    4661                 :   }
    4662               0 :   if (((aVariantMask & VARIANT_ATTR) != 0) &&
    4663                 :       (eCSSToken_Function == tk->mType) &&
    4664               0 :       tk->mIdent.LowerCaseEqualsLiteral("attr")) {
    4665               0 :     if (!ParseAttr(aValue)) {
    4666               0 :       SkipUntil(')');
    4667               0 :       return false;
    4668                 :     }
    4669               0 :     return true;
    4670                 :   }
    4671               0 :   if (((aVariantMask & VARIANT_TIMING_FUNCTION) != 0) &&
    4672                 :       (eCSSToken_Function == tk->mType)) {
    4673               0 :     if (tk->mIdent.LowerCaseEqualsLiteral("cubic-bezier")) {
    4674               0 :       if (!ParseTransitionTimingFunctionValues(aValue)) {
    4675               0 :         SkipUntil(')');
    4676               0 :         return false;
    4677                 :       }
    4678               0 :       return true;
    4679                 :     }
    4680               0 :     if (tk->mIdent.LowerCaseEqualsLiteral("steps")) {
    4681               0 :       if (!ParseTransitionStepTimingFunctionValues(aValue)) {
    4682               0 :         SkipUntil(')');
    4683               0 :         return false;
    4684                 :       }
    4685               0 :       return true;
    4686                 :     }
    4687                 :   }
    4688               0 :   if ((aVariantMask & VARIANT_CALC) &&
    4689                 :       (eCSSToken_Function == tk->mType) &&
    4690               0 :       tk->mIdent.LowerCaseEqualsLiteral("-moz-calc")) {
    4691                 :     // calc() currently allows only lengths and percents inside it.
    4692               0 :     return ParseCalc(aValue, aVariantMask & VARIANT_LP);
    4693                 :   }
    4694                 : 
    4695               0 :   UngetToken();
    4696               0 :   return false;
    4697                 : }
    4698                 : 
    4699                 : 
    4700                 : bool
    4701               0 : CSSParserImpl::ParseCounter(nsCSSValue& aValue)
    4702                 : {
    4703               0 :   nsCSSUnit unit = (mToken.mIdent.LowerCaseEqualsLiteral("counter") ?
    4704               0 :                     eCSSUnit_Counter : eCSSUnit_Counters);
    4705                 : 
    4706                 :   // A non-iterative for loop to break out when an error occurs.
    4707                 :   for (;;) {
    4708               0 :     if (!GetToken(true)) {
    4709               0 :       break;
    4710                 :     }
    4711               0 :     if (eCSSToken_Ident != mToken.mType) {
    4712               0 :       UngetToken();
    4713               0 :       break;
    4714                 :     }
    4715                 : 
    4716                 :     nsRefPtr<nsCSSValue::Array> val =
    4717               0 :       nsCSSValue::Array::Create(unit == eCSSUnit_Counter ? 2 : 3);
    4718                 : 
    4719               0 :     val->Item(0).SetStringValue(mToken.mIdent, eCSSUnit_Ident);
    4720                 : 
    4721               0 :     if (eCSSUnit_Counters == unit) {
    4722                 :       // must have a comma and then a separator string
    4723               0 :       if (!ExpectSymbol(',', true) || !GetToken(true)) {
    4724                 :         break;
    4725                 :       }
    4726               0 :       if (eCSSToken_String != mToken.mType) {
    4727               0 :         UngetToken();
    4728                 :         break;
    4729                 :       }
    4730               0 :       val->Item(1).SetStringValue(mToken.mIdent, eCSSUnit_String);
    4731                 :     }
    4732                 : 
    4733                 :     // get optional type
    4734               0 :     PRInt32 type = NS_STYLE_LIST_STYLE_DECIMAL;
    4735               0 :     if (ExpectSymbol(',', true)) {
    4736               0 :       if (!GetToken(true)) {
    4737                 :         break;
    4738                 :       }
    4739                 :       nsCSSKeyword keyword;
    4740               0 :       if (eCSSToken_Ident != mToken.mType ||
    4741               0 :           (keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent)) ==
    4742                 :             eCSSKeyword_UNKNOWN ||
    4743                 :           !nsCSSProps::FindKeyword(keyword, nsCSSProps::kListStyleKTable,
    4744               0 :                                    type)) {
    4745               0 :         UngetToken();
    4746                 :         break;
    4747                 :       }
    4748                 :     }
    4749                 : 
    4750               0 :     PRInt32 typeItem = eCSSUnit_Counters == unit ? 2 : 1;
    4751               0 :     val->Item(typeItem).SetIntValue(type, eCSSUnit_Enumerated);
    4752                 : 
    4753               0 :     if (!ExpectSymbol(')', true)) {
    4754                 :       break;
    4755                 :     }
    4756                 : 
    4757               0 :     aValue.SetArrayValue(val, unit);
    4758               0 :     return true;
    4759                 :   }
    4760                 : 
    4761               0 :   SkipUntil(')');
    4762               0 :   return false;
    4763                 : }
    4764                 : 
    4765                 : bool
    4766               0 : CSSParserImpl::ParseAttr(nsCSSValue& aValue)
    4767                 : {
    4768               0 :   if (!GetToken(true)) {
    4769               0 :     return false;
    4770                 :   }
    4771                 : 
    4772               0 :   nsAutoString attr;
    4773               0 :   if (eCSSToken_Ident == mToken.mType) {  // attr name or namespace
    4774               0 :     nsAutoString  holdIdent(mToken.mIdent);
    4775               0 :     if (ExpectSymbol('|', false)) {  // namespace
    4776               0 :       PRInt32 nameSpaceID = GetNamespaceIdForPrefix(holdIdent);
    4777               0 :       if (nameSpaceID == kNameSpaceID_Unknown) {
    4778               0 :         return false;
    4779                 :       }
    4780               0 :       attr.AppendInt(nameSpaceID, 10);
    4781               0 :       attr.Append(PRUnichar('|'));
    4782               0 :       if (! GetToken(false)) {
    4783               0 :         REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
    4784               0 :         return false;
    4785                 :       }
    4786               0 :       if (eCSSToken_Ident == mToken.mType) {
    4787               0 :         attr.Append(mToken.mIdent);
    4788                 :       }
    4789                 :       else {
    4790               0 :         REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
    4791               0 :         UngetToken();
    4792               0 :         return false;
    4793                 :       }
    4794                 :     }
    4795                 :     else {  // no namespace
    4796               0 :       attr = holdIdent;
    4797                 :     }
    4798                 :   }
    4799               0 :   else if (mToken.IsSymbol('*')) {  // namespace wildcard
    4800                 :     // Wildcard namespace makes no sense here and is not allowed
    4801               0 :     REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
    4802               0 :     UngetToken();
    4803               0 :     return false;
    4804                 :   }
    4805               0 :   else if (mToken.IsSymbol('|')) {  // explicit NO namespace
    4806               0 :     if (! GetToken(false)) {
    4807               0 :       REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
    4808               0 :       return false;
    4809                 :     }
    4810               0 :     if (eCSSToken_Ident == mToken.mType) {
    4811               0 :       attr.Append(mToken.mIdent);
    4812                 :     }
    4813                 :     else {
    4814               0 :       REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
    4815               0 :       UngetToken();
    4816               0 :       return false;
    4817                 :     }
    4818                 :   }
    4819                 :   else {
    4820               0 :     REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected);
    4821               0 :     UngetToken();
    4822               0 :     return false;
    4823                 :   }
    4824               0 :   if (!ExpectSymbol(')', true)) {
    4825               0 :     return false;
    4826                 :   }
    4827               0 :   aValue.SetStringValue(attr, eCSSUnit_Attr);
    4828               0 :   return true;
    4829                 : }
    4830                 : 
    4831                 : bool
    4832               0 : CSSParserImpl::SetValueToURL(nsCSSValue& aValue, const nsString& aURL)
    4833                 : {
    4834               0 :   if (!mSheetPrincipal) {
    4835                 :     NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
    4836               0 :                   "origin principal");
    4837               0 :     return false;
    4838                 :   }
    4839                 : 
    4840               0 :   nsRefPtr<nsStringBuffer> buffer(nsCSSValue::BufferFromString(aURL));
    4841                 : 
    4842                 :   // Note: urlVal retains its own reference to |buffer|.
    4843                 :   nsCSSValue::URL *urlVal =
    4844               0 :     new nsCSSValue::URL(buffer, mBaseURI, mSheetURI, mSheetPrincipal);
    4845               0 :   aValue.SetURLValue(urlVal);
    4846               0 :   return true;
    4847                 : }
    4848                 : 
    4849                 : /**
    4850                 :  * Parse the arguments of -moz-image-rect() function.
    4851                 :  * -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
    4852                 :  */
    4853                 : bool
    4854               0 : CSSParserImpl::ParseImageRect(nsCSSValue& aImage)
    4855                 : {
    4856                 :   // A non-iterative for loop to break out when an error occurs.
    4857                 :   for (;;) {
    4858               0 :     nsCSSValue newFunction;
    4859                 :     static const PRUint32 kNumArgs = 5;
    4860                 :     nsCSSValue::Array* func =
    4861               0 :       newFunction.InitFunction(eCSSKeyword__moz_image_rect, kNumArgs);
    4862                 : 
    4863                 :     // func->Item(0) is reserved for the function name.
    4864               0 :     nsCSSValue& url    = func->Item(1);
    4865               0 :     nsCSSValue& top    = func->Item(2);
    4866               0 :     nsCSSValue& right  = func->Item(3);
    4867               0 :     nsCSSValue& bottom = func->Item(4);
    4868               0 :     nsCSSValue& left   = func->Item(5);
    4869                 : 
    4870               0 :     nsAutoString urlString;
    4871               0 :     if (!ParseURLOrString(urlString) ||
    4872               0 :         !SetValueToURL(url, urlString) ||
    4873               0 :         !ExpectSymbol(',', true)) {
    4874                 :       break;
    4875                 :     }
    4876                 : 
    4877                 :     static const PRInt32 VARIANT_SIDE = VARIANT_NUMBER | VARIANT_PERCENT;
    4878               0 :     if (!ParseNonNegativeVariant(top, VARIANT_SIDE, nsnull) ||
    4879               0 :         !ExpectSymbol(',', true) ||
    4880               0 :         !ParseNonNegativeVariant(right, VARIANT_SIDE, nsnull) ||
    4881               0 :         !ExpectSymbol(',', true) ||
    4882               0 :         !ParseNonNegativeVariant(bottom, VARIANT_SIDE, nsnull) ||
    4883               0 :         !ExpectSymbol(',', true) ||
    4884               0 :         !ParseNonNegativeVariant(left, VARIANT_SIDE, nsnull) ||
    4885               0 :         !ExpectSymbol(')', true))
    4886                 :       break;
    4887                 : 
    4888               0 :     aImage = newFunction;
    4889               0 :     return true;
    4890                 :   }
    4891                 : 
    4892               0 :   SkipUntil(')');
    4893               0 :   return false;
    4894                 : }
    4895                 : 
    4896                 : // <element>: -moz-element(# <element_id> )
    4897                 : bool
    4898               0 : CSSParserImpl::ParseElement(nsCSSValue& aValue)
    4899                 : {
    4900                 :   // A non-iterative for loop to break out when an error occurs.
    4901                 :   for (;;) {
    4902               0 :     if (!GetToken(true))
    4903               0 :       break;
    4904                 : 
    4905               0 :     if (mToken.mType == eCSSToken_ID) {
    4906               0 :       aValue.SetStringValue(mToken.mIdent, eCSSUnit_Element);
    4907                 :     } else {
    4908               0 :       UngetToken();
    4909               0 :       break;
    4910                 :     }
    4911                 : 
    4912               0 :     if (!ExpectSymbol(')', true))
    4913               0 :       break;
    4914                 : 
    4915               0 :     return true;
    4916                 :   }
    4917                 : 
    4918                 :   // If we detect a syntax error, we must match the opening parenthesis of the
    4919                 :   // function with the closing parenthesis and skip all the tokens in between.
    4920               0 :   SkipUntil(')');
    4921               0 :   return false;
    4922                 : }
    4923                 : 
    4924                 : // <color-stop> : <color> [ <percentage> | <length> ]?
    4925                 : bool
    4926               0 : CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient)
    4927                 : {
    4928               0 :   nsCSSValueGradientStop* stop = aGradient->mStops.AppendElement();
    4929               0 :   if (!ParseVariant(stop->mColor, VARIANT_COLOR, nsnull)) {
    4930               0 :     return false;
    4931                 :   }
    4932                 : 
    4933                 :   // Stop positions do not have to fall between the starting-point and
    4934                 :   // ending-point, so we don't use ParseNonNegativeVariant.
    4935               0 :   if (!ParseVariant(stop->mLocation, VARIANT_LP, nsnull)) {
    4936               0 :     stop->mLocation.SetNoneValue();
    4937                 :   }
    4938               0 :   return true;
    4939                 : }
    4940                 : 
    4941                 : // <gradient>
    4942                 : //    : linear-gradient( <gradient-line>? <color-stops> ')'
    4943                 : //    : radial-gradient( <gradient-line>? <gradient-shape-size>?
    4944                 : //                       <color-stops> ')'
    4945                 : //
    4946                 : // <gradient-line> : [ to [left | right] || [top | bottom] ] ,
    4947                 : //                 | <legacy-gradient-line>
    4948                 : // <legacy-gradient-line> : [ <bg-position> || <angle>] ,
    4949                 : //
    4950                 : // <gradient-shape-size> : [<gradient-shape> || <gradient-size>] ,
    4951                 : // <gradient-shape> : circle | ellipse
    4952                 : // <gradient-size> : closest-side | closest-corner
    4953                 : //                 | farthest-side | farthest-corner
    4954                 : //                 | contain | cover
    4955                 : //
    4956                 : // <color-stops> : <color-stop> , <color-stop> [, <color-stop>]*
    4957                 : bool
    4958               0 : CSSParserImpl::ParseGradient(nsCSSValue& aValue, bool aIsRadial,
    4959                 :                              bool aIsRepeating)
    4960                 : {
    4961                 :   nsRefPtr<nsCSSValueGradient> cssGradient
    4962               0 :     = new nsCSSValueGradient(aIsRadial, aIsRepeating);
    4963                 : 
    4964                 :   // <gradient-line>
    4965                 :   // N.B. ParseBoxPositionValues is not guaranteed to put back
    4966                 :   // everything it scanned if it fails, so we must only call it
    4967                 :   // if there is no alternative to consuming a <box-position>.
    4968                 :   // ParseVariant, as used here, will either succeed and consume
    4969                 :   // a single token, or fail and consume none, so we can be more
    4970                 :   // cavalier about calling it.
    4971                 : 
    4972               0 :   if (!GetToken(true)) {
    4973               0 :     return false;
    4974                 :   }
    4975                 : 
    4976               0 :   bool toCorner = false;
    4977               0 :   if (mToken.mType == eCSSToken_Ident &&
    4978               0 :       mToken.mIdent.LowerCaseEqualsLiteral("to")) {
    4979               0 :     toCorner = true;
    4980               0 :     if (!GetToken(true)) {
    4981               0 :       return false;
    4982                 :     }
    4983                 :   }
    4984                 : 
    4985               0 :   nsCSSTokenType ty = mToken.mType;
    4986               0 :   nsString id = mToken.mIdent;
    4987               0 :   cssGradient->mIsToCorner = toCorner;
    4988               0 :   UngetToken();
    4989                 : 
    4990               0 :   bool haveGradientLine = false;
    4991               0 :   switch (ty) {
    4992                 :   case eCSSToken_Percentage:
    4993                 :   case eCSSToken_Number:
    4994                 :   case eCSSToken_Dimension:
    4995               0 :     haveGradientLine = true;
    4996               0 :     break;
    4997                 : 
    4998                 :   case eCSSToken_Function:
    4999               0 :     if (id.LowerCaseEqualsLiteral("-moz-calc")) {
    5000               0 :       haveGradientLine = true;
    5001               0 :       break;
    5002                 :     }
    5003                 :     // fall through
    5004                 :   case eCSSToken_ID:
    5005                 :   case eCSSToken_Ref:
    5006                 :     // this is a color
    5007               0 :     break;
    5008                 : 
    5009                 :   case eCSSToken_Ident: {
    5010                 :     // This is only a gradient line if it's a box position keyword.
    5011               0 :     nsCSSKeyword kw = nsCSSKeywords::LookupKeyword(id);
    5012                 :     PRInt32 junk;
    5013               0 :     if (kw != eCSSKeyword_UNKNOWN &&
    5014                 :         nsCSSProps::FindKeyword(kw, nsCSSProps::kBackgroundPositionKTable,
    5015               0 :                                 junk)) {
    5016               0 :       haveGradientLine = true;
    5017                 :     }
    5018               0 :     break;
    5019                 :   }
    5020                 : 
    5021                 :   default:
    5022                 :     // error
    5023               0 :     SkipUntil(')');
    5024               0 :     return false;
    5025                 :   }
    5026                 : 
    5027               0 :   if (haveGradientLine) {
    5028               0 :     if (toCorner) {
    5029                 :       // "to" syntax only allows box position keywords
    5030               0 :       if (ty != eCSSToken_Ident) {
    5031               0 :         SkipUntil(')');
    5032               0 :         return false;
    5033                 :       }
    5034                 : 
    5035                 :       // "to" syntax doesn't allow explicit "center"
    5036               0 :       if (!ParseBoxPositionValues(cssGradient->mBgPos, false, false)) {
    5037               0 :         SkipUntil(')');
    5038               0 :         return false;
    5039                 :       }
    5040                 : 
    5041               0 :       const nsCSSValue& xValue = cssGradient->mBgPos.mXValue;
    5042               0 :       const nsCSSValue& yValue = cssGradient->mBgPos.mYValue;
    5043               0 :       if (xValue.GetUnit() != eCSSUnit_Enumerated ||
    5044               0 :           !(xValue.GetIntValue() & (NS_STYLE_BG_POSITION_LEFT |
    5045                 :                                     NS_STYLE_BG_POSITION_CENTER |
    5046               0 :                                     NS_STYLE_BG_POSITION_RIGHT)) ||
    5047               0 :           yValue.GetUnit() != eCSSUnit_Enumerated ||
    5048               0 :           !(yValue.GetIntValue() & (NS_STYLE_BG_POSITION_TOP |
    5049                 :                                     NS_STYLE_BG_POSITION_CENTER |
    5050               0 :                                     NS_STYLE_BG_POSITION_BOTTOM))) {
    5051               0 :         SkipUntil(')');
    5052               0 :         return false;
    5053                 :       }
    5054                 : 
    5055               0 :       if (!ExpectSymbol(',', true)) {
    5056               0 :         SkipUntil(')');
    5057               0 :         return false;
    5058                 :       }
    5059                 :     } else {
    5060                 :       bool haveAngle =
    5061               0 :         ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nsnull);
    5062                 : 
    5063                 :       // if we got an angle, we might now have a comma, ending the gradient-line
    5064               0 :       if (!haveAngle || !ExpectSymbol(',', true)) {
    5065               0 :         if (!ParseBoxPositionValues(cssGradient->mBgPos, false)) {
    5066               0 :           SkipUntil(')');
    5067               0 :           return false;
    5068                 :         }
    5069                 : 
    5070               0 :         if (!ExpectSymbol(',', true) &&
    5071                 :             // if we didn't already get an angle, we might have one now,
    5072                 :             // otherwise it's an error
    5073                 :             (haveAngle ||
    5074               0 :              !ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nsnull) ||
    5075                 :              // now we better have a comma
    5076               0 :              !ExpectSymbol(',', true))) {
    5077               0 :           SkipUntil(')');
    5078               0 :           return false;
    5079                 :         }
    5080                 :       }
    5081                 :     }
    5082                 :   }
    5083                 : 
    5084                 :   // radial gradients might have a <gradient-shape-size> here
    5085               0 :   if (aIsRadial) {
    5086                 :     bool haveShape =
    5087               0 :       ParseVariant(cssGradient->mRadialShape, VARIANT_KEYWORD,
    5088               0 :                    nsCSSProps::kRadialGradientShapeKTable);
    5089                 :     bool haveSize =
    5090               0 :       ParseVariant(cssGradient->mRadialSize, VARIANT_KEYWORD,
    5091               0 :                    nsCSSProps::kRadialGradientSizeKTable);
    5092                 : 
    5093                 :     // could be in either order
    5094               0 :     if (!haveShape) {
    5095                 :       haveShape =
    5096               0 :         ParseVariant(cssGradient->mRadialShape, VARIANT_KEYWORD,
    5097               0 :                      nsCSSProps::kRadialGradientShapeKTable);
    5098                 :     }
    5099               0 :     if ((haveShape || haveSize) && !ExpectSymbol(',', true)) {
    5100               0 :       SkipUntil(')');
    5101               0 :       return false;
    5102                 :     }
    5103                 :   }
    5104                 : 
    5105                 :   // At least two color stops are required
    5106               0 :   if (!ParseColorStop(cssGradient) ||
    5107               0 :       !ExpectSymbol(',', true) ||
    5108               0 :       !ParseColorStop(cssGradient)) {
    5109               0 :     SkipUntil(')');
    5110               0 :     return false;
    5111                 :   }
    5112                 : 
    5113                 :   // Additional color stops
    5114               0 :   while (ExpectSymbol(',', true)) {
    5115               0 :     if (!ParseColorStop(cssGradient)) {
    5116               0 :       SkipUntil(')');
    5117               0 :       return false;
    5118                 :     }
    5119                 :   }
    5120                 : 
    5121               0 :   if (!ExpectSymbol(')', true)) {
    5122               0 :     SkipUntil(')');
    5123               0 :     return false;
    5124                 :   }
    5125                 : 
    5126               0 :   aValue.SetGradientValue(cssGradient);
    5127               0 :   return true;
    5128                 : }
    5129                 : 
    5130                 : PRInt32
    5131               0 : CSSParserImpl::ParseChoice(nsCSSValue aValues[],
    5132                 :                            const nsCSSProperty aPropIDs[], PRInt32 aNumIDs)
    5133                 : {
    5134               0 :   PRInt32 found = 0;
    5135               0 :   nsAutoParseCompoundProperty compound(this);
    5136                 : 
    5137                 :   PRInt32 loop;
    5138               0 :   for (loop = 0; loop < aNumIDs; loop++) {
    5139                 :     // Try each property parser in order
    5140               0 :     PRInt32 hadFound = found;
    5141                 :     PRInt32 index;
    5142               0 :     for (index = 0; index < aNumIDs; index++) {
    5143               0 :       PRInt32 bit = 1 << index;
    5144               0 :       if ((found & bit) == 0) {
    5145               0 :         if (ParseSingleValueProperty(aValues[index], aPropIDs[index])) {
    5146               0 :           found |= bit;
    5147                 :           // It's more efficient to break since it will reset |hadFound|
    5148                 :           // to |found|.  Furthermore, ParseListStyle depends on our going
    5149                 :           // through the properties in order for each value..
    5150               0 :           break;
    5151                 :         }
    5152                 :       }
    5153                 :     }
    5154               0 :     if (found == hadFound) {  // found nothing new
    5155               0 :       break;
    5156                 :     }
    5157                 :   }
    5158               0 :   if (0 < found) {
    5159               0 :     if (1 == found) { // only first property
    5160               0 :       if (eCSSUnit_Inherit == aValues[0].GetUnit()) { // one inherit, all inherit
    5161               0 :         for (loop = 1; loop < aNumIDs; loop++) {
    5162               0 :           aValues[loop].SetInheritValue();
    5163                 :         }
    5164               0 :         found = ((1 << aNumIDs) - 1);
    5165                 :       }
    5166               0 :       else if (eCSSUnit_Initial == aValues[0].GetUnit()) { // one initial, all initial
    5167               0 :         for (loop = 1; loop < aNumIDs; loop++) {
    5168               0 :           aValues[loop].SetInitialValue();
    5169                 :         }
    5170               0 :         found = ((1 << aNumIDs) - 1);
    5171                 :       }
    5172                 :     }
    5173                 :     else {  // more than one value, verify no inherits or initials
    5174               0 :       for (loop = 0; loop < aNumIDs; loop++) {
    5175               0 :         if (eCSSUnit_Inherit == aValues[loop].GetUnit()) {
    5176               0 :           found = -1;
    5177               0 :           break;
    5178                 :         }
    5179               0 :         else if (eCSSUnit_Initial == aValues[loop].GetUnit()) {
    5180               0 :           found = -1;
    5181               0 :           break;
    5182                 :         }
    5183                 :       }
    5184                 :     }
    5185                 :   }
    5186               0 :   return found;
    5187                 : }
    5188                 : 
    5189                 : void
    5190               0 : CSSParserImpl::AppendValue(nsCSSProperty aPropID, const nsCSSValue& aValue)
    5191                 : {
    5192               0 :   mTempData.AddLonghandProperty(aPropID, aValue);
    5193               0 : }
    5194                 : 
    5195                 : /**
    5196                 :  * Parse a "box" property. Box properties have 1 to 4 values. When less
    5197                 :  * than 4 values are provided a standard mapping is used to replicate
    5198                 :  * existing values.
    5199                 :  */
    5200                 : bool
    5201               0 : CSSParserImpl::ParseBoxProperties(const nsCSSProperty aPropIDs[])
    5202                 : {
    5203                 :   // Get up to four values for the property
    5204               0 :   PRInt32 count = 0;
    5205               0 :   nsCSSRect result;
    5206               0 :   NS_FOR_CSS_SIDES (index) {
    5207               0 :     if (! ParseSingleValueProperty(result.*(nsCSSRect::sides[index]),
    5208               0 :                                    aPropIDs[index])) {
    5209               0 :       break;
    5210                 :     }
    5211               0 :     count++;
    5212                 :   }
    5213               0 :   if ((count == 0) || (false == ExpectEndProperty())) {
    5214               0 :     return false;
    5215                 :   }
    5216                 : 
    5217               0 :   if (1 < count) { // verify no more than single inherit or initial
    5218               0 :     NS_FOR_CSS_SIDES (index) {
    5219               0 :       nsCSSUnit unit = (result.*(nsCSSRect::sides[index])).GetUnit();
    5220               0 :       if (eCSSUnit_Inherit == unit || eCSSUnit_Initial == unit) {
    5221               0 :         return false;
    5222                 :       }
    5223                 :     }
    5224                 :   }
    5225                 : 
    5226                 :   // Provide missing values by replicating some of the values found
    5227               0 :   switch (count) {
    5228                 :     case 1: // Make right == top
    5229               0 :       result.mRight = result.mTop;
    5230                 :     case 2: // Make bottom == top
    5231               0 :       result.mBottom = result.mTop;
    5232                 :     case 3: // Make left == right
    5233               0 :       result.mLeft = result.mRight;
    5234                 :   }
    5235                 : 
    5236               0 :   NS_FOR_CSS_SIDES (index) {
    5237               0 :     AppendValue(aPropIDs[index], result.*(nsCSSRect::sides[index]));
    5238                 :   }
    5239               0 :   return true;
    5240                 : }
    5241                 : 
    5242                 : // Similar to ParseBoxProperties, except there is only one property
    5243                 : // with the result as its value, not four. Requires values be nonnegative.
    5244                 : bool
    5245               0 : CSSParserImpl::ParseGroupedBoxProperty(PRInt32 aVariantMask,
    5246                 :                                        /** outparam */ nsCSSValue& aValue)
    5247                 : {
    5248               0 :   nsCSSRect& result = aValue.SetRectValue();
    5249                 : 
    5250               0 :   PRInt32 count = 0;
    5251               0 :   NS_FOR_CSS_SIDES (index) {
    5252               0 :     if (!ParseNonNegativeVariant(result.*(nsCSSRect::sides[index]),
    5253               0 :                                  aVariantMask, nsnull)) {
    5254               0 :       break;
    5255                 :     }
    5256               0 :     count++;
    5257                 :   }
    5258                 : 
    5259               0 :   if (count == 0) {
    5260               0 :     return false;
    5261                 :   }
    5262                 : 
    5263                 :   // Provide missing values by replicating some of the values found
    5264               0 :   switch (count) {
    5265                 :     case 1: // Make right == top
    5266               0 :       result.mRight = result.mTop;
    5267                 :     case 2: // Make bottom == top
    5268               0 :       result.mBottom = result.mTop;
    5269                 :     case 3: // Make left == right
    5270               0 :       result.mLeft = result.mRight;
    5271                 :   }
    5272                 : 
    5273               0 :   return true;
    5274                 : }
    5275                 : 
    5276                 : bool
    5277               0 : CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty,
    5278                 :                                            PRInt32 aSourceType)
    5279                 : {
    5280               0 :   const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(aProperty);
    5281               0 :   NS_ASSERTION(subprops[3] == eCSSProperty_UNKNOWN,
    5282                 :                "not box property with physical vs. logical cascading");
    5283               0 :   nsCSSValue value;
    5284               0 :   if (!ParseSingleValueProperty(value, subprops[0]) ||
    5285               0 :       !ExpectEndProperty())
    5286               0 :     return false;
    5287                 : 
    5288               0 :   AppendValue(subprops[0], value);
    5289               0 :   nsCSSValue typeVal(aSourceType, eCSSUnit_Enumerated);
    5290               0 :   AppendValue(subprops[1], typeVal);
    5291               0 :   AppendValue(subprops[2], typeVal);
    5292               0 :   return true;
    5293                 : }
    5294                 : 
    5295                 : bool
    5296               0 : CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID)
    5297                 : {
    5298               0 :   nsCSSValue dimenX, dimenY;
    5299                 :   // required first value
    5300               0 :   if (! ParseNonNegativeVariant(dimenX, VARIANT_HLP | VARIANT_CALC, nsnull))
    5301               0 :     return false;
    5302                 : 
    5303                 :   // optional second value (forbidden if first value is inherit/initial)
    5304               0 :   if (dimenX.GetUnit() != eCSSUnit_Inherit &&
    5305               0 :       dimenX.GetUnit() != eCSSUnit_Initial) {
    5306               0 :     ParseNonNegativeVariant(dimenY, VARIANT_LP | VARIANT_CALC, nsnull);
    5307                 :   }
    5308                 : 
    5309               0 :   if (dimenX == dimenY || dimenY.GetUnit() == eCSSUnit_Null) {
    5310               0 :     AppendValue(aPropID, dimenX);
    5311                 :   } else {
    5312               0 :     nsCSSValue value;
    5313               0 :     value.SetPairValue(dimenX, dimenY);
    5314               0 :     AppendValue(aPropID, value);
    5315                 :   }
    5316               0 :   return true;
    5317                 : }
    5318                 : 
    5319                 : bool
    5320               0 : CSSParserImpl::ParseBoxCornerRadii(const nsCSSProperty aPropIDs[])
    5321                 : {
    5322                 :   // Rectangles are used as scratch storage.
    5323                 :   // top => top-left, right => top-right,
    5324                 :   // bottom => bottom-right, left => bottom-left.
    5325               0 :   nsCSSRect dimenX, dimenY;
    5326               0 :   PRInt32 countX = 0, countY = 0;
    5327                 : 
    5328               0 :   NS_FOR_CSS_SIDES (side) {
    5329               0 :     if (! ParseNonNegativeVariant(dimenX.*nsCSSRect::sides[side],
    5330                 :                                   (side > 0 ? 0 : VARIANT_INHERIT) |
    5331                 :                                     VARIANT_LP | VARIANT_CALC,
    5332               0 :                                   nsnull))
    5333               0 :       break;
    5334               0 :     countX++;
    5335                 :   }
    5336               0 :   if (countX == 0)
    5337               0 :     return false;
    5338                 : 
    5339               0 :   if (ExpectSymbol('/', true)) {
    5340               0 :     NS_FOR_CSS_SIDES (side) {
    5341               0 :       if (! ParseNonNegativeVariant(dimenY.*nsCSSRect::sides[side],
    5342               0 :                                     VARIANT_LP | VARIANT_CALC, nsnull))
    5343               0 :         break;
    5344               0 :       countY++;
    5345                 :     }
    5346               0 :     if (countY == 0)
    5347               0 :       return false;
    5348                 :   }
    5349               0 :   if (!ExpectEndProperty())
    5350               0 :     return false;
    5351                 : 
    5352                 :   // if 'initial' or 'inherit' was used, it must be the only value
    5353               0 :   if (countX > 1 || countY > 0) {
    5354               0 :     nsCSSUnit unit = dimenX.mTop.GetUnit();
    5355               0 :     if (eCSSUnit_Inherit == unit || eCSSUnit_Initial == unit)
    5356               0 :       return false;
    5357                 :   }
    5358                 : 
    5359                 :   // if we have no Y-values, use the X-values
    5360               0 :   if (countY == 0) {
    5361               0 :     dimenY = dimenX;
    5362               0 :     countY = countX;
    5363                 :   }
    5364                 : 
    5365                 :   // Provide missing values by replicating some of the values found
    5366               0 :   switch (countX) {
    5367               0 :     case 1: dimenX.mRight = dimenX.mTop;  // top-right same as top-left, and
    5368               0 :     case 2: dimenX.mBottom = dimenX.mTop; // bottom-right same as top-left, and 
    5369               0 :     case 3: dimenX.mLeft = dimenX.mRight; // bottom-left same as top-right
    5370                 :   }
    5371                 : 
    5372               0 :   switch (countY) {
    5373               0 :     case 1: dimenY.mRight = dimenY.mTop;  // top-right same as top-left, and
    5374               0 :     case 2: dimenY.mBottom = dimenY.mTop; // bottom-right same as top-left, and 
    5375               0 :     case 3: dimenY.mLeft = dimenY.mRight; // bottom-left same as top-right
    5376                 :   }
    5377                 : 
    5378               0 :   NS_FOR_CSS_SIDES(side) {
    5379               0 :     nsCSSValue& x = dimenX.*nsCSSRect::sides[side];
    5380               0 :     nsCSSValue& y = dimenY.*nsCSSRect::sides[side];
    5381                 : 
    5382               0 :     if (x == y) {
    5383               0 :       AppendValue(aPropIDs[side], x);
    5384                 :     } else {
    5385               0 :       nsCSSValue pair;
    5386               0 :       pair.SetPairValue(x, y);
    5387               0 :       AppendValue(aPropIDs[side], pair);
    5388                 :     }
    5389                 :   }
    5390               0 :   return true;
    5391                 : }
    5392                 : 
    5393                 : // These must be in CSS order (top,right,bottom,left) for indexing to work
    5394                 : static const nsCSSProperty kBorderStyleIDs[] = {
    5395                 :   eCSSProperty_border_top_style,
    5396                 :   eCSSProperty_border_right_style_value,
    5397                 :   eCSSProperty_border_bottom_style,
    5398                 :   eCSSProperty_border_left_style_value
    5399                 : };
    5400                 : static const nsCSSProperty kBorderWidthIDs[] = {
    5401                 :   eCSSProperty_border_top_width,
    5402                 :   eCSSProperty_border_right_width_value,
    5403                 :   eCSSProperty_border_bottom_width,
    5404                 :   eCSSProperty_border_left_width_value
    5405                 : };
    5406                 : static const nsCSSProperty kBorderColorIDs[] = {
    5407                 :   eCSSProperty_border_top_color,
    5408                 :   eCSSProperty_border_right_color_value,
    5409                 :   eCSSProperty_border_bottom_color,
    5410                 :   eCSSProperty_border_left_color_value
    5411                 : };
    5412                 : static const nsCSSProperty kBorderRadiusIDs[] = {
    5413                 :   eCSSProperty_border_top_left_radius,
    5414                 :   eCSSProperty_border_top_right_radius,
    5415                 :   eCSSProperty_border_bottom_right_radius,
    5416                 :   eCSSProperty_border_bottom_left_radius
    5417                 : };
    5418                 : static const nsCSSProperty kOutlineRadiusIDs[] = {
    5419                 :   eCSSProperty__moz_outline_radius_topLeft,
    5420                 :   eCSSProperty__moz_outline_radius_topRight,
    5421                 :   eCSSProperty__moz_outline_radius_bottomRight,
    5422                 :   eCSSProperty__moz_outline_radius_bottomLeft
    5423                 : };
    5424                 : 
    5425                 : bool
    5426               0 : CSSParserImpl::ParseProperty(nsCSSProperty aPropID)
    5427                 : {
    5428               0 :   NS_ASSERTION(aPropID < eCSSProperty_COUNT, "index out of range");
    5429               0 :   switch (nsCSSProps::PropertyParseType(aPropID)) {
    5430                 :     case CSS_PROPERTY_PARSE_INACCESSIBLE: {
    5431                 :       // The user can't use these
    5432               0 :       REPORT_UNEXPECTED(PEInaccessibleProperty2);
    5433               0 :       return false;
    5434                 :     }
    5435                 :     case CSS_PROPERTY_PARSE_FUNCTION: {
    5436               0 :       return ParsePropertyByFunction(aPropID);
    5437                 :     }
    5438                 :     case CSS_PROPERTY_PARSE_VALUE: {
    5439               0 :       nsCSSValue value;
    5440               0 :       if (ParseSingleValueProperty(value, aPropID)) {
    5441               0 :         if (ExpectEndProperty()) {
    5442               0 :           AppendValue(aPropID, value);
    5443               0 :           return true;
    5444                 :         }
    5445                 :         // XXX Report errors?
    5446                 :       }
    5447                 :       // XXX Report errors?
    5448               0 :       return false;
    5449                 :     }
    5450                 :     case CSS_PROPERTY_PARSE_VALUE_LIST: {
    5451               0 :       return ParseValueList(aPropID);
    5452                 :     }
    5453                 :   }
    5454               0 :   NS_ABORT_IF_FALSE(false,
    5455                 :                     "Property's flags field in nsCSSPropList.h is missing "
    5456                 :                     "one of the CSS_PROPERTY_PARSE_* constants");
    5457               0 :   return false;
    5458                 : }
    5459                 : 
    5460                 : bool
    5461               0 : CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID)
    5462                 : {
    5463               0 :   switch (aPropID) {  // handle shorthand or multiple properties
    5464                 :   case eCSSProperty_background:
    5465               0 :     return ParseBackground();
    5466                 :   case eCSSProperty_background_repeat:
    5467               0 :     return ParseBackgroundRepeat();
    5468                 :   case eCSSProperty_background_position:
    5469               0 :     return ParseBackgroundPosition();
    5470                 :   case eCSSProperty_background_size:
    5471               0 :     return ParseBackgroundSize();
    5472                 :   case eCSSProperty_border:
    5473               0 :     return ParseBorderSide(kBorderTopIDs, true);
    5474                 :   case eCSSProperty_border_color:
    5475               0 :     return ParseBorderColor();
    5476                 :   case eCSSProperty_border_spacing:
    5477               0 :     return ParseBorderSpacing();
    5478                 :   case eCSSProperty_border_style:
    5479               0 :     return ParseBorderStyle();
    5480                 :   case eCSSProperty_border_bottom:
    5481               0 :     return ParseBorderSide(kBorderBottomIDs, false);
    5482                 :   case eCSSProperty_border_end:
    5483                 :     return ParseDirectionalBorderSide(kBorderEndIDs,
    5484               0 :                                       NS_BOXPROP_SOURCE_LOGICAL);
    5485                 :   case eCSSProperty_border_left:
    5486                 :     return ParseDirectionalBorderSide(kBorderLeftIDs,
    5487               0 :                                       NS_BOXPROP_SOURCE_PHYSICAL);
    5488                 :   case eCSSProperty_border_right:
    5489                 :     return ParseDirectionalBorderSide(kBorderRightIDs,
    5490               0 :                                       NS_BOXPROP_SOURCE_PHYSICAL);
    5491                 :   case eCSSProperty_border_start:
    5492                 :     return ParseDirectionalBorderSide(kBorderStartIDs,
    5493               0 :                                       NS_BOXPROP_SOURCE_LOGICAL);
    5494                 :   case eCSSProperty_border_top:
    5495               0 :     return ParseBorderSide(kBorderTopIDs, false);
    5496                 :   case eCSSProperty_border_bottom_colors:
    5497                 :   case eCSSProperty_border_left_colors:
    5498                 :   case eCSSProperty_border_right_colors:
    5499                 :   case eCSSProperty_border_top_colors:
    5500               0 :     return ParseBorderColors(aPropID);
    5501                 :   case eCSSProperty_border_image_slice:
    5502               0 :     return ParseBorderImageSlice(true, nsnull);
    5503                 :   case eCSSProperty_border_image_width:
    5504               0 :     return ParseBorderImageWidth(true);
    5505                 :   case eCSSProperty_border_image_outset:
    5506               0 :     return ParseBorderImageOutset(true);
    5507                 :   case eCSSProperty_border_image_repeat:
    5508               0 :     return ParseBorderImageRepeat(true);
    5509                 :   case eCSSProperty_border_image:
    5510               0 :     return ParseBorderImage();
    5511                 :   case eCSSProperty_border_width:
    5512               0 :     return ParseBorderWidth();
    5513                 :   case eCSSProperty_border_end_color:
    5514                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_end_color,
    5515               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5516                 :   case eCSSProperty_border_left_color:
    5517                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_left_color,
    5518               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5519                 :   case eCSSProperty_border_right_color:
    5520                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_right_color,
    5521               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5522                 :   case eCSSProperty_border_start_color:
    5523                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_start_color,
    5524               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5525                 :   case eCSSProperty_border_end_width:
    5526                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_end_width,
    5527               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5528                 :   case eCSSProperty_border_left_width:
    5529                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_left_width,
    5530               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5531                 :   case eCSSProperty_border_right_width:
    5532                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_right_width,
    5533               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5534                 :   case eCSSProperty_border_start_width:
    5535                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_start_width,
    5536               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5537                 :   case eCSSProperty_border_end_style:
    5538                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_end_style,
    5539               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5540                 :   case eCSSProperty_border_left_style:
    5541                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_left_style,
    5542               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5543                 :   case eCSSProperty_border_right_style:
    5544                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_right_style,
    5545               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5546                 :   case eCSSProperty_border_start_style:
    5547                 :     return ParseDirectionalBoxProperty(eCSSProperty_border_start_style,
    5548               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5549                 :   case eCSSProperty_border_radius:
    5550               0 :     return ParseBoxCornerRadii(kBorderRadiusIDs);
    5551                 :   case eCSSProperty__moz_outline_radius:
    5552               0 :     return ParseBoxCornerRadii(kOutlineRadiusIDs);
    5553                 : 
    5554                 :   case eCSSProperty_border_top_left_radius:
    5555                 :   case eCSSProperty_border_top_right_radius:
    5556                 :   case eCSSProperty_border_bottom_right_radius:
    5557                 :   case eCSSProperty_border_bottom_left_radius:
    5558                 :   case eCSSProperty__moz_outline_radius_topLeft:
    5559                 :   case eCSSProperty__moz_outline_radius_topRight:
    5560                 :   case eCSSProperty__moz_outline_radius_bottomRight:
    5561                 :   case eCSSProperty__moz_outline_radius_bottomLeft:
    5562               0 :     return ParseBoxCornerRadius(aPropID);
    5563                 : 
    5564                 :   case eCSSProperty_box_shadow:
    5565                 :   case eCSSProperty_text_shadow:
    5566               0 :     return ParseShadowList(aPropID);
    5567                 : 
    5568                 :   case eCSSProperty_clip:
    5569               0 :     return ParseRect(eCSSProperty_clip);
    5570                 :   case eCSSProperty__moz_columns:
    5571               0 :     return ParseColumns();
    5572                 :   case eCSSProperty__moz_column_rule:
    5573               0 :     return ParseBorderSide(kColumnRuleIDs, false);
    5574                 :   case eCSSProperty_content:
    5575               0 :     return ParseContent();
    5576                 :   case eCSSProperty_counter_increment:
    5577                 :   case eCSSProperty_counter_reset:
    5578               0 :     return ParseCounterData(aPropID);
    5579                 :   case eCSSProperty_cursor:
    5580               0 :     return ParseCursor();
    5581                 :   case eCSSProperty_font:
    5582               0 :     return ParseFont();
    5583                 :   case eCSSProperty_image_region:
    5584               0 :     return ParseRect(eCSSProperty_image_region);
    5585                 :   case eCSSProperty_list_style:
    5586               0 :     return ParseListStyle();
    5587                 :   case eCSSProperty_margin:
    5588               0 :     return ParseMargin();
    5589                 :   case eCSSProperty_margin_end:
    5590                 :     return ParseDirectionalBoxProperty(eCSSProperty_margin_end,
    5591               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5592                 :   case eCSSProperty_margin_left:
    5593                 :     return ParseDirectionalBoxProperty(eCSSProperty_margin_left,
    5594               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5595                 :   case eCSSProperty_margin_right:
    5596                 :     return ParseDirectionalBoxProperty(eCSSProperty_margin_right,
    5597               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5598                 :   case eCSSProperty_margin_start:
    5599                 :     return ParseDirectionalBoxProperty(eCSSProperty_margin_start,
    5600               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5601                 :   case eCSSProperty_outline:
    5602               0 :     return ParseOutline();
    5603                 :   case eCSSProperty_overflow:
    5604               0 :     return ParseOverflow();
    5605                 :   case eCSSProperty_padding:
    5606               0 :     return ParsePadding();
    5607                 :   case eCSSProperty_padding_end:
    5608                 :     return ParseDirectionalBoxProperty(eCSSProperty_padding_end,
    5609               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5610                 :   case eCSSProperty_padding_left:
    5611                 :     return ParseDirectionalBoxProperty(eCSSProperty_padding_left,
    5612               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5613                 :   case eCSSProperty_padding_right:
    5614                 :     return ParseDirectionalBoxProperty(eCSSProperty_padding_right,
    5615               0 :                                        NS_BOXPROP_SOURCE_PHYSICAL);
    5616                 :   case eCSSProperty_padding_start:
    5617                 :     return ParseDirectionalBoxProperty(eCSSProperty_padding_start,
    5618               0 :                                        NS_BOXPROP_SOURCE_LOGICAL);
    5619                 :   case eCSSProperty_quotes:
    5620               0 :     return ParseQuotes();
    5621                 :   case eCSSProperty_size:
    5622               0 :     return ParseSize();
    5623                 :   case eCSSProperty_text_decoration:
    5624               0 :     return ParseTextDecoration();
    5625                 :   case eCSSProperty__moz_transform:
    5626               0 :     return ParseMozTransform();
    5627                 :   case eCSSProperty__moz_transform_origin:
    5628               0 :     return ParseMozTransformOrigin(false);
    5629                 :   case eCSSProperty_perspective_origin:
    5630               0 :     return ParseMozTransformOrigin(true);
    5631                 :   case eCSSProperty_transition:
    5632               0 :     return ParseTransition();
    5633                 :   case eCSSProperty_animation:
    5634               0 :     return ParseAnimation();
    5635                 :   case eCSSProperty_transition_property:
    5636               0 :     return ParseTransitionProperty();
    5637                 :   case eCSSProperty_fill:
    5638                 :   case eCSSProperty_stroke:
    5639               0 :     return ParsePaint(aPropID);
    5640                 :   case eCSSProperty_stroke_dasharray:
    5641               0 :     return ParseDasharray();
    5642                 :   case eCSSProperty_marker:
    5643               0 :     return ParseMarker();
    5644                 :   default:
    5645               0 :     NS_ABORT_IF_FALSE(false, "should not be called");
    5646               0 :     return false;
    5647                 :   }
    5648                 : }
    5649                 : 
    5650                 : // Bits used in determining which background position info we have
    5651                 : #define BG_CENTER  NS_STYLE_BG_POSITION_CENTER
    5652                 : #define BG_TOP     NS_STYLE_BG_POSITION_TOP
    5653                 : #define BG_BOTTOM  NS_STYLE_BG_POSITION_BOTTOM
    5654                 : #define BG_LEFT    NS_STYLE_BG_POSITION_LEFT
    5655                 : #define BG_RIGHT   NS_STYLE_BG_POSITION_RIGHT
    5656                 : #define BG_CTB    (BG_CENTER | BG_TOP | BG_BOTTOM)
    5657                 : #define BG_TB     (BG_TOP | BG_BOTTOM)
    5658                 : #define BG_CLR    (BG_CENTER | BG_LEFT | BG_RIGHT)
    5659                 : #define BG_LR     (BG_LEFT | BG_RIGHT)
    5660                 : 
    5661                 : bool
    5662               0 : CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
    5663                 :                                         nsCSSProperty aPropID)
    5664                 : {
    5665               0 :   if (aPropID == eCSSPropertyExtra_x_none_value) {
    5666               0 :     return ParseVariant(aValue, VARIANT_NONE | VARIANT_INHERIT, nsnull);
    5667                 :   }
    5668                 : 
    5669               0 :   if (aPropID == eCSSPropertyExtra_x_auto_value) {
    5670               0 :     return ParseVariant(aValue, VARIANT_AUTO | VARIANT_INHERIT, nsnull);
    5671                 :   }
    5672                 : 
    5673               0 :   if (aPropID < 0 || aPropID >= eCSSProperty_COUNT_no_shorthands) {
    5674               0 :     NS_ABORT_IF_FALSE(false, "not a single value property");
    5675               0 :     return false;
    5676                 :   }
    5677                 : 
    5678               0 :   if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_VALUE_PARSER_FUNCTION)) {
    5679               0 :     switch (aPropID) {
    5680                 :       case eCSSProperty_font_family:
    5681               0 :         return ParseFamily(aValue);
    5682                 :       case eCSSProperty_font_weight:
    5683               0 :         return ParseFontWeight(aValue);
    5684                 :       case eCSSProperty_marks:
    5685               0 :         return ParseMarks(aValue);
    5686                 :       case eCSSProperty_text_decoration_line:
    5687               0 :         return ParseTextDecorationLine(aValue);
    5688                 :       case eCSSProperty_text_overflow:
    5689               0 :         return ParseTextOverflow(aValue);
    5690                 :       case eCSSProperty_unicode_bidi:
    5691               0 :         return ParseUnicodeBidi(aValue);
    5692                 :       default:
    5693               0 :         NS_ABORT_IF_FALSE(false, "should not reach here");
    5694               0 :         return false;
    5695                 :     }
    5696                 :   }
    5697                 : 
    5698               0 :   PRUint32 variant = nsCSSProps::ParserVariant(aPropID);
    5699               0 :   if (variant == 0) {
    5700               0 :     NS_ABORT_IF_FALSE(false, "not a single value property");
    5701               0 :     return false;
    5702                 :   }
    5703                 : 
    5704                 :   // We only allow 'script-level' when unsafe rules are enabled, because
    5705                 :   // otherwise it could interfere with rulenode optimizations if used in
    5706                 :   // a non-MathML-enabled document.
    5707               0 :   if (aPropID == eCSSProperty_script_level && !mUnsafeRulesEnabled)
    5708               0 :     return false;
    5709                 : 
    5710               0 :   const PRInt32 *kwtable = nsCSSProps::kKeywordTableTable[aPropID];
    5711               0 :   switch (nsCSSProps::ValueRestrictions(aPropID)) {
    5712                 :     default:
    5713               0 :       NS_ABORT_IF_FALSE(false, "should not be reached");
    5714                 :     case 0:
    5715               0 :       return ParseVariant(aValue, variant, kwtable);
    5716                 :     case CSS_PROPERTY_VALUE_NONNEGATIVE:
    5717               0 :       return ParseNonNegativeVariant(aValue, variant, kwtable);
    5718                 :     case CSS_PROPERTY_VALUE_AT_LEAST_ONE:
    5719               0 :       return ParseOneOrLargerVariant(aValue, variant, kwtable);
    5720                 :   }
    5721                 : }
    5722                 : 
    5723                 : // nsFont::EnumerateFamilies callback for ParseFontDescriptorValue
    5724               0 : struct NS_STACK_CLASS ExtractFirstFamilyData {
    5725                 :   nsAutoString mFamilyName;
    5726                 :   bool mGood;
    5727               0 :   ExtractFirstFamilyData() : mFamilyName(), mGood(false) {}
    5728                 : };
    5729                 : 
    5730                 : static bool
    5731               0 : ExtractFirstFamily(const nsString& aFamily,
    5732                 :                    bool aGeneric,
    5733                 :                    void* aData)
    5734                 : {
    5735               0 :   ExtractFirstFamilyData* realData = (ExtractFirstFamilyData*) aData;
    5736               0 :   if (aGeneric || realData->mFamilyName.Length() > 0) {
    5737               0 :     realData->mGood = false;
    5738               0 :     return false;
    5739                 :   }
    5740               0 :   realData->mFamilyName.Assign(aFamily);
    5741               0 :   realData->mGood = true;
    5742               0 :   return true;
    5743                 : }
    5744                 : 
    5745                 : // font-descriptor: descriptor ':' value ';'
    5746                 : // caller has advanced mToken to point at the descriptor
    5747                 : bool
    5748               0 : CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID,
    5749                 :                                         nsCSSValue& aValue)
    5750                 : {
    5751               0 :   switch (aDescID) {
    5752                 :     // These four are similar to the properties of the same name,
    5753                 :     // possibly with more restrictions on the values they can take.
    5754                 :   case eCSSFontDesc_Family: {
    5755               0 :     if (!ParseFamily(aValue) ||
    5756               0 :         aValue.GetUnit() != eCSSUnit_Families)
    5757               0 :       return false;
    5758                 : 
    5759                 :     // the style parameters to the nsFont constructor are ignored,
    5760                 :     // because it's only being used to call EnumerateFamilies
    5761               0 :     nsAutoString valueStr;
    5762               0 :     aValue.GetStringValue(valueStr);
    5763               0 :     nsFont font(valueStr, 0, 0, 0, 0, 0, 0);
    5764               0 :     ExtractFirstFamilyData dat;
    5765                 : 
    5766               0 :     font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat);
    5767               0 :     if (!dat.mGood)
    5768               0 :       return false;
    5769                 : 
    5770               0 :     aValue.SetStringValue(dat.mFamilyName, eCSSUnit_String);
    5771               0 :     return true;
    5772                 :   }
    5773                 : 
    5774                 :   case eCSSFontDesc_Style:
    5775                 :     // property is VARIANT_HMK|VARIANT_SYSFONT
    5776                 :     return ParseVariant(aValue, VARIANT_KEYWORD | VARIANT_NORMAL,
    5777               0 :                         nsCSSProps::kFontStyleKTable);
    5778                 : 
    5779                 :   case eCSSFontDesc_Weight:
    5780               0 :     return (ParseFontWeight(aValue) &&
    5781               0 :             aValue.GetUnit() != eCSSUnit_Inherit &&
    5782               0 :             aValue.GetUnit() != eCSSUnit_Initial &&
    5783               0 :             (aValue.GetUnit() != eCSSUnit_Enumerated ||
    5784               0 :              (aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER &&
    5785               0 :               aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER)));
    5786                 : 
    5787                 :   case eCSSFontDesc_Stretch:
    5788                 :     // property is VARIANT_HK|VARIANT_SYSFONT
    5789                 :     return ParseVariant(aValue, VARIANT_KEYWORD,
    5790               0 :                         nsCSSProps::kFontStretchKTable);
    5791                 : 
    5792                 :     // These two are unique to @font-face and have their own special grammar.
    5793                 :   case eCSSFontDesc_Src:
    5794               0 :     return ParseFontSrc(aValue);
    5795                 : 
    5796                 :   case eCSSFontDesc_UnicodeRange:
    5797               0 :     return ParseFontRanges(aValue);
    5798                 : 
    5799                 :   case eCSSFontDesc_FontFeatureSettings:
    5800                 :   case eCSSFontDesc_FontLanguageOverride:
    5801               0 :     return ParseVariant(aValue, VARIANT_NORMAL | VARIANT_STRING, nsnull);
    5802                 : 
    5803                 :   case eCSSFontDesc_UNKNOWN:
    5804                 :   case eCSSFontDesc_COUNT:
    5805               0 :     NS_NOTREACHED("bad nsCSSFontDesc code");
    5806                 :   }
    5807                 :   // explicitly do NOT have a default case to let the compiler
    5808                 :   // help find missing descriptors
    5809               0 :   return false;
    5810                 : }
    5811                 : 
    5812                 : void
    5813               0 : CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties)
    5814                 : {
    5815               0 :   nsCSSValue physical(NS_BOXPROP_SOURCE_PHYSICAL, eCSSUnit_Enumerated);
    5816               0 :   for (const nsCSSProperty *prop = aSourceProperties;
    5817                 :        *prop != eCSSProperty_UNKNOWN; ++prop) {
    5818               0 :     AppendValue(*prop, physical);
    5819                 :   }
    5820               0 : }
    5821                 : 
    5822                 : static nsCSSValue
    5823               0 : BoxPositionMaskToCSSValue(PRInt32 aMask, bool isX)
    5824                 : {
    5825               0 :   PRInt32 val = NS_STYLE_BG_POSITION_CENTER;
    5826               0 :   if (isX) {
    5827               0 :     if (aMask & BG_LEFT) {
    5828               0 :       val = NS_STYLE_BG_POSITION_LEFT;
    5829                 :     }
    5830               0 :     else if (aMask & BG_RIGHT) {
    5831               0 :       val = NS_STYLE_BG_POSITION_RIGHT;
    5832                 :     }
    5833                 :   }
    5834                 :   else {
    5835               0 :     if (aMask & BG_TOP) {
    5836               0 :       val = NS_STYLE_BG_POSITION_TOP;
    5837                 :     }
    5838               0 :     else if (aMask & BG_BOTTOM) {
    5839               0 :       val = NS_STYLE_BG_POSITION_BOTTOM;
    5840                 :     }
    5841                 :   }
    5842                 : 
    5843               0 :   return nsCSSValue(val, eCSSUnit_Enumerated);
    5844                 : }
    5845                 : 
    5846                 : bool
    5847               0 : CSSParserImpl::ParseBackground()
    5848                 : {
    5849               0 :   nsAutoParseCompoundProperty compound(this);
    5850                 : 
    5851                 :   // background-color can only be set once, so it's not a list.
    5852               0 :   nsCSSValue color;
    5853                 : 
    5854                 :   // Check first for inherit/initial.
    5855               0 :   if (ParseVariant(color, VARIANT_INHERIT, nsnull)) {
    5856                 :     // must be alone
    5857               0 :     if (!ExpectEndProperty()) {
    5858               0 :       return false;
    5859                 :     }
    5860               0 :     for (const nsCSSProperty* subprops =
    5861               0 :            nsCSSProps::SubpropertyEntryFor(eCSSProperty_background);
    5862                 :          *subprops != eCSSProperty_UNKNOWN; ++subprops) {
    5863               0 :       AppendValue(*subprops, color);
    5864                 :     }
    5865               0 :     return true;
    5866                 :   }
    5867                 : 
    5868               0 :   nsCSSValue image, repeat, attachment, clip, origin, position, size;
    5869                 :   BackgroundParseState state(color, image.SetListValue(), 
    5870                 :                              repeat.SetPairListValue(),
    5871                 :                              attachment.SetListValue(), clip.SetListValue(),
    5872                 :                              origin.SetListValue(), position.SetListValue(),
    5873               0 :                              size.SetPairListValue());
    5874                 : 
    5875               0 :   for (;;) {
    5876               0 :     if (!ParseBackgroundItem(state)) {
    5877               0 :       return false;
    5878                 :     }
    5879               0 :     if (CheckEndProperty()) {
    5880                 :       break;
    5881                 :     }
    5882                 :     // If we saw a color, this must be the last item.
    5883               0 :     if (color.GetUnit() != eCSSUnit_Null) {
    5884               0 :       REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);
    5885               0 :       return false;
    5886                 :     }
    5887                 :     // Otherwise, a comma is mandatory.
    5888               0 :     if (!ExpectSymbol(',', true)) {
    5889               0 :       return false;
    5890                 :     }
    5891                 :     // Chain another entry on all the lists.
    5892               0 :     state.mImage->mNext = new nsCSSValueList;
    5893               0 :     state.mImage = state.mImage->mNext;
    5894               0 :     state.mRepeat->mNext = new nsCSSValuePairList;
    5895               0 :     state.mRepeat = state.mRepeat->mNext;
    5896               0 :     state.mAttachment->mNext = new nsCSSValueList;
    5897               0 :     state.mAttachment = state.mAttachment->mNext;
    5898               0 :     state.mClip->mNext = new nsCSSValueList;
    5899               0 :     state.mClip = state.mClip->mNext;
    5900               0 :     state.mOrigin->mNext = new nsCSSValueList;
    5901               0 :     state.mOrigin = state.mOrigin->mNext;
    5902               0 :     state.mPosition->mNext = new nsCSSValueList;
    5903               0 :     state.mPosition = state.mPosition->mNext;
    5904               0 :     state.mSize->mNext = new nsCSSValuePairList;
    5905               0 :     state.mSize = state.mSize->mNext;
    5906                 :   }
    5907                 : 
    5908                 :   // If we get to this point without seeing a color, provide a default.
    5909               0 :   if (color.GetUnit() == eCSSUnit_Null) {
    5910               0 :     color.SetColorValue(NS_RGBA(0,0,0,0));
    5911                 :   }
    5912                 : 
    5913               0 :   AppendValue(eCSSProperty_background_image,      image);
    5914               0 :   AppendValue(eCSSProperty_background_repeat,     repeat);
    5915               0 :   AppendValue(eCSSProperty_background_attachment, attachment);
    5916               0 :   AppendValue(eCSSProperty_background_clip,       clip);
    5917               0 :   AppendValue(eCSSProperty_background_origin,     origin);
    5918               0 :   AppendValue(eCSSProperty_background_position,   position);
    5919               0 :   AppendValue(eCSSProperty_background_size,       size);
    5920               0 :   AppendValue(eCSSProperty_background_color,      color);
    5921               0 :   return true;
    5922                 : }
    5923                 : 
    5924                 : // Parse one item of the background shorthand property.
    5925                 : bool
    5926               0 : CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState)
    5927                 : 
    5928                 : {
    5929                 :   // Fill in the values that the shorthand will set if we don't find
    5930                 :   // other values.
    5931               0 :   aState.mImage->mValue.SetNoneValue();
    5932                 :   aState.mRepeat->mXValue.SetIntValue(NS_STYLE_BG_REPEAT_REPEAT,
    5933               0 :                                       eCSSUnit_Enumerated);
    5934               0 :   aState.mRepeat->mYValue.Reset();
    5935                 :   aState.mAttachment->mValue.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL,
    5936               0 :                                          eCSSUnit_Enumerated);
    5937                 :   aState.mClip->mValue.SetIntValue(NS_STYLE_BG_CLIP_BORDER,
    5938               0 :                                    eCSSUnit_Enumerated);
    5939                 :   aState.mOrigin->mValue.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING,
    5940               0 :                                      eCSSUnit_Enumerated);
    5941               0 :   nsRefPtr<nsCSSValue::Array> positionArr = nsCSSValue::Array::Create(4);
    5942               0 :   aState.mPosition->mValue.SetArrayValue(positionArr, eCSSUnit_Array);
    5943               0 :   positionArr->Item(1).SetPercentValue(0.0f);
    5944               0 :   positionArr->Item(3).SetPercentValue(0.0f);
    5945               0 :   aState.mSize->mXValue.SetAutoValue();
    5946               0 :   aState.mSize->mYValue.SetAutoValue();
    5947                 : 
    5948               0 :   bool haveColor = false,
    5949               0 :          haveImage = false,
    5950               0 :          haveRepeat = false,
    5951               0 :          haveAttach = false,
    5952               0 :          havePosition = false,
    5953               0 :          haveOrigin = false,
    5954               0 :          haveSomething = false;
    5955                 : 
    5956               0 :   while (GetToken(true)) {
    5957               0 :     nsCSSTokenType tt = mToken.mType;
    5958               0 :     UngetToken(); // ...but we'll still cheat and use mToken
    5959               0 :     if (tt == eCSSToken_Symbol) {
    5960                 :       // ExpectEndProperty only looks for symbols, and nothing else will
    5961                 :       // show up as one.
    5962               0 :       break;
    5963                 :     }
    5964                 : 
    5965               0 :     if (tt == eCSSToken_Ident) {
    5966               0 :       nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
    5967                 :       PRInt32 dummy;
    5968               0 :       if (keyword == eCSSKeyword_inherit ||
    5969                 :           keyword == eCSSKeyword__moz_initial) {
    5970               0 :         return false;
    5971               0 :       } else if (keyword == eCSSKeyword_none) {
    5972               0 :         if (haveImage)
    5973               0 :           return false;
    5974               0 :         haveImage = true;
    5975               0 :         if (!ParseSingleValueProperty(aState.mImage->mValue,
    5976               0 :                                       eCSSProperty_background_image)) {
    5977               0 :           NS_NOTREACHED("should be able to parse");
    5978               0 :           return false;
    5979                 :         }
    5980               0 :       } else if (nsCSSProps::FindKeyword(keyword,
    5981                 :                    nsCSSProps::kBackgroundAttachmentKTable, dummy)) {
    5982               0 :         if (haveAttach)
    5983               0 :           return false;
    5984               0 :         haveAttach = true;
    5985               0 :         if (!ParseSingleValueProperty(aState.mAttachment->mValue,
    5986               0 :                                       eCSSProperty_background_attachment)) {
    5987               0 :           NS_NOTREACHED("should be able to parse");
    5988               0 :           return false;
    5989                 :         }
    5990               0 :       } else if (nsCSSProps::FindKeyword(keyword,
    5991                 :                    nsCSSProps::kBackgroundRepeatKTable, dummy)) {
    5992               0 :         if (haveRepeat)
    5993               0 :           return false;
    5994               0 :         haveRepeat = true;
    5995               0 :         nsCSSValuePair scratch;
    5996               0 :         if (!ParseBackgroundRepeatValues(scratch)) {
    5997               0 :           NS_NOTREACHED("should be able to parse");
    5998               0 :           return false;
    5999                 :         }
    6000               0 :         aState.mRepeat->mXValue = scratch.mXValue;
    6001               0 :         aState.mRepeat->mYValue = scratch.mYValue;
    6002               0 :       } else if (nsCSSProps::FindKeyword(keyword,
    6003                 :                    nsCSSProps::kBackgroundPositionKTable, dummy)) {
    6004               0 :         if (havePosition)
    6005               0 :           return false;
    6006               0 :         havePosition = true;
    6007               0 :         if (!ParseBackgroundPositionValues(aState.mPosition->mValue, false)) {
    6008               0 :           return false;
    6009                 :         }
    6010               0 :       } else if (nsCSSProps::FindKeyword(keyword,
    6011                 :                    nsCSSProps::kBackgroundOriginKTable, dummy)) {
    6012               0 :         if (haveOrigin)
    6013               0 :           return false;
    6014               0 :         haveOrigin = true;
    6015               0 :         if (!ParseSingleValueProperty(aState.mOrigin->mValue,
    6016               0 :                                       eCSSProperty_background_origin)) {
    6017               0 :           NS_NOTREACHED("should be able to parse");
    6018               0 :           return false;
    6019                 :         }
    6020                 :         MOZ_STATIC_ASSERT(NS_STYLE_BG_CLIP_BORDER ==
    6021                 :                           NS_STYLE_BG_ORIGIN_BORDER &&
    6022                 :                           NS_STYLE_BG_CLIP_PADDING ==
    6023                 :                           NS_STYLE_BG_ORIGIN_PADDING &&
    6024                 :                           NS_STYLE_BG_CLIP_CONTENT ==
    6025                 :                           NS_STYLE_BG_ORIGIN_CONTENT,
    6026                 :                           "bg-clip and bg-origin style constants must agree");
    6027                 : 
    6028               0 :         aState.mClip->mValue = aState.mOrigin->mValue;
    6029                 :       } else {
    6030               0 :         if (haveColor)
    6031               0 :           return false;
    6032               0 :         haveColor = true;
    6033               0 :         if (!ParseSingleValueProperty(aState.mColor,
    6034               0 :                                       eCSSProperty_background_color)) {
    6035               0 :           return false;
    6036                 :         }
    6037                 :       }
    6038               0 :     } else if (tt == eCSSToken_URL ||
    6039                 :                (tt == eCSSToken_Function &&
    6040               0 :                 (mToken.mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient") ||
    6041               0 :                  mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient") ||
    6042               0 :                  mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") ||
    6043               0 :                  mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") ||
    6044               0 :                  mToken.mIdent.LowerCaseEqualsLiteral("-moz-image-rect") ||
    6045               0 :                  mToken.mIdent.LowerCaseEqualsLiteral("-moz-element")))) {
    6046               0 :       if (haveImage)
    6047               0 :         return false;
    6048               0 :       haveImage = true;
    6049               0 :       if (!ParseSingleValueProperty(aState.mImage->mValue,
    6050               0 :                                     eCSSProperty_background_image)) {
    6051               0 :         return false;
    6052                 :       }
    6053               0 :     } else if (tt == eCSSToken_Dimension ||
    6054                 :                tt == eCSSToken_Number ||
    6055                 :                tt == eCSSToken_Percentage ||
    6056                 :                (tt == eCSSToken_Function &&
    6057               0 :                 mToken.mIdent.LowerCaseEqualsLiteral("-moz-calc"))) {
    6058               0 :       if (havePosition)
    6059               0 :         return false;
    6060               0 :       havePosition = true;
    6061               0 :       if (!ParseBackgroundPositionValues(aState.mPosition->mValue, false)) {
    6062               0 :         return false;
    6063                 :       }
    6064                 :     } else {
    6065               0 :       if (haveColor)
    6066               0 :         return false;
    6067               0 :       haveColor = true;
    6068                 :       // Note: This parses 'inherit' and 'initial', but
    6069                 :       // we've already checked for them, so it's ok.
    6070               0 :       if (!ParseSingleValueProperty(aState.mColor,
    6071               0 :                                     eCSSProperty_background_color)) {
    6072               0 :         return false;
    6073                 :       }
    6074                 :     }
    6075               0 :     haveSomething = true;
    6076                 :   }
    6077                 : 
    6078               0 :   return haveSomething;
    6079                 : }
    6080                 : 
    6081                 : // This function is very similar to ParseBackgroundPosition and
    6082                 : // ParseBackgroundSize.
    6083                 : bool
    6084               0 : CSSParserImpl::ParseValueList(nsCSSProperty aPropID)
    6085                 : {
    6086                 :   // aPropID is a single value prop-id
    6087               0 :   nsCSSValue value;
    6088               0 :   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6089                 :     // 'initial' and 'inherit' stand alone, no list permitted.
    6090               0 :     if (!ExpectEndProperty()) {
    6091               0 :       return false;
    6092                 :     }
    6093                 :   } else {
    6094               0 :     nsCSSValueList* item = value.SetListValue();
    6095               0 :     for (;;) {
    6096               0 :       if (!ParseSingleValueProperty(item->mValue, aPropID)) {
    6097               0 :         return false;
    6098                 :       }
    6099               0 :       if (CheckEndProperty()) {
    6100               0 :         break;
    6101                 :       }
    6102               0 :       if (!ExpectSymbol(',', true)) {
    6103               0 :         return false;
    6104                 :       }
    6105               0 :       item->mNext = new nsCSSValueList;
    6106               0 :       item = item->mNext;
    6107                 :     }
    6108                 :   }
    6109               0 :   AppendValue(aPropID, value);
    6110               0 :   return true;
    6111                 : }
    6112                 : 
    6113                 : bool
    6114               0 : CSSParserImpl::ParseBackgroundRepeat()
    6115                 : {
    6116               0 :   nsCSSValue value;
    6117               0 :   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6118                 :     // 'initial' and 'inherit' stand alone, no list permitted.
    6119               0 :     if (!ExpectEndProperty()) {
    6120               0 :       return false;
    6121                 :     }
    6122                 :   } else {
    6123               0 :     nsCSSValuePair valuePair;
    6124               0 :     if (!ParseBackgroundRepeatValues(valuePair)) {
    6125               0 :       return false;
    6126                 :     }
    6127               0 :     nsCSSValuePairList* item = value.SetPairListValue();
    6128               0 :     for (;;) {
    6129               0 :       item->mXValue = valuePair.mXValue;
    6130               0 :       item->mYValue = valuePair.mYValue;
    6131               0 :       if (CheckEndProperty()) {
    6132                 :         break;
    6133                 :       }
    6134               0 :       if (!ExpectSymbol(',', true)) {
    6135               0 :         return false;
    6136                 :       }
    6137               0 :       if (!ParseBackgroundRepeatValues(valuePair)) {
    6138               0 :         return false;
    6139                 :       }
    6140               0 :       item->mNext = new nsCSSValuePairList;
    6141               0 :       item = item->mNext;
    6142                 :     }
    6143                 :   }
    6144                 : 
    6145               0 :   AppendValue(eCSSProperty_background_repeat, value);
    6146               0 :   return true;
    6147                 : }
    6148                 : 
    6149                 : bool
    6150               0 : CSSParserImpl::ParseBackgroundRepeatValues(nsCSSValuePair& aValue) 
    6151                 : {
    6152               0 :   nsCSSValue& xValue = aValue.mXValue;
    6153               0 :   nsCSSValue& yValue = aValue.mYValue;
    6154                 :   
    6155               0 :   if (ParseEnum(xValue, nsCSSProps::kBackgroundRepeatKTable)) {
    6156               0 :     PRInt32 value = xValue.GetIntValue();
    6157                 :     // For single values set yValue as eCSSUnit_Null.
    6158               0 :     if (value == NS_STYLE_BG_REPEAT_REPEAT_X ||
    6159                 :         value == NS_STYLE_BG_REPEAT_REPEAT_Y ||
    6160               0 :         !ParseEnum(yValue, nsCSSProps::kBackgroundRepeatPartKTable)) {
    6161                 :       // the caller will fail cases like "repeat-x no-repeat"
    6162                 :       // by expecting a list separator or an end property.
    6163               0 :       yValue.Reset();
    6164                 :     }
    6165               0 :     return true;
    6166                 :   }
    6167                 :   
    6168               0 :   return false;
    6169                 : }
    6170                 : 
    6171                 : // This function is very similar to ParseBackgroundList and ParseBackgroundSize.
    6172                 : bool
    6173               0 : CSSParserImpl::ParseBackgroundPosition()
    6174                 : {
    6175               0 :   nsCSSValue value;
    6176               0 :   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6177                 :     // 'initial' and 'inherit' stand alone, no list permitted.
    6178               0 :     if (!ExpectEndProperty()) {
    6179               0 :       return false;
    6180                 :     }
    6181                 :   } else {
    6182               0 :     nsCSSValue itemValue;
    6183               0 :     if (!ParseBackgroundPositionValues(itemValue, false)) {
    6184               0 :       return false;
    6185                 :     }
    6186               0 :     nsCSSValueList* item = value.SetListValue();
    6187               0 :     for (;;) {
    6188               0 :       item->mValue = itemValue;
    6189               0 :       if (CheckEndProperty()) {
    6190                 :         break;
    6191                 :       }
    6192               0 :       if (!ExpectSymbol(',', true)) {
    6193               0 :         return false;
    6194                 :       }
    6195               0 :       if (!ParseBackgroundPositionValues(itemValue, false)) {
    6196               0 :         return false;
    6197                 :       }
    6198               0 :       item->mNext = new nsCSSValueList;
    6199               0 :       item = item->mNext;
    6200                 :     }
    6201                 :   }
    6202               0 :   AppendValue(eCSSProperty_background_position, value);
    6203               0 :   return true;
    6204                 : }
    6205                 : 
    6206                 : /**
    6207                 :  * BoxPositionMaskToCSSValue and ParseBoxPositionValues are used
    6208                 :  * for parsing the CSS 2.1 background-position syntax (which has at
    6209                 :  * most two values).  (Compare to the css3-background syntax which
    6210                 :  * takes up to four values.)  Some current CSS specifications that
    6211                 :  * use background-position-like syntax still use this old syntax.
    6212                 :  **
    6213                 :  * Parses two values that correspond to positions in a box.  These can be
    6214                 :  * values corresponding to percentages of the box, raw offsets, or keywords
    6215                 :  * like "top," "left center," etc.
    6216                 :  *
    6217                 :  * @param aOut The nsCSSValuePair in which to place the result.
    6218                 :  * @param aAcceptsInherit If true, 'inherit' and 'initial' are legal values
    6219                 :  * @param aAllowExplicitCenter If true, 'center' is a legal value
    6220                 :  * @return Whether or not the operation succeeded.
    6221                 :  */
    6222               0 : bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut,
    6223                 :                                            bool aAcceptsInherit,
    6224                 :                                            bool aAllowExplicitCenter)
    6225                 : {
    6226                 :   // First try a percentage or a length value
    6227               0 :   nsCSSValue &xValue = aOut.mXValue,
    6228               0 :              &yValue = aOut.mYValue;
    6229                 :   PRInt32 variantMask =
    6230               0 :     (aAcceptsInherit ? VARIANT_INHERIT : 0) | VARIANT_LP | VARIANT_CALC;
    6231               0 :   if (ParseVariant(xValue, variantMask, nsnull)) {
    6232               0 :     if (eCSSUnit_Inherit == xValue.GetUnit() ||
    6233               0 :         eCSSUnit_Initial == xValue.GetUnit()) {  // both are inherited or both are set to initial
    6234               0 :       yValue = xValue;
    6235               0 :       return true;
    6236                 :     }
    6237                 :     // We have one percentage/length/calc. Get the optional second
    6238                 :     // percentage/length/calc/keyword.
    6239               0 :     if (ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nsnull)) {
    6240                 :       // We have two numbers
    6241               0 :       return true;
    6242                 :     }
    6243                 : 
    6244               0 :     if (ParseEnum(yValue, nsCSSProps::kBackgroundPositionKTable)) {
    6245               0 :       PRInt32 yVal = yValue.GetIntValue();
    6246               0 :       if (!(yVal & BG_CTB)) {
    6247                 :         // The second keyword can only be 'center', 'top', or 'bottom'
    6248               0 :         return false;
    6249                 :       }
    6250               0 :       yValue = BoxPositionMaskToCSSValue(yVal, false);
    6251               0 :       return true;
    6252                 :     }
    6253                 : 
    6254                 :     // If only one percentage or length value is given, it sets the
    6255                 :     // horizontal position only, and the vertical position will be 50%.
    6256               0 :     yValue.SetPercentValue(0.5f);
    6257               0 :     return true;
    6258                 :   }
    6259                 : 
    6260                 :   // Now try keywords. We do this manually to allow for the first
    6261                 :   // appearance of "center" to apply to the either the x or y
    6262                 :   // position (it's ambiguous so we have to disambiguate). Each
    6263                 :   // allowed keyword value is assigned it's own bit. We don't allow
    6264                 :   // any duplicate keywords other than center. We try to get two
    6265                 :   // keywords but it's okay if there is only one.
    6266               0 :   PRInt32 mask = 0;
    6267               0 :   if (ParseEnum(xValue, nsCSSProps::kBackgroundPositionKTable)) {
    6268               0 :     PRInt32 bit = xValue.GetIntValue();
    6269               0 :     mask |= bit;
    6270               0 :     if (ParseEnum(xValue, nsCSSProps::kBackgroundPositionKTable)) {
    6271               0 :       bit = xValue.GetIntValue();
    6272               0 :       if (mask & (bit & ~BG_CENTER)) {
    6273                 :         // Only the 'center' keyword can be duplicated.
    6274               0 :         return false;
    6275                 :       }
    6276               0 :       mask |= bit;
    6277                 :     }
    6278                 :     else {
    6279                 :       // Only one keyword.  See if we have a length, percentage, or calc.
    6280               0 :       if (ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nsnull)) {
    6281               0 :         if (!(mask & BG_CLR)) {
    6282                 :           // The first keyword can only be 'center', 'left', or 'right'
    6283               0 :           return false;
    6284                 :         }
    6285                 : 
    6286               0 :         xValue = BoxPositionMaskToCSSValue(mask, true);
    6287               0 :         return true;
    6288                 :       }
    6289                 :     }
    6290                 :   }
    6291                 : 
    6292                 :   // Check for bad input. Bad input consists of no matching keywords,
    6293                 :   // or pairs of x keywords or pairs of y keywords.
    6294               0 :   if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) ||
    6295                 :       (mask == (BG_LEFT | BG_RIGHT)) ||
    6296               0 :       (!aAllowExplicitCenter && (mask & BG_CENTER))) {
    6297               0 :     return false;
    6298                 :   }
    6299                 : 
    6300                 :   // Create style values
    6301               0 :   xValue = BoxPositionMaskToCSSValue(mask, true);
    6302               0 :   yValue = BoxPositionMaskToCSSValue(mask, false);
    6303               0 :   return true;
    6304                 : }
    6305                 : 
    6306               0 : bool CSSParserImpl::ParseBackgroundPositionValues(nsCSSValue& aOut,
    6307                 :                                                   bool aAcceptsInherit)
    6308                 : {
    6309                 :   // css3-background allows positions to be defined as offsets
    6310                 :   // from an edge. There can be 2 keywords and 2 offsets given. These
    6311                 :   // four 'values' are stored in an array in the following order:
    6312                 :   // [keyword offset keyword offset]. If a keyword or offset isn't
    6313                 :   // parsed the value of the corresponding array element is set
    6314                 :   // to eCSSUnit_Null by a call to nsCSSValue::Reset().
    6315               0 :   if (aAcceptsInherit && ParseVariant(aOut, VARIANT_INHERIT, nsnull)) {
    6316               0 :     return true;
    6317                 :   }
    6318                 : 
    6319               0 :   nsRefPtr<nsCSSValue::Array> value = nsCSSValue::Array::Create(4);
    6320               0 :   aOut.SetArrayValue(value, eCSSUnit_Array);
    6321                 : 
    6322                 :   // The following clarifies organisation of the array.
    6323               0 :   nsCSSValue &xEdge   = value->Item(0),
    6324               0 :              &xOffset = value->Item(1),
    6325               0 :              &yEdge   = value->Item(2),
    6326               0 :              &yOffset = value->Item(3);
    6327                 : 
    6328                 :   // Parse all the values into the array.
    6329               0 :   PRUint32 valueCount = 0;
    6330               0 :   for (PRInt32 i = 0; i < 4; i++) {
    6331               0 :     if (!ParseVariant(value->Item(i), VARIANT_LPCALC | VARIANT_KEYWORD,
    6332               0 :                       nsCSSProps::kBackgroundPositionKTable)) {
    6333               0 :       break;
    6334                 :     }
    6335               0 :     ++valueCount;
    6336                 :   }
    6337                 : 
    6338               0 :   switch (valueCount) {
    6339                 :     case 4:
    6340                 :       // "If three or four values are given, then each <percentage> or <length>
    6341                 :       // represents an offset and must be preceded by a keyword, which specifies
    6342                 :       // from which edge the offset is given."
    6343               0 :       if (eCSSUnit_Enumerated != xEdge.GetUnit() ||
    6344               0 :           BG_CENTER == xEdge.GetIntValue() ||
    6345               0 :           eCSSUnit_Enumerated == xOffset.GetUnit() ||
    6346               0 :           eCSSUnit_Enumerated != yEdge.GetUnit() ||
    6347               0 :           BG_CENTER == yEdge.GetIntValue() ||
    6348               0 :           eCSSUnit_Enumerated == yOffset.GetUnit()) {
    6349               0 :         return false;
    6350                 :       }
    6351               0 :       break;
    6352                 :     case 3:
    6353                 :       // "If three or four values are given, then each <percentage> or<length>
    6354                 :       // represents an offset and must be preceded by a keyword, which specifies
    6355                 :       // from which edge the offset is given." ... "If three values are given,
    6356                 :       // the missing offset is assumed to be zero."
    6357               0 :       if (eCSSUnit_Enumerated != value->Item(1).GetUnit()) {
    6358                 :         // keyword offset keyword
    6359                 :         // Second value is non-keyword, thus first value must be a non-center
    6360                 :         // keyword.
    6361               0 :         if (eCSSUnit_Enumerated != value->Item(0).GetUnit() ||
    6362               0 :             BG_CENTER == value->Item(0).GetIntValue()) {
    6363               0 :           return false;
    6364                 :         }
    6365                 : 
    6366                 :         // Remaining value must be a keyword.
    6367               0 :         if (eCSSUnit_Enumerated != value->Item(2).GetUnit()) {
    6368               0 :           return false;
    6369                 :         }
    6370                 : 
    6371               0 :         yOffset.Reset(); // Everything else is in the correct position.
    6372               0 :       } else if (eCSSUnit_Enumerated != value->Item(2).GetUnit()) {
    6373                 :         // keyword keyword offset
    6374                 :         // Third value is non-keyword, thus second value must be non-center
    6375                 :         // keyword.
    6376               0 :         if (BG_CENTER == value->Item(1).GetIntValue()) {
    6377               0 :           return false;
    6378                 :         }
    6379                 : 
    6380                 :         // Remaining value must be a keyword.
    6381               0 :         if (eCSSUnit_Enumerated != value->Item(0).GetUnit()) {
    6382               0 :           return false;
    6383                 :         }
    6384                 : 
    6385                 :         // Move the values to the correct position in the array.
    6386               0 :         value->Item(3) = value->Item(2); // yOffset
    6387               0 :         value->Item(2) = value->Item(1); // yEdge
    6388               0 :         value->Item(1).Reset(); // xOffset
    6389                 :       } else {
    6390               0 :         return false;
    6391                 :       }
    6392               0 :       break;
    6393                 :     case 2:
    6394                 :       // "If two values are given and at least one value is not a keyword, then
    6395                 :       // the first value represents the horizontal position (or offset) and the
    6396                 :       // second represents the vertical position (or offset)"
    6397               0 :       if (eCSSUnit_Enumerated == value->Item(0).GetUnit()) {
    6398               0 :         if (eCSSUnit_Enumerated == value->Item(1).GetUnit()) {
    6399                 :           // keyword keyword
    6400               0 :           value->Item(2) = value->Item(1); // move yEdge to correct position
    6401               0 :           xOffset.Reset();
    6402               0 :           yOffset.Reset();
    6403                 :         } else {
    6404                 :           // keyword offset
    6405                 :           // First value must represent horizontal position.
    6406               0 :           if ((BG_TOP | BG_BOTTOM) & value->Item(0).GetIntValue()) {
    6407               0 :             return false;
    6408                 :           }
    6409               0 :           value->Item(3) = value->Item(1); // move yOffset to correct position
    6410               0 :           xOffset.Reset();
    6411               0 :           yEdge.Reset();
    6412                 :         }
    6413                 :       } else {
    6414               0 :         if (eCSSUnit_Enumerated == value->Item(1).GetUnit()) {
    6415                 :           // offset keyword
    6416                 :           // Second value must represent vertical position.
    6417               0 :           if ((BG_LEFT | BG_RIGHT) & value->Item(1).GetIntValue()) {
    6418               0 :             return false;
    6419                 :           }
    6420               0 :           value->Item(2) = value->Item(1); // move yEdge to correct position
    6421               0 :           value->Item(1) = value->Item(0); // move xOffset to correct position
    6422               0 :           xEdge.Reset();
    6423               0 :           yOffset.Reset();
    6424                 :         } else {
    6425                 :           // offset offset
    6426               0 :           value->Item(3) = value->Item(1); // move yOffset to correct position
    6427               0 :           value->Item(1) = value->Item(0); // move xOffset to correct position
    6428               0 :           xEdge.Reset();
    6429               0 :           yEdge.Reset();
    6430                 :         }
    6431                 :       }
    6432               0 :       break;
    6433                 :     case 1:
    6434                 :       // "If only one value is specified, the second value is assumed to be
    6435                 :       // center."
    6436               0 :       if (eCSSUnit_Enumerated == value->Item(0).GetUnit()) {
    6437               0 :         xOffset.Reset();
    6438                 :       } else {
    6439               0 :         value->Item(1) = value->Item(0); // move xOffset to correct position
    6440               0 :         xEdge.Reset();
    6441                 :       }
    6442               0 :       yEdge.SetIntValue(NS_STYLE_BG_POSITION_CENTER, eCSSUnit_Enumerated);
    6443               0 :       yOffset.Reset();
    6444               0 :       break;
    6445                 :     default:
    6446               0 :       return false;
    6447                 :   }
    6448                 : 
    6449                 :   // For compatibility with CSS2.1 code the edges can be unspecified.
    6450                 :   // Unspecified edges are recorded as NULL.
    6451               0 :   NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit()  ||
    6452                 :                 eCSSUnit_Null       == xEdge.GetUnit()) &&
    6453                 :                (eCSSUnit_Enumerated == yEdge.GetUnit()  ||
    6454                 :                 eCSSUnit_Null       == yEdge.GetUnit()) &&
    6455                 :                 eCSSUnit_Enumerated != xOffset.GetUnit()  &&
    6456                 :                 eCSSUnit_Enumerated != yOffset.GetUnit(),
    6457                 :                 "Unexpected units");
    6458                 : 
    6459                 :   // Keywords in first and second pairs can not both be vertical or
    6460                 :   // horizontal keywords. (eg. left right, bottom top). Additionally,
    6461                 :   // non-center keyword can not be duplicated (eg. left left).
    6462                 :   PRInt32 xEdgeEnum =
    6463               0 :           xEdge.GetUnit() == eCSSUnit_Enumerated ? xEdge.GetIntValue() : 0;
    6464                 :   PRInt32 yEdgeEnum =
    6465               0 :           yEdge.GetUnit() == eCSSUnit_Enumerated ? yEdge.GetIntValue() : 0;
    6466               0 :   if ((xEdgeEnum | yEdgeEnum) == (BG_LEFT | BG_RIGHT) ||
    6467                 :       (xEdgeEnum | yEdgeEnum) == (BG_TOP | BG_BOTTOM) ||
    6468                 :       (xEdgeEnum & yEdgeEnum & ~BG_CENTER)) {
    6469               0 :     return false;
    6470                 :   }
    6471                 : 
    6472                 :   // The values could be in an order that is different than expected.
    6473                 :   // eg. x contains vertical information, y contains horizontal information.
    6474                 :   // Swap if incorrect order.
    6475               0 :   if (xEdgeEnum & (BG_TOP | BG_BOTTOM) ||
    6476                 :       yEdgeEnum & (BG_LEFT | BG_RIGHT)) {
    6477               0 :     nsCSSValue swapEdge = xEdge;
    6478               0 :     nsCSSValue swapOffset = xOffset;
    6479               0 :     xEdge = yEdge;
    6480               0 :     xOffset = yOffset;
    6481               0 :     yEdge = swapEdge;
    6482               0 :     yOffset = swapOffset;
    6483                 :   }
    6484                 : 
    6485               0 :   return true;
    6486                 : }
    6487                 : 
    6488                 : // This function is very similar to ParseBackgroundList and
    6489                 : // ParseBackgroundPosition.
    6490                 : bool
    6491               0 : CSSParserImpl::ParseBackgroundSize()
    6492                 : {
    6493               0 :   nsCSSValue value;
    6494               0 :   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6495                 :     // 'initial' and 'inherit' stand alone, no list permitted.
    6496               0 :     if (!ExpectEndProperty()) {
    6497               0 :       return false;
    6498                 :     }
    6499                 :   } else {
    6500               0 :     nsCSSValuePair valuePair;
    6501               0 :     if (!ParseBackgroundSizeValues(valuePair)) {
    6502               0 :       return false;
    6503                 :     }
    6504               0 :     nsCSSValuePairList* item = value.SetPairListValue();
    6505               0 :     for (;;) {
    6506               0 :       item->mXValue = valuePair.mXValue;
    6507               0 :       item->mYValue = valuePair.mYValue;
    6508               0 :       if (CheckEndProperty()) {
    6509                 :         break;
    6510                 :       }
    6511               0 :       if (!ExpectSymbol(',', true)) {
    6512               0 :         return false;
    6513                 :       }
    6514               0 :       if (!ParseBackgroundSizeValues(valuePair)) {
    6515               0 :         return false;
    6516                 :       }
    6517               0 :       item->mNext = new nsCSSValuePairList;
    6518               0 :       item = item->mNext;
    6519                 :     }
    6520                 :   }
    6521               0 :   AppendValue(eCSSProperty_background_size, value);
    6522               0 :   return true;
    6523                 : }
    6524                 : 
    6525                 : /**
    6526                 :  * Parses two values that correspond to lengths for the background-size
    6527                 :  * property.  These can be one or two lengths (or the 'auto' keyword) or
    6528                 :  * percentages corresponding to the element's dimensions or the single keywords
    6529                 :  * 'contain' or 'cover'.  'initial' and 'inherit' must be handled by the caller
    6530                 :  * if desired.
    6531                 :  *
    6532                 :  * @param aOut The nsCSSValuePair in which to place the result.
    6533                 :  * @return Whether or not the operation succeeded.
    6534                 :  */
    6535                 : #define BG_SIZE_VARIANT (VARIANT_LP | VARIANT_AUTO | VARIANT_CALC)
    6536               0 : bool CSSParserImpl::ParseBackgroundSizeValues(nsCSSValuePair &aOut)
    6537                 : {
    6538                 :   // First try a percentage or a length value
    6539               0 :   nsCSSValue &xValue = aOut.mXValue,
    6540               0 :              &yValue = aOut.mYValue;
    6541               0 :   if (ParseNonNegativeVariant(xValue, BG_SIZE_VARIANT, nsnull)) {
    6542                 :     // We have one percentage/length/calc/auto. Get the optional second
    6543                 :     // percentage/length/calc/keyword.
    6544               0 :     if (ParseNonNegativeVariant(yValue, BG_SIZE_VARIANT, nsnull)) {
    6545                 :       // We have a second percentage/length/calc/auto.
    6546               0 :       return true;
    6547                 :     }
    6548                 : 
    6549                 :     // If only one percentage or length value is given, it sets the
    6550                 :     // horizontal size only, and the vertical size will be as if by 'auto'.
    6551               0 :     yValue.SetAutoValue();
    6552               0 :     return true;
    6553                 :   }
    6554                 : 
    6555                 :   // Now address 'contain' and 'cover'.
    6556               0 :   if (!ParseEnum(xValue, nsCSSProps::kBackgroundSizeKTable))
    6557               0 :     return false;
    6558               0 :   yValue.Reset();
    6559               0 :   return true;
    6560                 : }
    6561                 : #undef BG_SIZE_VARIANT
    6562                 : 
    6563                 : bool
    6564               0 : CSSParserImpl::ParseBorderColor()
    6565                 : {
    6566                 :   static const nsCSSProperty kBorderColorSources[] = {
    6567                 :     eCSSProperty_border_left_color_ltr_source,
    6568                 :     eCSSProperty_border_left_color_rtl_source,
    6569                 :     eCSSProperty_border_right_color_ltr_source,
    6570                 :     eCSSProperty_border_right_color_rtl_source,
    6571                 :     eCSSProperty_UNKNOWN
    6572                 :   };
    6573                 : 
    6574                 :   // do this now, in case 4 values weren't specified
    6575               0 :   InitBoxPropsAsPhysical(kBorderColorSources);
    6576               0 :   return ParseBoxProperties(kBorderColorIDs);
    6577                 : }
    6578                 : 
    6579                 : void
    6580               0 : CSSParserImpl::SetBorderImageInitialValues()
    6581                 : {
    6582                 :   // border-image-source: none
    6583               0 :   nsCSSValue source;
    6584               0 :   source.SetNoneValue();
    6585               0 :   AppendValue(eCSSProperty_border_image_source, source);
    6586                 : 
    6587                 :   // border-image-slice: 100%
    6588               0 :   nsCSSValue sliceBoxValue;
    6589               0 :   nsCSSRect& sliceBox = sliceBoxValue.SetRectValue();
    6590               0 :   sliceBox.SetAllSidesTo(nsCSSValue(1.0f, eCSSUnit_Percent));
    6591               0 :   nsCSSValue slice;
    6592               0 :   nsCSSValueList* sliceList = slice.SetListValue();
    6593               0 :   sliceList->mValue = sliceBoxValue;
    6594               0 :   AppendValue(eCSSProperty_border_image_slice, slice);
    6595                 : 
    6596                 :   // border-image-width: 1
    6597               0 :   nsCSSValue width;
    6598               0 :   nsCSSRect& widthBox = width.SetRectValue();
    6599               0 :   widthBox.SetAllSidesTo(nsCSSValue(1.0f, eCSSUnit_Number));
    6600               0 :   AppendValue(eCSSProperty_border_image_width, width);
    6601                 : 
    6602                 :   // border-image-outset: 0
    6603               0 :   nsCSSValue outset;
    6604               0 :   nsCSSRect& outsetBox = outset.SetRectValue();
    6605               0 :   outsetBox.SetAllSidesTo(nsCSSValue(0.0f, eCSSUnit_Number));
    6606               0 :   AppendValue(eCSSProperty_border_image_outset, outset);
    6607                 : 
    6608                 :   // border-image-repeat: repeat
    6609               0 :   nsCSSValue repeat;
    6610               0 :   nsCSSValuePair repeatPair;
    6611                 :   repeatPair.SetBothValuesTo(nsCSSValue(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH,
    6612               0 :                                         eCSSUnit_Enumerated));
    6613               0 :   repeat.SetPairValue(&repeatPair);
    6614               0 :   AppendValue(eCSSProperty_border_image_repeat, repeat);
    6615               0 : }
    6616                 : 
    6617                 : bool
    6618               0 : CSSParserImpl::ParseBorderImageSlice(bool aAcceptsInherit,
    6619                 :                                      bool* aConsumedTokens)
    6620                 : {
    6621                 :   // border-image-slice: initial | [<number>|<percentage>]{1,4} && fill?
    6622               0 :   nsCSSValue value;
    6623                 : 
    6624               0 :   if (aConsumedTokens) {
    6625               0 :     *aConsumedTokens = true;
    6626                 :   }
    6627                 : 
    6628               0 :   if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6629                 :     // Keyword "inherit" can not be mixed, so we are done.
    6630               0 :     AppendValue(eCSSProperty_border_image_slice, value);
    6631               0 :     return true;
    6632                 :   }
    6633                 : 
    6634                 :   // Try parsing "fill" value.
    6635               0 :   nsCSSValue imageSliceFillValue;
    6636                 :   bool hasFill = ParseEnum(imageSliceFillValue,
    6637               0 :                            nsCSSProps::kBorderImageSliceKTable);
    6638                 : 
    6639                 :   // Parse the box dimensions.
    6640               0 :   nsCSSValue imageSliceBoxValue;
    6641               0 :   if (!ParseGroupedBoxProperty(VARIANT_PN, imageSliceBoxValue)) {
    6642               0 :     if (!hasFill && aConsumedTokens) {
    6643               0 :       *aConsumedTokens = false;
    6644                 :     }
    6645                 : 
    6646               0 :     return false;
    6647                 :   }
    6648                 : 
    6649                 :   // Try parsing "fill" keyword again if the first time failed because keyword
    6650                 :   // and slice dimensions can be in any order.
    6651               0 :   if (!hasFill) {
    6652                 :     hasFill = ParseEnum(imageSliceFillValue,
    6653               0 :                         nsCSSProps::kBorderImageSliceKTable);
    6654                 :   }
    6655                 : 
    6656               0 :   nsCSSValueList* borderImageSlice = value.SetListValue();
    6657                 :   // Put the box value into the list.
    6658               0 :   borderImageSlice->mValue = imageSliceBoxValue;
    6659                 : 
    6660               0 :   if (hasFill) {
    6661                 :     // Put the "fill" value into the list.
    6662               0 :     borderImageSlice->mNext = new nsCSSValueList;
    6663               0 :     borderImageSlice->mNext->mValue = imageSliceFillValue;
    6664                 :   }
    6665                 : 
    6666               0 :   AppendValue(eCSSProperty_border_image_slice, value);
    6667               0 :   return true;
    6668                 : }
    6669                 : 
    6670                 : bool
    6671               0 : CSSParserImpl::ParseBorderImageWidth(bool aAcceptsInherit)
    6672                 : {
    6673                 :   // border-image-width: initial | [<length>|<number>|<percentage>|auto]{1,4}
    6674               0 :   nsCSSValue value;
    6675                 : 
    6676               0 :   if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6677                 :     // Keyword "inherit" can no be mixed, so we are done.
    6678               0 :     AppendValue(eCSSProperty_border_image_width, value);
    6679               0 :     return true;
    6680                 :   }
    6681                 : 
    6682                 :   // Parse the box dimensions.
    6683               0 :   if (!ParseGroupedBoxProperty(VARIANT_ALPN, value)) {
    6684               0 :     return false;
    6685                 :   }
    6686                 : 
    6687               0 :   AppendValue(eCSSProperty_border_image_width, value);
    6688               0 :   return true;
    6689                 : }
    6690                 : 
    6691                 : bool
    6692               0 : CSSParserImpl::ParseBorderImageOutset(bool aAcceptsInherit)
    6693                 : {
    6694                 :   // border-image-outset: initial | [<length>|<number>]{1,4}
    6695               0 :   nsCSSValue value;
    6696                 : 
    6697               0 :   if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6698                 :     // Keyword "inherit" can not be mixed, so we are done.
    6699               0 :     AppendValue(eCSSProperty_border_image_outset, value);
    6700               0 :     return true;
    6701                 :   }
    6702                 : 
    6703                 :   // Parse the box dimensions.
    6704               0 :   if (!ParseGroupedBoxProperty(VARIANT_LN, value)) {
    6705               0 :     return false;
    6706                 :   }
    6707                 : 
    6708               0 :   AppendValue(eCSSProperty_border_image_outset, value);
    6709               0 :   return true;
    6710                 : }
    6711                 : 
    6712                 : bool
    6713               0 : CSSParserImpl::ParseBorderImageRepeat(bool aAcceptsInherit)
    6714                 : {
    6715               0 :   nsCSSValue value;
    6716               0 :   if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6717                 :     // Keyword "inherit" can not be mixed, so we are done.
    6718               0 :     AppendValue(eCSSProperty_border_image_repeat, value);
    6719               0 :     return true;
    6720                 :   }
    6721                 : 
    6722               0 :   nsCSSValuePair result;
    6723               0 :   if (!ParseEnum(result.mXValue, nsCSSProps::kBorderImageRepeatKTable)) {
    6724               0 :     return false;
    6725                 :   }
    6726                 : 
    6727                 :   // optional second keyword, defaults to first
    6728               0 :   if (!ParseEnum(result.mYValue, nsCSSProps::kBorderImageRepeatKTable)) {
    6729               0 :     result.mYValue = result.mXValue;
    6730                 :   }
    6731                 : 
    6732               0 :   value.SetPairValue(&result);
    6733               0 :   AppendValue(eCSSProperty_border_image_repeat, value);
    6734               0 :   return true;
    6735                 : }
    6736                 : 
    6737                 : bool
    6738               0 : CSSParserImpl::ParseBorderImage()
    6739                 : {
    6740               0 :   nsAutoParseCompoundProperty compound(this);
    6741                 : 
    6742                 :   // border-image: inherit |
    6743                 :   // <border-image-source> ||
    6744                 :   // <border-image-slice>
    6745                 :   //   [ / <border-image-width>?
    6746                 :   //     [ / <border-image-outset>]?]? ||
    6747                 :   // <border-image-repeat>
    6748                 : 
    6749               0 :   nsCSSValue value;
    6750               0 :   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    6751               0 :     AppendValue(eCSSProperty_border_image_source, value);
    6752               0 :     AppendValue(eCSSProperty_border_image_slice, value);
    6753               0 :     AppendValue(eCSSProperty_border_image_width, value);
    6754               0 :     AppendValue(eCSSProperty_border_image_outset, value);
    6755               0 :     AppendValue(eCSSProperty_border_image_repeat, value);
    6756                 :     // Keyword "inherit" can't be mixed, so we are done.
    6757               0 :     return true;
    6758                 :   }
    6759                 : 
    6760                 :   // No empty property.
    6761               0 :   if (CheckEndProperty()) {
    6762               0 :     return false;
    6763                 :   }
    6764                 : 
    6765                 :   // Shorthand properties are required to set everything they can.
    6766               0 :   SetBorderImageInitialValues();
    6767                 : 
    6768               0 :   bool foundSource = false;
    6769               0 :   bool foundSliceWidthOutset = false;
    6770               0 :   bool foundRepeat = false;
    6771                 : 
    6772                 :   // This loop is used to handle the parsing of border-image properties which
    6773                 :   // can appear in any order.
    6774               0 :   nsCSSValue imageSourceValue;
    6775               0 :   while (!CheckEndProperty()) {
    6776                 :     // <border-image-source>
    6777               0 :     if (!foundSource && ParseVariant(imageSourceValue, VARIANT_UO, nsnull)) {
    6778               0 :       AppendValue(eCSSProperty_border_image_source, imageSourceValue);
    6779               0 :       foundSource = true;
    6780               0 :       continue;
    6781                 :     }
    6782                 : 
    6783                 :     // <border-image-slice>
    6784                 :     // ParseBorderImageSlice is weird.  It may consume tokens and then return
    6785                 :     // false, because it parses a property with two required components that
    6786                 :     // can appear in either order.  Since the tokens that were consumed cannot
    6787                 :     // parse as anything else we care about, this isn't a problem.
    6788               0 :     if (!foundSliceWidthOutset) {
    6789               0 :       bool sliceConsumedTokens = false;
    6790               0 :       if (ParseBorderImageSlice(false, &sliceConsumedTokens)) {
    6791               0 :         foundSliceWidthOutset = true;
    6792                 : 
    6793                 :         // [ / <border-image-width>?
    6794               0 :         if (ExpectSymbol('/', true)) {
    6795               0 :           ParseBorderImageWidth(false);
    6796                 : 
    6797                 :           // [ / <border-image-outset>
    6798               0 :           if (ExpectSymbol('/', true)) {
    6799               0 :             if (!ParseBorderImageOutset(false)) {
    6800               0 :               return false;
    6801                 :             }
    6802                 :           }
    6803                 :         }
    6804                 : 
    6805               0 :         continue;
    6806                 :       } else {
    6807                 :         // If we consumed some tokens for <border-image-slice> but did not
    6808                 :         // successfully parse it, we have an error.
    6809               0 :         if (sliceConsumedTokens) {
    6810               0 :           return false;
    6811                 :         }
    6812                 :       }
    6813                 :     }
    6814                 : 
    6815                 :     // <border-image-repeat>
    6816               0 :     if (!foundRepeat && ParseBorderImageRepeat(false)) {
    6817               0 :       foundRepeat = true;
    6818               0 :       continue;
    6819                 :     }
    6820                 : 
    6821               0 :     return false;
    6822                 :   }
    6823                 : 
    6824               0 :   return true;
    6825                 : }
    6826                 : 
    6827                 : bool
    6828               0 : CSSParserImpl::ParseBorderSpacing()
    6829                 : {
    6830               0 :   nsCSSValue xValue, yValue;
    6831               0 :   if (!ParseNonNegativeVariant(xValue, VARIANT_HL | VARIANT_CALC, nsnull)) {
    6832               0 :     return false;
    6833                 :   }
    6834                 : 
    6835                 :   // If we have one length, get the optional second length.
    6836                 :   // set the second value equal to the first.
    6837               0 :   if (xValue.IsLengthUnit() || xValue.IsCalcUnit()) {
    6838               0 :     ParseNonNegativeVariant(yValue, VARIANT_LENGTH | VARIANT_CALC, nsnull);
    6839                 :   }
    6840                 : 
    6841               0 :   if (!ExpectEndProperty()) {
    6842               0 :     return false;
    6843                 :   }
    6844                 : 
    6845               0 :   if (yValue == xValue || yValue.GetUnit() == eCSSUnit_Null) {
    6846               0 :     AppendValue(eCSSProperty_border_spacing, xValue);
    6847                 :   } else {
    6848               0 :     nsCSSValue pair;
    6849               0 :     pair.SetPairValue(xValue, yValue);
    6850               0 :     AppendValue(eCSSProperty_border_spacing, pair);
    6851                 :   }
    6852               0 :   return true;
    6853                 : }
    6854                 : 
    6855                 : bool
    6856               0 : CSSParserImpl::ParseBorderSide(const nsCSSProperty aPropIDs[],
    6857                 :                                bool aSetAllSides)
    6858                 : {
    6859               0 :   const PRInt32 numProps = 3;
    6860               0 :   nsCSSValue  values[numProps];
    6861                 : 
    6862               0 :   PRInt32 found = ParseChoice(values, aPropIDs, numProps);
    6863               0 :   if ((found < 1) || (false == ExpectEndProperty())) {
    6864               0 :     return false;
    6865                 :   }
    6866                 : 
    6867               0 :   if ((found & 1) == 0) { // Provide default border-width
    6868               0 :     values[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated);
    6869                 :   }
    6870               0 :   if ((found & 2) == 0) { // Provide default border-style
    6871               0 :     values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated);
    6872                 :   }
    6873               0 :   if ((found & 4) == 0) { // text color will be used
    6874               0 :     values[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
    6875                 :   }
    6876                 : 
    6877               0 :   if (aSetAllSides) {
    6878                 :     static const nsCSSProperty kBorderSources[] = {
    6879                 :       eCSSProperty_border_left_color_ltr_source,
    6880                 :       eCSSProperty_border_left_color_rtl_source,
    6881                 :       eCSSProperty_border_right_color_ltr_source,
    6882                 :       eCSSProperty_border_right_color_rtl_source,
    6883                 :       eCSSProperty_border_left_style_ltr_source,
    6884                 :       eCSSProperty_border_left_style_rtl_source,
    6885                 :       eCSSProperty_border_right_style_ltr_source,
    6886                 :       eCSSProperty_border_right_style_rtl_source,
    6887                 :       eCSSProperty_border_left_width_ltr_source,
    6888                 :       eCSSProperty_border_left_width_rtl_source,
    6889                 :       eCSSProperty_border_right_width_ltr_source,
    6890                 :       eCSSProperty_border_right_width_rtl_source,
    6891                 :       eCSSProperty_UNKNOWN
    6892                 :     };
    6893                 : 
    6894               0 :     InitBoxPropsAsPhysical(kBorderSources);
    6895                 : 
    6896                 :     // Parsing "border" shorthand; set all four sides to the same thing
    6897               0 :     for (PRInt32 index = 0; index < 4; index++) {
    6898                 :       NS_ASSERTION(numProps == 3, "This code needs updating");
    6899               0 :       AppendValue(kBorderWidthIDs[index], values[0]);
    6900               0 :       AppendValue(kBorderStyleIDs[index], values[1]);
    6901               0 :       AppendValue(kBorderColorIDs[index], values[2]);
    6902                 :     }
    6903                 : 
    6904                 :     static const nsCSSProperty kBorderColorsProps[] = {
    6905                 :       eCSSProperty_border_top_colors,
    6906                 :       eCSSProperty_border_right_colors,
    6907                 :       eCSSProperty_border_bottom_colors,
    6908                 :       eCSSProperty_border_left_colors
    6909                 :     };
    6910                 : 
    6911                 :     // Set the other properties that the border shorthand sets to their
    6912                 :     // initial values.
    6913               0 :     nsCSSValue extraValue;
    6914               0 :     switch (values[0].GetUnit()) {
    6915                 :     case eCSSUnit_Inherit:
    6916                 :     case eCSSUnit_Initial:
    6917               0 :       extraValue = values[0];
    6918                 :       // Set value of border-image properties to initial/inherit
    6919               0 :       AppendValue(eCSSProperty_border_image_source, extraValue);
    6920               0 :       AppendValue(eCSSProperty_border_image_slice, extraValue);
    6921               0 :       AppendValue(eCSSProperty_border_image_width, extraValue);
    6922               0 :       AppendValue(eCSSProperty_border_image_outset, extraValue);
    6923               0 :       AppendValue(eCSSProperty_border_image_repeat, extraValue);
    6924               0 :       break;
    6925                 :     default:
    6926               0 :       extraValue.SetNoneValue();
    6927               0 :       SetBorderImageInitialValues();
    6928               0 :       break;
    6929                 :     }
    6930               0 :     NS_FOR_CSS_SIDES(side) {
    6931               0 :       AppendValue(kBorderColorsProps[side], extraValue);
    6932                 :     }
    6933                 :   }
    6934                 :   else {
    6935                 :     // Just set our one side
    6936               0 :     for (PRInt32 index = 0; index < numProps; index++) {
    6937               0 :       AppendValue(aPropIDs[index], values[index]);
    6938                 :     }
    6939                 :   }
    6940               0 :   return true;
    6941                 : }
    6942                 : 
    6943                 : bool
    6944               0 : CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs[],
    6945                 :                                           PRInt32 aSourceType)
    6946                 : {
    6947               0 :   const PRInt32 numProps = 3;
    6948               0 :   nsCSSValue  values[numProps];
    6949                 : 
    6950               0 :   PRInt32 found = ParseChoice(values, aPropIDs, numProps);
    6951               0 :   if ((found < 1) || (false == ExpectEndProperty())) {
    6952               0 :     return false;
    6953                 :   }
    6954                 : 
    6955               0 :   if ((found & 1) == 0) { // Provide default border-width
    6956               0 :     values[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated);
    6957                 :   }
    6958               0 :   if ((found & 2) == 0) { // Provide default border-style
    6959               0 :     values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated);
    6960                 :   }
    6961               0 :   if ((found & 4) == 0) { // text color will be used
    6962               0 :     values[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
    6963                 :   }
    6964               0 :   for (PRInt32 index = 0; index < numProps; index++) {
    6965                 :     const nsCSSProperty* subprops =
    6966               0 :       nsCSSProps::SubpropertyEntryFor(aPropIDs[index + numProps]);
    6967               0 :     NS_ASSERTION(subprops[3] == eCSSProperty_UNKNOWN,
    6968                 :                  "not box property with physical vs. logical cascading");
    6969               0 :     AppendValue(subprops[0], values[index]);
    6970               0 :     nsCSSValue typeVal(aSourceType, eCSSUnit_Enumerated);
    6971               0 :     AppendValue(subprops[1], typeVal);
    6972               0 :     AppendValue(subprops[2], typeVal);
    6973                 :   }
    6974               0 :   return true;
    6975                 : }
    6976                 : 
    6977                 : bool
    6978               0 : CSSParserImpl::ParseBorderStyle()
    6979                 : {
    6980                 :   static const nsCSSProperty kBorderStyleSources[] = {
    6981                 :     eCSSProperty_border_left_style_ltr_source,
    6982                 :     eCSSProperty_border_left_style_rtl_source,
    6983                 :     eCSSProperty_border_right_style_ltr_source,
    6984                 :     eCSSProperty_border_right_style_rtl_source,
    6985                 :     eCSSProperty_UNKNOWN
    6986                 :   };
    6987                 : 
    6988                 :   // do this now, in case 4 values weren't specified
    6989               0 :   InitBoxPropsAsPhysical(kBorderStyleSources);
    6990               0 :   return ParseBoxProperties(kBorderStyleIDs);
    6991                 : }
    6992                 : 
    6993                 : bool
    6994               0 : CSSParserImpl::ParseBorderWidth()
    6995                 : {
    6996                 :   static const nsCSSProperty kBorderWidthSources[] = {
    6997                 :     eCSSProperty_border_left_width_ltr_source,
    6998                 :     eCSSProperty_border_left_width_rtl_source,
    6999                 :     eCSSProperty_border_right_width_ltr_source,
    7000                 :     eCSSProperty_border_right_width_rtl_source,
    7001                 :     eCSSProperty_UNKNOWN
    7002                 :   };
    7003                 : 
    7004                 :   // do this now, in case 4 values weren't specified
    7005               0 :   InitBoxPropsAsPhysical(kBorderWidthSources);
    7006               0 :   return ParseBoxProperties(kBorderWidthIDs);
    7007                 : }
    7008                 : 
    7009                 : bool
    7010               0 : CSSParserImpl::ParseBorderColors(nsCSSProperty aProperty)
    7011                 : {
    7012               0 :   nsCSSValue value;
    7013               0 :   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
    7014                 :     // 'inherit', 'initial', and 'none' are only allowed on their own
    7015               0 :     if (!ExpectEndProperty()) {
    7016               0 :       return false;
    7017                 :     }
    7018                 :   } else {
    7019               0 :     nsCSSValueList *cur = value.SetListValue();
    7020               0 :     for (;;) {
    7021               0 :       if (!ParseVariant(cur->mValue, VARIANT_COLOR | VARIANT_KEYWORD,
    7022               0 :                         nsCSSProps::kBorderColorKTable)) {
    7023               0 :         return false;
    7024                 :       }
    7025               0 :       if (CheckEndProperty()) {
    7026               0 :         break;
    7027                 :       }
    7028               0 :       cur->mNext = new nsCSSValueList;
    7029               0 :       cur = cur->mNext;
    7030                 :     }
    7031                 :   }
    7032               0 :   AppendValue(aProperty, value);
    7033               0 :   return true;
    7034                 : }
    7035                 : 
    7036                 : // Parse the top level of a calc() expression.
    7037                 : bool
    7038               0 : CSSParserImpl::ParseCalc(nsCSSValue &aValue, PRInt32 aVariantMask)
    7039                 : {
    7040                 :   // Parsing calc expressions requires, in a number of cases, looking
    7041                 :   // for a token that is *either* a value of the property or a number.
    7042                 :   // This can be done without lookahead when we assume that the property
    7043                 :   // values cannot themselves be numbers.
    7044               0 :   NS_ASSERTION(!(aVariantMask & VARIANT_NUMBER), "unexpected variant mask");
    7045               0 :   NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask");
    7046                 : 
    7047                 :   // One-iteration loop so we can break to the error-handling case.
    7048                 :   do {
    7049                 :     // The toplevel of a calc() is always an nsCSSValue::Array of length 1.
    7050               0 :     nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1);
    7051                 : 
    7052               0 :     if (!ParseCalcAdditiveExpression(arr->Item(0), aVariantMask))
    7053                 :       break;
    7054                 : 
    7055               0 :     if (!ExpectSymbol(')', true))
    7056                 :       break;
    7057                 : 
    7058               0 :     aValue.SetArrayValue(arr, eCSSUnit_Calc);
    7059               0 :     return true;
    7060                 :   } while (false);
    7061                 : 
    7062               0 :   SkipUntil(')');
    7063               0 :   return false;
    7064                 : }
    7065                 : 
    7066                 : // We optimize away the <value-expression> production given that
    7067                 : // ParseVariant consumes initial whitespace and we call
    7068                 : // ExpectSymbol(')') with true for aSkipWS.
    7069                 : //  * If aVariantMask is VARIANT_NUMBER, this function parses the
    7070                 : //    <number-additive-expression> production.
    7071                 : //  * If aVariantMask does not contain VARIANT_NUMBER, this function
    7072                 : //    parses the <value-additive-expression> production.
    7073                 : //  * Otherwise (VARIANT_NUMBER and other bits) this function parses
    7074                 : //    whichever one of the productions matches ***and modifies
    7075                 : //    aVariantMask*** to reflect which one it has parsed by either
    7076                 : //    removing VARIANT_NUMBER or removing all other bits.
    7077                 : // It does so iteratively, but builds the correct recursive
    7078                 : // data structure.
    7079                 : bool
    7080               0 : CSSParserImpl::ParseCalcAdditiveExpression(nsCSSValue& aValue,
    7081                 :                                            PRInt32& aVariantMask)
    7082                 : {
    7083               0 :   NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask");
    7084               0 :   nsCSSValue *storage = &aValue;
    7085               0 :   for (;;) {
    7086                 :     bool haveWS;
    7087               0 :     if (!ParseCalcMultiplicativeExpression(*storage, aVariantMask, &haveWS))
    7088               0 :       return false;
    7089                 : 
    7090               0 :     if (!haveWS || !GetToken(false))
    7091               0 :       return true;
    7092                 :     nsCSSUnit unit;
    7093               0 :     if (mToken.IsSymbol('+')) {
    7094               0 :       unit = eCSSUnit_Calc_Plus;
    7095               0 :     } else if (mToken.IsSymbol('-')) {
    7096               0 :       unit = eCSSUnit_Calc_Minus;
    7097                 :     } else {
    7098               0 :       UngetToken();
    7099               0 :       return true;
    7100                 :     }
    7101               0 :     if (!RequireWhitespace())
    7102               0 :       return false;
    7103                 : 
    7104               0 :     nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(2);
    7105               0 :     arr->Item(0) = aValue;
    7106               0 :     storage = &arr->Item(1);
    7107               0 :     aValue.SetArrayValue(arr, unit);
    7108                 :   }
    7109                 : }
    7110                 : 
    7111                 : struct ReduceNumberCalcOps : public mozilla::css::BasicFloatCalcOps,
    7112                 :                              public mozilla::css::CSSValueInputCalcOps
    7113                 : {
    7114               0 :   result_type ComputeLeafValue(const nsCSSValue& aValue)
    7115                 :   {
    7116               0 :     NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
    7117               0 :     return aValue.GetFloatValue();
    7118                 :   }
    7119                 : 
    7120               0 :   float ComputeNumber(const nsCSSValue& aValue)
    7121                 :   {
    7122               0 :     return mozilla::css::ComputeCalc(aValue, *this);
    7123                 :   }
    7124                 : };
    7125                 : 
    7126                 : //  * If aVariantMask is VARIANT_NUMBER, this function parses the
    7127                 : //    <number-multiplicative-expression> production.
    7128                 : //  * If aVariantMask does not contain VARIANT_NUMBER, this function
    7129                 : //    parses the <value-multiplicative-expression> production.
    7130                 : //  * Otherwise (VARIANT_NUMBER and other bits) this function parses
    7131                 : //    whichever one of the productions matches ***and modifies
    7132                 : //    aVariantMask*** to reflect which one it has parsed by either
    7133                 : //    removing VARIANT_NUMBER or removing all other bits.
    7134                 : // It does so iteratively, but builds the correct recursive data
    7135                 : // structure.
    7136                 : // This function always consumes *trailing* whitespace when it returns
    7137                 : // true; whether there was any such whitespace is returned in the
    7138                 : // aHadFinalWS parameter.
    7139                 : bool
    7140               0 : CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
    7141                 :                                                  PRInt32& aVariantMask,
    7142                 :                                                  bool *aHadFinalWS)
    7143                 : {
    7144               0 :   NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask");
    7145               0 :   bool gotValue = false; // already got the part with the unit
    7146               0 :   bool afterDivision = false;
    7147                 : 
    7148               0 :   nsCSSValue *storage = &aValue;
    7149               0 :   for (;;) {
    7150                 :     PRInt32 variantMask;
    7151               0 :     if (afterDivision || gotValue) {
    7152               0 :       variantMask = VARIANT_NUMBER;
    7153                 :     } else {
    7154               0 :       variantMask = aVariantMask | VARIANT_NUMBER;
    7155                 :     }
    7156               0 :     if (!ParseCalcTerm(*storage, variantMask))
    7157               0 :       return false;
    7158               0 :     NS_ABORT_IF_FALSE(variantMask != 0,
    7159                 :                       "ParseCalcTerm did not set variantMask appropriately");
    7160               0 :     NS_ABORT_IF_FALSE(!(variantMask & VARIANT_NUMBER) ||
    7161                 :                       !(variantMask & ~PRInt32(VARIANT_NUMBER)),
    7162                 :                       "ParseCalcTerm did not set variantMask appropriately");
    7163                 : 
    7164               0 :     if (variantMask & VARIANT_NUMBER) {
    7165                 :       // Simplify the value immediately so we can check for division by
    7166                 :       // zero.
    7167                 :       ReduceNumberCalcOps ops;
    7168               0 :       float number = mozilla::css::ComputeCalc(*storage, ops);
    7169               0 :       if (number == 0.0 && afterDivision)
    7170               0 :         return false;
    7171               0 :       storage->SetFloatValue(number, eCSSUnit_Number);
    7172                 :     } else {
    7173               0 :       gotValue = true;
    7174                 : 
    7175               0 :       if (storage != &aValue) {
    7176                 :         // Simplify any numbers in the Times_L position (which are
    7177                 :         // not simplified by the check above).
    7178               0 :         NS_ABORT_IF_FALSE(storage == &aValue.GetArrayValue()->Item(1),
    7179                 :                           "unexpected relationship to current storage");
    7180               0 :         nsCSSValue &leftValue = aValue.GetArrayValue()->Item(0);
    7181                 :         ReduceNumberCalcOps ops;
    7182               0 :         float number = mozilla::css::ComputeCalc(leftValue, ops);
    7183               0 :         leftValue.SetFloatValue(number, eCSSUnit_Number);
    7184                 :       }
    7185                 :     }
    7186                 : 
    7187               0 :     bool hadWS = RequireWhitespace();
    7188               0 :     if (!GetToken(false)) {
    7189               0 :       *aHadFinalWS = hadWS;
    7190               0 :       break;
    7191                 :     }
    7192                 :     nsCSSUnit unit;
    7193               0 :     if (mToken.IsSymbol('*')) {
    7194               0 :       unit = gotValue ? eCSSUnit_Calc_Times_R : eCSSUnit_Calc_Times_L;
    7195               0 :       afterDivision = false;
    7196               0 :     } else if (mToken.IsSymbol('/')) {
    7197               0 :       unit = eCSSUnit_Calc_Divided;
    7198               0 :       afterDivision = true;
    7199                 :     } else {
    7200               0 :       UngetToken();
    7201               0 :       *aHadFinalWS = hadWS;
    7202               0 :       break;
    7203                 :     }
    7204                 : 
    7205               0 :     nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(2);
    7206               0 :     arr->Item(0) = aValue;
    7207               0 :     storage = &arr->Item(1);
    7208               0 :     aValue.SetArrayValue(arr, unit);
    7209                 :   }
    7210                 : 
    7211                 :   // Adjust aVariantMask (see comments above function) to reflect which
    7212                 :   // option we took.
    7213               0 :   if (aVariantMask & VARIANT_NUMBER) {
    7214               0 :     if (gotValue) {
    7215               0 :       aVariantMask &= ~PRInt32(VARIANT_NUMBER);
    7216                 :     } else {
    7217               0 :       aVariantMask = VARIANT_NUMBER;
    7218                 :     }
    7219                 :   } else {
    7220               0 :     if (!gotValue) {
    7221                 :       // We had to find a value, but we didn't.
    7222               0 :       return false;
    7223                 :     }
    7224                 :   }
    7225                 : 
    7226               0 :   return true;
    7227                 : }
    7228                 : 
    7229                 : //  * If aVariantMask is VARIANT_NUMBER, this function parses the
    7230                 : //    <number-term> production.
    7231                 : //  * If aVariantMask does not contain VARIANT_NUMBER, this function
    7232                 : //    parses the <value-term> production.
    7233                 : //  * Otherwise (VARIANT_NUMBER and other bits) this function parses
    7234                 : //    whichever one of the productions matches ***and modifies
    7235                 : //    aVariantMask*** to reflect which one it has parsed by either
    7236                 : //    removing VARIANT_NUMBER or removing all other bits.
    7237                 : bool
    7238               0 : CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, PRInt32& aVariantMask)
    7239                 : {
    7240               0 :   NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask");
    7241               0 :   if (!GetToken(true))
    7242               0 :     return false;
    7243                 :   // Either an additive expression in parentheses...
    7244               0 :   if (mToken.IsSymbol('(')) {
    7245               0 :     if (!ParseCalcAdditiveExpression(aValue, aVariantMask) ||
    7246               0 :         !ExpectSymbol(')', true)) {
    7247               0 :       SkipUntil(')');
    7248               0 :       return false;
    7249                 :     }
    7250               0 :     return true;
    7251                 :   }
    7252                 :   // ... or just a value
    7253               0 :   UngetToken();
    7254                 :   // Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
    7255                 :   // always gets picked up 
    7256               0 :   if (!ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nsnull)) {
    7257               0 :     return false;
    7258                 :   }
    7259                 :   // ...and do the VARIANT_NUMBER check ourselves.
    7260               0 :   if (!(aVariantMask & VARIANT_NUMBER) && aValue.GetUnit() == eCSSUnit_Number) {
    7261               0 :     return false;
    7262                 :   }
    7263                 :   // If we did the value parsing, we need to adjust aVariantMask to
    7264                 :   // reflect which option we took (see above).
    7265               0 :   if (aVariantMask & VARIANT_NUMBER) {
    7266               0 :     if (aValue.GetUnit() == eCSSUnit_Number) {
    7267               0 :       aVariantMask = VARIANT_NUMBER;
    7268                 :     } else {
    7269               0 :       aVariantMask &= ~PRInt32(VARIANT_NUMBER);
    7270                 :     }
    7271                 :   }
    7272               0 :   return true;
    7273                 : }
    7274                 : 
    7275                 : // This function consumes all consecutive whitespace and returns whether
    7276                 : // there was any.
    7277                 : bool
    7278               0 : CSSParserImpl::RequireWhitespace()
    7279                 : {
    7280               0 :   if (!GetToken(false))
    7281               0 :     return false;
    7282               0 :   if (mToken.mType != eCSSToken_WhiteSpace) {
    7283               0 :     UngetToken();
    7284               0 :     return false;
    7285                 :   }
    7286                 :   // Skip any additional whitespace tokens.
    7287               0 :   if (GetToken(true)) {
    7288               0 :     UngetToken();
    7289                 :   }
    7290               0 :   return true;
    7291                 : }
    7292                 : 
    7293                 : bool
    7294               0 : CSSParserImpl::ParseRect(nsCSSProperty aPropID)
    7295                 : {
    7296               0 :   if (! GetToken(true)) {
    7297               0 :     return false;
    7298                 :   }
    7299                 : 
    7300               0 :   nsCSSValue val;
    7301                 : 
    7302               0 :   if (mToken.mType == eCSSToken_Ident) {
    7303               0 :     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
    7304               0 :     switch (keyword) {
    7305                 :       case eCSSKeyword_auto:
    7306               0 :         if (!ExpectEndProperty()) {
    7307               0 :           return false;
    7308                 :         }
    7309               0 :         val.SetAutoValue();
    7310               0 :         break;
    7311                 :       case eCSSKeyword_inherit:
    7312               0 :         if (!ExpectEndProperty()) {
    7313               0 :           return false;
    7314                 :         }
    7315               0 :         val.SetInheritValue();
    7316               0 :         break;
    7317                 :       case eCSSKeyword__moz_initial:
    7318               0 :         if (!ExpectEndProperty()) {
    7319               0 :           return false;
    7320                 :         }
    7321               0 :         val.SetInitialValue();
    7322               0 :         break;
    7323                 :       default:
    7324               0 :         UngetToken();
    7325               0 :         return false;
    7326                 :     }
    7327               0 :   } else if (mToken.mType == eCSSToken_Function &&
    7328               0 :              mToken.mIdent.LowerCaseEqualsLiteral("rect")) {
    7329               0 :     nsCSSRect& rect = val.SetRectValue();
    7330                 :     bool useCommas;
    7331               0 :     NS_FOR_CSS_SIDES(side) {
    7332               0 :       if (! ParseVariant(rect.*(nsCSSRect::sides[side]),
    7333               0 :                          VARIANT_AL, nsnull)) {
    7334               0 :         return false;
    7335                 :       }
    7336               0 :       if (side == 0) {
    7337               0 :         useCommas = ExpectSymbol(',', true);
    7338               0 :       } else if (useCommas && side < 3) {
    7339                 :         // Skip optional commas between elements, but only if the first
    7340                 :         // separator was a comma.
    7341               0 :         if (!ExpectSymbol(',', true)) {
    7342               0 :           return false;
    7343                 :         }
    7344                 :       }
    7345                 :     }
    7346               0 :     if (!ExpectSymbol(')', true)) {
    7347               0 :       return false;
    7348                 :     }
    7349               0 :     if (!ExpectEndProperty()) {
    7350               0 :       return false;
    7351                 :     }
    7352                 :   } else {
    7353               0 :     UngetToken();
    7354               0 :     return false;
    7355                 :   }
    7356                 : 
    7357               0 :   AppendValue(aPropID, val);
    7358               0 :   return true;
    7359                 : }
    7360                 : 
    7361                 : bool
    7362               0 : CSSParserImpl::ParseColumns()
    7363                 : {
    7364                 :   // We use a similar "fake value" hack to ParseListStyle, because
    7365                 :   // "auto" is acceptable for both column-count and column-width.
    7366                 :   // If the fake "auto" value is found, and one of the real values isn't,
    7367                 :   // that means the fake auto value is meant for the real value we didn't
    7368                 :   // find.
    7369                 :   static const nsCSSProperty columnIDs[] = {
    7370                 :     eCSSPropertyExtra_x_auto_value,
    7371                 :     eCSSProperty__moz_column_count,
    7372                 :     eCSSProperty__moz_column_width
    7373                 :   };
    7374               0 :   const PRInt32 numProps = NS_ARRAY_LENGTH(columnIDs);
    7375                 : 
    7376               0 :   nsCSSValue values[numProps];
    7377               0 :   PRInt32 found = ParseChoice(values, columnIDs, numProps);
    7378               0 :   if (found < 1 || !ExpectEndProperty()) {
    7379               0 :     return false;
    7380                 :   }
    7381               0 :   if ((found & (1|2|4)) == (1|2|4) &&
    7382               0 :       values[0].GetUnit() ==  eCSSUnit_Auto) {
    7383                 :     // We filled all 3 values, which is invalid
    7384               0 :     return false;
    7385                 :   }
    7386                 : 
    7387               0 :   if ((found & 2) == 0) {
    7388                 :     // Provide auto column-count
    7389               0 :     values[1].SetAutoValue();
    7390                 :   }
    7391               0 :   if ((found & 4) == 0) {
    7392                 :     // Provide auto column-width
    7393               0 :     values[2].SetAutoValue();
    7394                 :   }
    7395                 : 
    7396                 :   // Start at index 1 to skip the fake auto value.
    7397               0 :   for (PRInt32 index = 1; index < numProps; index++) {
    7398               0 :     AppendValue(columnIDs[index], values[index]);
    7399                 :   }
    7400               0 :   return true;
    7401                 : }
    7402                 : 
    7403                 : #define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
    7404                 :                          VARIANT_KEYWORD)
    7405                 : bool
    7406               0 : CSSParserImpl::ParseContent()
    7407                 : {
    7408                 :   // We need to divide the 'content' keywords into two classes for
    7409                 :   // ParseVariant's sake, so we can't just use nsCSSProps::kContentKTable.
    7410                 :   static const PRInt32 kContentListKWs[] = {
    7411                 :     eCSSKeyword_open_quote, NS_STYLE_CONTENT_OPEN_QUOTE,
    7412                 :     eCSSKeyword_close_quote, NS_STYLE_CONTENT_CLOSE_QUOTE,
    7413                 :     eCSSKeyword_no_open_quote, NS_STYLE_CONTENT_NO_OPEN_QUOTE,
    7414                 :     eCSSKeyword_no_close_quote, NS_STYLE_CONTENT_NO_CLOSE_QUOTE,
    7415                 :     eCSSKeyword_UNKNOWN,-1
    7416                 :   };
    7417                 : 
    7418                 :   static const PRInt32 kContentSolitaryKWs[] = {
    7419                 :     eCSSKeyword__moz_alt_content, NS_STYLE_CONTENT_ALT_CONTENT,
    7420                 :     eCSSKeyword_UNKNOWN,-1
    7421                 :   };
    7422                 : 
    7423                 :   // Verify that these two lists add up to the size of
    7424                 :   // nsCSSProps::kContentKTable.
    7425               0 :   NS_ABORT_IF_FALSE(nsCSSProps::kContentKTable[
    7426                 :                       ArrayLength(kContentListKWs) +
    7427                 :                       ArrayLength(kContentSolitaryKWs) - 4] ==
    7428                 :                     eCSSKeyword_UNKNOWN &&
    7429                 :                     nsCSSProps::kContentKTable[
    7430                 :                       ArrayLength(kContentListKWs) +
    7431                 :                       ArrayLength(kContentSolitaryKWs) - 3] == -1,
    7432                 :                     "content keyword tables out of sync");
    7433                 : 
    7434               0 :   nsCSSValue value;
    7435               0 :   if (ParseVariant(value, VARIANT_HMK | VARIANT_NONE,
    7436                 :                    kContentSolitaryKWs)) {
    7437                 :     // 'inherit', 'initial', 'normal', 'none', and 'alt-content' must be alone
    7438               0 :     if (!ExpectEndProperty()) {
    7439               0 :       return false;
    7440                 :     }
    7441                 :   } else {
    7442               0 :     nsCSSValueList* cur = value.SetListValue();
    7443               0 :     for (;;) {
    7444               0 :       if (!ParseVariant(cur->mValue, VARIANT_CONTENT, kContentListKWs)) {
    7445               0 :         return false;
    7446                 :       }
    7447               0 :       if (CheckEndProperty()) {
    7448               0 :         break;
    7449                 :       }
    7450               0 :       cur->mNext = new nsCSSValueList;
    7451               0 :       cur = cur->mNext;
    7452                 :     }
    7453                 :   }
    7454               0 :   AppendValue(eCSSProperty_content, value);
    7455               0 :   return true;
    7456                 : }
    7457                 : 
    7458                 : bool
    7459               0 : CSSParserImpl::ParseCounterData(nsCSSProperty aPropID)
    7460                 : {
    7461               0 :   nsCSSValue value;
    7462               0 :   if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
    7463               0 :     if (!GetToken(true) || mToken.mType != eCSSToken_Ident) {
    7464               0 :       return false;
    7465                 :     }
    7466                 : 
    7467               0 :     nsCSSValuePairList *cur = value.SetPairListValue();
    7468               0 :     for (;;) {
    7469               0 :       cur->mXValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident);
    7470               0 :       if (!GetToken(true)) {
    7471               0 :         break;
    7472                 :       }
    7473               0 :       if (mToken.mType == eCSSToken_Number && mToken.mIntegerValid) {
    7474               0 :         cur->mYValue.SetIntValue(mToken.mInteger, eCSSUnit_Integer);
    7475                 :       } else {
    7476               0 :         UngetToken();
    7477                 :       }
    7478               0 :       if (CheckEndProperty()) {
    7479               0 :         break;
    7480                 :       }
    7481               0 :       if (!GetToken(true) || mToken.mType != eCSSToken_Ident) {
    7482               0 :         return false;
    7483                 :       }
    7484               0 :       cur->mNext = new nsCSSValuePairList;
    7485               0 :       cur = cur->mNext;
    7486                 :     }
    7487                 :   }
    7488               0 :   AppendValue(aPropID, value);
    7489               0 :   return true;
    7490                 : }
    7491                 : 
    7492                 : bool
    7493               0 : CSSParserImpl::ParseCursor()
    7494                 : {
    7495               0 :   nsCSSValue value;
    7496               0 :   if (ParseVariant(value, VARIANT_INHERIT, nsnull)) {
    7497                 :     // 'inherit' and 'initial' must be alone
    7498               0 :     if (!ExpectEndProperty()) {
    7499               0 :       return false;
    7500                 :     }
    7501                 :   } else {
    7502               0 :     nsCSSValueList* cur = value.SetListValue();
    7503               0 :     for (;;) {
    7504               0 :       if (!ParseVariant(cur->mValue, VARIANT_UK, nsCSSProps::kCursorKTable)) {
    7505               0 :         return false;
    7506                 :       }
    7507               0 :       if (cur->mValue.GetUnit() != eCSSUnit_URL) { // keyword must be last
    7508               0 :         if (ExpectEndProperty()) {
    7509               0 :           break;
    7510                 :         }
    7511               0 :         return false;
    7512                 :       }
    7513                 : 
    7514                 :       // We have a URL, so make a value array with three values.
    7515               0 :       nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(3);
    7516               0 :       val->Item(0) = cur->mValue;
    7517                 : 
    7518                 :       // Parse optional x and y position of cursor hotspot (css3-ui).
    7519               0 :       if (ParseVariant(val->Item(1), VARIANT_NUMBER, nsnull)) {
    7520                 :         // If we have one number, we must have two.
    7521               0 :         if (!ParseVariant(val->Item(2), VARIANT_NUMBER, nsnull)) {
    7522               0 :           return false;
    7523                 :         }
    7524                 :       }
    7525               0 :       cur->mValue.SetArrayValue(val, eCSSUnit_Array);
    7526                 : 
    7527               0 :       if (!ExpectSymbol(',', true)) { // url must not be last
    7528               0 :         return false;
    7529                 :       }
    7530               0 :       cur->mNext = new nsCSSValueList;
    7531               0 :       cur = cur->mNext;
    7532                 :     }
    7533                 :   }
    7534               0 :   AppendValue(eCSSProperty_cursor, value);
    7535               0 :   return true;
    7536                 : }
    7537                 : 
    7538                 : 
    7539                 : bool
    7540               0 : CSSParserImpl::ParseFont()
    7541                 : {
    7542                 :   static const nsCSSProperty fontIDs[] = {
    7543                 :     eCSSProperty_font_style,
    7544                 :     eCSSProperty_font_variant,
    7545                 :     eCSSProperty_font_weight
    7546                 :   };
    7547                 : 
    7548               0 :   nsCSSValue  family;
    7549               0 :   if (ParseVariant(family, VARIANT_HK, nsCSSProps::kFontKTable)) {
    7550               0 :     if (ExpectEndProperty()) {
    7551               0 :       if (eCSSUnit_Inherit == family.GetUnit() ||
    7552               0 :           eCSSUnit_Initial == family.GetUnit()) {
    7553               0 :         AppendValue(eCSSProperty__x_system_font, nsCSSValue(eCSSUnit_None));
    7554               0 :         AppendValue(eCSSProperty_font_family, family);
    7555               0 :         AppendValue(eCSSProperty_font_style, family);
    7556               0 :         AppendValue(eCSSProperty_font_variant, family);
    7557               0 :         AppendValue(eCSSProperty_font_weight, family);
    7558               0 :         AppendValue(eCSSProperty_font_size, family);
    7559               0 :         AppendValue(eCSSProperty_line_height, family);
    7560               0 :         AppendValue(eCSSProperty_font_stretch, family);
    7561               0 :         AppendValue(eCSSProperty_font_size_adjust, family);
    7562               0 :         AppendValue(eCSSProperty_font_feature_settings, family);
    7563               0 :         AppendValue(eCSSProperty_font_language_override, family);
    7564                 :       }
    7565                 :       else {
    7566               0 :         AppendValue(eCSSProperty__x_system_font, family);
    7567               0 :         nsCSSValue systemFont(eCSSUnit_System_Font);
    7568               0 :         AppendValue(eCSSProperty_font_family, systemFont);
    7569               0 :         AppendValue(eCSSProperty_font_style, systemFont);
    7570               0 :         AppendValue(eCSSProperty_font_variant, systemFont);
    7571               0 :         AppendValue(eCSSProperty_font_weight, systemFont);
    7572               0 :         AppendValue(eCSSProperty_font_size, systemFont);
    7573               0 :         AppendValue(eCSSProperty_line_height, systemFont);
    7574               0 :         AppendValue(eCSSProperty_font_stretch, systemFont);
    7575               0 :         AppendValue(eCSSProperty_font_size_adjust, systemFont);
    7576               0 :         AppendValue(eCSSProperty_font_feature_settings, systemFont);
    7577               0 :         AppendValue(eCSSProperty_font_language_override, systemFont);
    7578                 :       }
    7579               0 :       return true;
    7580                 :     }
    7581               0 :     return false;
    7582                 :   }
    7583                 : 
    7584                 :   // Get optional font-style, font-variant and font-weight (in any order)
    7585               0 :   const PRInt32 numProps = 3;
    7586               0 :   nsCSSValue  values[numProps];
    7587               0 :   PRInt32 found = ParseChoice(values, fontIDs, numProps);
    7588               0 :   if ((found < 0) || (eCSSUnit_Inherit == values[0].GetUnit()) ||
    7589               0 :       (eCSSUnit_Initial == values[0].GetUnit())) { // illegal data
    7590               0 :     return false;
    7591                 :   }
    7592               0 :   if ((found & 1) == 0) {
    7593                 :     // Provide default font-style
    7594               0 :     values[0].SetIntValue(NS_FONT_STYLE_NORMAL, eCSSUnit_Enumerated);
    7595                 :   }
    7596               0 :   if ((found & 2) == 0) {
    7597                 :     // Provide default font-variant
    7598               0 :     values[1].SetIntValue(NS_FONT_VARIANT_NORMAL, eCSSUnit_Enumerated);
    7599                 :   }
    7600               0 :   if ((found & 4) == 0) {
    7601                 :     // Provide default font-weight
    7602               0 :     values[2].SetIntValue(NS_FONT_WEIGHT_NORMAL, eCSSUnit_Enumerated);
    7603                 :   }
    7604                 : 
    7605                 :   // Get mandatory font-size
    7606               0 :   nsCSSValue  size;
    7607               0 :   if (! ParseVariant(size, VARIANT_KEYWORD | VARIANT_LP, nsCSSProps::kFontSizeKTable)) {
    7608               0 :     return false;
    7609                 :   }
    7610                 : 
    7611                 :   // Get optional "/" line-height
    7612               0 :   nsCSSValue  lineHeight;
    7613               0 :   if (ExpectSymbol('/', true)) {
    7614               0 :     if (! ParseNonNegativeVariant(lineHeight,
    7615                 :                                   VARIANT_NUMBER | VARIANT_LP | VARIANT_NORMAL,
    7616               0 :                                   nsnull)) {
    7617               0 :       return false;
    7618                 :     }
    7619                 :   }
    7620                 :   else {
    7621               0 :     lineHeight.SetNormalValue();
    7622                 :   }
    7623                 : 
    7624                 :   // Get final mandatory font-family
    7625               0 :   nsAutoParseCompoundProperty compound(this);
    7626               0 :   if (ParseFamily(family)) {
    7627               0 :     if ((eCSSUnit_Inherit != family.GetUnit()) && (eCSSUnit_Initial != family.GetUnit()) &&
    7628               0 :         ExpectEndProperty()) {
    7629               0 :       AppendValue(eCSSProperty__x_system_font, nsCSSValue(eCSSUnit_None));
    7630               0 :       AppendValue(eCSSProperty_font_family, family);
    7631               0 :       AppendValue(eCSSProperty_font_style, values[0]);
    7632               0 :       AppendValue(eCSSProperty_font_variant, values[1]);
    7633               0 :       AppendValue(eCSSProperty_font_weight, values[2]);
    7634               0 :       AppendValue(eCSSProperty_font_size, size);
    7635               0 :       AppendValue(eCSSProperty_line_height, lineHeight);
    7636                 :       AppendValue(eCSSProperty_font_stretch,
    7637               0 :                   nsCSSValue(NS_FONT_STRETCH_NORMAL, eCSSUnit_Enumerated));
    7638               0 :       AppendValue(eCSSProperty_font_size_adjust, nsCSSValue(eCSSUnit_None));
    7639               0 :       AppendValue(eCSSProperty_font_feature_settings, nsCSSValue(eCSSUnit_Normal));
    7640               0 :       AppendValue(eCSSProperty_font_language_override, nsCSSValue(eCSSUnit_Normal));
    7641               0 :       return true;
    7642                 :     }
    7643                 :   }
    7644               0 :   return false;
    7645                 : }
    7646                 : 
    7647                 : bool
    7648               0 : CSSParserImpl::ParseFontWeight(nsCSSValue& aValue)
    7649                 : {
    7650               0 :   if (ParseVariant(aValue, VARIANT_HKI | VARIANT_SYSFONT,
    7651                 :                    nsCSSProps::kFontWeightKTable)) {
    7652               0 :     if (eCSSUnit_Integer == aValue.GetUnit()) { // ensure unit value
    7653               0 :       PRInt32 intValue = aValue.GetIntValue();
    7654               0 :       if ((100 <= intValue) &&
    7655                 :           (intValue <= 900) &&
    7656                 :           (0 == (intValue % 100))) {
    7657               0 :         return true;
    7658                 :       } else {
    7659               0 :         UngetToken();
    7660               0 :         return false;
    7661                 :       }
    7662                 :     }
    7663               0 :     return true;
    7664                 :   }
    7665               0 :   return false;
    7666                 : }
    7667                 : 
    7668                 : bool
    7669               0 : CSSParserImpl::ParseOneFamily(nsAString& aFamily)
    7670                 : {
    7671               0 :   if (!GetToken(true))
    7672               0 :     return false;
    7673                 : 
    7674               0 :   nsCSSToken* tk = &mToken;
    7675                 : 
    7676               0 :   if (eCSSToken_Ident == tk->mType) {
    7677               0 :     aFamily.Append(tk->mIdent);
    7678               0 :     for (;;) {
    7679               0 :       if (!GetToken(false))
    7680               0 :         break;
    7681                 : 
    7682               0 :       if (eCSSToken_Ident == tk->mType) {
    7683               0 :         aFamily.Append(tk->mIdent);
    7684               0 :       } else if (eCSSToken_WhiteSpace == tk->mType) {
    7685                 :         // Lookahead one token and drop whitespace if we are ending the
    7686                 :         // font name.
    7687               0 :         if (!GetToken(true))
    7688               0 :           break;
    7689                 : 
    7690               0 :         UngetToken();
    7691               0 :         if (eCSSToken_Ident == tk->mType)
    7692               0 :           aFamily.Append(PRUnichar(' '));
    7693                 :         else
    7694               0 :           break;
    7695                 :       } else {
    7696               0 :         UngetToken();
    7697               0 :         break;
    7698                 :       }
    7699                 :     }
    7700               0 :     return true;
    7701                 : 
    7702               0 :   } else if (eCSSToken_String == tk->mType) {
    7703               0 :     aFamily.Append(tk->mSymbol); // replace the quotes
    7704               0 :     aFamily.Append(tk->mIdent); // XXX What if it had escaped quotes?
    7705               0 :     aFamily.Append(tk->mSymbol);
    7706               0 :     return true;
    7707                 : 
    7708                 :   } else {
    7709               0 :     UngetToken();
    7710               0 :     return false;
    7711                 :   }
    7712                 : }
    7713                 : 
    7714                 : ///////////////////////////////////////////////////////
    7715                 : // -moz-transform Parsing Implementation
    7716                 : 
    7717                 : /* Reads a function list of arguments.  Do not call this function
    7718                 :  * directly; it's mean to be caled from ParseFunction.
    7719                 :  */
    7720                 : bool
    7721               0 : CSSParserImpl::ParseFunctionInternals(const PRInt32 aVariantMask[],
    7722                 :                                       PRUint16 aMinElems,
    7723                 :                                       PRUint16 aMaxElems,
    7724                 :                                       InfallibleTArray<nsCSSValue> &aOutput)
    7725                 : {
    7726               0 :   for (PRUint16 index = 0; index < aMaxElems; ++index) {
    7727               0 :     nsCSSValue newValue;
    7728               0 :     if (!ParseVariant(newValue, aVariantMask[index], nsnull))
    7729               0 :       return false;
    7730                 : 
    7731               0 :     aOutput.AppendElement(newValue);
    7732                 : 
    7733                 :     // See whether to continue or whether to look for end of function.
    7734               0 :     if (!ExpectSymbol(',', true)) {
    7735                 :       // We need to read the closing parenthesis, and also must take care
    7736                 :       // that we haven't read too few symbols.
    7737               0 :       return ExpectSymbol(')', true) && (index + 1) >= aMinElems;
    7738                 :     }
    7739                 :   }
    7740                 : 
    7741                 :   // If we're here, we finished looping without hitting the end, so we read too
    7742                 :   // many elements.
    7743               0 :   return false;
    7744                 : }
    7745                 : 
    7746                 : /* Parses a function [ input of the form (a [, b]*) ] and stores it
    7747                 :  * as an nsCSSValue that holds a function of the form
    7748                 :  * function-name arg1 arg2 ... argN
    7749                 :  *
    7750                 :  * On error, the return value is false.
    7751                 :  *
    7752                 :  * @param aFunction The name of the function that we're reading.
    7753                 :  * @param aAllowedTypes An array of values corresponding to the legal
    7754                 :  *        types for each element in the function.  The zeroth element in the
    7755                 :  *        array corresponds to the first function parameter, etc.  The length
    7756                 :  *        of this array _must_ be greater than or equal to aMaxElems or the
    7757                 :  *        behavior is undefined.
    7758                 :  * @param aMinElems Minimum number of elements to read.  Reading fewer than
    7759                 :  *        this many elements will result in the function failing.
    7760                 :  * @param aMaxElems Maximum number of elements to read.  Reading more than
    7761                 :  *        this many elements will result in the function failing.
    7762                 :  * @param aValue (out) The value that was parsed.
    7763                 :  */
    7764                 : bool
    7765               0 : CSSParserImpl::ParseFunction(const nsString &aFunction,
    7766                 :                              const PRInt32 aAllowedTypes[],
    7767                 :                              PRUint16 aMinElems, PRUint16 aMaxElems,
    7768                 :                              nsCSSValue &aValue)
    7769                 : {
    7770                 :   typedef InfallibleTArray<nsCSSValue>::size_type arrlen_t;
    7771                 : 
    7772                 :   /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
    7773                 :    * elements stored in the the nsCSSValue::Array.
    7774                 :    */
    7775                 :   static const arrlen_t MAX_ALLOWED_ELEMS = 0xFFFE;
    7776                 : 
    7777                 :   /* Make a copy of the function name, since the reference is _probably_ to
    7778                 :    * mToken.mIdent, which is going to get overwritten during the course of this
    7779                 :    * function.
    7780                 :    */
    7781               0 :   nsString functionName(aFunction);
    7782                 : 
    7783                 :   /* Read in a list of values as an array, failing if we can't or if
    7784                 :    * it's out of bounds.
    7785                 :    */
    7786               0 :   InfallibleTArray<nsCSSValue> foundValues;
    7787               0 :   if (!ParseFunctionInternals(aAllowedTypes, aMinElems, aMaxElems,
    7788               0 :                               foundValues))
    7789               0 :     return false;
    7790                 : 
    7791                 :   /* Now, convert this array into an nsCSSValue::Array object.
    7792                 :    * We'll need N + 1 spots, one for the function name and the rest for the
    7793                 :    * arguments.  In case the user has given us more than 2^16 - 2 arguments,
    7794                 :    * we'll truncate them at 2^16 - 2 arguments.
    7795                 :    */
    7796               0 :   PRUint16 numElements = (foundValues.Length() <= MAX_ALLOWED_ELEMS ?
    7797               0 :                           foundValues.Length() + 1 : MAX_ALLOWED_ELEMS);
    7798                 :   nsRefPtr<nsCSSValue::Array> convertedArray =
    7799               0 :     nsCSSValue::Array::Create(numElements);
    7800                 : 
    7801                 :   /* Copy things over. */
    7802               0 :   convertedArray->Item(0).SetStringValue(functionName, eCSSUnit_Ident);
    7803               0 :   for (PRUint16 index = 0; index + 1 < numElements; ++index)
    7804               0 :     convertedArray->Item(index + 1) = foundValues[static_cast<arrlen_t>(index)];
    7805                 : 
    7806                 :   /* Fill in the outparam value with the array. */
    7807               0 :   aValue.SetArrayValue(convertedArray, eCSSUnit_Function);
    7808                 : 
    7809                 :   /* Return it! */
    7810               0 :   return true;
    7811                 : }
    7812                 : 
    7813                 : /**
    7814                 :  * Given a token, determines the minimum and maximum number of function
    7815                 :  * parameters to read, along with the mask that should be used to read
    7816                 :  * those function parameters.  If the token isn't a transform function,
    7817                 :  * returns an error.
    7818                 :  *
    7819                 :  * @param aToken The token identifying the function.
    7820                 :  * @param aMinElems [out] The minimum number of elements to read.
    7821                 :  * @param aMaxElems [out] The maximum number of elements to read
    7822                 :  * @param aVariantMask [out] The variant mask to use during parsing
    7823                 :  * @return Whether the information was loaded successfully.
    7824                 :  */
    7825               0 : static bool GetFunctionParseInformation(nsCSSKeyword aToken,
    7826                 :                                           PRUint16 &aMinElems,
    7827                 :                                           PRUint16 &aMaxElems,
    7828                 :                                           const PRInt32 *& aVariantMask,
    7829                 :                                           bool &aIs3D)
    7830                 : {
    7831                 : /* These types represent the common variant masks that will be used to
    7832                 :    * parse out the individual functions.  The order in the enumeration
    7833                 :    * must match the order in which the masks are declared.
    7834                 :    */
    7835                 :   enum { eLengthPercentCalc,
    7836                 :          eLengthCalc,
    7837                 :          eTwoLengthPercentCalcs,
    7838                 :          eTwoLengthPercentCalcsOneLengthCalc,
    7839                 :          eAngle,
    7840                 :          eTwoAngles,
    7841                 :          eNumber,
    7842                 :          ePositiveLength,
    7843                 :          eTwoNumbers,
    7844                 :          eThreeNumbers,
    7845                 :          eThreeNumbersOneAngle,
    7846                 :          eMatrix,
    7847                 :          eMatrix3d,
    7848                 :          eNumVariantMasks };
    7849                 :   static const PRInt32 kMaxElemsPerFunction = 16;
    7850                 :   static const PRInt32 kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = {
    7851                 :     {VARIANT_LPCALC},
    7852                 :     {VARIANT_LENGTH|VARIANT_CALC},
    7853                 :     {VARIANT_LPCALC, VARIANT_LPCALC},
    7854                 :     {VARIANT_LPCALC, VARIANT_LPCALC, VARIANT_LENGTH|VARIANT_CALC},
    7855                 :     {VARIANT_ANGLE_OR_ZERO},
    7856                 :     {VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO},
    7857                 :     {VARIANT_NUMBER},
    7858                 :     {VARIANT_LENGTH|VARIANT_POSITIVE_LENGTH},
    7859                 :     {VARIANT_NUMBER, VARIANT_NUMBER},
    7860                 :     {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER},
    7861                 :     {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO},
    7862                 :     {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
    7863                 :      VARIANT_LPNCALC, VARIANT_LPNCALC},
    7864                 :     {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
    7865                 :      VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
    7866                 :      VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
    7867                 :      VARIANT_LPNCALC, VARIANT_LPNCALC, VARIANT_LNCALC, VARIANT_NUMBER}};
    7868                 : 
    7869                 : #ifdef DEBUG
    7870                 :   static const PRUint8 kVariantMaskLengths[eNumVariantMasks] =
    7871                 :     {1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 16};
    7872                 : #endif
    7873                 : 
    7874               0 :   PRInt32 variantIndex = eNumVariantMasks;
    7875                 : 
    7876               0 :   aIs3D = false;
    7877                 : 
    7878               0 :   switch (aToken) {
    7879                 :   case eCSSKeyword_translatex:
    7880                 :   case eCSSKeyword_translatey:
    7881                 :     /* Exactly one length or percent. */
    7882               0 :     variantIndex = eLengthPercentCalc;
    7883               0 :     aMinElems = 1U;
    7884               0 :     aMaxElems = 1U;
    7885               0 :     break;
    7886                 :   case eCSSKeyword_translatez:
    7887                 :     /* Exactly one length */
    7888               0 :     variantIndex = eLengthCalc;
    7889               0 :     aMinElems = 1U;
    7890               0 :     aMaxElems = 1U;
    7891               0 :     aIs3D = true;
    7892               0 :     break;
    7893                 :   case eCSSKeyword_translate3d:
    7894                 :     /* Exactly two lengthds or percents and a number */
    7895               0 :     variantIndex = eTwoLengthPercentCalcsOneLengthCalc;
    7896               0 :     aMinElems = 3U;
    7897               0 :     aMaxElems = 3U;
    7898               0 :     aIs3D = true;
    7899               0 :     break;
    7900                 :   case eCSSKeyword_scalez:
    7901               0 :     aIs3D = true;
    7902                 :   case eCSSKeyword_scalex:
    7903                 :   case eCSSKeyword_scaley:
    7904                 :     /* Exactly one scale factor. */
    7905               0 :     variantIndex = eNumber;
    7906               0 :     aMinElems = 1U;
    7907               0 :     aMaxElems = 1U;
    7908               0 :     break;
    7909                 :   case eCSSKeyword_scale3d:
    7910                 :     /* Exactly three scale factors. */
    7911               0 :     variantIndex = eThreeNumbers;
    7912               0 :     aMinElems = 3U;
    7913               0 :     aMaxElems = 3U;
    7914               0 :     aIs3D = true;
    7915               0 :     break;
    7916                 :   case eCSSKeyword_rotatex:
    7917                 :   case eCSSKeyword_rotatey:
    7918               0 :     aIs3D = true;
    7919                 :   case eCSSKeyword_rotate:
    7920                 :   case eCSSKeyword_rotatez:
    7921                 :     /* Exactly one angle. */
    7922               0 :     variantIndex = eAngle;
    7923               0 :     aMinElems = 1U;
    7924               0 :     aMaxElems = 1U;
    7925               0 :     break;
    7926                 :   case eCSSKeyword_rotate3d:
    7927               0 :     variantIndex = eThreeNumbersOneAngle;
    7928               0 :     aMinElems = 4U;
    7929               0 :     aMaxElems = 4U;
    7930               0 :     aIs3D = true;
    7931               0 :     break;
    7932                 :   case eCSSKeyword_translate:
    7933                 :     /* One or two lengths or percents. */
    7934               0 :     variantIndex = eTwoLengthPercentCalcs;
    7935               0 :     aMinElems = 1U;
    7936               0 :     aMaxElems = 2U;
    7937               0 :     break;
    7938                 :   case eCSSKeyword_skew:
    7939                 :     /* Exactly one or two angles. */
    7940               0 :     variantIndex = eTwoAngles;
    7941               0 :     aMinElems = 1U;
    7942               0 :     aMaxElems = 2U;
    7943               0 :     break;
    7944                 :   case eCSSKeyword_scale:
    7945                 :     /* One or two scale factors. */
    7946               0 :     variantIndex = eTwoNumbers;
    7947               0 :     aMinElems = 1U;
    7948               0 :     aMaxElems = 2U;
    7949               0 :     break;
    7950                 :   case eCSSKeyword_skewx:
    7951                 :     /* Exactly one angle. */
    7952               0 :     variantIndex = eAngle;
    7953               0 :     aMinElems = 1U;
    7954               0 :     aMaxElems = 1U;
    7955               0 :     break;
    7956                 :   case eCSSKeyword_skewy:
    7957                 :     /* Exactly one angle. */
    7958               0 :     variantIndex = eAngle;
    7959               0 :     aMinElems = 1U;
    7960               0 :     aMaxElems = 1U;
    7961               0 :     break;
    7962                 :   case eCSSKeyword_matrix:
    7963                 :     /* Six values, which can be numbers, lengths, or percents. */
    7964               0 :     variantIndex = eMatrix;
    7965               0 :     aMinElems = 6U;
    7966               0 :     aMaxElems = 6U;
    7967               0 :     break;
    7968                 :   case eCSSKeyword_matrix3d:
    7969                 :     /* 16 matrix values, all numbers */
    7970               0 :     variantIndex = eMatrix3d;
    7971               0 :     aMinElems = 16U;
    7972               0 :     aMaxElems = 16U;
    7973               0 :     aIs3D = true;
    7974               0 :     break;
    7975                 :   case eCSSKeyword_perspective:
    7976                 :     /* Exactly one scale number. */
    7977               0 :     variantIndex = ePositiveLength;
    7978               0 :     aMinElems = 1U;
    7979               0 :     aMaxElems = 1U;
    7980               0 :     aIs3D = true;
    7981               0 :     break;
    7982                 :   default:
    7983                 :     /* Oh dear, we didn't match.  Report an error. */
    7984               0 :     return false;
    7985                 :   }
    7986                 : 
    7987               0 :   NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!");
    7988               0 :   NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!");
    7989               0 :   NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!");
    7990               0 :   NS_ASSERTION(variantIndex >= 0, "Invalid variant mask!");
    7991               0 :   NS_ASSERTION(variantIndex < eNumVariantMasks, "Invalid variant mask!");
    7992                 : #ifdef DEBUG
    7993               0 :   NS_ASSERTION(aMaxElems <= kVariantMaskLengths[variantIndex],
    7994                 :                "Invalid aMaxElems for this variant mask.");
    7995                 : #endif
    7996                 : 
    7997                 :   // Convert the index into a mask.
    7998               0 :   aVariantMask = kVariantMasks[variantIndex];
    7999                 : 
    8000               0 :   return true;
    8001                 : }
    8002                 : 
    8003                 : /* Reads a single transform function from the tokenizer stream, reporting an
    8004                 :  * error if something goes wrong.
    8005                 :  */
    8006                 : bool
    8007               0 : CSSParserImpl::ParseSingleTransform(nsCSSValue& aValue, bool& aIs3D)
    8008                 : {
    8009               0 :   if (!GetToken(true))
    8010               0 :     return false;
    8011                 : 
    8012               0 :   if (mToken.mType != eCSSToken_Function) {
    8013               0 :     UngetToken();
    8014               0 :     return false;
    8015                 :   }
    8016                 : 
    8017                 :   const PRInt32* variantMask;
    8018                 :   PRUint16 minElems, maxElems;
    8019               0 :   nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
    8020                 : 
    8021               0 :   if (!GetFunctionParseInformation(keyword,
    8022               0 :                                    minElems, maxElems, variantMask, aIs3D))
    8023               0 :     return false;
    8024                 : 
    8025                 :   // Bug 721136: Normalize the identifier to lowercase, except that things
    8026                 :   // like scaleX should have the last character capitalized.  This matches
    8027                 :   // what other browsers do.
    8028               0 :   nsContentUtils::ASCIIToLower(mToken.mIdent);
    8029               0 :   switch (keyword) {
    8030                 :     case eCSSKeyword_rotatex:
    8031                 :     case eCSSKeyword_scalex:
    8032                 :     case eCSSKeyword_skewx:
    8033                 :     case eCSSKeyword_translatex:
    8034               0 :       mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('X'));
    8035               0 :       break;
    8036                 : 
    8037                 :     case eCSSKeyword_rotatey:
    8038                 :     case eCSSKeyword_scaley:
    8039                 :     case eCSSKeyword_skewy:
    8040                 :     case eCSSKeyword_translatey:
    8041               0 :       mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Y'));
    8042               0 :       break;
    8043                 : 
    8044                 :     case eCSSKeyword_rotatez:
    8045                 :     case eCSSKeyword_scalez:
    8046                 :     case eCSSKeyword_translatez:
    8047               0 :       mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Z'));
    8048               0 :       break;
    8049                 : 
    8050                 :     default:
    8051               0 :       break;
    8052                 :   }
    8053                 : 
    8054               0 :   return ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, aValue);
    8055                 : }
    8056                 : 
    8057                 : /* Parses a -moz-transform property list by continuously reading in properties
    8058                 :  * and constructing a matrix from it.
    8059                 :  */
    8060               0 : bool CSSParserImpl::ParseMozTransform()
    8061                 : {
    8062               0 :   nsCSSValue value;
    8063               0 :   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
    8064                 :     // 'inherit', 'initial', and 'none' must be alone
    8065               0 :     if (!ExpectEndProperty()) {
    8066               0 :       return false;
    8067                 :     }
    8068                 :   } else {
    8069               0 :     nsCSSValueList* cur = value.SetListValue();
    8070               0 :     for (;;) {
    8071                 :       bool is3D;
    8072               0 :       if (!ParseSingleTransform(cur->mValue, is3D)) {
    8073               0 :         return false;
    8074                 :       }
    8075               0 :       if (is3D && !nsLayoutUtils::Are3DTransformsEnabled()) {
    8076               0 :         return false;
    8077                 :       }
    8078               0 :       if (CheckEndProperty()) {
    8079               0 :         break;
    8080                 :       }
    8081               0 :       cur->mNext = new nsCSSValueList;
    8082               0 :       cur = cur->mNext;
    8083                 :     }
    8084                 :   }
    8085               0 :   AppendValue(eCSSProperty__moz_transform, value);
    8086               0 :   return true;
    8087                 : }
    8088                 : 
    8089               0 : bool CSSParserImpl::ParseMozTransformOrigin(bool aPerspective)
    8090                 : {
    8091               0 :   nsCSSValuePair position;
    8092               0 :   if (!ParseBoxPositionValues(position, true))
    8093               0 :     return false;
    8094                 : 
    8095               0 :   nsCSSProperty prop = eCSSProperty__moz_transform_origin;
    8096               0 :   if (aPerspective) {
    8097               0 :     if (!ExpectEndProperty()) {
    8098               0 :       return false;
    8099                 :     }
    8100               0 :     prop = eCSSProperty_perspective_origin;
    8101                 :   }
    8102                 : 
    8103                 :   // Unlike many other uses of pairs, this position should always be stored
    8104                 :   // as a pair, even if the values are the same, so it always serializes as
    8105                 :   // a pair, and to keep the computation code simple.
    8106               0 :   if (position.mXValue.GetUnit() == eCSSUnit_Inherit ||
    8107               0 :       position.mXValue.GetUnit() == eCSSUnit_Initial) {
    8108               0 :     NS_ABORT_IF_FALSE(position.mXValue == position.mYValue,
    8109                 :                       "inherit/initial only half?");
    8110               0 :     AppendValue(prop, position.mXValue);
    8111                 :   } else {
    8112               0 :     nsCSSValue value;
    8113               0 :     if (aPerspective) {
    8114               0 :       value.SetPairValue(position.mXValue, position.mYValue);
    8115                 :     } else {
    8116               0 :       nsCSSValue depth;
    8117               0 :       if (!ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nsnull) ||
    8118               0 :           !nsLayoutUtils::Are3DTransformsEnabled()) {
    8119               0 :         depth.Reset();
    8120                 :       }
    8121               0 :       value.SetTripletValue(position.mXValue, position.mYValue, depth);
    8122                 :     }
    8123                 : 
    8124               0 :     AppendValue(prop, value);
    8125                 :   }
    8126               0 :   return true;
    8127                 : }
    8128                 : 
    8129                 : bool
    8130               0 : CSSParserImpl::ParseFamily(nsCSSValue& aValue)
    8131                 : {
    8132               0 :   if (!GetToken(true))
    8133               0 :     return false;
    8134                 : 
    8135               0 :   if (eCSSToken_Ident == mToken.mType) {
    8136               0 :     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
    8137               0 :     if (keyword == eCSSKeyword_inherit) {
    8138               0 :       aValue.SetInheritValue();
    8139               0 :       return true;
    8140                 :     }
    8141               0 :     if (keyword == eCSSKeyword__moz_initial) {
    8142               0 :       aValue.SetInitialValue();
    8143               0 :       return true;
    8144                 :     }
    8145               0 :     if (keyword == eCSSKeyword__moz_use_system_font &&
    8146               0 :         !IsParsingCompoundProperty()) {
    8147               0 :       aValue.SetSystemFontValue();
    8148               0 :       return true;
    8149                 :     }
    8150                 :   }
    8151                 : 
    8152               0 :   UngetToken();
    8153                 : 
    8154               0 :   nsAutoString family;
    8155               0 :   for (;;) {
    8156               0 :     if (!ParseOneFamily(family))
    8157               0 :       return false;
    8158                 : 
    8159               0 :     if (!ExpectSymbol(',', true))
    8160                 :       break;
    8161                 : 
    8162               0 :     family.Append(PRUnichar(','));
    8163                 :   }
    8164                 : 
    8165               0 :   if (family.IsEmpty()) {
    8166               0 :     return false;
    8167                 :   }
    8168               0 :   aValue.SetStringValue(family, eCSSUnit_Families);
    8169               0 :   return true;
    8170                 : }
    8171                 : 
    8172                 : // src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*
    8173                 : // uri-src: uri [ 'format(' string ( ',' string )* ')' ]
    8174                 : // local-src: 'local(' ( string | ident ) ')'
    8175                 : 
    8176                 : bool
    8177               0 : CSSParserImpl::ParseFontSrc(nsCSSValue& aValue)
    8178                 : {
    8179                 :   // could we maybe turn nsCSSValue::Array into InfallibleTArray<nsCSSValue>?
    8180               0 :   InfallibleTArray<nsCSSValue> values;
    8181               0 :   nsCSSValue cur;
    8182               0 :   for (;;) {
    8183               0 :     if (!GetToken(true))
    8184               0 :       break;
    8185                 : 
    8186               0 :     if (mToken.mType == eCSSToken_URL) {
    8187               0 :       SetValueToURL(cur, mToken.mIdent);
    8188               0 :       values.AppendElement(cur);
    8189               0 :       if (!ParseFontSrcFormat(values))
    8190               0 :         return false;
    8191                 : 
    8192               0 :     } else if (mToken.mType == eCSSToken_Function &&
    8193               0 :                mToken.mIdent.LowerCaseEqualsLiteral("local")) {
    8194                 :       // css3-fonts does not specify a formal grammar for local().
    8195                 :       // The text permits both unquoted identifiers and quoted
    8196                 :       // strings.  We resolve this ambiguity in the spec by
    8197                 :       // assuming that the appropriate production is a single
    8198                 :       // <family-name>, possibly surrounded by whitespace.
    8199                 : 
    8200               0 :       nsAutoString family;
    8201               0 :       if (!ParseOneFamily(family)) {
    8202               0 :         SkipUntil(')');
    8203               0 :         return false;
    8204                 :       }
    8205               0 :       if (!ExpectSymbol(')', true)) {
    8206               0 :         SkipUntil(')');
    8207               0 :         return false;
    8208                 :       }
    8209                 : 
    8210                 :       // the style parameters to the nsFont constructor are ignored,
    8211                 :       // because it's only being used to call EnumerateFamilies
    8212               0 :       nsFont font(family, 0, 0, 0, 0, 0, 0);
    8213               0 :       ExtractFirstFamilyData dat;
    8214                 : 
    8215               0 :       font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat);
    8216               0 :       if (!dat.mGood)
    8217               0 :         return false;
    8218                 : 
    8219               0 :       cur.SetStringValue(dat.mFamilyName, eCSSUnit_Local_Font);
    8220               0 :       values.AppendElement(cur);
    8221                 :     } else {
    8222               0 :       return false;
    8223                 :     }
    8224                 : 
    8225               0 :     if (!ExpectSymbol(',', true))
    8226               0 :       break;
    8227                 :   }
    8228                 : 
    8229               0 :   if (values.Length() == 0)
    8230               0 :     return false;
    8231                 : 
    8232                 :   nsRefPtr<nsCSSValue::Array> srcVals
    8233               0 :     = nsCSSValue::Array::Create(values.Length());
    8234                 : 
    8235                 :   PRUint32 i;
    8236               0 :   for (i = 0; i < values.Length(); i++)
    8237               0 :     srcVals->Item(i) = values[i];
    8238               0 :   aValue.SetArrayValue(srcVals, eCSSUnit_Array);
    8239               0 :   return true;
    8240                 : }
    8241                 : 
    8242                 : bool
    8243               0 : CSSParserImpl::ParseFontSrcFormat(InfallibleTArray<nsCSSValue> & values)
    8244                 : {
    8245               0 :   if (!GetToken(true))
    8246               0 :     return true; // EOF harmless here
    8247               0 :   if (mToken.mType != eCSSToken_Function ||
    8248               0 :       !mToken.mIdent.LowerCaseEqualsLiteral("format")) {
    8249               0 :     UngetToken();
    8250               0 :     return true;
    8251                 :   }
    8252                 : 
    8253               0 :   do {
    8254               0 :     if (!GetToken(true))
    8255               0 :       return false; // EOF - no need for SkipUntil
    8256                 : 
    8257               0 :     if (mToken.mType != eCSSToken_String) {
    8258               0 :       UngetToken();
    8259               0 :       SkipUntil(')');
    8260               0 :       return false;
    8261                 :     }
    8262                 : 
    8263               0 :     nsCSSValue cur(mToken.mIdent, eCSSUnit_Font_Format);
    8264               0 :     values.AppendElement(cur);
    8265                 :   } while (ExpectSymbol(',', true));
    8266                 : 
    8267               0 :   if (!ExpectSymbol(')', true)) {
    8268               0 :     SkipUntil(')');
    8269               0 :     return false;
    8270                 :   }
    8271                 : 
    8272               0 :   return true;
    8273                 : }
    8274                 : 
    8275                 : // font-ranges: urange ( ',' urange )*
    8276                 : bool
    8277               0 : CSSParserImpl::ParseFontRanges(nsCSSValue& aValue)
    8278                 : {
    8279               0 :   InfallibleTArray<PRUint32> ranges;
    8280               0 :   for (;;) {
    8281               0 :     if (!GetToken(true))
    8282               0 :       break;
    8283                 : 
    8284               0 :     if (mToken.mType != eCSSToken_URange) {
    8285               0 :       UngetToken();
    8286               0 :       break;
    8287                 :     }
    8288                 : 
    8289                 :     // An invalid range token is a parsing error, causing the entire
    8290                 :     // descriptor to be ignored.
    8291               0 :     if (!mToken.mIntegerValid)
    8292               0 :       return false;
    8293                 : 
    8294               0 :     PRUint32 low = mToken.mInteger;
    8295               0 :     PRUint32 high = mToken.mInteger2;
    8296                 : 
    8297                 :     // A range that descends, or a range that is entirely outside the
    8298                 :     // current range of Unicode (U+0-10FFFF) is ignored, but does not
    8299                 :     // invalidate the descriptor.  A range that straddles the high end
    8300                 :     // is clipped.
    8301               0 :     if (low <= 0x10FFFF && low <= high) {
    8302               0 :       if (high > 0x10FFFF)
    8303               0 :         high = 0x10FFFF;
    8304                 : 
    8305               0 :       ranges.AppendElement(low);
    8306               0 :       ranges.AppendElement(high);
    8307                 :     }
    8308               0 :     if (!ExpectSymbol(',', true))
    8309               0 :       break;
    8310                 :   }
    8311                 : 
    8312               0 :   if (ranges.Length() == 0)
    8313               0 :     return false;
    8314                 : 
    8315                 :   nsRefPtr<nsCSSValue::Array> srcVals
    8316               0 :     = nsCSSValue::Array::Create(ranges.Length());
    8317                 : 
    8318               0 :   for (PRUint32 i = 0; i < ranges.Length(); i++)
    8319               0 :     srcVals->Item(i).SetIntValue(ranges[i], eCSSUnit_Integer);
    8320               0 :   aValue.SetArrayValue(srcVals, eCSSUnit_Array);
    8321               0 :   return true;
    8322                 : }
    8323                 : 
    8324                 : bool
    8325               0 : CSSParserImpl::ParseListStyle()
    8326                 : {
    8327                 :   // 'list-style' can accept 'none' for two different subproperties,
    8328                 :   // 'list-style-type' and 'list-style-position'.  In order to accept
    8329                 :   // 'none' as the value of either but still allow another value for
    8330                 :   // either, we need to ensure that the first 'none' we find gets
    8331                 :   // allocated to a dummy property instead.
    8332                 :   static const nsCSSProperty listStyleIDs[] = {
    8333                 :     eCSSPropertyExtra_x_none_value,
    8334                 :     eCSSProperty_list_style_type,
    8335                 :     eCSSProperty_list_style_position,
    8336                 :     eCSSProperty_list_style_image
    8337                 :   };
    8338                 : 
    8339               0 :   nsCSSValue values[NS_ARRAY_LENGTH(listStyleIDs)];
    8340                 :   PRInt32 found =
    8341               0 :     ParseChoice(values, listStyleIDs, ArrayLength(listStyleIDs));
    8342               0 :   if (found < 1 || !ExpectEndProperty()) {
    8343               0 :     return false;
    8344                 :   }
    8345                 : 
    8346               0 :   if ((found & (1|2|8)) == (1|2|8)) {
    8347               0 :     if (values[0].GetUnit() == eCSSUnit_None) {
    8348                 :       // We found a 'none' plus another value for both of
    8349                 :       // 'list-style-type' and 'list-style-image'.  This is a parse
    8350                 :       // error, since the 'none' has to count for at least one of them.
    8351               0 :       return false;
    8352                 :     } else {
    8353               0 :       NS_ASSERTION(found == (1|2|4|8) && values[0] == values[1] &&
    8354                 :                    values[0] == values[2] && values[0] == values[3],
    8355                 :                    "should be a special value");
    8356                 :     }
    8357                 :   }
    8358                 : 
    8359                 :   // Provide default values
    8360               0 :   if ((found & 2) == 0) {
    8361               0 :     if (found & 1) {
    8362               0 :       values[1].SetIntValue(NS_STYLE_LIST_STYLE_NONE, eCSSUnit_Enumerated);
    8363                 :     } else {
    8364               0 :       values[1].SetIntValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated);
    8365                 :     }
    8366                 :   }
    8367               0 :   if ((found & 4) == 0) {
    8368                 :     values[2].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE,
    8369               0 :                           eCSSUnit_Enumerated);
    8370                 :   }
    8371               0 :   if ((found & 8) == 0) {
    8372               0 :     values[3].SetNoneValue();
    8373                 :   }
    8374                 : 
    8375                 :   // Start at 1 to avoid appending fake value.
    8376               0 :   for (PRUint32 index = 1; index < ArrayLength(listStyleIDs); ++index) {
    8377               0 :     AppendValue(listStyleIDs[index], values[index]);
    8378                 :   }
    8379               0 :   return true;
    8380                 : }
    8381                 : 
    8382                 : bool
    8383               0 : CSSParserImpl::ParseMargin()
    8384                 : {
    8385                 :   static const nsCSSProperty kMarginSideIDs[] = {
    8386                 :     eCSSProperty_margin_top,
    8387                 :     eCSSProperty_margin_right_value,
    8388                 :     eCSSProperty_margin_bottom,
    8389                 :     eCSSProperty_margin_left_value
    8390                 :   };
    8391                 :   static const nsCSSProperty kMarginSources[] = {
    8392                 :     eCSSProperty_margin_left_ltr_source,
    8393                 :     eCSSProperty_margin_left_rtl_source,
    8394                 :     eCSSProperty_margin_right_ltr_source,
    8395                 :     eCSSProperty_margin_right_rtl_source,
    8396                 :     eCSSProperty_UNKNOWN
    8397                 :   };
    8398                 : 
    8399                 :   // do this now, in case 4 values weren't specified
    8400               0 :   InitBoxPropsAsPhysical(kMarginSources);
    8401               0 :   return ParseBoxProperties(kMarginSideIDs);
    8402                 : }
    8403                 : 
    8404                 : bool
    8405               0 : CSSParserImpl::ParseMarks(nsCSSValue& aValue)
    8406                 : {
    8407               0 :   if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kPageMarksKTable)) {
    8408               0 :     if (eCSSUnit_Enumerated == aValue.GetUnit()) {
    8409               0 :       if (NS_STYLE_PAGE_MARKS_NONE != aValue.GetIntValue() &&
    8410               0 :           false == CheckEndProperty()) {
    8411               0 :         nsCSSValue second;
    8412               0 :         if (ParseEnum(second, nsCSSProps::kPageMarksKTable)) {
    8413                 :           // 'none' keyword in conjuction with others is not allowed
    8414               0 :           if (NS_STYLE_PAGE_MARKS_NONE != second.GetIntValue()) {
    8415               0 :             aValue.SetIntValue(aValue.GetIntValue() | second.GetIntValue(),
    8416               0 :                                eCSSUnit_Enumerated);
    8417               0 :             return true;
    8418                 :           }
    8419                 :         }
    8420               0 :         return false;
    8421                 :       }
    8422                 :     }
    8423               0 :     return true;
    8424                 :   }
    8425               0 :   return false;
    8426                 : }
    8427                 : 
    8428                 : bool
    8429               0 : CSSParserImpl::ParseOutline()
    8430                 : {
    8431               0 :   const PRInt32 numProps = 3;
    8432                 :   static const nsCSSProperty kOutlineIDs[] = {
    8433                 :     eCSSProperty_outline_color,
    8434                 :     eCSSProperty_outline_style,
    8435                 :     eCSSProperty_outline_width
    8436                 :   };
    8437                 : 
    8438               0 :   nsCSSValue  values[numProps];
    8439               0 :   PRInt32 found = ParseChoice(values, kOutlineIDs, numProps);
    8440               0 :   if ((found < 1) || (false == ExpectEndProperty())) {
    8441               0 :     return false;
    8442                 :   }
    8443                 : 
    8444                 :   // Provide default values
    8445               0 :   if ((found & 1) == 0) { // Provide default outline-color
    8446               0 :     values[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
    8447                 :   }
    8448               0 :   if ((found & 2) == 0) { // Provide default outline-style
    8449               0 :     values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated);
    8450                 :   }
    8451               0 :   if ((found & 4) == 0) { // Provide default outline-width
    8452               0 :     values[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated);
    8453                 :   }
    8454                 : 
    8455                 :   PRInt32 index;
    8456               0 :   for (index = 0; index < numProps; index++) {
    8457               0 :     AppendValue(kOutlineIDs[index], values[index]);
    8458                 :   }
    8459               0 :   return true;
    8460                 : }
    8461                 : 
    8462                 : bool
    8463               0 : CSSParserImpl::ParseOverflow()
    8464                 : {
    8465               0 :   nsCSSValue overflow;
    8466               0 :   if (!ParseVariant(overflow, VARIANT_HK,
    8467               0 :                     nsCSSProps::kOverflowKTable) ||
    8468               0 :       !ExpectEndProperty())
    8469               0 :     return false;
    8470                 : 
    8471               0 :   nsCSSValue overflowX(overflow);
    8472               0 :   nsCSSValue overflowY(overflow);
    8473               0 :   if (eCSSUnit_Enumerated == overflow.GetUnit())
    8474               0 :     switch(overflow.GetIntValue()) {
    8475                 :       case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL:
    8476               0 :         overflowX.SetIntValue(NS_STYLE_OVERFLOW_SCROLL, eCSSUnit_Enumerated);
    8477               0 :         overflowY.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN, eCSSUnit_Enumerated);
    8478               0 :         break;
    8479                 :       case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL:
    8480               0 :         overflowX.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN, eCSSUnit_Enumerated);
    8481               0 :         overflowY.SetIntValue(NS_STYLE_OVERFLOW_SCROLL, eCSSUnit_Enumerated);
    8482               0 :         break;
    8483                 :     }
    8484               0 :   AppendValue(eCSSProperty_overflow_x, overflowX);
    8485               0 :   AppendValue(eCSSProperty_overflow_y, overflowY);
    8486               0 :   return true;
    8487                 : }
    8488                 : 
    8489                 : bool
    8490               0 : CSSParserImpl::ParsePadding()
    8491                 : {
    8492                 :   static const nsCSSProperty kPaddingSideIDs[] = {
    8493                 :     eCSSProperty_padding_top,
    8494                 :     eCSSProperty_padding_right_value,
    8495                 :     eCSSProperty_padding_bottom,
    8496                 :     eCSSProperty_padding_left_value
    8497                 :   };
    8498                 :   static const nsCSSProperty kPaddingSources[] = {
    8499                 :     eCSSProperty_padding_left_ltr_source,
    8500                 :     eCSSProperty_padding_left_rtl_source,
    8501                 :     eCSSProperty_padding_right_ltr_source,
    8502                 :     eCSSProperty_padding_right_rtl_source,
    8503                 :     eCSSProperty_UNKNOWN
    8504                 :   };
    8505                 : 
    8506                 :   // do this now, in case 4 values weren't specified
    8507               0 :   InitBoxPropsAsPhysical(kPaddingSources);
    8508               0 :   return ParseBoxProperties(kPaddingSideIDs);
    8509                 : }
    8510                 : 
    8511                 : bool
    8512               0 : CSSParserImpl::ParseQuotes()
    8513                 : {
    8514               0 :   nsCSSValue value;
    8515               0 :   if (!ParseVariant(value, VARIANT_HOS, nsnull)) {
    8516               0 :     return false;
    8517                 :   }
    8518               0 :   if (value.GetUnit() != eCSSUnit_String) {
    8519               0 :     if (!ExpectEndProperty()) {
    8520               0 :       return false;
    8521                 :     }
    8522                 :   } else {
    8523               0 :     nsCSSValue open = value;
    8524               0 :     nsCSSValuePairList* quotes = value.SetPairListValue();
    8525               0 :     for (;;) {
    8526               0 :       quotes->mXValue = open;
    8527                 :       // get mandatory close
    8528               0 :       if (!ParseVariant(quotes->mYValue, VARIANT_STRING, nsnull)) {
    8529               0 :         return false;
    8530                 :       }
    8531               0 :       if (CheckEndProperty()) {
    8532                 :         break;
    8533                 :       }
    8534                 :       // look for another open
    8535               0 :       if (!ParseVariant(open, VARIANT_STRING, nsnull)) {
    8536               0 :         return false;
    8537                 :       }
    8538               0 :       quotes->mNext = new nsCSSValuePairList;
    8539               0 :       quotes = quotes->mNext;
    8540                 :     }
    8541                 :   }
    8542               0 :   AppendValue(eCSSProperty_quotes, value);
    8543               0 :   return true;
    8544                 : }
    8545                 : 
    8546                 : bool
    8547               0 : CSSParserImpl::ParseSize()
    8548                 : {
    8549               0 :   nsCSSValue width, height;
    8550               0 :   if (!ParseVariant(width, VARIANT_AHKL, nsCSSProps::kPageSizeKTable)) {
    8551               0 :     return false;
    8552                 :   }
    8553               0 :   if (width.IsLengthUnit()) {
    8554               0 :     ParseVariant(height, VARIANT_LENGTH, nsnull);
    8555                 :   }
    8556               0 :   if (!ExpectEndProperty()) {
    8557               0 :     return false;
    8558                 :   }
    8559                 : 
    8560               0 :   if (width == height || height.GetUnit() == eCSSUnit_Null) {
    8561               0 :     AppendValue(eCSSProperty_size, width);
    8562                 :   } else {
    8563               0 :     nsCSSValue pair;
    8564               0 :     pair.SetPairValue(width, height);
    8565               0 :     AppendValue(eCSSProperty_size, pair);
    8566                 :   }
    8567               0 :   return true;
    8568                 : }
    8569                 : 
    8570                 : bool
    8571               0 : CSSParserImpl::ParseTextDecoration()
    8572                 : {
    8573                 :   enum {
    8574                 :     eDecorationNone         = NS_STYLE_TEXT_DECORATION_LINE_NONE,
    8575                 :     eDecorationUnderline    = NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
    8576                 :     eDecorationOverline     = NS_STYLE_TEXT_DECORATION_LINE_OVERLINE,
    8577                 :     eDecorationLineThrough  = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
    8578                 :     eDecorationBlink        = NS_STYLE_TEXT_DECORATION_LINE_BLINK,
    8579                 :     eDecorationPrefAnchors  = NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS
    8580                 :   };
    8581                 :   MOZ_STATIC_ASSERT((eDecorationNone ^ eDecorationUnderline ^
    8582                 :                      eDecorationOverline ^ eDecorationLineThrough ^
    8583                 :                      eDecorationBlink ^ eDecorationPrefAnchors) ==
    8584                 :                     (eDecorationNone | eDecorationUnderline |
    8585                 :                      eDecorationOverline | eDecorationLineThrough |
    8586                 :                      eDecorationBlink | eDecorationPrefAnchors),
    8587                 :                     "text decoration constants need to be bitmasks");
    8588                 : 
    8589                 :   static const PRInt32 kTextDecorationKTable[] = {
    8590                 :     eCSSKeyword_none,                   eDecorationNone,
    8591                 :     eCSSKeyword_underline,              eDecorationUnderline,
    8592                 :     eCSSKeyword_overline,               eDecorationOverline,
    8593                 :     eCSSKeyword_line_through,           eDecorationLineThrough,
    8594                 :     eCSSKeyword_blink,                  eDecorationBlink,
    8595                 :     eCSSKeyword__moz_anchor_decoration, eDecorationPrefAnchors,
    8596                 :     eCSSKeyword_UNKNOWN,-1
    8597                 :   };
    8598                 : 
    8599               0 :   nsCSSValue value;
    8600               0 :   if (!ParseVariant(value, VARIANT_HK, kTextDecorationKTable)) {
    8601               0 :     return false;
    8602                 :   }
    8603                 : 
    8604               0 :   nsCSSValue blink, line, style, color;
    8605               0 :   switch (value.GetUnit()) {
    8606                 :     case eCSSUnit_Enumerated: {
    8607                 :       // We shouldn't accept decoration line style and color via
    8608                 :       // text-decoration.
    8609                 :       color.SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
    8610               0 :                         eCSSUnit_Enumerated);
    8611                 :       style.SetIntValue(NS_STYLE_TEXT_DECORATION_STYLE_SOLID,
    8612               0 :                         eCSSUnit_Enumerated);
    8613                 : 
    8614               0 :       PRInt32 intValue = value.GetIntValue();
    8615               0 :       if (intValue == eDecorationNone) {
    8616               0 :         blink.SetIntValue(NS_STYLE_TEXT_BLINK_NONE, eCSSUnit_Enumerated);
    8617                 :         line.SetIntValue(NS_STYLE_TEXT_DECORATION_LINE_NONE,
    8618               0 :                          eCSSUnit_Enumerated);
    8619               0 :         break;
    8620                 :       }
    8621                 : 
    8622                 :       // look for more keywords
    8623               0 :       nsCSSValue keyword;
    8624                 :       PRInt32 index;
    8625               0 :       for (index = 0; index < 3; index++) {
    8626               0 :         if (!ParseEnum(keyword, kTextDecorationKTable)) {
    8627               0 :           break;
    8628                 :         }
    8629               0 :         PRInt32 newValue = keyword.GetIntValue();
    8630               0 :         if (newValue == eDecorationNone || newValue & intValue) {
    8631                 :           // 'none' keyword in conjuction with others is not allowed, and
    8632                 :           // duplicate keyword is not allowed.
    8633               0 :           return false;
    8634                 :         }
    8635               0 :         intValue |= newValue;
    8636                 :       }
    8637                 : 
    8638                 :       blink.SetIntValue((intValue & eDecorationBlink) != 0 ?
    8639                 :                           NS_STYLE_TEXT_BLINK_BLINK : NS_STYLE_TEXT_BLINK_NONE,
    8640               0 :                         eCSSUnit_Enumerated);
    8641               0 :       line.SetIntValue((intValue & ~eDecorationBlink), eCSSUnit_Enumerated);
    8642               0 :       break;
    8643                 :     }
    8644                 :     default:
    8645               0 :       blink = line = color = style = value;
    8646               0 :       break;
    8647                 :   }
    8648                 : 
    8649               0 :   AppendValue(eCSSProperty_text_blink, blink);
    8650               0 :   AppendValue(eCSSProperty_text_decoration_line, line);
    8651               0 :   AppendValue(eCSSProperty_text_decoration_color, color);
    8652               0 :   AppendValue(eCSSProperty_text_decoration_style, style);
    8653                 : 
    8654               0 :   return true;
    8655                 : }
    8656                 : 
    8657                 : bool
    8658               0 : CSSParserImpl::ParseTextDecorationLine(nsCSSValue& aValue)
    8659                 : {
    8660               0 :   if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTextDecorationLineKTable)) {
    8661               0 :     if (eCSSUnit_Enumerated == aValue.GetUnit()) {
    8662               0 :       PRInt32 intValue = aValue.GetIntValue();
    8663               0 :       if (intValue != NS_STYLE_TEXT_DECORATION_LINE_NONE) {
    8664                 :         // look for more keywords
    8665               0 :         nsCSSValue  keyword;
    8666                 :         PRInt32 index;
    8667               0 :         for (index = 0; index < 2; index++) {
    8668               0 :           if (ParseEnum(keyword, nsCSSProps::kTextDecorationLineKTable)) {
    8669               0 :             PRInt32 newValue = keyword.GetIntValue();
    8670               0 :             if (newValue == NS_STYLE_TEXT_DECORATION_LINE_NONE ||
    8671                 :                 newValue & intValue) {
    8672                 :               // 'none' keyword in conjuction with others is not allowed, and
    8673                 :               // duplicate keyword is not allowed.
    8674               0 :               return false;
    8675                 :             }
    8676               0 :             intValue |= newValue;
    8677                 :           }
    8678                 :           else {
    8679               0 :             break;
    8680                 :           }
    8681                 :         }
    8682               0 :         aValue.SetIntValue(intValue, eCSSUnit_Enumerated);
    8683                 :       }
    8684                 :     }
    8685               0 :     return true;
    8686                 :   }
    8687               0 :   return false;
    8688                 : }
    8689                 : 
    8690                 : bool
    8691               0 : CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue)
    8692                 : {
    8693               0 :   if (ParseVariant(aValue, VARIANT_INHERIT, nsnull)) {
    8694                 :     // 'inherit' and 'initial' must be alone
    8695               0 :     return true;
    8696                 :   }
    8697                 : 
    8698               0 :   nsCSSValue left;
    8699               0 :   if (!ParseVariant(left, VARIANT_KEYWORD | VARIANT_STRING,
    8700               0 :                     nsCSSProps::kTextOverflowKTable))
    8701               0 :     return false;
    8702                 : 
    8703               0 :   nsCSSValue right;
    8704               0 :   if (ParseVariant(right, VARIANT_KEYWORD | VARIANT_STRING,
    8705                 :                     nsCSSProps::kTextOverflowKTable))
    8706               0 :     aValue.SetPairValue(left, right);
    8707                 :   else {
    8708               0 :     aValue = left;
    8709                 :   }
    8710               0 :   return true;
    8711                 : }
    8712                 : 
    8713                 : bool
    8714               0 : CSSParserImpl::ParseUnicodeBidi(nsCSSValue& aValue)
    8715                 : {
    8716               0 :   if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kUnicodeBidiKTable)) {
    8717               0 :     if (eCSSUnit_Enumerated == aValue.GetUnit()) {
    8718               0 :       PRInt32 intValue = aValue.GetIntValue();
    8719                 :       // unicode-bidi can have either one or two values, but the only legal
    8720                 :       // combination of two values is 'isolate bidi-override'
    8721               0 :       if (intValue == NS_STYLE_UNICODE_BIDI_ISOLATE ||
    8722                 :           intValue == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
    8723                 :         // look for more keywords
    8724               0 :         nsCSSValue second;
    8725               0 :         if (ParseEnum(second, nsCSSProps::kUnicodeBidiKTable)) {
    8726               0 :           intValue |= second.GetIntValue();
    8727               0 :           if (intValue != (NS_STYLE_UNICODE_BIDI_ISOLATE |
    8728                 :                            NS_STYLE_UNICODE_BIDI_OVERRIDE)) {
    8729               0 :             return false;
    8730                 :           }
    8731                 :         }
    8732               0 :         aValue.SetIntValue(intValue, eCSSUnit_Enumerated);
    8733                 :       }
    8734                 :     }
    8735               0 :     return true;
    8736                 :   }
    8737               0 :   return false;
    8738                 : }
    8739                 :  
    8740                 : bool
    8741               0 : CSSParserImpl::ParseTransitionProperty()
    8742                 : {
    8743               0 :   nsCSSValue value;
    8744               0 :   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE | VARIANT_ALL,
    8745                 :                    nsnull)) {
    8746                 :     // 'inherit', 'initial', 'none', and 'all' must be alone
    8747               0 :     if (!ExpectEndProperty()) {
    8748               0 :       return false;
    8749                 :     }
    8750                 :   } else {
    8751                 :     // Accept a list of arbitrary identifiers.  They should be
    8752                 :     // CSS properties, but we want to accept any so that we
    8753                 :     // accept properties that we don't know about yet, e.g.
    8754                 :     // transition-property: invalid-property, left, opacity;
    8755               0 :     nsCSSValueList* cur = value.SetListValue();
    8756               0 :     for (;;) {
    8757               0 :       if (!ParseVariant(cur->mValue, VARIANT_IDENTIFIER, nsnull)) {
    8758               0 :         return false;
    8759                 :       }
    8760               0 :       nsDependentString str(cur->mValue.GetStringBufferValue());
    8761                 :       // Exclude 'none' and 'all' and 'inherit' and 'initial'
    8762                 :       // according to the same rules as for 'counter-reset' in CSS 2.1
    8763                 :       // (except 'counter-reset' doesn't exclude 'all' since it
    8764                 :       // doesn't support 'all' as a special value).
    8765               0 :       if (str.LowerCaseEqualsLiteral("none") ||
    8766               0 :           str.LowerCaseEqualsLiteral("all") ||
    8767               0 :           str.LowerCaseEqualsLiteral("inherit") ||
    8768               0 :           str.LowerCaseEqualsLiteral("initial")) {
    8769               0 :         return false;
    8770                 :       }
    8771               0 :       if (CheckEndProperty()) {
    8772                 :         break;
    8773                 :       }
    8774               0 :       if (!ExpectSymbol(',', true)) {
    8775               0 :         REPORT_UNEXPECTED_TOKEN(PEExpectedComma);
    8776               0 :         return false;
    8777                 :       }
    8778               0 :       cur->mNext = new nsCSSValueList;
    8779               0 :       cur = cur->mNext;
    8780                 :     }
    8781                 :   }
    8782               0 :   AppendValue(eCSSProperty_transition_property, value);
    8783               0 :   return true;
    8784                 : }
    8785                 : 
    8786                 : bool
    8787               0 : CSSParserImpl::ParseTransitionTimingFunctionValues(nsCSSValue& aValue)
    8788                 : {
    8789               0 :   NS_ASSERTION(!mHavePushBack &&
    8790                 :                mToken.mType == eCSSToken_Function &&
    8791                 :                mToken.mIdent.LowerCaseEqualsLiteral("cubic-bezier"),
    8792                 :                "unexpected initial state");
    8793                 : 
    8794               0 :   nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(4);
    8795                 : 
    8796                 :   float x1, x2, y1, y2;
    8797               0 :   if (!ParseTransitionTimingFunctionValueComponent(x1, ',', true) ||
    8798               0 :       !ParseTransitionTimingFunctionValueComponent(y1, ',', false) ||
    8799               0 :       !ParseTransitionTimingFunctionValueComponent(x2, ',', true) ||
    8800               0 :       !ParseTransitionTimingFunctionValueComponent(y2, ')', false)) {
    8801               0 :     return false;
    8802                 :   }
    8803                 : 
    8804               0 :   val->Item(0).SetFloatValue(x1, eCSSUnit_Number);
    8805               0 :   val->Item(1).SetFloatValue(y1, eCSSUnit_Number);
    8806               0 :   val->Item(2).SetFloatValue(x2, eCSSUnit_Number);
    8807               0 :   val->Item(3).SetFloatValue(y2, eCSSUnit_Number);
    8808                 : 
    8809               0 :   aValue.SetArrayValue(val, eCSSUnit_Cubic_Bezier);
    8810                 : 
    8811               0 :   return true;
    8812                 : }
    8813                 : 
    8814                 : bool
    8815               0 : CSSParserImpl::ParseTransitionTimingFunctionValueComponent(float& aComponent,
    8816                 :                                                            char aStop,
    8817                 :                                                            bool aCheckRange)
    8818                 : {
    8819               0 :   if (!GetToken(true)) {
    8820               0 :     return false;
    8821                 :   }
    8822               0 :   nsCSSToken* tk = &mToken;
    8823               0 :   if (tk->mType == eCSSToken_Number) {
    8824               0 :     float num = tk->mNumber;
    8825               0 :     if (aCheckRange && (num < 0.0 || num > 1.0)) {
    8826               0 :       return false;
    8827                 :     }
    8828               0 :     aComponent = num;
    8829               0 :     if (ExpectSymbol(aStop, true)) {
    8830               0 :       return true;
    8831                 :     }
    8832                 :   }
    8833               0 :   return false;
    8834                 : }
    8835                 : 
    8836                 : bool
    8837               0 : CSSParserImpl::ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue)
    8838                 : {
    8839               0 :   NS_ASSERTION(!mHavePushBack &&
    8840                 :                mToken.mType == eCSSToken_Function &&
    8841                 :                mToken.mIdent.LowerCaseEqualsLiteral("steps"),
    8842                 :                "unexpected initial state");
    8843                 : 
    8844               0 :   nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(2);
    8845                 : 
    8846               0 :   if (!ParseOneOrLargerVariant(val->Item(0), VARIANT_INTEGER, nsnull)) {
    8847               0 :     return false;
    8848                 :   }
    8849                 : 
    8850               0 :   PRInt32 type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END;
    8851               0 :   if (ExpectSymbol(',', true)) {
    8852               0 :     if (!GetToken(true)) {
    8853               0 :       return false;
    8854                 :     }
    8855               0 :     type = -1;
    8856               0 :     if (mToken.mType == eCSSToken_Ident) {
    8857               0 :       if (mToken.mIdent.LowerCaseEqualsLiteral("start")) {
    8858               0 :         type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START;
    8859               0 :       } else if (mToken.mIdent.LowerCaseEqualsLiteral("end")) {
    8860               0 :         type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END;
    8861                 :       }
    8862                 :     }
    8863               0 :     if (type == -1) {
    8864               0 :       UngetToken();
    8865               0 :       return false;
    8866                 :     }
    8867                 :   }
    8868               0 :   val->Item(1).SetIntValue(type, eCSSUnit_Enumerated);
    8869                 : 
    8870               0 :   if (!ExpectSymbol(')', true)) {
    8871               0 :     return false;
    8872                 :   }
    8873                 : 
    8874               0 :   aValue.SetArrayValue(val, eCSSUnit_Steps);
    8875               0 :   return true;
    8876                 : }
    8877                 : 
    8878                 : static nsCSSValueList*
    8879               0 : AppendValueToList(nsCSSValue& aContainer,
    8880                 :                   nsCSSValueList* aTail,
    8881                 :                   const nsCSSValue& aValue)
    8882                 : {
    8883                 :   nsCSSValueList* entry;
    8884               0 :   if (aContainer.GetUnit() == eCSSUnit_Null) {
    8885               0 :     NS_ABORT_IF_FALSE(!aTail, "should not have an entry");
    8886               0 :     entry = aContainer.SetListValue();
    8887                 :   } else {
    8888               0 :     NS_ABORT_IF_FALSE(!aTail->mNext, "should not have a next entry");
    8889               0 :     NS_ABORT_IF_FALSE(aContainer.GetUnit() == eCSSUnit_List, "not a list");
    8890               0 :     entry = new nsCSSValueList;
    8891               0 :     aTail->mNext = entry;
    8892                 :   }
    8893               0 :   entry->mValue = aValue;
    8894               0 :   return entry;
    8895                 : }
    8896                 : 
    8897                 : CSSParserImpl::ParseAnimationOrTransitionShorthandResult
    8898               0 : CSSParserImpl::ParseAnimationOrTransitionShorthand(
    8899                 :                  const nsCSSProperty* aProperties,
    8900                 :                  const nsCSSValue* aInitialValues,
    8901                 :                  nsCSSValue* aValues,
    8902                 :                  size_t aNumProperties)
    8903                 : {
    8904               0 :   nsCSSValue tempValue;
    8905                 :   // first see if 'inherit' or '-moz-initial' is specified.  If one is,
    8906                 :   // it can be the only thing specified, so don't attempt to parse any
    8907                 :   // additional properties
    8908               0 :   if (ParseVariant(tempValue, VARIANT_INHERIT, nsnull)) {
    8909               0 :     for (PRUint32 i = 0; i < aNumProperties; ++i) {
    8910               0 :       AppendValue(aProperties[i], tempValue);
    8911                 :     }
    8912               0 :     return eParseAnimationOrTransitionShorthand_Inherit;
    8913                 :   }
    8914                 : 
    8915                 :   static const size_t maxNumProperties = 7;
    8916               0 :   NS_ABORT_IF_FALSE(aNumProperties <= maxNumProperties,
    8917                 :                     "can't handle this many properties");
    8918                 :   nsCSSValueList *cur[maxNumProperties];
    8919                 :   bool parsedProperty[maxNumProperties];
    8920                 : 
    8921               0 :   for (size_t i = 0; i < aNumProperties; ++i) {
    8922               0 :     cur[i] = nsnull;
    8923                 :   }
    8924               0 :   bool atEOP = false; // at end of property?
    8925               0 :   for (;;) { // loop over comma-separated transitions or animations
    8926                 :     // whether a particular subproperty was specified for this
    8927                 :     // transition or animation
    8928               0 :     for (size_t i = 0; i < aNumProperties; ++i) {
    8929               0 :       parsedProperty[i] = false;
    8930                 :     }
    8931               0 :     for (;;) { // loop over values within a transition or animation
    8932               0 :       bool foundProperty = false;
    8933                 :       // check to see if we're at the end of one full transition or
    8934                 :       // animation definition (either because we hit a comma or because
    8935                 :       // we hit the end of the property definition)
    8936               0 :       if (ExpectSymbol(',', true))
    8937               0 :         break;
    8938               0 :       if (CheckEndProperty()) {
    8939               0 :         atEOP = true;
    8940               0 :         break;
    8941                 :       }
    8942                 : 
    8943                 :       // else, try to parse the next transition or animation sub-property
    8944               0 :       for (PRUint32 i = 0; !foundProperty && i < aNumProperties; ++i) {
    8945               0 :         if (!parsedProperty[i]) {
    8946                 :           // if we haven't found this property yet, try to parse it
    8947               0 :           if (ParseSingleValueProperty(tempValue, aProperties[i])) {
    8948               0 :             parsedProperty[i] = true;
    8949               0 :             cur[i] = AppendValueToList(aValues[i], cur[i], tempValue);
    8950               0 :             foundProperty = true;
    8951               0 :             break; // out of inner loop; continue looking for next sub-property
    8952                 :           }
    8953                 :         }
    8954                 :       }
    8955               0 :       if (!foundProperty) {
    8956                 :         // We're not at a ',' or at the end of the property, but we couldn't
    8957                 :         // parse any of the sub-properties, so the declaration is invalid.
    8958               0 :         return eParseAnimationOrTransitionShorthand_Error;
    8959                 :       }
    8960                 :     }
    8961                 : 
    8962                 :     // We hit the end of the property or the end of one transition
    8963                 :     // or animation definition, add its components to the list.
    8964               0 :     for (PRUint32 i = 0; i < aNumProperties; ++i) {
    8965                 :       // If all of the subproperties were not explicitly specified, fill
    8966                 :       // in the missing ones with initial values.
    8967               0 :       if (!parsedProperty[i]) {
    8968               0 :         cur[i] = AppendValueToList(aValues[i], cur[i], aInitialValues[i]);
    8969                 :       }
    8970                 :     }
    8971                 : 
    8972               0 :     if (atEOP)
    8973                 :       break;
    8974                 :     // else we just hit a ',' so continue parsing the next compound transition
    8975                 :   }
    8976                 : 
    8977               0 :   return eParseAnimationOrTransitionShorthand_Values;
    8978                 : }
    8979                 : 
    8980                 : bool
    8981               0 : CSSParserImpl::ParseTransition()
    8982                 : {
    8983                 :   static const nsCSSProperty kTransitionProperties[] = {
    8984                 :     eCSSProperty_transition_duration,
    8985                 :     eCSSProperty_transition_timing_function,
    8986                 :     // Must check 'transition-delay' after 'transition-duration', since
    8987                 :     // that's our assumption about what the spec means for the shorthand
    8988                 :     // syntax (the first time given is the duration, and the second
    8989                 :     // given is the delay).
    8990                 :     eCSSProperty_transition_delay,
    8991                 :     // Must check 'transition-property' after
    8992                 :     // 'transition-timing-function' since 'transition-property' accepts
    8993                 :     // any keyword.
    8994                 :     eCSSProperty_transition_property
    8995                 :   };
    8996                 :   static const PRUint32 numProps = NS_ARRAY_LENGTH(kTransitionProperties);
    8997                 :   // this is a shorthand property that accepts -property, -delay,
    8998                 :   // -duration, and -timing-function with some components missing.
    8999                 :   // there can be multiple transitions, separated with commas
    9000                 : 
    9001               0 :   nsCSSValue initialValues[numProps];
    9002               0 :   initialValues[0].SetFloatValue(0.0, eCSSUnit_Seconds);
    9003                 :   initialValues[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE,
    9004               0 :                                eCSSUnit_Enumerated);
    9005               0 :   initialValues[2].SetFloatValue(0.0, eCSSUnit_Seconds);
    9006               0 :   initialValues[3].SetAllValue();
    9007                 : 
    9008               0 :   nsCSSValue values[numProps];
    9009                 : 
    9010                 :   ParseAnimationOrTransitionShorthandResult spres =
    9011                 :     ParseAnimationOrTransitionShorthand(kTransitionProperties,
    9012               0 :                                         initialValues, values, numProps);
    9013               0 :   if (spres != eParseAnimationOrTransitionShorthand_Values) {
    9014               0 :     return spres != eParseAnimationOrTransitionShorthand_Error;
    9015                 :   }
    9016                 : 
    9017                 :   // Make two checks on the list for 'transition-property':
    9018                 :   //   + If there is more than one item, then none of the items can be
    9019                 :   //     'none' or 'all'.
    9020                 :   //   + None of the items can be 'inherit' or 'initial' (this is the case,
    9021                 :   //     like with counter-reset &c., where CSS 2.1 specifies 'initial', so
    9022                 :   //     we should check it without the -moz- prefix).
    9023                 :   {
    9024               0 :     NS_ABORT_IF_FALSE(kTransitionProperties[3] ==
    9025                 :                         eCSSProperty_transition_property,
    9026                 :                       "array index mismatch");
    9027               0 :     nsCSSValueList *l = values[3].GetListValue();
    9028               0 :     bool multipleItems = !!l->mNext;
    9029               0 :     do {
    9030               0 :       const nsCSSValue& val = l->mValue;
    9031               0 :       if (val.GetUnit() != eCSSUnit_Ident) {
    9032               0 :         NS_ABORT_IF_FALSE(val.GetUnit() == eCSSUnit_None ||
    9033                 :                           val.GetUnit() == eCSSUnit_All, "unexpected unit");
    9034               0 :         if (multipleItems) {
    9035                 :           // This is a syntax error.
    9036               0 :           return false;
    9037                 :         }
    9038                 : 
    9039                 :         // Unbox a solitary 'none' or 'all'.
    9040               0 :         if (val.GetUnit() == eCSSUnit_None) {
    9041               0 :           values[3].SetNoneValue();
    9042                 :         } else {
    9043               0 :           values[3].SetAllValue();
    9044                 :         }
    9045               0 :         break;
    9046                 :       }
    9047               0 :       nsDependentString str(val.GetStringBufferValue());
    9048               0 :       if (str.EqualsLiteral("inherit") || str.EqualsLiteral("initial")) {
    9049               0 :         return false;
    9050                 :       }
    9051                 :     } while ((l = l->mNext));
    9052                 :   }
    9053                 : 
    9054                 :   // Save all parsed transition sub-properties in mTempData
    9055               0 :   for (PRUint32 i = 0; i < numProps; ++i) {
    9056               0 :     AppendValue(kTransitionProperties[i], values[i]);
    9057                 :   }
    9058               0 :   return true;
    9059                 : }
    9060                 : 
    9061                 : bool
    9062               0 : CSSParserImpl::ParseAnimation()
    9063                 : {
    9064                 :   static const nsCSSProperty kAnimationProperties[] = {
    9065                 :     eCSSProperty_animation_duration,
    9066                 :     eCSSProperty_animation_timing_function,
    9067                 :     // Must check 'animation-delay' after 'animation-duration', since
    9068                 :     // that's our assumption about what the spec means for the shorthand
    9069                 :     // syntax (the first time given is the duration, and the second
    9070                 :     // given is the delay).
    9071                 :     eCSSProperty_animation_delay,
    9072                 :     eCSSProperty_animation_direction,
    9073                 :     eCSSProperty_animation_fill_mode,
    9074                 :     eCSSProperty_animation_iteration_count,
    9075                 :     // Must check 'animation-name' after 'animation-timing-function',
    9076                 :     // 'animation-direction', 'animation-fill-mode',
    9077                 :     // 'animation-iteration-count', and 'animation-play-state' since
    9078                 :     // 'animation-name' accepts any keyword.
    9079                 :     eCSSProperty_animation_name
    9080                 :   };
    9081                 :   static const PRUint32 numProps = NS_ARRAY_LENGTH(kAnimationProperties);
    9082                 :   // this is a shorthand property that accepts -property, -delay,
    9083                 :   // -duration, and -timing-function with some components missing.
    9084                 :   // there can be multiple animations, separated with commas
    9085                 : 
    9086               0 :   nsCSSValue initialValues[numProps];
    9087               0 :   initialValues[0].SetFloatValue(0.0, eCSSUnit_Seconds);
    9088                 :   initialValues[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE,
    9089               0 :                                eCSSUnit_Enumerated);
    9090               0 :   initialValues[2].SetFloatValue(0.0, eCSSUnit_Seconds);
    9091               0 :   initialValues[3].SetIntValue(NS_STYLE_ANIMATION_DIRECTION_NORMAL, eCSSUnit_Enumerated);
    9092               0 :   initialValues[4].SetIntValue(NS_STYLE_ANIMATION_FILL_MODE_NONE, eCSSUnit_Enumerated);
    9093               0 :   initialValues[5].SetFloatValue(1.0f, eCSSUnit_Number);
    9094               0 :   initialValues[6].SetNoneValue();
    9095                 : 
    9096               0 :   nsCSSValue values[numProps];
    9097                 : 
    9098                 :   ParseAnimationOrTransitionShorthandResult spres =
    9099                 :     ParseAnimationOrTransitionShorthand(kAnimationProperties,
    9100               0 :                                         initialValues, values, numProps);
    9101               0 :   if (spres != eParseAnimationOrTransitionShorthand_Values) {
    9102               0 :     return spres != eParseAnimationOrTransitionShorthand_Error;
    9103                 :   }
    9104                 : 
    9105                 :   // Save all parsed animation sub-properties in mTempData
    9106               0 :   for (PRUint32 i = 0; i < numProps; ++i) {
    9107               0 :     AppendValue(kAnimationProperties[i], values[i]);
    9108                 :   }
    9109               0 :   return true;
    9110                 : }
    9111                 : 
    9112                 : bool
    9113               0 : CSSParserImpl::ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow)
    9114                 : {
    9115                 :   // A shadow list item is an array, with entries in this sequence:
    9116                 :   enum {
    9117                 :     IndexX,
    9118                 :     IndexY,
    9119                 :     IndexRadius,
    9120                 :     IndexSpread,  // only for box-shadow
    9121                 :     IndexColor,
    9122                 :     IndexInset    // only for box-shadow
    9123                 :   };
    9124                 : 
    9125               0 :   nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(6);
    9126                 : 
    9127               0 :   if (aIsBoxShadow) {
    9128                 :     // Optional inset keyword (ignore errors)
    9129               0 :     ParseVariant(val->Item(IndexInset), VARIANT_KEYWORD,
    9130               0 :                  nsCSSProps::kBoxShadowTypeKTable);
    9131                 :   }
    9132                 : 
    9133               0 :   nsCSSValue xOrColor;
    9134               0 :   bool haveColor = false;
    9135               0 :   if (!ParseVariant(xOrColor, VARIANT_COLOR | VARIANT_LENGTH | VARIANT_CALC,
    9136               0 :                     nsnull)) {
    9137               0 :     return false;
    9138                 :   }
    9139               0 :   if (xOrColor.IsLengthUnit() || xOrColor.IsCalcUnit()) {
    9140               0 :     val->Item(IndexX) = xOrColor;
    9141                 :   } else {
    9142                 :     // Must be a color (as string or color value)
    9143               0 :     NS_ASSERTION(xOrColor.GetUnit() == eCSSUnit_Ident ||
    9144                 :                  xOrColor.GetUnit() == eCSSUnit_Color ||
    9145                 :                  xOrColor.GetUnit() == eCSSUnit_EnumColor,
    9146                 :                  "Must be a color value");
    9147               0 :     val->Item(IndexColor) = xOrColor;
    9148               0 :     haveColor = true;
    9149                 : 
    9150                 :     // X coordinate mandatory after color
    9151               0 :     if (!ParseVariant(val->Item(IndexX), VARIANT_LENGTH | VARIANT_CALC,
    9152               0 :                       nsnull)) {
    9153               0 :       return false;
    9154                 :     }
    9155                 :   }
    9156                 : 
    9157                 :   // Y coordinate; mandatory
    9158               0 :   if (!ParseVariant(val->Item(IndexY), VARIANT_LENGTH | VARIANT_CALC,
    9159               0 :                     nsnull)) {
    9160               0 :     return false;
    9161                 :   }
    9162                 : 
    9163                 :   // Optional radius. Ignore errors except if they pass a negative
    9164                 :   // value which we must reject. If we use ParseNonNegativeVariant
    9165                 :   // we can't tell the difference between an unspecified radius
    9166                 :   // and a negative radius.
    9167               0 :   if (ParseVariant(val->Item(IndexRadius), VARIANT_LENGTH | VARIANT_CALC,
    9168               0 :                    nsnull) &&
    9169               0 :       val->Item(IndexRadius).IsLengthUnit() &&
    9170               0 :       val->Item(IndexRadius).GetFloatValue() < 0) {
    9171               0 :     return false;
    9172                 :   }
    9173                 : 
    9174               0 :   if (aIsBoxShadow) {
    9175                 :     // Optional spread
    9176               0 :     ParseVariant(val->Item(IndexSpread), VARIANT_LENGTH | VARIANT_CALC, nsnull);
    9177                 :   }
    9178                 : 
    9179               0 :   if (!haveColor) {
    9180                 :     // Optional color
    9181               0 :     ParseVariant(val->Item(IndexColor), VARIANT_COLOR, nsnull);
    9182                 :   }
    9183                 : 
    9184               0 :   if (aIsBoxShadow && val->Item(IndexInset).GetUnit() == eCSSUnit_Null) {
    9185                 :     // Optional inset keyword
    9186               0 :     ParseVariant(val->Item(IndexInset), VARIANT_KEYWORD,
    9187               0 :                  nsCSSProps::kBoxShadowTypeKTable);
    9188                 :   }
    9189                 : 
    9190               0 :   aValue.SetArrayValue(val, eCSSUnit_Array);
    9191               0 :   return true;
    9192                 : }
    9193                 : 
    9194                 : bool
    9195               0 : CSSParserImpl::ParseShadowList(nsCSSProperty aProperty)
    9196                 : {
    9197               0 :   nsAutoParseCompoundProperty compound(this);
    9198               0 :   bool isBoxShadow = aProperty == eCSSProperty_box_shadow;
    9199                 : 
    9200               0 :   nsCSSValue value;
    9201               0 :   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
    9202                 :     // 'inherit', 'initial', and 'none' must be alone
    9203               0 :     if (!ExpectEndProperty()) {
    9204               0 :       return false;
    9205                 :     }
    9206                 :   } else {
    9207               0 :     nsCSSValueList* cur = value.SetListValue();
    9208               0 :     for (;;) {
    9209               0 :       if (!ParseShadowItem(cur->mValue, isBoxShadow)) {
    9210               0 :         return false;
    9211                 :       }
    9212               0 :       if (CheckEndProperty()) {
    9213               0 :         break;
    9214                 :       }
    9215               0 :       if (!ExpectSymbol(',', true)) {
    9216               0 :         return false;
    9217                 :       }
    9218               0 :       cur->mNext = new nsCSSValueList;
    9219               0 :       cur = cur->mNext;
    9220                 :     }
    9221                 :   }
    9222               0 :   AppendValue(aProperty, value);
    9223               0 :   return true;
    9224                 : }
    9225                 : 
    9226                 : PRInt32
    9227               0 : CSSParserImpl::GetNamespaceIdForPrefix(const nsString& aPrefix)
    9228                 : {
    9229               0 :   NS_PRECONDITION(!aPrefix.IsEmpty(), "Must have a prefix here");
    9230                 : 
    9231               0 :   PRInt32 nameSpaceID = kNameSpaceID_Unknown;
    9232               0 :   if (mNameSpaceMap) {
    9233                 :     // user-specified identifiers are case-sensitive (bug 416106)
    9234               0 :     nsCOMPtr<nsIAtom> prefix = do_GetAtom(aPrefix);
    9235               0 :     if (!prefix) {
    9236               0 :       NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
    9237                 :     }
    9238               0 :     nameSpaceID = mNameSpaceMap->FindNameSpaceID(prefix);
    9239                 :   }
    9240                 :   // else no declared namespaces
    9241                 : 
    9242               0 :   if (nameSpaceID == kNameSpaceID_Unknown) {   // unknown prefix, dump it
    9243                 :     const PRUnichar *params[] = {
    9244               0 :       aPrefix.get()
    9245               0 :     };
    9246               0 :     REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params);
    9247               0 :     mFoundUnresolvablePrefix = true;
    9248                 :   }
    9249                 : 
    9250               0 :   return nameSpaceID;
    9251                 : }
    9252                 : 
    9253                 : void
    9254             220 : CSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector& aSelector)
    9255                 : {
    9256             220 :   if (mNameSpaceMap) {
    9257               0 :     aSelector.SetNameSpace(mNameSpaceMap->FindNameSpaceID(nsnull));
    9258                 :   } else {
    9259             220 :     aSelector.SetNameSpace(kNameSpaceID_Unknown); // wildcard
    9260                 :   }
    9261             220 : }
    9262                 : 
    9263                 : bool
    9264               0 : CSSParserImpl::ParsePaint(nsCSSProperty aPropID)
    9265                 : {
    9266               0 :   nsCSSValue x, y;
    9267               0 :   if (!ParseVariant(x, VARIANT_HC | VARIANT_NONE | VARIANT_URL, nsnull))
    9268               0 :     return false;
    9269               0 :   if (x.GetUnit() == eCSSUnit_URL) {
    9270               0 :     if (!ParseVariant(y, VARIANT_COLOR | VARIANT_NONE, nsnull))
    9271               0 :       y.SetColorValue(NS_RGB(0, 0, 0));
    9272                 :   }
    9273               0 :   if (!ExpectEndProperty())
    9274               0 :     return false;
    9275                 : 
    9276               0 :   if (x.GetUnit() != eCSSUnit_URL) {
    9277               0 :     AppendValue(aPropID, x);
    9278                 :   } else {
    9279               0 :     nsCSSValue val;
    9280               0 :     val.SetPairValue(x, y);
    9281               0 :     AppendValue(aPropID, val);
    9282                 :   }
    9283               0 :   return true;
    9284                 : }
    9285                 : 
    9286                 : bool
    9287               0 : CSSParserImpl::ParseDasharray()
    9288                 : {
    9289               0 :   nsCSSValue value;
    9290               0 :   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
    9291                 :     // 'inherit', 'initial', and 'none' are only allowed on their own
    9292               0 :     if (!ExpectEndProperty()) {
    9293               0 :       return false;
    9294                 :     }
    9295                 :   } else {
    9296               0 :     nsCSSValueList *cur = value.SetListValue();
    9297               0 :     for (;;) {
    9298               0 :       if (!ParseNonNegativeVariant(cur->mValue, VARIANT_LPN, nsnull)) {
    9299               0 :         return false;
    9300                 :       }
    9301               0 :       if (CheckEndProperty()) {
    9302               0 :         break;
    9303                 :       }
    9304                 :       // skip optional commas between elements
    9305               0 :       (void)ExpectSymbol(',', true);
    9306                 : 
    9307               0 :       cur->mNext = new nsCSSValueList;
    9308               0 :       cur = cur->mNext;
    9309                 :     }
    9310                 :   }
    9311               0 :   AppendValue(eCSSProperty_stroke_dasharray, value);
    9312               0 :   return true;
    9313                 : }
    9314                 : 
    9315                 : bool
    9316               0 : CSSParserImpl::ParseMarker()
    9317                 : {
    9318               0 :   nsCSSValue marker;
    9319               0 :   if (ParseSingleValueProperty(marker, eCSSProperty_marker_end)) {
    9320               0 :     if (ExpectEndProperty()) {
    9321               0 :       AppendValue(eCSSProperty_marker_end, marker);
    9322               0 :       AppendValue(eCSSProperty_marker_mid, marker);
    9323               0 :       AppendValue(eCSSProperty_marker_start, marker);
    9324               0 :       return true;
    9325                 :     }
    9326                 :   }
    9327               0 :   return false;
    9328                 : }
    9329                 : 
    9330                 : } // anonymous namespace
    9331                 : 
    9332                 : // Recycling of parser implementation objects
    9333                 : 
    9334                 : static CSSParserImpl* gFreeList = nsnull;
    9335                 : 
    9336             110 : nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
    9337                 :                          nsCSSStyleSheet* aSheet)
    9338                 : {
    9339             110 :   CSSParserImpl *impl = gFreeList;
    9340             110 :   if (impl) {
    9341              98 :     gFreeList = impl->mNextFree;
    9342              98 :     impl->mNextFree = nsnull;
    9343                 :   } else {
    9344              12 :     impl = new CSSParserImpl();
    9345                 :   }
    9346                 : 
    9347             110 :   if (aLoader) {
    9348             110 :     impl->SetChildLoader(aLoader);
    9349             110 :     impl->SetQuirkMode(aLoader->GetCompatibilityMode() ==
    9350             110 :                        eCompatibility_NavQuirks);
    9351                 :   }
    9352             110 :   if (aSheet) {
    9353               0 :     impl->SetStyleSheet(aSheet);
    9354                 :   }
    9355                 : 
    9356             110 :   mImpl = static_cast<void*>(impl);
    9357             110 : }
    9358                 : 
    9359             110 : nsCSSParser::~nsCSSParser()
    9360                 : {
    9361             110 :   CSSParserImpl *impl = static_cast<CSSParserImpl*>(mImpl);
    9362             110 :   impl->Reset();
    9363             110 :   impl->mNextFree = gFreeList;
    9364             110 :   gFreeList = impl;
    9365             110 : }
    9366                 : 
    9367                 : /* static */ void
    9368            1364 : nsCSSParser::Shutdown()
    9369                 : {
    9370            1364 :   CSSParserImpl *tofree = gFreeList;
    9371                 :   CSSParserImpl *next;
    9372            2740 :   while (tofree)
    9373                 :     {
    9374              12 :       next = tofree->mNextFree;
    9375              12 :       delete tofree;
    9376              12 :       tofree = next;
    9377                 :     }
    9378            1364 : }
    9379                 : 
    9380                 : // Wrapper methods
    9381                 : 
    9382                 : nsresult
    9383               0 : nsCSSParser::SetStyleSheet(nsCSSStyleSheet* aSheet)
    9384                 : {
    9385                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9386               0 :     SetStyleSheet(aSheet);
    9387                 : }
    9388                 : 
    9389                 : nsresult
    9390               0 : nsCSSParser::SetQuirkMode(bool aQuirkMode)
    9391                 : {
    9392                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9393               0 :     SetQuirkMode(aQuirkMode);
    9394                 : }
    9395                 : 
    9396                 : nsresult
    9397               0 : nsCSSParser::SetSVGMode(bool aSVGMode)
    9398                 : {
    9399                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9400               0 :     SetSVGMode(aSVGMode);
    9401                 : }
    9402                 : 
    9403                 : nsresult
    9404               0 : nsCSSParser::SetChildLoader(mozilla::css::Loader* aChildLoader)
    9405                 : {
    9406                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9407               0 :     SetChildLoader(aChildLoader);
    9408                 : }
    9409                 : 
    9410                 : nsresult
    9411               0 : nsCSSParser::ParseSheet(const nsAString& aInput,
    9412                 :                         nsIURI*          aSheetURI,
    9413                 :                         nsIURI*          aBaseURI,
    9414                 :                         nsIPrincipal*    aSheetPrincipal,
    9415                 :                         PRUint32         aLineNumber,
    9416                 :                         bool             aAllowUnsafeRules)
    9417                 : {
    9418                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9419                 :     ParseSheet(aInput, aSheetURI, aBaseURI, aSheetPrincipal, aLineNumber,
    9420               0 :                aAllowUnsafeRules);
    9421                 : }
    9422                 : 
    9423                 : nsresult
    9424               0 : nsCSSParser::ParseStyleAttribute(const nsAString&  aAttributeValue,
    9425                 :                                  nsIURI*           aDocURI,
    9426                 :                                  nsIURI*           aBaseURI,
    9427                 :                                  nsIPrincipal*     aNodePrincipal,
    9428                 :                                  css::StyleRule**  aResult)
    9429                 : {
    9430                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9431                 :     ParseStyleAttribute(aAttributeValue, aDocURI, aBaseURI,
    9432               0 :                         aNodePrincipal, aResult);
    9433                 : }
    9434                 : 
    9435                 : nsresult
    9436               0 : nsCSSParser::ParseDeclarations(const nsAString&  aBuffer,
    9437                 :                                nsIURI*           aSheetURI,
    9438                 :                                nsIURI*           aBaseURI,
    9439                 :                                nsIPrincipal*     aSheetPrincipal,
    9440                 :                                css::Declaration* aDeclaration,
    9441                 :                                bool*           aChanged)
    9442                 : {
    9443                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9444                 :     ParseDeclarations(aBuffer, aSheetURI, aBaseURI, aSheetPrincipal,
    9445               0 :                       aDeclaration, aChanged);
    9446                 : }
    9447                 : 
    9448                 : nsresult
    9449               0 : nsCSSParser::ParseRule(const nsAString&        aRule,
    9450                 :                        nsIURI*                 aSheetURI,
    9451                 :                        nsIURI*                 aBaseURI,
    9452                 :                        nsIPrincipal*           aSheetPrincipal,
    9453                 :                        nsCOMArray<css::Rule>&  aResult)
    9454                 : {
    9455                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9456               0 :     ParseRule(aRule, aSheetURI, aBaseURI, aSheetPrincipal, aResult);
    9457                 : }
    9458                 : 
    9459                 : nsresult
    9460               0 : nsCSSParser::ParseProperty(const nsCSSProperty aPropID,
    9461                 :                            const nsAString&    aPropValue,
    9462                 :                            nsIURI*             aSheetURI,
    9463                 :                            nsIURI*             aBaseURI,
    9464                 :                            nsIPrincipal*       aSheetPrincipal,
    9465                 :                            css::Declaration*   aDeclaration,
    9466                 :                            bool*             aChanged,
    9467                 :                            bool                aIsImportant)
    9468                 : {
    9469                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9470                 :     ParseProperty(aPropID, aPropValue, aSheetURI, aBaseURI,
    9471               0 :                   aSheetPrincipal, aDeclaration, aChanged, aIsImportant);
    9472                 : }
    9473                 : 
    9474                 : nsresult
    9475               0 : nsCSSParser::ParseMediaList(const nsSubstring& aBuffer,
    9476                 :                             nsIURI*            aURI,
    9477                 :                             PRUint32           aLineNumber,
    9478                 :                             nsMediaList*       aMediaList,
    9479                 :                             bool               aHTMLMode)
    9480                 : {
    9481                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9482               0 :     ParseMediaList(aBuffer, aURI, aLineNumber, aMediaList, aHTMLMode);
    9483                 : }
    9484                 : 
    9485                 : nsresult
    9486               0 : nsCSSParser::ParseColorString(const nsSubstring& aBuffer,
    9487                 :                               nsIURI*            aURI,
    9488                 :                               PRUint32           aLineNumber,
    9489                 :                               nscolor*           aColor)
    9490                 : {
    9491                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9492               0 :     ParseColorString(aBuffer, aURI, aLineNumber, aColor);
    9493                 : }
    9494                 : 
    9495                 : nsresult
    9496             110 : nsCSSParser::ParseSelectorString(const nsSubstring&  aSelectorString,
    9497                 :                                  nsIURI*             aURI,
    9498                 :                                  PRUint32            aLineNumber,
    9499                 :                                  nsCSSSelectorList** aSelectorList)
    9500                 : {
    9501                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9502             110 :     ParseSelectorString(aSelectorString, aURI, aLineNumber, aSelectorList);
    9503                 : }
    9504                 : 
    9505                 : already_AddRefed<nsCSSKeyframeRule>
    9506               0 : nsCSSParser::ParseKeyframeRule(const nsSubstring& aBuffer,
    9507                 :                                nsIURI*            aURI,
    9508                 :                                PRUint32           aLineNumber)
    9509                 : {
    9510                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9511               0 :     ParseKeyframeRule(aBuffer, aURI, aLineNumber);
    9512                 : }
    9513                 : 
    9514                 : bool
    9515               0 : nsCSSParser::ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
    9516                 :                                          nsIURI*            aURI,
    9517                 :                                          PRUint32           aLineNumber,
    9518                 :                                          InfallibleTArray<float>& aSelectorList)
    9519                 : {
    9520                 :   return static_cast<CSSParserImpl*>(mImpl)->
    9521                 :     ParseKeyframeSelectorString(aSelectorString, aURI, aLineNumber,
    9522               0 :                                 aSelectorList);
    9523                 : }

Generated by: LCOV version 1.7