LCOV - code coverage report
Current view: directory - layout/style - nsCSSParser.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 4094 171 4.2 %
Date: 2012-06-02 Functions: 199 23 11.6 %

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

Generated by: LCOV version 1.7