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
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/
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
15 * The Original Code is mozilla.org code.
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.
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>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
44 /* parsing of CSS stylesheets, based on a token stream from the CSS scanner */
46 #include "nsICSSParser.h"
47 #include "nsCSSProps.h"
48 #include "nsCSSKeywords.h"
49 #include "nsCSSScanner.h"
50 #include "nsICSSLoader.h"
51 #include "nsICSSStyleRule.h"
52 #include "nsICSSImportRule.h"
53 #include "nsCSSRules.h"
54 #include "nsICSSNameSpaceRule.h"
55 #include "nsIUnicharInputStream.h"
56 #include "nsICSSStyleSheet.h"
57 #include "nsCSSDeclaration.h"
58 #include "nsStyleConsts.h"
60 #include "nsNetUtil.h"
63 #include "nsReadableUtils.h"
64 #include "nsUnicharUtils.h"
66 #include "nsVoidArray.h"
67 #include "nsCOMArray.h"
69 #include "nsStyleConsts.h"
70 #include "nsCSSPseudoClasses.h"
71 #include "nsCSSPseudoElements.h"
72 #include "nsCSSAnonBoxes.h"
73 #include "nsINameSpaceManager.h"
74 #include "nsXMLNameSpaceMap.h"
75 #include "nsThemeConstants.h"
76 #include "nsContentErrors.h"
77 #include "nsPrintfCString.h"
78 #include "nsIMediaList.h"
79 #include "nsILookAndFeel.h"
80 #include "nsStyleUtil.h"
81 #include "nsIPrincipal.h"
84 #include "nsContentUtils.h"
85 #include "nsDOMError.h"
86 #include "nsAutoPtr.h"
89 // Flags for ParseVariant method
90 #define VARIANT_KEYWORD 0x000001 // K
91 #define VARIANT_LENGTH 0x000002 // L
92 #define VARIANT_PERCENT 0x000004 // P
93 #define VARIANT_COLOR 0x000008 // C eCSSUnit_Color, eCSSUnit_String (e.g. "red")
94 #define VARIANT_URL 0x000010 // U
95 #define VARIANT_NUMBER 0x000020 // N
96 #define VARIANT_INTEGER 0x000040 // I
97 #define VARIANT_ANGLE 0x000080 // G
98 #define VARIANT_FREQUENCY 0x000100 // F
99 #define VARIANT_TIME 0x000200 // T
100 #define VARIANT_STRING 0x000400 // S
101 #define VARIANT_COUNTER 0x000800 //
102 #define VARIANT_ATTR 0x001000 //
103 #define VARIANT_IDENTIFIER 0x002000 // D
104 #define VARIANT_AUTO 0x010000 // A
105 #define VARIANT_INHERIT 0x020000 // H eCSSUnit_Initial, eCSSUnit_Inherit
106 #define VARIANT_NONE 0x040000 // O
107 #define VARIANT_NORMAL 0x080000 // M
108 #define VARIANT_SYSFONT 0x100000 // eCSSUnit_System_Font
110 // Common combinations of variants
111 #define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
112 #define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)
113 #define VARIANT_AH (VARIANT_AUTO | VARIANT_INHERIT)
114 #define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
115 #define VARIANT_AHI (VARIANT_AH | VARIANT_INTEGER)
116 #define VARIANT_AHK (VARIANT_AH | VARIANT_KEYWORD)
117 #define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)
118 #define VARIANT_AUK (VARIANT_AUTO | VARIANT_URL | VARIANT_KEYWORD)
119 #define VARIANT_AHUK (VARIANT_AH | VARIANT_URL | VARIANT_KEYWORD)
120 #define VARIANT_AHL (VARIANT_AH | VARIANT_LENGTH)
121 #define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
122 #define VARIANT_HK (VARIANT_INHERIT | VARIANT_KEYWORD)
123 #define VARIANT_HKF (VARIANT_HK | VARIANT_FREQUENCY)
124 #define VARIANT_HKL (VARIANT_HK | VARIANT_LENGTH)
125 #define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
126 #define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)
127 #define VARIANT_HL (VARIANT_INHERIT | VARIANT_LENGTH)
128 #define VARIANT_HI (VARIANT_INHERIT | VARIANT_INTEGER)
129 #define VARIANT_HLP (VARIANT_HL | VARIANT_PERCENT)
130 #define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
131 #define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
132 #define VARIANT_HTP (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
133 #define VARIANT_HMK (VARIANT_HK | VARIANT_NORMAL)
134 #define VARIANT_HMKI (VARIANT_HMK | VARIANT_INTEGER)
135 #define VARIANT_HC (VARIANT_INHERIT | VARIANT_COLOR)
136 #define VARIANT_HCK (VARIANT_HK | VARIANT_COLOR)
137 #define VARIANT_HUO (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
138 #define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
139 #define VARIANT_HPN (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
140 #define VARIANT_HOK (VARIANT_HK | VARIANT_NONE)
141 #define VARIANT_HN (VARIANT_INHERIT | VARIANT_NUMBER)
142 #define VARIANT_HON (VARIANT_HN | VARIANT_NONE)
143 #define VARIANT_HOS (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
145 //----------------------------------------------------------------------
147 // Your basic top-down recursive descent style parser
148 class CSSParserImpl
: public nsICSSParser
{
151 virtual ~CSSParserImpl();
155 NS_IMETHOD
SetStyleSheet(nsICSSStyleSheet
* aSheet
);
157 NS_IMETHOD
SetCaseSensitive(PRBool aCaseSensitive
);
159 NS_IMETHOD
SetQuirkMode(PRBool aQuirkMode
);
162 NS_IMETHOD
SetSVGMode(PRBool aSVGMode
);
165 NS_IMETHOD
SetChildLoader(nsICSSLoader
* aChildLoader
);
167 NS_IMETHOD
Parse(nsIUnicharInputStream
* aInput
,
170 nsIPrincipal
* aSheetPrincipal
,
171 PRUint32 aLineNumber
,
172 PRBool aAllowUnsafeRules
);
174 NS_IMETHOD
ParseStyleAttribute(const nsAString
& aAttributeValue
,
177 nsIPrincipal
* aNodePrincipal
,
178 nsICSSStyleRule
** aResult
);
180 NS_IMETHOD
ParseAndAppendDeclaration(const nsAString
& aBuffer
,
183 nsIPrincipal
* aSheetPrincipal
,
184 nsCSSDeclaration
* aDeclaration
,
185 PRBool aParseOnlyOneDecl
,
187 PRBool aClearOldDecl
);
189 NS_IMETHOD
ParseRule(const nsAString
& aRule
,
192 nsIPrincipal
* aSheetPrincipal
,
193 nsCOMArray
<nsICSSRule
>& aResult
);
195 NS_IMETHOD
ParseProperty(const nsCSSProperty aPropID
,
196 const nsAString
& aPropValue
,
199 nsIPrincipal
* aSheetPrincipal
,
200 nsCSSDeclaration
* aDeclaration
,
203 NS_IMETHOD
ParseMediaList(const nsSubstring
& aBuffer
,
204 nsIURI
* aURL
, // for error reporting
205 PRUint32 aLineNumber
, // for error reporting
206 nsMediaList
* aMediaList
,
209 NS_IMETHOD
ParseColorString(const nsSubstring
& aBuffer
,
210 nsIURI
* aURL
, // for error reporting
211 PRUint32 aLineNumber
, // for error reporting
214 NS_IMETHOD
ParseSelectorString(const nsSubstring
& aSelectorString
,
215 nsIURI
* aURL
, // for error reporting
216 PRUint32 aLineNumber
, // for error reporting
217 nsCSSSelectorList
**aSelectorList
);
219 void AppendRule(nsICSSRule
* aRule
);
222 class nsAutoParseCompoundProperty
;
223 friend class nsAutoParseCompoundProperty
;
226 * This helper class automatically calls SetParsingCompoundProperty in its
227 * constructor and takes care of resetting it to false in its destructor.
229 class nsAutoParseCompoundProperty
{
231 nsAutoParseCompoundProperty(CSSParserImpl
* aParser
) : mParser(aParser
)
233 NS_ASSERTION(!aParser
->IsParsingCompoundProperty(),
234 "already parsing compound property");
235 NS_ASSERTION(aParser
, "Null parser?");
236 aParser
->SetParsingCompoundProperty(PR_TRUE
);
239 ~nsAutoParseCompoundProperty()
241 mParser
->SetParsingCompoundProperty(PR_FALSE
);
244 CSSParserImpl
* mParser
;
247 void InitScanner(nsIUnicharInputStream
* aInput
, nsIURI
* aSheetURI
,
248 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
249 nsIPrincipal
* aSheetPrincipal
);
250 // the caller must hold on to aBuffer until parsing is done
251 void InitScanner(const nsSubstring
& aString
, nsIURI
* aSheetURI
,
252 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
253 nsIPrincipal
* aSheetPrincipal
);
254 void ReleaseScanner(void);
256 PRBool
IsSVGMode() const {
257 return mScanner
.IsSVGMode();
261 PRBool
GetToken(PRBool aSkipWS
);
262 PRBool
GetURLToken();
265 void AssertInitialState() {
266 NS_PRECONDITION(!mHTMLMediaMode
, "Bad initial state");
267 NS_PRECONDITION(!mUnresolvablePrefixException
, "Bad initial state");
268 NS_PRECONDITION(!mParsingCompoundProperty
, "Bad initial state");
271 PRBool
ExpectSymbol(PRUnichar aSymbol
, PRBool aSkipWS
);
272 PRBool
ExpectEndProperty();
273 PRBool
CheckEndProperty();
274 nsSubstring
* NextIdent();
275 void SkipUntil(PRUnichar aStopSymbol
);
276 void SkipUntilOneOf(const PRUnichar
* aStopSymbolChars
);
279 PRBool
SkipDeclaration(PRBool aCheckForBraces
);
280 PRBool
GetNonCloseParenToken(PRBool aSkipWS
);
282 PRBool
PushGroup(nsICSSGroupRule
* aRule
);
285 PRBool
ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aProcessData
);
286 PRBool
ParseAtRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
287 PRBool
ParseCharsetRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
288 PRBool
ParseImportRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
289 PRBool
GatherURL(nsString
& aURL
);
290 PRBool
GatherMedia(nsMediaList
* aMedia
,
291 PRUnichar aStopSymbol
);
292 PRBool
ParseMediaQuery(PRUnichar aStopSymbol
, nsMediaQuery
**aQuery
,
293 PRBool
*aParsedSomething
, PRBool
*aHitStop
);
294 PRBool
ParseMediaQueryExpression(nsMediaQuery
* aQuery
);
295 PRBool
ProcessImport(const nsString
& aURLSpec
,
297 RuleAppendFunc aAppendFunc
,
299 PRBool
ParseGroupRule(nsICSSGroupRule
* aRule
, RuleAppendFunc aAppendFunc
,
301 PRBool
ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
302 PRBool
ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
303 PRBool
ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
304 PRBool
ProcessNameSpace(const nsString
& aPrefix
,
305 const nsString
& aURLSpec
, RuleAppendFunc aAppendFunc
,
308 PRBool
ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
309 PRBool
ParseFontDescriptor(nsCSSFontFaceRule
* aRule
);
310 PRBool
ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
313 PRBool
ParsePageRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
315 enum nsSelectorParsingStatus
{
316 // we have parsed a selector and we saw a token that cannot be
317 // part of a selector:
318 eSelectorParsingStatus_Done
,
319 // we should continue parsing the selector:
320 eSelectorParsingStatus_Continue
,
321 // same as "Done" but we did not find a selector:
322 eSelectorParsingStatus_Empty
,
323 // we saw an unexpected token or token value,
324 // or we saw end-of-file with an unfinished selector:
325 eSelectorParsingStatus_Error
327 nsSelectorParsingStatus
ParseIDSelector(PRInt32
& aDataMask
,
328 nsCSSSelector
& aSelector
);
330 nsSelectorParsingStatus
ParseClassSelector(PRInt32
& aDataMask
,
331 nsCSSSelector
& aSelector
);
333 nsSelectorParsingStatus
ParsePseudoSelector(PRInt32
& aDataMask
,
334 nsCSSSelector
& aSelector
,
337 nsSelectorParsingStatus
ParseAttributeSelector(PRInt32
& aDataMask
,
338 nsCSSSelector
& aSelector
);
340 nsSelectorParsingStatus
ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
341 nsCSSSelector
& aSelector
,
344 nsSelectorParsingStatus
ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
347 nsSelectorParsingStatus
ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
350 nsSelectorParsingStatus
ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
351 nsCSSSelector
& aSelector
);
353 nsSelectorParsingStatus
ParseSelector(nsCSSSelector
& aSelectorResult
);
355 // If aTerminateAtBrace is true, the selector list is done when we
356 // hit a '{'. Otherwise, it's done when we hit EOF.
357 PRBool
ParseSelectorList(nsCSSSelectorList
*& aListHead
,
358 PRBool aTerminateAtBrace
);
359 PRBool
ParseSelectorGroup(nsCSSSelectorList
*& aListHead
);
360 nsCSSDeclaration
* ParseDeclarationBlock(PRBool aCheckForBraces
);
361 PRBool
ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
362 PRBool aCheckForBraces
,
363 PRBool aMustCallValueAppended
,
365 // After a parse error parsing |aPropID|, clear the data in
367 void ClearTempData(nsCSSProperty aPropID
);
368 // After a successful parse of |aPropID|, transfer data from
369 // |mTempData| to |mData|. Set |*aChanged| to true if something
370 // changed, but leave it unmodified otherwise. If aMustCallValueAppended
371 // is false, will not call ValueAppended on aDeclaration if the property
372 // is already set in it.
373 void TransferTempData(nsCSSDeclaration
* aDeclaration
,
374 nsCSSProperty aPropID
, PRBool aIsImportant
,
375 PRBool aMustCallValueAppended
,
377 void DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
378 nsCSSProperty aPropID
, PRBool aIsImportant
,
379 PRBool aMustCallValueAppended
,
381 PRBool
ParseProperty(nsCSSProperty aPropID
);
382 PRBool
ParseSingleValueProperty(nsCSSValue
& aValue
,
383 nsCSSProperty aPropID
);
386 PRBool
ParseTreePseudoElement(nsCSSSelector
& aSelector
);
389 void InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
);
391 // Property specific parsing routines
392 PRBool
ParseAzimuth(nsCSSValue
& aValue
);
393 PRBool
ParseBackground();
394 PRBool
ParseBackgroundPosition();
395 PRBool
ParseBackgroundPositionValues();
396 PRBool
ParseBoxPosition(nsCSSValuePair
& aOut
);
397 PRBool
ParseBoxPositionValues(nsCSSValuePair
& aOut
);
398 PRBool
ParseBorderColor();
399 PRBool
ParseBorderColors(nsCSSValueList
** aResult
,
400 nsCSSProperty aProperty
);
401 PRBool
ParseBorderImage();
402 PRBool
ParseBorderSpacing();
403 PRBool
ParseBorderSide(const nsCSSProperty aPropIDs
[],
404 PRBool aSetAllSides
);
405 PRBool
ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
406 PRInt32 aSourceType
);
407 PRBool
ParseBorderStyle();
408 PRBool
ParseBorderWidth();
409 // for 'clip' and '-moz-image-region'
410 PRBool
ParseRect(nsCSSRect
& aRect
,
411 nsCSSProperty aPropID
);
412 PRBool
DoParseRect(nsCSSRect
& aRect
);
413 PRBool
ParseContent();
414 PRBool
ParseCounterData(nsCSSValuePairList
** aResult
,
415 nsCSSProperty aPropID
);
417 PRBool
ParseCursor();
419 PRBool
ParseFontWeight(nsCSSValue
& aValue
);
420 PRBool
ParseOneFamily(nsAString
& aValue
);
421 PRBool
ParseFamily(nsCSSValue
& aValue
);
422 PRBool
ParseFontSrc(nsCSSValue
& aValue
);
423 PRBool
ParseFontSrcFormat(nsTArray
<nsCSSValue
>& values
);
424 PRBool
ParseFontRanges(nsCSSValue
& aValue
);
425 PRBool
ParseListStyle();
426 PRBool
ParseMargin();
427 PRBool
ParseMarks(nsCSSValue
& aValue
);
428 PRBool
ParseMozTransform();
429 PRBool
ParseOutline();
430 PRBool
ParseOverflow();
431 PRBool
ParsePadding();
433 PRBool
ParseQuotes();
435 PRBool
ParseTextDecoration(nsCSSValue
& aValue
);
437 nsCSSValueList
* ParseCSSShadowList(PRBool aUsesSpread
);
438 PRBool
ParseTextShadow();
439 PRBool
ParseBoxShadow();
442 PRBool
ParsePaint(nsCSSValuePair
* aResult
,
443 nsCSSProperty aPropID
);
444 PRBool
ParseDasharray();
445 PRBool
ParseMarker();
448 // Reused utility parsing routines
449 void AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
);
450 PRBool
ParseBoxProperties(nsCSSRect
& aResult
,
451 const nsCSSProperty aPropIDs
[]);
452 PRBool
ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
453 PRInt32 aSourceType
);
454 PRBool
ParseBoxCornerRadius(const nsCSSProperty aPropID
);
455 PRBool
ParseBoxCornerRadii(nsCSSCornerSizes
& aRadii
,
456 const nsCSSProperty aPropIDs
[]);
457 PRInt32
ParseChoice(nsCSSValue aValues
[],
458 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
);
459 PRBool
ParseColor(nsCSSValue
& aValue
);
460 PRBool
ParseColorComponent(PRUint8
& aComponent
,
461 PRInt32
& aType
, char aStop
);
462 // ParseHSLColor parses everything starting with the opening '('
463 // up through and including the aStop char.
464 PRBool
ParseHSLColor(nscolor
& aColor
, char aStop
);
465 // ParseColorOpacity will enforce that the color ends with a ')'
467 PRBool
ParseColorOpacity(PRUint8
& aOpacity
);
468 PRBool
ParseEnum(nsCSSValue
& aValue
, const PRInt32 aKeywordTable
[]);
469 PRBool
ParseVariant(nsCSSValue
& aValue
,
470 PRInt32 aVariantMask
,
471 const PRInt32 aKeywordTable
[]);
472 PRBool
ParsePositiveVariant(nsCSSValue
& aValue
,
473 PRInt32 aVariantMask
,
474 const PRInt32 aKeywordTable
[]);
475 PRBool
ParseCounter(nsCSSValue
& aValue
);
476 PRBool
ParseAttr(nsCSSValue
& aValue
);
477 PRBool
ParseURL(nsCSSValue
& aValue
);
478 PRBool
TranslateDimension(nsCSSValue
& aValue
, PRInt32 aVariantMask
,
479 float aNumber
, const nsString
& aUnit
);
481 void SetParsingCompoundProperty(PRBool aBool
) {
482 NS_ASSERTION(aBool
== PR_TRUE
|| aBool
== PR_FALSE
, "bad PRBool value");
483 mParsingCompoundProperty
= aBool
;
485 PRBool
IsParsingCompoundProperty(void) const {
486 return mParsingCompoundProperty
;
489 /* Functions for -moz-transform Parsing */
490 PRBool
ReadSingleTransform(nsCSSValueList
**& aTail
);
491 PRBool
ParseFunction(const nsString
&aFunction
, const PRInt32 aAllowedTypes
[],
492 PRUint16 aMinElems
, PRUint16 aMaxElems
,
494 PRBool
ParseFunctionInternals(const PRInt32 aVariantMask
[],
497 nsTArray
<nsCSSValue
>& aOutput
);
499 /* Functions for -moz-transform-origin Parsing */
500 PRBool
ParseMozTransformOrigin();
503 /* Find and return the correct namespace ID for the prefix aPrefix.
504 If the prefix cannot be resolved to a namespace, this method will
505 return false. Otherwise it will return true. When returning
506 false, it may set the low-level error code, depending on the
507 value of mUnresolvablePrefixException.
509 This method never returns kNameSpaceID_Unknown or
510 kNameSpaceID_None for aNameSpaceID while returning true.
512 PRBool
GetNamespaceIdForPrefix(const nsString
& aPrefix
,
513 PRInt32
* aNameSpaceID
);
515 /* Find the correct default namespace, and set it on aSelector. */
516 void SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
);
518 // Current token. The value is valid after calling GetToken and invalidated
523 nsCSSScanner mScanner
;
525 // The URI to be used as a base for relative URIs.
526 nsCOMPtr
<nsIURI
> mBaseURL
;
528 // The URI to be used as an HTTP "Referer" and for error reporting.
529 nsCOMPtr
<nsIURI
> mSheetURL
;
531 // The principal of the sheet involved
532 nsCOMPtr
<nsIPrincipal
> mSheetPrincipal
;
534 // The sheet we're parsing into
535 nsCOMPtr
<nsICSSStyleSheet
> mSheet
;
537 // Used for @import rules
538 nsICSSLoader
* mChildLoader
; // not ref counted, it owns us
540 // Sheet section we're in. This is used to enforce correct ordering of the
541 // various rule types (eg the fact that a @charset rule must come before
542 // anything else). Note that there are checks of similar things in various
543 // places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
547 eCSSSection_NameSpace
,
550 nsCSSSection mSection
;
552 nsXMLNameSpaceMap
*mNameSpaceMap
; // weak, mSheet owns it
554 // After an UngetToken is done this flag is true. The next call to
555 // GetToken clears the flag.
556 PRPackedBool mHavePushBack
: 1;
558 // True if we are in quirks mode; false in standards or almost standards mode
559 PRPackedBool mNavQuirkMode
: 1;
561 // True if unsafe rules should be allowed
562 PRPackedBool mUnsafeRulesEnabled
: 1;
564 // True for parsing media lists for HTML attributes, where we have to
565 // ignore CSS comments.
566 PRPackedBool mHTMLMediaMode
: 1;
568 // True if tagnames and attributes are case-sensitive
569 PRPackedBool mCaseSensitive
: 1;
571 // This flag is set when parsing a non-box shorthand; it's used to not apply
572 // some quirks during shorthand parsing
573 PRPackedBool mParsingCompoundProperty
: 1;
575 // If this flag is true, failure to resolve a namespace prefix
576 // should set the low-level error to NS_ERROR_DOM_NAMESPACE_ERR
577 PRPackedBool mUnresolvablePrefixException
: 1;
579 // Stack of rule groups; used for @media and such.
580 nsCOMArray
<nsICSSGroupRule
> mGroupStack
;
582 // During the parsing of a property (which may be a shorthand), the data
583 // are stored in |mTempData|. (It is needed to ensure that parser
584 // errors cause the data to be ignored, and to ensure that a
585 // non-'!important' declaration does not override an '!important'
587 nsCSSExpandedDataBlock mTempData
;
589 // All data from successfully parsed properties are placed into |mData|.
590 nsCSSExpandedDataBlock mData
;
593 PRPackedBool mScannerInited
;
597 static void AppendRuleToArray(nsICSSRule
* aRule
, void* aArray
)
599 static_cast<nsCOMArray
<nsICSSRule
>*>(aArray
)->AppendObject(aRule
);
602 static void AppendRuleToSheet(nsICSSRule
* aRule
, void* aParser
)
604 CSSParserImpl
* parser
= (CSSParserImpl
*) aParser
;
605 parser
->AppendRule(aRule
);
609 NS_NewCSSParser(nsICSSParser
** aInstancePtrResult
)
611 CSSParserImpl
*it
= new CSSParserImpl();
614 return NS_ERROR_OUT_OF_MEMORY
;
617 return it
->QueryInterface(NS_GET_IID(nsICSSParser
), (void **) aInstancePtrResult
);
620 #ifdef CSS_REPORT_PARSE_ERRORS
622 #define REPORT_UNEXPECTED(msg_) \
623 mScanner.ReportUnexpected(#msg_)
625 #define REPORT_UNEXPECTED_P(msg_, params_) \
626 mScanner.ReportUnexpectedParams(#msg_, params_, NS_ARRAY_LENGTH(params_))
628 #define REPORT_UNEXPECTED_EOF(lf_) \
629 mScanner.ReportUnexpectedEOF(#lf_)
631 #define REPORT_UNEXPECTED_EOF_CHAR(ch_) \
632 mScanner.ReportUnexpectedEOF(ch_)
634 #define REPORT_UNEXPECTED_TOKEN(msg_) \
635 mScanner.ReportUnexpectedToken(mToken, #msg_)
637 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_) \
638 mScanner.ReportUnexpectedTokenParams(mToken, #msg_, \
639 params_, NS_ARRAY_LENGTH(params_))
642 #define OUTPUT_ERROR() \
643 mScanner.OutputError()
645 #define CLEAR_ERROR() \
646 mScanner.ClearError()
650 #define REPORT_UNEXPECTED(msg_)
651 #define REPORT_UNEXPECTED_P(msg_, params_)
652 #define REPORT_UNEXPECTED_EOF(lf_)
653 #define REPORT_UNEXPECTED_EOF_CHAR(ch_)
654 #define REPORT_UNEXPECTED_TOKEN(msg_)
655 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_)
656 #define OUTPUT_ERROR()
657 #define CLEAR_ERROR()
661 CSSParserImpl::CSSParserImpl()
664 mChildLoader(nsnull
),
665 mSection(eCSSSection_Charset
),
666 mNameSpaceMap(nsnull
),
667 mHavePushBack(PR_FALSE
),
668 mNavQuirkMode(PR_FALSE
),
669 mUnsafeRulesEnabled(PR_FALSE
),
670 mHTMLMediaMode(PR_FALSE
),
671 mCaseSensitive(PR_FALSE
),
672 mParsingCompoundProperty(PR_FALSE
),
673 mUnresolvablePrefixException(PR_FALSE
)
675 , mScannerInited(PR_FALSE
)
680 NS_IMPL_ISUPPORTS1(CSSParserImpl
, nsICSSParser
)
682 CSSParserImpl::~CSSParserImpl()
684 mData
.AssertInitialState();
685 mTempData
.AssertInitialState();
689 CSSParserImpl::SetStyleSheet(nsICSSStyleSheet
* aSheet
)
691 if (aSheet
!= mSheet
) {
692 // Switch to using the new sheet, if any
696 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
698 mNameSpaceMap
= nsnull
;
706 CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive
)
708 NS_ASSERTION(aCaseSensitive
== PR_TRUE
|| aCaseSensitive
== PR_FALSE
, "bad PRBool value");
709 mCaseSensitive
= aCaseSensitive
;
714 CSSParserImpl::SetQuirkMode(PRBool aQuirkMode
)
716 NS_ASSERTION(aQuirkMode
== PR_TRUE
|| aQuirkMode
== PR_FALSE
, "bad PRBool value");
717 mNavQuirkMode
= aQuirkMode
;
723 CSSParserImpl::SetSVGMode(PRBool aSVGMode
)
725 NS_ASSERTION(aSVGMode
== PR_TRUE
|| aSVGMode
== PR_FALSE
,
727 mScanner
.SetSVGMode(aSVGMode
);
733 CSSParserImpl::SetChildLoader(nsICSSLoader
* aChildLoader
)
735 mChildLoader
= aChildLoader
; // not ref counted, it owns us
740 CSSParserImpl::InitScanner(nsIUnicharInputStream
* aInput
, nsIURI
* aSheetURI
,
741 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
742 nsIPrincipal
* aSheetPrincipal
)
744 NS_ASSERTION(! mScannerInited
, "already have scanner");
746 mScanner
.Init(aInput
, nsnull
, 0, aSheetURI
, aLineNumber
);
748 mScannerInited
= PR_TRUE
;
751 mSheetURL
= aSheetURI
;
752 mSheetPrincipal
= aSheetPrincipal
;
754 mHavePushBack
= PR_FALSE
;
758 CSSParserImpl::InitScanner(const nsSubstring
& aString
, nsIURI
* aSheetURI
,
759 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
760 nsIPrincipal
* aSheetPrincipal
)
762 // Having it not own the string is OK since the caller will hold on to
763 // the stream until we're done parsing.
764 NS_ASSERTION(! mScannerInited
, "already have scanner");
766 mScanner
.Init(nsnull
, aString
.BeginReading(), aString
.Length(), aSheetURI
, aLineNumber
);
769 mScannerInited
= PR_TRUE
;
772 mSheetURL
= aSheetURI
;
773 mSheetPrincipal
= aSheetPrincipal
;
775 mHavePushBack
= PR_FALSE
;
779 CSSParserImpl::ReleaseScanner(void)
783 mScannerInited
= PR_FALSE
;
787 mSheetPrincipal
= nsnull
;
792 CSSParserImpl::Parse(nsIUnicharInputStream
* aInput
,
795 nsIPrincipal
* aSheetPrincipal
,
796 PRUint32 aLineNumber
,
797 PRBool aAllowUnsafeRules
)
799 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
801 NS_ASSERTION(nsnull
!= aBaseURI
, "need base URL");
802 NS_ASSERTION(nsnull
!= aSheetURI
, "need sheet URL");
803 AssertInitialState();
805 NS_PRECONDITION(mSheet
, "Must have sheet to parse into");
806 NS_ENSURE_STATE(mSheet
);
809 nsCOMPtr
<nsIURI
> uri
;
810 mSheet
->GetSheetURI(getter_AddRefs(uri
));
812 NS_ASSERTION(NS_SUCCEEDED(aSheetURI
->Equals(uri
, &equal
)) && equal
,
813 "Sheet URI does not match passed URI");
814 NS_ASSERTION(NS_SUCCEEDED(mSheet
->Principal()->Equals(aSheetPrincipal
,
817 "Sheet principal does not match passed principal");
820 InitScanner(aInput
, aSheetURI
, aLineNumber
, aBaseURI
, aSheetPrincipal
);
822 PRInt32 ruleCount
= 0;
823 mSheet
->StyleRuleCount(ruleCount
);
825 nsICSSRule
* lastRule
= nsnull
;
826 mSheet
->GetStyleRuleAt(ruleCount
- 1, lastRule
);
829 lastRule
->GetType(type
);
831 case nsICSSRule::CHARSET_RULE
:
832 case nsICSSRule::IMPORT_RULE
:
833 mSection
= eCSSSection_Import
;
835 case nsICSSRule::NAMESPACE_RULE
:
836 mSection
= eCSSSection_NameSpace
;
839 mSection
= eCSSSection_General
;
842 NS_RELEASE(lastRule
);
846 mSection
= eCSSSection_Charset
; // sheet is empty, any rules are fair
849 mUnsafeRulesEnabled
= aAllowUnsafeRules
;
851 nsCSSToken
* tk
= &mToken
;
853 // Get next non-whitespace token
854 if (!GetToken(PR_TRUE
)) {
858 if (eCSSToken_HTMLComment
== tk
->mType
) {
859 continue; // legal here only
861 if (eCSSToken_AtKeyword
== tk
->mType
) {
862 ParseAtRule(AppendRuleToSheet
, this);
866 if (ParseRuleSet(AppendRuleToSheet
, this)) {
867 mSection
= eCSSSection_General
;
872 mUnsafeRulesEnabled
= PR_FALSE
;
874 // XXX check for low level errors
879 * Determines whether the identifier contained in the given string is a
880 * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1.
883 NonMozillaVendorIdentifier(const nsAString
& ident
)
885 return (ident
.First() == PRUnichar('-') &&
886 !StringBeginsWith(ident
, NS_LITERAL_STRING("-moz-"))) ||
887 ident
.First() == PRUnichar('_');
892 CSSParserImpl::ParseStyleAttribute(const nsAString
& aAttributeValue
,
895 nsIPrincipal
* aNodePrincipal
,
896 nsICSSStyleRule
** aResult
)
898 NS_PRECONDITION(aNodePrincipal
, "Must have principal here!");
899 AssertInitialState();
901 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
904 InitScanner(aAttributeValue
, aDocURL
, 0, aBaseURL
, aNodePrincipal
);
906 mSection
= eCSSSection_General
;
908 // In quirks mode, allow style declarations to have braces or not
911 if (mNavQuirkMode
&& GetToken(PR_TRUE
)) {
912 haveBraces
= eCSSToken_Symbol
== mToken
.mType
&&
913 '{' == mToken
.mSymbol
;
917 haveBraces
= PR_FALSE
;
920 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(haveBraces
);
922 // Create a style rule for the declaration
923 nsICSSStyleRule
* rule
= nsnull
;
924 nsresult rv
= NS_NewCSSStyleRule(&rule
, nsnull
, declaration
);
926 declaration
->RuleAbort();
938 // XXX check for low level errors
943 CSSParserImpl::ParseAndAppendDeclaration(const nsAString
& aBuffer
,
946 nsIPrincipal
* aSheetPrincipal
,
947 nsCSSDeclaration
* aDeclaration
,
948 PRBool aParseOnlyOneDecl
,
950 PRBool aClearOldDecl
)
952 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
953 AssertInitialState();
955 *aChanged
= PR_FALSE
;
957 InitScanner(aBuffer
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
959 mSection
= eCSSSection_General
;
962 mData
.AssertInitialState();
963 aDeclaration
->ClearData();
964 // We could check if it was already empty, but...
967 aDeclaration
->ExpandTo(&mData
);
972 // If we cleared the old decl, then we want to be calling
973 // ValueAppended as we parse.
974 if (!ParseDeclaration(aDeclaration
, PR_FALSE
, aClearOldDecl
, aChanged
)) {
975 rv
= mScanner
.GetLowLevelError();
979 if (!SkipDeclaration(PR_FALSE
)) {
980 rv
= mScanner
.GetLowLevelError();
984 } while (!aParseOnlyOneDecl
);
985 aDeclaration
->CompressFrom(&mData
);
992 CSSParserImpl::ParseRule(const nsAString
& aRule
,
995 nsIPrincipal
* aSheetPrincipal
,
996 nsCOMArray
<nsICSSRule
>& aResult
)
998 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
999 AssertInitialState();
1001 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1003 InitScanner(aRule
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1005 mSection
= eCSSSection_Charset
; // callers are responsible for rejecting invalid rules.
1007 nsCSSToken
* tk
= &mToken
;
1008 // Get first non-whitespace token
1009 if (!GetToken(PR_TRUE
)) {
1010 REPORT_UNEXPECTED(PEParseRuleWSOnly
);
1012 } else if (eCSSToken_AtKeyword
== tk
->mType
) {
1013 ParseAtRule(AppendRuleToArray
, &aResult
);
1017 ParseRuleSet(AppendRuleToArray
, &aResult
);
1021 // XXX check for low-level errors
1026 CSSParserImpl::ParseProperty(const nsCSSProperty aPropID
,
1027 const nsAString
& aPropValue
,
1030 nsIPrincipal
* aSheetPrincipal
,
1031 nsCSSDeclaration
* aDeclaration
,
1034 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1035 AssertInitialState();
1037 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1038 NS_ASSERTION(nsnull
!= aDeclaration
, "Need declaration to parse into!");
1039 *aChanged
= PR_FALSE
;
1041 InitScanner(aPropValue
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1043 mSection
= eCSSSection_General
;
1045 if (eCSSProperty_UNKNOWN
== aPropID
) { // unknown property
1046 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1047 const PRUnichar
*params
[] = {
1050 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
1051 REPORT_UNEXPECTED(PEDeclDropped
);
1057 mData
.AssertInitialState();
1058 mTempData
.AssertInitialState();
1059 aDeclaration
->ExpandTo(&mData
);
1060 nsresult result
= NS_OK
;
1061 PRBool parsedOK
= ParseProperty(aPropID
);
1062 if (parsedOK
&& !GetToken(PR_TRUE
)) {
1063 TransferTempData(aDeclaration
, aPropID
, PR_FALSE
, PR_FALSE
, aChanged
);
1066 // Junk at end of property value.
1067 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
1069 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1070 const PRUnichar
*params
[] = {
1073 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
1074 REPORT_UNEXPECTED(PEDeclDropped
);
1076 ClearTempData(aPropID
);
1077 result
= mScanner
.GetLowLevelError();
1081 aDeclaration
->CompressFrom(&mData
);
1088 CSSParserImpl::ParseMediaList(const nsSubstring
& aBuffer
,
1089 nsIURI
* aURL
, // for error reporting
1090 PRUint32 aLineNumber
, // for error reporting
1091 nsMediaList
* aMediaList
,
1094 // XXX Are there cases where the caller wants to keep what it already
1095 // has in case of parser error?
1096 aMediaList
->Clear();
1098 // fake base URL since media lists don't have URLs in them
1099 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1101 AssertInitialState();
1102 NS_ASSERTION(aHTMLMode
== PR_TRUE
|| aHTMLMode
== PR_FALSE
,
1104 mHTMLMediaMode
= aHTMLMode
;
1106 // XXXldb We need to make the scanner not skip CSS comments! (Or
1109 // For aHTMLMode, we used to follow the parsing rules in
1110 // http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors
1111 // which wouldn't work for media queries since they remove all but the
1112 // first word. However, they're changed in
1113 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2
1114 // (as of 2008-05-29) which says that the media attribute just points
1115 // to a media query. (The main substative difference is the relative
1116 // precedence of commas and paretheses.)
1118 if (!GatherMedia(aMediaList
, PRUnichar(0))) {
1119 aMediaList
->Clear();
1120 aMediaList
->SetNonEmpty(); // don't match anything
1121 if (!mHTMLMediaMode
) {
1125 nsresult rv
= mScanner
.GetLowLevelError();
1128 mHTMLMediaMode
= PR_FALSE
;
1134 CSSParserImpl::ParseColorString(const nsSubstring
& aBuffer
,
1135 nsIURI
* aURL
, // for error reporting
1136 PRUint32 aLineNumber
, // for error reporting
1139 AssertInitialState();
1140 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1143 PRBool colorParsed
= ParseColor(value
);
1144 nsresult rv
= mScanner
.GetLowLevelError();
1149 return NS_FAILED(rv
) ? rv
: NS_ERROR_FAILURE
;
1152 if (value
.GetUnit() == eCSSUnit_String
) {
1154 if (NS_ColorNameToRGB(nsDependentString(value
.GetStringBufferValue()), &rgba
)) {
1158 } else if (value
.GetUnit() == eCSSUnit_Color
) {
1159 (*aColor
) = value
.GetColorValue();
1161 } else if (value
.GetUnit() == eCSSUnit_EnumColor
) {
1162 PRInt32 intValue
= value
.GetIntValue();
1163 if (intValue
>= 0) {
1164 nsCOMPtr
<nsILookAndFeel
> lfSvc
= do_GetService("@mozilla.org/widget/lookandfeel;1");
1167 rv
= lfSvc
->GetColor((nsILookAndFeel::nsColorID
) value
.GetIntValue(), rgba
);
1168 if (NS_SUCCEEDED(rv
))
1172 // XXX - this is NS_COLOR_CURRENTCOLOR, NS_COLOR_MOZ_HYPERLINKTEXT, etc.
1173 // which we don't handle as per the ParseColorString definition. Should
1174 // remove this limitation at some point.
1175 rv
= NS_ERROR_FAILURE
;
1183 CSSParserImpl::ParseSelectorString(const nsSubstring
& aSelectorString
,
1184 nsIURI
* aURL
, // for error reporting
1185 PRUint32 aLineNumber
, // for error reporting
1186 nsCSSSelectorList
**aSelectorList
)
1188 InitScanner(aSelectorString
, aURL
, aLineNumber
, aURL
, nsnull
);
1190 AssertInitialState();
1192 mUnresolvablePrefixException
= PR_TRUE
;
1194 PRBool success
= ParseSelectorList(*aSelectorList
, PR_FALSE
);
1195 nsresult rv
= mScanner
.GetLowLevelError();
1199 mUnresolvablePrefixException
= PR_FALSE
;
1202 NS_ASSERTION(*aSelectorList
, "Should have list!");
1206 NS_ASSERTION(!*aSelectorList
, "Shouldn't have list!");
1207 if (NS_SUCCEEDED(rv
)) {
1208 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
1213 //----------------------------------------------------------------------
1216 CSSParserImpl::GetToken(PRBool aSkipWS
)
1219 if (!mHavePushBack
) {
1220 if (!mScanner
.Next(mToken
)) {
1224 mHavePushBack
= PR_FALSE
;
1225 if (aSkipWS
&& (eCSSToken_WhiteSpace
== mToken
.mType
)) {
1234 CSSParserImpl::GetURLToken()
1237 // XXXldb This pushback code doesn't make sense.
1238 if (! mHavePushBack
) {
1239 if (! mScanner
.NextURL(mToken
)) {
1243 mHavePushBack
= PR_FALSE
;
1244 if (eCSSToken_WhiteSpace
!= mToken
.mType
) {
1252 CSSParserImpl::UngetToken()
1254 NS_PRECONDITION(mHavePushBack
== PR_FALSE
, "double pushback");
1255 mHavePushBack
= PR_TRUE
;
1259 CSSParserImpl::ExpectSymbol(PRUnichar aSymbol
,
1262 if (!GetToken(aSkipWS
)) {
1263 // CSS2.1 specifies that all "open constructs" are to be closed at
1264 // EOF. It simplifies higher layers if we claim to have found an
1265 // ), ], }, or ; if we encounter EOF while looking for one of them.
1266 // Do still issue a diagnostic, to aid debugging.
1267 if (aSymbol
== ')' || aSymbol
== ']' ||
1268 aSymbol
== '}' || aSymbol
== ';') {
1269 REPORT_UNEXPECTED_EOF_CHAR(aSymbol
);
1275 if (mToken
.IsSymbol(aSymbol
)) {
1282 // Checks to see if we're at the end of a property. If an error occurs during
1283 // the check, does not signal a parse error.
1285 CSSParserImpl::CheckEndProperty()
1287 if (!GetToken(PR_TRUE
)) {
1288 return PR_TRUE
; // properties may end with eof
1290 if ((eCSSToken_Symbol
== mToken
.mType
) &&
1291 ((';' == mToken
.mSymbol
) ||
1292 ('!' == mToken
.mSymbol
) ||
1293 ('}' == mToken
.mSymbol
))) {
1294 // XXX need to verify that ! is only followed by "important [;|}]
1295 // XXX this requires a multi-token pushback buffer
1303 // Checks if we're at the end of a property, raising an error if we're not.
1305 CSSParserImpl::ExpectEndProperty()
1307 if (CheckEndProperty())
1310 // If we're here, we read something incorrect, so we should report it.
1311 REPORT_UNEXPECTED_TOKEN(PRExpectEndValue
);
1317 CSSParserImpl::NextIdent()
1319 // XXX Error reporting?
1320 if (!GetToken(PR_TRUE
)) {
1323 if (eCSSToken_Ident
!= mToken
.mType
) {
1327 return &mToken
.mIdent
;
1331 CSSParserImpl::SkipAtRule()
1334 if (!GetToken(PR_TRUE
)) {
1335 REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF
);
1338 if (eCSSToken_Symbol
== mToken
.mType
) {
1339 PRUnichar symbol
= mToken
.mSymbol
;
1340 if (symbol
== ';') {
1343 if (symbol
== '{') {
1346 } else if (symbol
== '(') {
1348 } else if (symbol
== '[') {
1357 CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc
,
1360 if ((mSection
<= eCSSSection_Charset
) &&
1361 (mToken
.mIdent
.LowerCaseEqualsLiteral("charset"))) {
1362 if (ParseCharsetRule(aAppendFunc
, aData
)) {
1363 mSection
= eCSSSection_Import
; // only one charset allowed
1367 if ((mSection
<= eCSSSection_Import
) &&
1368 mToken
.mIdent
.LowerCaseEqualsLiteral("import")) {
1369 if (ParseImportRule(aAppendFunc
, aData
)) {
1370 mSection
= eCSSSection_Import
;
1374 if ((mSection
<= eCSSSection_NameSpace
) &&
1375 mToken
.mIdent
.LowerCaseEqualsLiteral("namespace")) {
1376 if (ParseNameSpaceRule(aAppendFunc
, aData
)) {
1377 mSection
= eCSSSection_NameSpace
;
1381 if (mToken
.mIdent
.LowerCaseEqualsLiteral("media")) {
1382 if (ParseMediaRule(aAppendFunc
, aData
)) {
1383 mSection
= eCSSSection_General
;
1387 if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-document")) {
1388 if (ParseMozDocumentRule(aAppendFunc
, aData
)) {
1389 mSection
= eCSSSection_General
;
1393 if (mToken
.mIdent
.LowerCaseEqualsLiteral("font-face")) {
1394 if (ParseFontFaceRule(aAppendFunc
, aData
)) {
1395 mSection
= eCSSSection_General
;
1399 if (mToken
.mIdent
.LowerCaseEqualsLiteral("page")) {
1400 if (ParsePageRule(aAppendFunc
, aData
)) {
1401 mSection
= eCSSSection_General
;
1406 if (!NonMozillaVendorIdentifier(mToken
.mIdent
)) {
1407 REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule
);
1411 // Skip over unsupported at rule, don't advance section
1412 return SkipAtRule();
1416 CSSParserImpl::ParseCharsetRule(RuleAppendFunc aAppendFunc
,
1419 if (!GetToken(PR_TRUE
)) {
1420 REPORT_UNEXPECTED_EOF(PECharsetRuleEOF
);
1424 if (eCSSToken_String
!= mToken
.mType
) {
1425 REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString
);
1429 nsAutoString charset
= mToken
.mIdent
;
1431 if (!ExpectSymbol(';', PR_TRUE
)) {
1435 nsCOMPtr
<nsICSSRule
> rule
;
1436 NS_NewCSSCharsetRule(getter_AddRefs(rule
), charset
);
1439 (*aAppendFunc
)(rule
, aData
);
1446 CSSParserImpl::GatherURL(nsString
& aURL
)
1448 if (!GetToken(PR_TRUE
)) {
1451 if (eCSSToken_String
== mToken
.mType
) {
1452 aURL
= mToken
.mIdent
;
1455 else if (eCSSToken_Function
== mToken
.mType
&&
1456 mToken
.mIdent
.LowerCaseEqualsLiteral("url") &&
1457 ExpectSymbol('(', PR_FALSE
) &&
1459 (eCSSToken_String
== mToken
.mType
||
1460 eCSSToken_URL
== mToken
.mType
)) {
1461 aURL
= mToken
.mIdent
;
1462 if (ExpectSymbol(')', PR_TRUE
)) {
1470 CSSParserImpl::ParseMediaQuery(PRUnichar aStopSymbol
,
1471 nsMediaQuery
**aQuery
,
1472 PRBool
*aParsedSomething
,
1476 *aParsedSomething
= PR_FALSE
;
1477 *aHitStop
= PR_FALSE
;
1479 // "If the comma-separated list is the empty list it is assumed to
1480 // specify the media query 'all'." (css3-mediaqueries, section
1482 if (!GetToken(PR_TRUE
)) {
1483 *aHitStop
= PR_TRUE
;
1484 // expected termination by EOF
1485 if (aStopSymbol
== PRUnichar(0))
1488 // unexpected termination by EOF
1489 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1493 if (eCSSToken_Symbol
== mToken
.mType
&&
1494 mToken
.mSymbol
== aStopSymbol
) {
1495 *aHitStop
= PR_TRUE
;
1501 *aParsedSomething
= PR_TRUE
;
1503 nsAutoPtr
<nsMediaQuery
> query(new nsMediaQuery
);
1505 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1509 if (ExpectSymbol('(', PR_TRUE
)) {
1510 // we got an expression without a media type
1511 UngetToken(); // so ParseMediaQueryExpression can handle it
1512 query
->SetType(nsGkAtoms::all
);
1513 query
->SetTypeOmitted();
1514 // Just parse the first expression here.
1515 if (!ParseMediaQueryExpression(query
)) {
1517 query
->SetHadUnknownExpression();
1520 nsCOMPtr
<nsIAtom
> mediaType
;
1521 PRBool gotNotOrOnly
= PR_FALSE
;
1523 if (!GetToken(PR_TRUE
)) {
1524 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1527 if (eCSSToken_Ident
!= mToken
.mType
) {
1528 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent
);
1532 // case insensitive from CSS - must be lower cased
1533 ToLowerCase(mToken
.mIdent
);
1534 mediaType
= do_GetAtom(mToken
.mIdent
);
1536 (mediaType
!= nsGkAtoms::_not
&& mediaType
!= nsGkAtoms::only
))
1538 gotNotOrOnly
= PR_TRUE
;
1539 if (mediaType
== nsGkAtoms::_not
)
1540 query
->SetNegated();
1542 query
->SetHasOnly();
1544 query
->SetType(mediaType
);
1548 if (!GetToken(PR_TRUE
)) {
1549 *aHitStop
= PR_TRUE
;
1550 // expected termination by EOF
1551 if (aStopSymbol
== PRUnichar(0))
1554 // unexpected termination by EOF
1555 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1559 if (eCSSToken_Symbol
== mToken
.mType
&&
1560 mToken
.mSymbol
== aStopSymbol
) {
1561 *aHitStop
= PR_TRUE
;
1565 if (eCSSToken_Symbol
== mToken
.mType
&& mToken
.mSymbol
== ',') {
1566 // Done with the expressions for this query
1569 if (eCSSToken_Ident
!= mToken
.mType
||
1570 !mToken
.mIdent
.LowerCaseEqualsLiteral("and")) {
1571 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma
);
1575 if (!ParseMediaQueryExpression(query
)) {
1577 query
->SetHadUnknownExpression();
1580 *aQuery
= query
.forget();
1584 // Returns false only when there is a low-level error in the scanner
1587 CSSParserImpl::GatherMedia(nsMediaList
* aMedia
,
1588 PRUnichar aStopSymbol
)
1591 nsAutoPtr
<nsMediaQuery
> query
;
1592 PRBool parsedSomething
, hitStop
;
1593 if (!ParseMediaQuery(aStopSymbol
, getter_Transfers(query
),
1594 &parsedSomething
, &hitStop
)) {
1595 NS_ASSERTION(!hitStop
, "should return true when hit stop");
1596 if (NS_FAILED(mScanner
.GetLowLevelError())) {
1599 const PRUnichar stopChars
[] =
1600 { PRUnichar(','), aStopSymbol
/* may be null */, PRUnichar(0) };
1601 SkipUntilOneOf(stopChars
);
1602 // Rely on SkipUntilOneOf leaving mToken around as the last token read.
1603 if (mToken
.mType
== eCSSToken_Symbol
&& mToken
.mSymbol
== aStopSymbol
) {
1608 if (parsedSomething
) {
1609 aMedia
->SetNonEmpty();
1612 nsresult rv
= aMedia
->AppendQuery(query
);
1613 if (NS_FAILED(rv
)) {
1614 mScanner
.SetLowLevelError(rv
);
1626 CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery
* aQuery
)
1628 if (!ExpectSymbol('(', PR_TRUE
)) {
1629 REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart
);
1632 if (! GetToken(PR_TRUE
)) {
1633 REPORT_UNEXPECTED_EOF(PEMQExpressionEOF
);
1636 if (eCSSToken_Ident
!= mToken
.mType
) {
1637 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1642 nsMediaExpression
*expr
= aQuery
->NewExpression();
1644 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1649 // case insensitive from CSS - must be lower cased
1650 ToLowerCase(mToken
.mIdent
);
1651 const PRUnichar
*featureString
;
1652 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("min-"))) {
1653 expr
->mRange
= nsMediaExpression::eMin
;
1654 featureString
= mToken
.mIdent
.get() + 4;
1655 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("max-"))) {
1656 expr
->mRange
= nsMediaExpression::eMax
;
1657 featureString
= mToken
.mIdent
.get() + 4;
1659 expr
->mRange
= nsMediaExpression::eEqual
;
1660 featureString
= mToken
.mIdent
.get();
1663 nsCOMPtr
<nsIAtom
> mediaFeatureAtom
= do_GetAtom(featureString
);
1664 const nsMediaFeature
*feature
= nsMediaFeatures::features
;
1665 for (; feature
->mName
; ++feature
) {
1666 if (*(feature
->mName
) == mediaFeatureAtom
) {
1670 if (!feature
->mName
||
1671 (expr
->mRange
!= nsMediaExpression::eEqual
&&
1672 feature
->mRangeType
!= nsMediaFeature::eMinMaxAllowed
)) {
1673 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1677 expr
->mFeature
= feature
;
1679 if (!GetToken(PR_TRUE
) || mToken
.IsSymbol(')')) {
1680 // Query expressions for any feature can be given without a value.
1681 // However, min/max prefixes are not allowed.
1682 if (expr
->mRange
!= nsMediaExpression::eEqual
) {
1683 REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue
);
1686 expr
->mValue
.Reset();
1690 if (!mToken
.IsSymbol(':')) {
1691 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd
);
1697 switch (feature
->mValueType
) {
1698 case nsMediaFeature::eLength
:
1699 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_LENGTH
, nsnull
);
1701 case nsMediaFeature::eInteger
:
1702 case nsMediaFeature::eBoolInteger
:
1703 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_INTEGER
, nsnull
);
1704 // Enforce extra restrictions for eBoolInteger
1706 feature
->mValueType
== nsMediaFeature::eBoolInteger
&&
1707 expr
->mValue
.GetIntValue() > 1)
1710 case nsMediaFeature::eIntRatio
:
1712 // Two integers separated by '/', with optional whitespace on
1713 // either side of the '/'.
1714 nsRefPtr
<nsCSSValue::Array
> a
= nsCSSValue::Array::Create(2);
1716 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1720 expr
->mValue
.SetArrayValue(a
, eCSSUnit_Array
);
1721 // We don't bother with ParsePositiveVariant since we have to
1722 // check for != 0 as well; no need to worry about the UngetToken
1723 // since we're throwing out up to the next ')' anyway.
1724 rv
= ParseVariant(a
->Item(0), VARIANT_INTEGER
, nsnull
) &&
1725 a
->Item(0).GetIntValue() > 0 &&
1726 ExpectSymbol('/', PR_TRUE
) &&
1727 ParseVariant(a
->Item(1), VARIANT_INTEGER
, nsnull
) &&
1728 a
->Item(1).GetIntValue() > 0;
1731 case nsMediaFeature::eResolution
:
1732 rv
= GetToken(PR_TRUE
) && mToken
.IsDimension() &&
1733 mToken
.mIntegerValid
&& mToken
.mNumber
> 0.0f
;
1735 // No worries about whether unitless zero is allowed, since the
1736 // value must be positive (and we checked that above).
1737 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(), "IsDimension lied");
1738 if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpi")) {
1739 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Inch
);
1740 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpcm")) {
1741 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Centimeter
);
1747 case nsMediaFeature::eEnumerated
:
1748 rv
= ParseVariant(expr
->mValue
, VARIANT_KEYWORD
,
1749 feature
->mKeywordTable
);
1752 if (!rv
|| !ExpectSymbol(')', PR_TRUE
)) {
1753 REPORT_UNEXPECTED(PEMQExpectedFeatureValue
);
1761 // Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"
1763 CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc
, void* aData
)
1765 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1767 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1772 if (!GatherURL(url
)) {
1773 REPORT_UNEXPECTED_TOKEN(PEImportNotURI
);
1777 if (!ExpectSymbol(';', PR_TRUE
)) {
1778 if (!GatherMedia(media
, ';') ||
1779 !ExpectSymbol(';', PR_TRUE
)) {
1780 REPORT_UNEXPECTED_TOKEN(PEImportUnexpected
);
1781 // don't advance section, simply ignore invalid @import
1785 // Safe to assert this, since we ensured that there is something
1786 // other than the ';' coming after the @import's url() token.
1787 NS_ASSERTION(media
->Count() != 0, "media list must be nonempty");
1790 ProcessImport(url
, media
, aAppendFunc
, aData
);
1796 CSSParserImpl::ProcessImport(const nsString
& aURLSpec
,
1797 nsMediaList
* aMedia
,
1798 RuleAppendFunc aAppendFunc
,
1801 nsCOMPtr
<nsICSSImportRule
> rule
;
1802 nsresult rv
= NS_NewCSSImportRule(getter_AddRefs(rule
), aURLSpec
, aMedia
);
1803 if (NS_FAILED(rv
)) {
1804 mScanner
.SetLowLevelError(rv
);
1807 (*aAppendFunc
)(rule
, aData
);
1810 nsCOMPtr
<nsIURI
> url
;
1811 // XXX should pass a charset!
1812 rv
= NS_NewURI(getter_AddRefs(url
), aURLSpec
, nsnull
, mBaseURL
);
1814 if (NS_FAILED(rv
)) {
1815 // import url is bad
1816 // XXX log this somewhere for easier web page debugging
1817 mScanner
.SetLowLevelError(rv
);
1821 mChildLoader
->LoadChildSheet(mSheet
, url
, aMedia
, rule
);
1827 // Parse the {} part of an @media or @-moz-document rule.
1829 CSSParserImpl::ParseGroupRule(nsICSSGroupRule
* aRule
,
1830 RuleAppendFunc aAppendFunc
,
1833 // XXXbz this could use better error reporting throughout the method
1834 if (!ExpectSymbol('{', PR_TRUE
)) {
1838 // push rule on stack, loop over children
1839 if (!PushGroup(aRule
)) {
1840 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1843 nsCSSSection holdSection
= mSection
;
1844 mSection
= eCSSSection_General
;
1847 // Get next non-whitespace token
1848 if (! GetToken(PR_TRUE
)) {
1849 REPORT_UNEXPECTED_EOF(PEGroupRuleEOF
);
1852 if (mToken
.IsSymbol('}')) { // done!
1856 if (eCSSToken_AtKeyword
== mToken
.mType
) {
1857 SkipAtRule(); // group rules cannot contain @rules
1861 ParseRuleSet(AppendRuleToSheet
, this);
1865 if (!ExpectSymbol('}', PR_TRUE
)) {
1866 mSection
= holdSection
;
1869 (*aAppendFunc
)(aRule
, aData
);
1873 // Parse a CSS2 media rule: "@media medium [, medium] { ... }"
1875 CSSParserImpl::ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aData
)
1877 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1879 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1883 if (GatherMedia(media
, '{')) {
1884 // XXXbz this could use better error reporting throughout the method
1885 nsRefPtr
<nsCSSMediaRule
> rule(new nsCSSMediaRule());
1886 // Append first, so when we do SetMedia() the rule
1887 // knows what its stylesheet is.
1888 if (rule
&& ParseGroupRule(rule
, aAppendFunc
, aData
)) {
1889 rule
->SetMedia(media
);
1897 // Parse a @-moz-document rule. This is like an @media rule, but instead
1898 // of a medium it has a nonempty list of items where each item is either
1899 // url(), url-prefix(), or domain().
1901 CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aData
)
1903 nsCSSDocumentRule::URL
*urls
= nsnull
;
1904 nsCSSDocumentRule::URL
**next
= &urls
;
1906 if (!GetToken(PR_TRUE
) ||
1907 eCSSToken_Function
!= mToken
.mType
||
1908 !(mToken
.mIdent
.LowerCaseEqualsLiteral("url") ||
1909 mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix") ||
1910 mToken
.mIdent
.LowerCaseEqualsLiteral("domain"))) {
1911 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc
);
1915 nsCSSDocumentRule::URL
*cur
= *next
= new nsCSSDocumentRule::URL
;
1917 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1922 if (mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
1923 cur
->func
= nsCSSDocumentRule::eURL
;
1924 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix")) {
1925 cur
->func
= nsCSSDocumentRule::eURLPrefix
;
1926 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("domain")) {
1927 cur
->func
= nsCSSDocumentRule::eDomain
;
1930 if (!ExpectSymbol('(', PR_FALSE
) ||
1932 (eCSSToken_String
!= mToken
.mType
&&
1933 eCSSToken_URL
!= mToken
.mType
)) {
1934 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI
);
1938 if (!ExpectSymbol(')', PR_TRUE
)) {
1943 // We could try to make the URL (as long as it's not domain())
1944 // canonical and absolute with NS_NewURI and GetSpec, but I'm
1945 // inclined to think we shouldn't.
1946 CopyUTF16toUTF8(mToken
.mIdent
, cur
->url
);
1947 } while (ExpectSymbol(',', PR_TRUE
));
1949 nsRefPtr
<nsCSSDocumentRule
> rule(new nsCSSDocumentRule());
1951 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1955 rule
->SetURLs(urls
);
1957 return ParseGroupRule(rule
, aAppendFunc
, aData
);
1960 // Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"
1962 CSSParserImpl::ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
1964 if (!GetToken(PR_TRUE
)) {
1965 REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF
);
1969 nsAutoString prefix
;
1972 if (eCSSToken_Ident
== mToken
.mType
) {
1973 prefix
= mToken
.mIdent
;
1974 // user-specified identifiers are case-sensitive (bug 416106)
1975 if (! GetToken(PR_TRUE
)) {
1976 REPORT_UNEXPECTED_EOF(PEAtNSURIEOF
);
1981 if (eCSSToken_String
== mToken
.mType
) {
1982 url
= mToken
.mIdent
;
1983 if (ExpectSymbol(';', PR_TRUE
)) {
1984 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
1988 else if ((eCSSToken_Function
== mToken
.mType
) &&
1989 (mToken
.mIdent
.LowerCaseEqualsLiteral("url"))) {
1990 if (ExpectSymbol('(', PR_FALSE
)) {
1991 if (GetURLToken()) {
1992 if ((eCSSToken_String
== mToken
.mType
) || (eCSSToken_URL
== mToken
.mType
)) {
1993 url
= mToken
.mIdent
;
1994 if (ExpectSymbol(')', PR_TRUE
)) {
1995 if (ExpectSymbol(';', PR_TRUE
)) {
1996 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
2004 REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected
);
2010 CSSParserImpl::ProcessNameSpace(const nsString
& aPrefix
,
2011 const nsString
& aURLSpec
,
2012 RuleAppendFunc aAppendFunc
,
2015 PRBool result
= PR_FALSE
;
2017 nsCOMPtr
<nsICSSNameSpaceRule
> rule
;
2018 nsCOMPtr
<nsIAtom
> prefix
;
2020 if (!aPrefix
.IsEmpty()) {
2021 prefix
= do_GetAtom(aPrefix
);
2024 NS_NewCSSNameSpaceRule(getter_AddRefs(rule
), prefix
, aURLSpec
);
2026 (*aAppendFunc
)(rule
, aData
);
2028 // If this was the first namespace rule encountered, it will trigger
2029 // creation of a namespace map.
2030 if (!mNameSpaceMap
) {
2031 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
2038 // font-face-rule: '@font-face' '{' font-description '}'
2039 // font-description: font-descriptor+
2041 CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
2043 if (!ExpectSymbol('{', PR_TRUE
))
2046 nsRefPtr
<nsCSSFontFaceRule
> rule(new nsCSSFontFaceRule());
2048 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2053 if (!GetToken(PR_TRUE
)) {
2054 REPORT_UNEXPECTED_EOF(PEFontFaceEOF
);
2057 if (mToken
.IsSymbol('}')) { // done!
2062 // ignore extra semicolons
2063 if (mToken
.IsSymbol(';'))
2066 if (!ParseFontDescriptor(rule
)) {
2067 REPORT_UNEXPECTED(PEDeclSkipped
);
2069 if (!SkipDeclaration(PR_TRUE
))
2073 if (!ExpectSymbol('}', PR_TRUE
))
2075 (*aAppendFunc
)(rule
, aData
);
2079 // font-descriptor: font-family-desc
2080 // | font-style-desc
2081 // | font-weight-desc
2082 // | font-stretch-desc
2084 // | unicode-range-desc
2086 // All font-*-desc productions follow the pattern
2087 // IDENT ':' value ';'
2089 // On entry to this function, mToken is the IDENT.
2092 CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule
* aRule
)
2094 if (eCSSToken_Ident
!= mToken
.mType
) {
2095 REPORT_UNEXPECTED_TOKEN(PEFontDescExpected
);
2099 nsString descName
= mToken
.mIdent
;
2100 if (!ExpectSymbol(':', PR_TRUE
)) {
2101 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
2106 nsCSSFontDesc descID
= nsCSSProps::LookupFontDesc(descName
);
2109 if (descID
== eCSSFontDesc_UNKNOWN
) {
2110 if (NonMozillaVendorIdentifier(descName
)) {
2111 // silently skip other vendors' extensions
2112 SkipDeclaration(PR_TRUE
);
2115 const PRUnichar
*params
[] = {
2118 REPORT_UNEXPECTED_P(PEUnknownFontDesc
, params
);
2123 if (!ParseFontDescriptorValue(descID
, value
)) {
2124 const PRUnichar
*params
[] = {
2127 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
2131 if (!ExpectEndProperty())
2134 aRule
->SetDesc(descID
, value
);
2140 CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc
, void* aData
)
2142 // XXX not yet implemented
2147 CSSParserImpl::SkipUntil(PRUnichar aStopSymbol
)
2149 nsCSSToken
* tk
= &mToken
;
2151 if (!GetToken(PR_TRUE
)) {
2154 if (eCSSToken_Symbol
== tk
->mType
) {
2155 PRUnichar symbol
= tk
->mSymbol
;
2156 if (symbol
== aStopSymbol
) {
2158 } else if ('{' == symbol
) {
2160 } else if ('[' == symbol
) {
2162 } else if ('(' == symbol
) {
2170 CSSParserImpl::SkipUntilOneOf(const PRUnichar
* aStopSymbolChars
)
2172 nsCSSToken
* tk
= &mToken
;
2173 nsDependentString
stopSymbolChars(aStopSymbolChars
);
2175 if (!GetToken(PR_TRUE
)) {
2178 if (eCSSToken_Symbol
== tk
->mType
) {
2179 PRUnichar symbol
= tk
->mSymbol
;
2180 if (stopSymbolChars
.FindChar(symbol
) != -1) {
2182 } else if ('{' == symbol
) {
2184 } else if ('[' == symbol
) {
2186 } else if ('(' == symbol
) {
2194 CSSParserImpl::GetNonCloseParenToken(PRBool aSkipWS
)
2196 if (!GetToken(aSkipWS
))
2198 if (mToken
.mType
== eCSSToken_Symbol
&& mToken
.mSymbol
== ')') {
2206 CSSParserImpl::SkipDeclaration(PRBool aCheckForBraces
)
2208 nsCSSToken
* tk
= &mToken
;
2210 if (!GetToken(PR_TRUE
)) {
2211 if (aCheckForBraces
) {
2212 REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF
);
2216 if (eCSSToken_Symbol
== tk
->mType
) {
2217 PRUnichar symbol
= tk
->mSymbol
;
2218 if (';' == symbol
) {
2221 if (aCheckForBraces
) {
2222 if ('}' == symbol
) {
2227 if ('{' == symbol
) {
2229 } else if ('(' == symbol
) {
2231 } else if ('[' == symbol
) {
2240 CSSParserImpl::SkipRuleSet()
2242 nsCSSToken
* tk
= &mToken
;
2244 if (!GetToken(PR_TRUE
)) {
2245 REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF
);
2248 if (eCSSToken_Symbol
== tk
->mType
) {
2249 PRUnichar symbol
= tk
->mSymbol
;
2250 if ('{' == symbol
) {
2254 if ('(' == symbol
) {
2256 } else if ('[' == symbol
) {
2264 CSSParserImpl::PushGroup(nsICSSGroupRule
* aRule
)
2266 if (mGroupStack
.AppendObject(aRule
))
2273 CSSParserImpl::PopGroup(void)
2275 PRInt32 count
= mGroupStack
.Count();
2277 mGroupStack
.RemoveObjectAt(count
- 1);
2282 CSSParserImpl::AppendRule(nsICSSRule
* aRule
)
2284 PRInt32 count
= mGroupStack
.Count();
2286 mGroupStack
[count
- 1]->AppendStyleRule(aRule
);
2289 mSheet
->AppendStyleRule(aRule
);
2294 CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aData
)
2296 // First get the list of selectors for the rule
2297 nsCSSSelectorList
* slist
= nsnull
;
2298 PRUint32 linenum
= mScanner
.GetLineNumber();
2299 if (! ParseSelectorList(slist
, PR_TRUE
)) {
2300 REPORT_UNEXPECTED(PEBadSelectorRSIgnored
);
2305 NS_ASSERTION(nsnull
!= slist
, "null selector list");
2308 // Next parse the declaration block
2309 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(PR_TRUE
);
2310 if (nsnull
== declaration
) {
2311 // XXX skip something here
2318 fputs("{\n", stdout
);
2319 declaration
->List();
2320 fputs("}\n", stdout
);
2323 // Translate the selector list and declaration block into style data
2325 nsCOMPtr
<nsICSSStyleRule
> rule
;
2326 NS_NewCSSStyleRule(getter_AddRefs(rule
), slist
, declaration
);
2328 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2332 rule
->SetLineNumber(linenum
);
2333 (*aAppendFunc
)(rule
, aData
);
2339 CSSParserImpl::ParseSelectorList(nsCSSSelectorList
*& aListHead
,
2340 PRBool aTerminateAtBrace
)
2342 nsCSSSelectorList
* list
= nsnull
;
2343 if (! ParseSelectorGroup(list
)) {
2344 // must have at least one selector group
2348 NS_ASSERTION(nsnull
!= list
, "no selector list");
2351 // After that there must either be a "," or a "{" (the latter if
2352 // aTerminateAtBrace is true)
2353 nsCSSToken
* tk
= &mToken
;
2355 if (! GetToken(PR_TRUE
)) {
2356 if (!aTerminateAtBrace
) {
2360 REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF
);
2364 if (eCSSToken_Symbol
== tk
->mType
) {
2365 if (',' == tk
->mSymbol
) {
2366 nsCSSSelectorList
* newList
= nsnull
;
2367 // Another selector group must follow
2368 if (! ParseSelectorGroup(newList
)) {
2371 // add new list to the end of the selector list
2372 list
->mNext
= newList
;
2375 } else if ('{' == tk
->mSymbol
&& aTerminateAtBrace
) {
2380 REPORT_UNEXPECTED_TOKEN(PESelectorListExtra
);
2390 static PRBool
IsSinglePseudoClass(const nsCSSSelector
& aSelector
)
2392 return PRBool((aSelector
.mNameSpace
== kNameSpaceID_Unknown
) &&
2393 (aSelector
.mTag
== nsnull
) &&
2394 (aSelector
.mIDList
== nsnull
) &&
2395 (aSelector
.mClassList
== nsnull
) &&
2396 (aSelector
.mAttrList
== nsnull
) &&
2397 (aSelector
.mNegations
== nsnull
) &&
2398 (aSelector
.mPseudoClassList
!= nsnull
) &&
2399 (aSelector
.mPseudoClassList
->mNext
== nsnull
));
2403 static PRBool
IsTreePseudoElement(nsIAtom
* aPseudo
)
2406 aPseudo
->GetUTF8String(&str
);
2407 static const char moz_tree
[] = ":-moz-tree-";
2408 return nsCRT::strncmp(str
, moz_tree
, PRInt32(sizeof(moz_tree
)-1)) == 0;
2413 CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList
*& aList
)
2415 nsAutoPtr
<nsCSSSelectorList
> list
;
2416 PRUnichar combinator
= PRUnichar(0);
2418 PRBool havePseudoElement
= PR_FALSE
;
2419 PRBool done
= PR_FALSE
;
2421 nsAutoPtr
<nsCSSSelector
> newSelector(new nsCSSSelector());
2423 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2426 nsSelectorParsingStatus parsingStatus
=
2427 ParseSelector(*newSelector
);
2428 if (parsingStatus
== eSelectorParsingStatus_Empty
) {
2430 REPORT_UNEXPECTED(PESelectorGroupNoSelector
);
2434 if (parsingStatus
== eSelectorParsingStatus_Error
) {
2438 if (nsnull
== list
) {
2439 list
= new nsCSSSelectorList();
2440 if (nsnull
== list
) {
2441 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2445 list
->AddSelector(newSelector
);
2446 nsCSSSelector
* listSel
= list
->mSelectors
;
2448 // pull out pseudo elements here
2449 nsPseudoClassList
* prevList
= nsnull
;
2450 nsPseudoClassList
* pseudoClassList
= listSel
->mPseudoClassList
;
2451 while (nsnull
!= pseudoClassList
) {
2452 if (! nsCSSPseudoClasses::IsPseudoClass(pseudoClassList
->mAtom
)) {
2453 havePseudoElement
= PR_TRUE
;
2454 if (IsSinglePseudoClass(*listSel
)) { // convert to pseudo element selector
2455 nsIAtom
* pseudoElement
= pseudoClassList
->mAtom
; // steal ref count
2456 pseudoClassList
->mAtom
= nsnull
;
2458 if (listSel
->mNext
) {// more to the selector
2459 listSel
->mOperator
= PRUnichar('>');
2460 nsAutoPtr
<nsCSSSelector
> empty(new nsCSSSelector());
2462 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2465 list
->AddSelector(empty
); // leave a blank (universal) selector in the middle
2466 listSel
= list
->mSelectors
; // use the new one for the pseudo
2468 listSel
->mTag
= pseudoElement
;
2470 else { // append new pseudo element selector
2471 nsAutoPtr
<nsCSSSelector
> pseudoTagSelector(new nsCSSSelector());
2472 if (!pseudoTagSelector
) {
2473 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2476 pseudoTagSelector
->mTag
= pseudoClassList
->mAtom
; // steal ref count
2478 if (IsTreePseudoElement(pseudoTagSelector
->mTag
)) {
2479 // Take the remaining "pseudoclasses" that we parsed
2480 // inside the tree pseudoelement's ()-list, and
2481 // make our new selector have these pseudoclasses
2482 // in its pseudoclass list.
2483 pseudoTagSelector
->mPseudoClassList
= pseudoClassList
->mNext
;
2484 pseudoClassList
->mNext
= nsnull
;
2487 list
->AddSelector(pseudoTagSelector
);
2488 pseudoClassList
->mAtom
= nsnull
;
2489 listSel
->mOperator
= PRUnichar('>');
2490 if (nsnull
== prevList
) { // delete list entry
2491 listSel
->mPseudoClassList
= pseudoClassList
->mNext
;
2494 prevList
->mNext
= pseudoClassList
->mNext
;
2496 pseudoClassList
->mNext
= nsnull
;
2497 delete pseudoClassList
;
2498 weight
+= listSel
->CalcWeight(); // capture weight from remainder
2500 break; // only one pseudo element per selector
2502 prevList
= pseudoClassList
;
2503 pseudoClassList
= pseudoClassList
->mNext
;
2506 combinator
= PRUnichar(0);
2507 if (!GetToken(PR_FALSE
)) {
2511 // Assume we are done unless we find a combinator here.
2513 if (eCSSToken_WhiteSpace
== mToken
.mType
) {
2514 if (!GetToken(PR_TRUE
)) {
2520 if (eCSSToken_Symbol
== mToken
.mType
&&
2521 ('+' == mToken
.mSymbol
||
2522 '>' == mToken
.mSymbol
||
2523 '~' == mToken
.mSymbol
)) {
2525 combinator
= mToken
.mSymbol
;
2526 list
->mSelectors
->SetOperator(combinator
);
2529 if (eCSSToken_Symbol
== mToken
.mType
&&
2530 ('{' == mToken
.mSymbol
||
2531 ',' == mToken
.mSymbol
)) {
2532 // End of this selector group
2535 UngetToken(); // give it back to selector if we're not done, or make sure
2536 // we see it as the end of the selector if we are.
2539 if (havePseudoElement
) {
2543 weight
+= listSel
->CalcWeight();
2547 if (PRUnichar(0) != combinator
) { // no dangling combinators
2549 // This should report the problematic combinator
2550 REPORT_UNEXPECTED(PESelectorGroupExtraCombinator
);
2552 aList
= list
.forget();
2554 aList
->mWeight
= weight
;
2556 return PRBool(nsnull
!= aList
);
2559 #define SEL_MASK_NSPACE 0x01
2560 #define SEL_MASK_ELEM 0x02
2561 #define SEL_MASK_ID 0x04
2562 #define SEL_MASK_CLASS 0x08
2563 #define SEL_MASK_ATTRIB 0x10
2564 #define SEL_MASK_PCLASS 0x20
2565 #define SEL_MASK_PELEM 0x40
2568 // Parses an ID selector #name
2570 CSSParserImpl::nsSelectorParsingStatus
2571 CSSParserImpl::ParseIDSelector(PRInt32
& aDataMask
,
2572 nsCSSSelector
& aSelector
)
2574 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(),
2575 "Empty mIdent in eCSSToken_ID token?");
2576 aDataMask
|= SEL_MASK_ID
;
2577 aSelector
.AddID(mToken
.mIdent
);
2578 return eSelectorParsingStatus_Continue
;
2582 // Parses a class selector .name
2584 CSSParserImpl::nsSelectorParsingStatus
2585 CSSParserImpl::ParseClassSelector(PRInt32
& aDataMask
,
2586 nsCSSSelector
& aSelector
)
2588 if (! GetToken(PR_FALSE
)) { // get ident
2589 REPORT_UNEXPECTED_EOF(PEClassSelEOF
);
2590 return eSelectorParsingStatus_Error
;
2592 if (eCSSToken_Ident
!= mToken
.mType
) { // malformed selector
2593 REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent
);
2595 return eSelectorParsingStatus_Error
;
2597 aDataMask
|= SEL_MASK_CLASS
;
2599 aSelector
.AddClass(mToken
.mIdent
);
2601 return eSelectorParsingStatus_Continue
;
2605 // Parse a type element selector or a universal selector
2606 // namespace|type or namespace|* or *|* or *
2608 CSSParserImpl::nsSelectorParsingStatus
2609 CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
2610 nsCSSSelector
& aSelector
,
2613 nsAutoString buffer
;
2614 if (mToken
.IsSymbol('*')) { // universal element selector, or universal namespace
2615 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2616 aDataMask
|= SEL_MASK_NSPACE
;
2617 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // namespace wildcard
2619 if (! GetToken(PR_FALSE
)) {
2620 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2621 return eSelectorParsingStatus_Error
;
2623 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2624 aDataMask
|= SEL_MASK_ELEM
;
2625 if (mCaseSensitive
) {
2626 aSelector
.SetTag(mToken
.mIdent
);
2629 ToLowerCase(mToken
.mIdent
, buffer
);
2630 aSelector
.SetTag(buffer
);
2633 else if (mToken
.IsSymbol('*')) { // universal selector
2634 aDataMask
|= SEL_MASK_ELEM
;
2638 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2640 return eSelectorParsingStatus_Error
;
2643 else { // was universal element selector
2644 SetDefaultNamespaceOnSelector(aSelector
);
2645 aDataMask
|= SEL_MASK_ELEM
;
2646 // don't set any tag in the selector
2648 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2649 return eSelectorParsingStatus_Done
;
2652 else if (eCSSToken_Ident
== mToken
.mType
) { // element name or namespace name
2653 buffer
= mToken
.mIdent
; // hang on to ident
2655 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2656 aDataMask
|= SEL_MASK_NSPACE
;
2657 PRInt32 nameSpaceID
;
2658 if (!GetNamespaceIdForPrefix(buffer
, &nameSpaceID
)) {
2659 return eSelectorParsingStatus_Error
;
2661 aSelector
.SetNameSpace(nameSpaceID
);
2663 if (! GetToken(PR_FALSE
)) {
2664 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2665 return eSelectorParsingStatus_Error
;
2667 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2668 aDataMask
|= SEL_MASK_ELEM
;
2669 if (mCaseSensitive
) {
2670 aSelector
.SetTag(mToken
.mIdent
);
2673 ToLowerCase(mToken
.mIdent
, buffer
);
2674 aSelector
.SetTag(buffer
);
2677 else if (mToken
.IsSymbol('*')) { // universal selector
2678 aDataMask
|= SEL_MASK_ELEM
;
2682 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2684 return eSelectorParsingStatus_Error
;
2687 else { // was element name
2688 SetDefaultNamespaceOnSelector(aSelector
);
2689 if (mCaseSensitive
) {
2690 aSelector
.SetTag(buffer
);
2693 ToLowerCase(buffer
);
2694 aSelector
.SetTag(buffer
);
2696 aDataMask
|= SEL_MASK_ELEM
;
2698 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2699 return eSelectorParsingStatus_Done
;
2702 else if (mToken
.IsSymbol('|')) { // No namespace
2703 aDataMask
|= SEL_MASK_NSPACE
;
2704 aSelector
.SetNameSpace(kNameSpaceID_None
); // explicit NO namespace
2706 // get mandatory tag
2707 if (! GetToken(PR_FALSE
)) {
2708 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2709 return eSelectorParsingStatus_Error
;
2711 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2712 aDataMask
|= SEL_MASK_ELEM
;
2713 if (mCaseSensitive
) {
2714 aSelector
.SetTag(mToken
.mIdent
);
2717 ToLowerCase(mToken
.mIdent
, buffer
);
2718 aSelector
.SetTag(buffer
);
2721 else if (mToken
.IsSymbol('*')) { // universal selector
2722 aDataMask
|= SEL_MASK_ELEM
;
2726 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2728 return eSelectorParsingStatus_Error
;
2730 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2731 return eSelectorParsingStatus_Done
;
2735 SetDefaultNamespaceOnSelector(aSelector
);
2739 // restore last token read in case of a negated type selector
2742 return eSelectorParsingStatus_Continue
;
2746 // Parse attribute selectors [attr], [attr=value], [attr|=value],
2747 // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
2749 CSSParserImpl::nsSelectorParsingStatus
2750 CSSParserImpl::ParseAttributeSelector(PRInt32
& aDataMask
,
2751 nsCSSSelector
& aSelector
)
2753 if (! GetToken(PR_TRUE
)) { // premature EOF
2754 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2755 return eSelectorParsingStatus_Error
;
2758 PRInt32 nameSpaceID
= kNameSpaceID_None
;
2760 if (mToken
.IsSymbol('*')) { // wildcard namespace
2761 nameSpaceID
= kNameSpaceID_Unknown
;
2762 if (ExpectSymbol('|', PR_FALSE
)) {
2763 if (! GetToken(PR_FALSE
)) { // premature EOF
2764 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2765 return eSelectorParsingStatus_Error
;
2767 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2768 attr
= mToken
.mIdent
;
2771 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2773 return eSelectorParsingStatus_Error
;
2777 REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar
);
2778 return eSelectorParsingStatus_Error
;
2781 else if (mToken
.IsSymbol('|')) { // NO namespace
2782 if (! GetToken(PR_FALSE
)) { // premature EOF
2783 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2784 return eSelectorParsingStatus_Error
;
2786 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2787 attr
= mToken
.mIdent
;
2790 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2792 return eSelectorParsingStatus_Error
;
2795 else if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
2796 attr
= mToken
.mIdent
; // hang on to it
2797 if (ExpectSymbol('|', PR_FALSE
)) { // was a namespace
2798 if (!GetNamespaceIdForPrefix(attr
, &nameSpaceID
)) {
2799 return eSelectorParsingStatus_Error
;
2801 if (! GetToken(PR_FALSE
)) { // premature EOF
2802 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2803 return eSelectorParsingStatus_Error
;
2805 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2806 attr
= mToken
.mIdent
;
2809 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2811 return eSelectorParsingStatus_Error
;
2816 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
2818 return eSelectorParsingStatus_Error
;
2821 if (! mCaseSensitive
) {
2824 if (! GetToken(PR_TRUE
)) { // premature EOF
2825 REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF
);
2826 return eSelectorParsingStatus_Error
;
2828 if ((eCSSToken_Symbol
== mToken
.mType
) ||
2829 (eCSSToken_Includes
== mToken
.mType
) ||
2830 (eCSSToken_Dashmatch
== mToken
.mType
) ||
2831 (eCSSToken_Beginsmatch
== mToken
.mType
) ||
2832 (eCSSToken_Endsmatch
== mToken
.mType
) ||
2833 (eCSSToken_Containsmatch
== mToken
.mType
)) {
2835 if (eCSSToken_Includes
== mToken
.mType
) {
2836 func
= NS_ATTR_FUNC_INCLUDES
;
2838 else if (eCSSToken_Dashmatch
== mToken
.mType
) {
2839 func
= NS_ATTR_FUNC_DASHMATCH
;
2841 else if (eCSSToken_Beginsmatch
== mToken
.mType
) {
2842 func
= NS_ATTR_FUNC_BEGINSMATCH
;
2844 else if (eCSSToken_Endsmatch
== mToken
.mType
) {
2845 func
= NS_ATTR_FUNC_ENDSMATCH
;
2847 else if (eCSSToken_Containsmatch
== mToken
.mType
) {
2848 func
= NS_ATTR_FUNC_CONTAINSMATCH
;
2850 else if (']' == mToken
.mSymbol
) {
2851 aDataMask
|= SEL_MASK_ATTRIB
;
2852 aSelector
.AddAttribute(nameSpaceID
, attr
);
2853 func
= NS_ATTR_FUNC_SET
;
2855 else if ('=' == mToken
.mSymbol
) {
2856 func
= NS_ATTR_FUNC_EQUALS
;
2859 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2860 UngetToken(); // bad function
2861 return eSelectorParsingStatus_Error
;
2863 if (NS_ATTR_FUNC_SET
!= func
) { // get value
2864 if (! GetToken(PR_TRUE
)) { // premature EOF
2865 REPORT_UNEXPECTED_EOF(PEAttSelValueEOF
);
2866 return eSelectorParsingStatus_Error
;
2868 if ((eCSSToken_Ident
== mToken
.mType
) || (eCSSToken_String
== mToken
.mType
)) {
2869 nsAutoString
value(mToken
.mIdent
);
2870 if (! GetToken(PR_TRUE
)) { // premature EOF
2871 REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF
);
2872 return eSelectorParsingStatus_Error
;
2874 if (mToken
.IsSymbol(']')) {
2875 PRBool isCaseSensitive
= PR_TRUE
;
2877 // If we're parsing a style sheet for an HTML document, and
2878 // the attribute selector is for a non-namespaced attribute,
2879 // then check to see if it's one of the known attributes whose
2880 // VALUE is case-insensitive.
2881 if (!mCaseSensitive
&& nameSpaceID
== kNameSpaceID_None
) {
2882 static const char* caseInsensitiveHTMLAttribute
[] = {
2883 // list based on http://www.w3.org/TR/html4/
2929 // additional attributes not in HTML4
2930 "direction", // marquee
2934 const char* htmlAttr
;
2935 while ((htmlAttr
= caseInsensitiveHTMLAttribute
[i
++])) {
2936 if (attr
.EqualsIgnoreCase(htmlAttr
)) {
2937 isCaseSensitive
= PR_FALSE
;
2942 aDataMask
|= SEL_MASK_ATTRIB
;
2943 aSelector
.AddAttribute(nameSpaceID
, attr
, func
, value
, isCaseSensitive
);
2946 REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose
);
2948 return eSelectorParsingStatus_Error
;
2952 REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue
);
2954 return eSelectorParsingStatus_Error
;
2959 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2960 UngetToken(); // bad dog, no biscut!
2961 return eSelectorParsingStatus_Error
;
2963 return eSelectorParsingStatus_Continue
;
2967 // Parse pseudo-classes and pseudo-elements
2969 CSSParserImpl::nsSelectorParsingStatus
2970 CSSParserImpl::ParsePseudoSelector(PRInt32
& aDataMask
,
2971 nsCSSSelector
& aSelector
,
2974 if (! GetToken(PR_FALSE
)) { // premature eof
2975 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2976 return eSelectorParsingStatus_Error
;
2979 // First, find out whether we are parsing a CSS3 pseudo-element
2980 PRBool parsingPseudoElement
= PR_FALSE
;
2981 if (mToken
.IsSymbol(':')) {
2982 parsingPseudoElement
= PR_TRUE
;
2983 if (! GetToken(PR_FALSE
)) { // premature eof
2984 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2985 return eSelectorParsingStatus_Error
;
2989 // Do some sanity-checking on the token
2990 if (eCSSToken_Ident
!= mToken
.mType
&& eCSSToken_Function
!= mToken
.mType
) {
2991 // malformed selector
2992 REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName
);
2994 return eSelectorParsingStatus_Error
;
2997 // OK, now we know we have an mIdent. Atomize it. All the atoms, for
2998 // pseudo-classes as well as pseudo-elements, start with a single ':'.
2999 nsAutoString buffer
;
3000 buffer
.Append(PRUnichar(':'));
3001 buffer
.Append(mToken
.mIdent
);
3002 ToLowerCase(buffer
);
3003 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(buffer
);
3005 // stash away some info about this pseudo so we only have to get it once.
3006 PRBool isTreePseudo
= PR_FALSE
;
3008 isTreePseudo
= IsTreePseudoElement(pseudo
);
3009 // If a tree pseudo-element is using the function syntax, it will
3010 // get isTree set here and will pass the check below that only
3011 // allows functions if they are in our list of things allowed to be
3012 // functions. If it is _not_ using the function syntax, isTree will
3013 // be false, and it will still pass that check. So the tree
3014 // pseudo-elements are allowed to be either functions or not, as
3016 PRBool isTree
= (eCSSToken_Function
== mToken
.mType
) && isTreePseudo
;
3018 PRBool isPseudoElement
= nsCSSPseudoElements::IsPseudoElement(pseudo
);
3019 // anonymous boxes are only allowed if they're the tree boxes or we have
3020 // enabled unsafe rules
3021 PRBool isAnonBox
= nsCSSAnonBoxes::IsAnonBox(pseudo
) &&
3022 (mUnsafeRulesEnabled
|| isTreePseudo
);
3023 PRBool isPseudoClass
= nsCSSPseudoClasses::IsPseudoClass(pseudo
);
3025 if (!isPseudoClass
&& !isPseudoElement
&& !isAnonBox
) {
3026 // Not a pseudo-class, not a pseudo-element.... forget it
3027 REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown
);
3029 return eSelectorParsingStatus_Error
;
3032 // If it's a function token, it better be on our "ok" list, and if the name
3033 // is that of a function pseudo it better be a function token
3034 if ((eCSSToken_Function
== mToken
.mType
) !=
3039 nsCSSPseudoClasses::notPseudo
== pseudo
||
3040 nsCSSPseudoClasses::HasStringArg(pseudo
) ||
3041 nsCSSPseudoClasses::HasNthPairArg(pseudo
))) {
3042 // There are no other function pseudos
3043 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc
);
3045 return eSelectorParsingStatus_Error
;
3048 // If it starts with "::", it better be a pseudo-element
3049 if (parsingPseudoElement
&&
3052 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE
);
3054 return eSelectorParsingStatus_Error
;
3057 if (!parsingPseudoElement
&& nsCSSPseudoClasses::notPseudo
== pseudo
) {
3058 if (aIsNegated
) { // :not() can't be itself negated
3059 REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot
);
3061 return eSelectorParsingStatus_Error
;
3063 // CSS 3 Negation pseudo-class takes one simple selector as argument
3064 nsSelectorParsingStatus parsingStatus
=
3065 ParseNegatedSimpleSelector(aDataMask
, aSelector
);
3066 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3067 return parsingStatus
;
3070 else if (!parsingPseudoElement
&& isPseudoClass
) {
3071 aDataMask
|= SEL_MASK_PCLASS
;
3072 if (nsCSSPseudoClasses::HasStringArg(pseudo
)) {
3073 nsSelectorParsingStatus parsingStatus
=
3074 ParsePseudoClassWithIdentArg(aSelector
, pseudo
);
3075 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3076 return parsingStatus
;
3079 else if (nsCSSPseudoClasses::HasNthPairArg(pseudo
)) {
3080 nsSelectorParsingStatus parsingStatus
=
3081 ParsePseudoClassWithNthPairArg(aSelector
, pseudo
);
3082 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3083 return parsingStatus
;
3087 aSelector
.AddPseudoClass(pseudo
);
3090 else if (isPseudoElement
|| isAnonBox
) {
3091 // Pseudo-element. Make some more sanity checks.
3093 if (aIsNegated
) { // pseudo-elements can't be negated
3094 REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot
);
3096 return eSelectorParsingStatus_Error
;
3098 // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
3099 // to have a single ':' on them. Others (CSS3+ pseudo-elements and
3100 // various -moz-* pseudo-elements) must have |parsingPseudoElement|
3102 if (!parsingPseudoElement
&&
3103 !nsCSSPseudoElements::IsCSS2PseudoElement(pseudo
)
3108 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly
);
3110 return eSelectorParsingStatus_Error
;
3113 if (0 == (aDataMask
& SEL_MASK_PELEM
)) {
3114 aDataMask
|= SEL_MASK_PELEM
;
3115 aSelector
.AddPseudoClass(pseudo
); // store it here, it gets pulled later
3119 // We have encountered a pseudoelement of the form
3120 // -moz-tree-xxxx(a,b,c). We parse (a,b,c) and add each
3121 // item in the list to the pseudoclass list. They will be pulled
3122 // from the list later along with the pseudo-element.
3123 if (!ParseTreePseudoElement(aSelector
)) {
3124 return eSelectorParsingStatus_Error
;
3129 // ensure selector ends here, must be followed by EOF, space, '{' or ','
3130 if (GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3131 if ((eCSSToken_WhiteSpace
== mToken
.mType
) ||
3132 (mToken
.IsSymbol('{') || mToken
.IsSymbol(','))) {
3134 return eSelectorParsingStatus_Done
;
3136 REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing
);
3138 return eSelectorParsingStatus_Error
;
3141 else { // multiple pseudo elements, not legal
3142 REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE
);
3144 return eSelectorParsingStatus_Error
;
3149 // We should never end up here. Indeed, if we ended up here, we know (from
3150 // the current if/else cascade) that !isPseudoElement and !isAnonBox. But
3151 // then due to our earlier check we know that isPseudoClass. Since we
3152 // didn't fall into the isPseudoClass case in this cascade, we must have
3153 // parsingPseudoElement. But we've already checked the
3154 // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if
3156 NS_NOTREACHED("How did this happen?");
3159 return eSelectorParsingStatus_Continue
;
3163 // Parse the argument of a negation pseudo-class :not()
3165 CSSParserImpl::nsSelectorParsingStatus
3166 CSSParserImpl::ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
3167 nsCSSSelector
& aSelector
)
3169 // Check if we have the first parenthesis
3170 if (!ExpectSymbol('(', PR_FALSE
)) {
3171 REPORT_UNEXPECTED_TOKEN(PENegationBadArg
);
3172 return eSelectorParsingStatus_Error
;
3175 if (! GetToken(PR_TRUE
)) { // premature eof
3176 REPORT_UNEXPECTED_EOF(PENegationEOF
);
3177 return eSelectorParsingStatus_Error
;
3180 // Create a new nsCSSSelector and add it to the end of
3181 // aSelector.mNegations.
3182 // Given the current parsing rules, every selector in mNegations
3183 // contains only one simple selector (css3 definition) within it.
3184 // This could easily change in future versions of CSS, and the only
3185 // thing we need to change to support that is this parsing code and the
3186 // serialization code for nsCSSSelector.
3187 nsCSSSelector
*newSel
= new nsCSSSelector();
3189 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
3190 return eSelectorParsingStatus_Error
;
3192 nsCSSSelector
* negations
= &aSelector
;
3193 while (negations
->mNegations
) {
3194 negations
= negations
->mNegations
;
3196 negations
->mNegations
= newSel
;
3198 nsSelectorParsingStatus parsingStatus
;
3199 if (eCSSToken_ID
== mToken
.mType
) { // #id
3200 parsingStatus
= ParseIDSelector(aDataMask
, *newSel
);
3202 else if (mToken
.IsSymbol('.')) { // .class
3203 parsingStatus
= ParseClassSelector(aDataMask
, *newSel
);
3205 else if (mToken
.IsSymbol(':')) { // :pseudo
3206 parsingStatus
= ParsePseudoSelector(aDataMask
, *newSel
, PR_TRUE
);
3208 else if (mToken
.IsSymbol('[')) { // [attribute
3209 parsingStatus
= ParseAttributeSelector(aDataMask
, *newSel
);
3212 // then it should be a type element or universal selector
3213 parsingStatus
= ParseTypeOrUniversalSelector(aDataMask
, *newSel
, PR_TRUE
);
3215 if (eSelectorParsingStatus_Error
== parsingStatus
) {
3216 REPORT_UNEXPECTED_TOKEN(PENegationBadInner
);
3217 return parsingStatus
;
3219 // close the parenthesis
3220 if (!ExpectSymbol(')', PR_TRUE
)) {
3221 REPORT_UNEXPECTED_TOKEN(PENegationNoClose
);
3222 return eSelectorParsingStatus_Error
;
3225 NS_ASSERTION(newSel
->mNameSpace
== kNameSpaceID_Unknown
||
3226 (!newSel
->mIDList
&& !newSel
->mClassList
&&
3227 !newSel
->mPseudoClassList
&& !newSel
->mAttrList
),
3228 "Need to fix the serialization code to deal with this");
3230 return eSelectorParsingStatus_Continue
;
3234 // Parse the argument of a pseudo-class that has an ident arg
3236 CSSParserImpl::nsSelectorParsingStatus
3237 CSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
3240 // Check if we have the first parenthesis
3241 if (!ExpectSymbol('(', PR_FALSE
)) {
3242 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3243 return eSelectorParsingStatus_Error
;
3246 if (! GetToken(PR_TRUE
)) { // premature eof
3247 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3248 return eSelectorParsingStatus_Error
;
3250 // We expect an identifier with a language abbreviation
3251 if (eCSSToken_Ident
!= mToken
.mType
) {
3252 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent
);
3254 // XXX Call SkipUntil to the next ")"?
3255 return eSelectorParsingStatus_Error
;
3258 // Add the pseudo with the language parameter
3259 aSelector
.AddPseudoClass(aPseudo
, mToken
.mIdent
.get());
3261 // close the parenthesis
3262 if (!ExpectSymbol(')', PR_TRUE
)) {
3263 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3264 // XXX Call SkipUntil to the next ")"?
3265 return eSelectorParsingStatus_Error
;
3268 return eSelectorParsingStatus_Continue
;
3271 CSSParserImpl::nsSelectorParsingStatus
3272 CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
3275 PRInt32 numbers
[2] = { 0, 0 };
3276 PRBool lookForB
= PR_TRUE
;
3278 // Check whether we have the first parenthesis
3279 if (!ExpectSymbol('(', PR_FALSE
)) {
3280 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3281 return eSelectorParsingStatus_Error
;
3284 // Follow the whitespace rules as proposed in
3285 // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
3287 if (! GetToken(PR_TRUE
)) {
3288 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3289 return eSelectorParsingStatus_Error
;
3292 if (eCSSToken_Ident
== mToken
.mType
|| eCSSToken_Dimension
== mToken
.mType
) {
3293 // The CSS tokenization doesn't handle :nth-child() containing - well:
3294 // 2n-1 is a dimension
3295 // n-1 is an identifier
3296 // The easiest way to deal with that is to push everything from the
3297 // minus on back onto the scanner's pushback buffer.
3298 PRUint32 truncAt
= 0;
3299 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("n-"))) {
3301 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("-n-"))) {
3305 for (PRUint32 i
= mToken
.mIdent
.Length() - 1; i
>= truncAt
; --i
) {
3306 mScanner
.Pushback(mToken
.mIdent
[i
]);
3308 mToken
.mIdent
.Truncate(truncAt
);
3312 if (eCSSToken_Ident
== mToken
.mType
) {
3313 if (mToken
.mIdent
.EqualsIgnoreCase("odd")) {
3316 lookForB
= PR_FALSE
;
3318 else if (mToken
.mIdent
.EqualsIgnoreCase("even")) {
3321 lookForB
= PR_FALSE
;
3323 else if (mToken
.mIdent
.EqualsIgnoreCase("n")) {
3326 else if (mToken
.mIdent
.EqualsIgnoreCase("-n")) {
3330 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3331 // XXX Call SkipUntil to the next ")"?
3332 return eSelectorParsingStatus_Error
;
3335 else if (eCSSToken_Number
== mToken
.mType
) {
3336 if (!mToken
.mIntegerValid
) {
3337 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3338 // XXX Call SkipUntil to the next ")"?
3339 return eSelectorParsingStatus_Error
;
3341 numbers
[1] = mToken
.mInteger
;
3342 lookForB
= PR_FALSE
;
3344 else if (eCSSToken_Dimension
== mToken
.mType
) {
3345 if (!mToken
.mIntegerValid
|| !mToken
.mIdent
.EqualsIgnoreCase("n")) {
3346 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3347 // XXX Call SkipUntil to the next ")"?
3348 return eSelectorParsingStatus_Error
;
3350 numbers
[0] = mToken
.mInteger
;
3352 // XXX If it's a ')', is that valid? (as 0n+0)
3354 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3355 // XXX Call SkipUntil to the next ")" (unless this is one already)?
3356 return eSelectorParsingStatus_Error
;
3359 if (! GetToken(PR_TRUE
)) {
3360 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3361 return eSelectorParsingStatus_Error
;
3363 if (lookForB
&& !mToken
.IsSymbol(')')) {
3364 // The '+' or '-' sign can optionally be separated by whitespace.
3365 // If it is separated by whitespace from what follows it, it appears
3366 // as a separate token rather than part of the number token.
3367 PRBool haveSign
= PR_FALSE
;
3369 if (mToken
.IsSymbol('+') || mToken
.IsSymbol('-')) {
3371 if (mToken
.IsSymbol('-')) {
3374 if (! GetToken(PR_TRUE
)) {
3375 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3376 return eSelectorParsingStatus_Error
;
3379 if (eCSSToken_Number
!= mToken
.mType
||
3380 !mToken
.mIntegerValid
|| mToken
.mHasSign
== haveSign
) {
3381 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3382 // XXX Call SkipUntil to the next ")"?
3383 return eSelectorParsingStatus_Error
;
3385 numbers
[1] = mToken
.mInteger
* sign
;
3386 if (! GetToken(PR_TRUE
)) {
3387 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3388 return eSelectorParsingStatus_Error
;
3391 if (!mToken
.IsSymbol(')')) {
3392 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3393 // XXX Call SkipUntil to the next ")"?
3394 return eSelectorParsingStatus_Error
;
3396 aSelector
.AddPseudoClass(aPseudo
, numbers
);
3397 return eSelectorParsingStatus_Continue
;
3402 * This is the format for selectors:
3403 * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
3405 CSSParserImpl::nsSelectorParsingStatus
3406 CSSParserImpl::ParseSelector(nsCSSSelector
& aSelector
)
3408 if (! GetToken(PR_TRUE
)) {
3409 REPORT_UNEXPECTED_EOF(PESelectorEOF
);
3410 return eSelectorParsingStatus_Error
;
3413 PRInt32 dataMask
= 0;
3414 nsSelectorParsingStatus parsingStatus
=
3415 ParseTypeOrUniversalSelector(dataMask
, aSelector
, PR_FALSE
);
3416 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3417 return parsingStatus
;
3421 if (eCSSToken_ID
== mToken
.mType
) { // #id
3422 parsingStatus
= ParseIDSelector(dataMask
, aSelector
);
3424 else if (mToken
.IsSymbol('.')) { // .class
3425 parsingStatus
= ParseClassSelector(dataMask
, aSelector
);
3427 else if (mToken
.IsSymbol(':')) { // :pseudo
3428 parsingStatus
= ParsePseudoSelector(dataMask
, aSelector
, PR_FALSE
);
3430 else if (mToken
.IsSymbol('[')) { // [attribute
3431 parsingStatus
= ParseAttributeSelector(dataMask
, aSelector
);
3433 else { // not a selector token, we're done
3434 parsingStatus
= eSelectorParsingStatus_Done
;
3438 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3439 return parsingStatus
;
3442 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3443 return eSelectorParsingStatus_Done
;
3447 return dataMask
? parsingStatus
: eSelectorParsingStatus_Empty
;
3451 CSSParserImpl::ParseDeclarationBlock(PRBool aCheckForBraces
)
3453 if (aCheckForBraces
) {
3454 if (!ExpectSymbol('{', PR_TRUE
)) {
3455 REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart
);
3460 nsCSSDeclaration
* declaration
= new nsCSSDeclaration();
3461 mData
.AssertInitialState();
3465 if (!ParseDeclaration(declaration
, aCheckForBraces
,
3466 PR_TRUE
, &changed
)) {
3467 if (!SkipDeclaration(aCheckForBraces
)) {
3470 if (aCheckForBraces
) {
3471 if (ExpectSymbol('}', PR_TRUE
)) {
3475 // Since the skipped declaration didn't end the block we parse
3476 // the next declaration.
3479 declaration
->CompressFrom(&mData
);
3484 // The types to pass to ParseColorComponent. These correspond to the
3485 // various datatypes that can go within rgb().
3486 #define COLOR_TYPE_UNKNOWN 0
3487 #define COLOR_TYPE_INTEGERS 1
3488 #define COLOR_TYPE_PERCENTAGES 2
3491 CSSParserImpl::ParseColor(nsCSSValue
& aValue
)
3493 if (!GetToken(PR_TRUE
)) {
3494 REPORT_UNEXPECTED_EOF(PEColorEOF
);
3498 nsCSSToken
* tk
= &mToken
;
3500 switch (tk
->mType
) {
3504 if (NS_HexToRGB(tk
->mIdent
, &rgba
)) {
3505 aValue
.SetColorValue(rgba
);
3510 case eCSSToken_Ident
:
3511 if (NS_ColorNameToRGB(tk
->mIdent
, &rgba
)) {
3512 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
3516 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
3517 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
3519 if (nsCSSProps::FindKeyword(keyword
, nsCSSProps::kColorKTable
, value
)) {
3520 aValue
.SetIntValue(value
, eCSSUnit_EnumColor
);
3526 case eCSSToken_Function
:
3527 if (mToken
.mIdent
.LowerCaseEqualsLiteral("rgb")) {
3528 // rgb ( component , component , component )
3530 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3531 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3532 ParseColorComponent(r
, type
, ',') &&
3533 ParseColorComponent(g
, type
, ',') &&
3534 ParseColorComponent(b
, type
, ')')) {
3535 aValue
.SetColorValue(NS_RGB(r
,g
,b
));
3538 return PR_FALSE
; // already pushed back
3540 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
3541 mToken
.mIdent
.LowerCaseEqualsLiteral("rgba")) {
3542 // rgba ( component , component , component , opacity )
3544 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3545 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3546 ParseColorComponent(r
, type
, ',') &&
3547 ParseColorComponent(g
, type
, ',') &&
3548 ParseColorComponent(b
, type
, ',') &&
3549 ParseColorOpacity(a
)) {
3550 aValue
.SetColorValue(NS_RGBA(r
, g
, b
, a
));
3553 return PR_FALSE
; // already pushed back
3555 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("hsl")) {
3556 // hsl ( hue , saturation , lightness )
3557 // "hue" is a number, "saturation" and "lightness" are percentages.
3558 if (ParseHSLColor(rgba
, ')')) {
3559 aValue
.SetColorValue(rgba
);
3564 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
3565 mToken
.mIdent
.LowerCaseEqualsLiteral("hsla")) {
3566 // hsla ( hue , saturation , lightness , opacity )
3567 // "hue" is a number, "saturation" and "lightness" are percentages,
3568 // "opacity" is a number.
3570 if (ParseHSLColor(rgba
, ',') &&
3571 ParseColorOpacity(a
)) {
3572 aValue
.SetColorValue(NS_RGBA(NS_GET_R(rgba
), NS_GET_G(rgba
),
3573 NS_GET_B(rgba
), a
));
3583 // try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)
3584 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) {
3585 // - If the string starts with 'a-f', the nsCSSScanner builds the
3586 // token as a eCSSToken_Ident and we can parse the string as a
3587 // 'xxyyzz' RGB color.
3588 // - If it only contains '0-9' digits, the token is a
3589 // eCSSToken_Number and it must be converted back to a 6
3590 // characters string to be parsed as a RGB color.
3591 // - If it starts with '0-9' and contains any 'a-f', the token is a
3592 // eCSSToken_Dimension, the mNumber part must be converted back to
3593 // a string and the mIdent part must be appended to that string so
3594 // that the resulting string has 6 characters.
3595 // Note: This is a hack for Nav compatibility. Do not attempt to
3596 // simplify it by hacking into the ncCSSScanner. This would be very
3600 switch (tk
->mType
) {
3601 case eCSSToken_Ident
:
3602 str
.Assign(tk
->mIdent
);
3605 case eCSSToken_Number
:
3606 if (tk
->mIntegerValid
) {
3607 PR_snprintf(buffer
, sizeof(buffer
), "%06d", tk
->mInteger
);
3608 str
.AssignWithConversion(buffer
);
3612 case eCSSToken_Dimension
:
3613 if (tk
->mIdent
.Length() <= 6) {
3614 PR_snprintf(buffer
, sizeof(buffer
), "%06.0f", tk
->mNumber
);
3616 temp
.AssignWithConversion(buffer
);
3617 temp
.Right(str
, 6 - tk
->mIdent
.Length());
3618 str
.Append(tk
->mIdent
);
3622 // There is a whole bunch of cases that are
3623 // not handled by this switch. Ignore them.
3626 if (NS_HexToRGB(str
, &rgba
)) {
3627 aValue
.SetColorValue(rgba
);
3633 REPORT_UNEXPECTED_TOKEN(PEColorNotColor
);
3638 // aType will be set if we have already parsed other color components
3639 // in this color spec
3641 CSSParserImpl::ParseColorComponent(PRUint8
& aComponent
,
3645 if (!GetToken(PR_TRUE
)) {
3646 REPORT_UNEXPECTED_EOF(PEColorComponentEOF
);
3650 nsCSSToken
* tk
= &mToken
;
3651 switch (tk
->mType
) {
3652 case eCSSToken_Number
:
3654 case COLOR_TYPE_UNKNOWN
:
3655 aType
= COLOR_TYPE_INTEGERS
;
3657 case COLOR_TYPE_INTEGERS
:
3659 case COLOR_TYPE_PERCENTAGES
:
3660 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3664 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3667 if (!mToken
.mIntegerValid
) {
3668 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3672 value
= tk
->mNumber
;
3674 case eCSSToken_Percentage
:
3676 case COLOR_TYPE_UNKNOWN
:
3677 aType
= COLOR_TYPE_PERCENTAGES
;
3679 case COLOR_TYPE_INTEGERS
:
3680 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3683 case COLOR_TYPE_PERCENTAGES
:
3686 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3688 value
= tk
->mNumber
* 255.0f
;
3691 REPORT_UNEXPECTED_TOKEN(PEColorBadRGBContents
);
3695 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3696 if (value
< 0.0f
) value
= 0.0f
;
3697 if (value
> 255.0f
) value
= 255.0f
;
3698 aComponent
= NSToIntRound(value
);
3701 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3702 const PRUnichar
*params
[] = {
3706 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3712 CSSParserImpl::ParseHSLColor(nscolor
& aColor
,
3716 if (!ExpectSymbol('(', PR_FALSE
)) {
3717 NS_ERROR("How did this get to be a function token?");
3722 if (!GetToken(PR_TRUE
)) {
3723 REPORT_UNEXPECTED_EOF(PEColorHueEOF
);
3726 if (mToken
.mType
!= eCSSToken_Number
) {
3727 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3733 // hue values are wraparound
3736 if (!ExpectSymbol(',', PR_TRUE
)) {
3737 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3741 // Get the saturation
3742 if (!GetToken(PR_TRUE
)) {
3743 REPORT_UNEXPECTED_EOF(PEColorSaturationEOF
);
3746 if (mToken
.mType
!= eCSSToken_Percentage
) {
3747 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3752 if (s
< 0.0f
) s
= 0.0f
;
3753 if (s
> 1.0f
) s
= 1.0f
;
3755 if (!ExpectSymbol(',', PR_TRUE
)) {
3756 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3760 // Get the lightness
3761 if (!GetToken(PR_TRUE
)) {
3762 REPORT_UNEXPECTED_EOF(PEColorLightnessEOF
);
3765 if (mToken
.mType
!= eCSSToken_Percentage
) {
3766 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3771 if (l
< 0.0f
) l
= 0.0f
;
3772 if (l
> 1.0f
) l
= 1.0f
;
3774 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3775 aColor
= NS_HSL2RGB(h
, s
, l
);
3779 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3780 const PRUnichar
*params
[] = {
3784 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3790 CSSParserImpl::ParseColorOpacity(PRUint8
& aOpacity
)
3792 if (!GetToken(PR_TRUE
)) {
3793 REPORT_UNEXPECTED_EOF(PEColorOpacityEOF
);
3797 if (mToken
.mType
!= eCSSToken_Number
) {
3798 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3803 if (mToken
.mNumber
< 0.0f
) {
3804 mToken
.mNumber
= 0.0f
;
3805 } else if (mToken
.mNumber
> 1.0f
) {
3806 mToken
.mNumber
= 1.0f
;
3809 PRUint8 value
= nsStyleUtil::FloatToColorComponent(mToken
.mNumber
);
3810 NS_ASSERTION(fabs(mToken
.mNumber
- value
/255.0f
) <= 0.5f
,
3811 "FloatToColorComponent did something weird");
3813 if (!ExpectSymbol(')', PR_TRUE
)) {
3814 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
3825 CSSParserImpl::ParseTreePseudoElement(nsCSSSelector
& aSelector
)
3827 if (ExpectSymbol('(', PR_FALSE
)) {
3828 while (!ExpectSymbol(')', PR_TRUE
)) {
3829 if (!GetToken(PR_TRUE
)) {
3832 else if (eCSSToken_Ident
== mToken
.mType
) {
3833 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(mToken
.mIdent
);
3834 aSelector
.AddPseudoClass(pseudo
);
3836 else if (eCSSToken_Symbol
== mToken
.mType
) {
3837 if (!mToken
.IsSymbol(','))
3840 else return PR_FALSE
;
3848 //----------------------------------------------------------------------
3851 CSSParserImpl::ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
3852 PRBool aCheckForBraces
,
3853 PRBool aMustCallValueAppended
,
3856 mTempData
.AssertInitialState();
3858 // Get property name
3859 nsCSSToken
* tk
= &mToken
;
3860 nsAutoString propertyName
;
3862 if (!GetToken(PR_TRUE
)) {
3863 if (aCheckForBraces
) {
3864 REPORT_UNEXPECTED_EOF(PEDeclEndEOF
);
3868 if (eCSSToken_Ident
== tk
->mType
) {
3869 propertyName
= tk
->mIdent
;
3870 // grab the ident before the ExpectSymbol trashes the token
3871 if (!ExpectSymbol(':', PR_TRUE
)) {
3872 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
3873 REPORT_UNEXPECTED(PEDeclDropped
);
3879 if (tk
->IsSymbol(';')) {
3880 // dangling semicolons are skipped
3884 if (!tk
->IsSymbol('}')) {
3885 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected
);
3886 REPORT_UNEXPECTED(PEDeclSkipped
);
3889 // Not a declaration...
3894 // Map property name to its ID and then parse the property
3895 nsCSSProperty propID
= nsCSSProps::LookupProperty(propertyName
);
3896 if (eCSSProperty_UNKNOWN
== propID
) { // unknown property
3897 if (!NonMozillaVendorIdentifier(propertyName
)) {
3898 const PRUnichar
*params
[] = {
3901 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
3902 REPORT_UNEXPECTED(PEDeclDropped
);
3908 if (! ParseProperty(propID
)) {
3909 // XXX Much better to put stuff in the value parsers instead...
3910 const PRUnichar
*params
[] = {
3913 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
3914 REPORT_UNEXPECTED(PEDeclDropped
);
3916 ClearTempData(propID
);
3921 // See if the declaration is followed by a "!important" declaration
3922 PRBool isImportant
= PR_FALSE
;
3923 if (!GetToken(PR_TRUE
)) {
3924 // EOF is a perfectly good way to end a declaration and declaration block
3925 TransferTempData(aDeclaration
, propID
, isImportant
,
3926 aMustCallValueAppended
, aChanged
);
3930 if (eCSSToken_Symbol
== tk
->mType
&& '!' == tk
->mSymbol
) {
3931 // Look for important ident
3932 if (!GetToken(PR_TRUE
)) {
3933 // Premature eof is not ok
3934 REPORT_UNEXPECTED_EOF(PEImportantEOF
);
3935 ClearTempData(propID
);
3938 if ((eCSSToken_Ident
!= tk
->mType
) ||
3939 !tk
->mIdent
.LowerCaseEqualsLiteral("important")) {
3940 REPORT_UNEXPECTED_TOKEN(PEExpectedImportant
);
3943 ClearTempData(propID
);
3946 isImportant
= PR_TRUE
;
3949 // Not a !important declaration
3953 // Make sure valid property declaration is terminated with either a
3954 // semicolon, EOF or a right-curly-brace (this last only when
3955 // aCheckForBraces is true).
3956 if (!GetToken(PR_TRUE
)) {
3957 // EOF is a perfectly good way to end a declaration and declaration block
3958 TransferTempData(aDeclaration
, propID
, isImportant
,
3959 aMustCallValueAppended
, aChanged
);
3962 if (eCSSToken_Symbol
== tk
->mType
) {
3963 if (';' == tk
->mSymbol
) {
3964 TransferTempData(aDeclaration
, propID
, isImportant
,
3965 aMustCallValueAppended
, aChanged
);
3968 if (aCheckForBraces
&& '}' == tk
->mSymbol
) {
3969 // Unget the '}' so we'll be able to tell that this is the end
3970 // of the declaration block when we unwind from here.
3972 TransferTempData(aDeclaration
, propID
, isImportant
,
3973 aMustCallValueAppended
, aChanged
);
3977 if (aCheckForBraces
)
3978 REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2
);
3980 REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd
);
3981 REPORT_UNEXPECTED(PEDeclDropped
);
3983 ClearTempData(propID
);
3988 CSSParserImpl::ClearTempData(nsCSSProperty aPropID
)
3990 if (nsCSSProps::IsShorthand(aPropID
)) {
3991 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
3992 mTempData
.ClearProperty(*p
);
3995 mTempData
.ClearProperty(aPropID
);
3997 mTempData
.AssertInitialState();
4001 CSSParserImpl::TransferTempData(nsCSSDeclaration
* aDeclaration
,
4002 nsCSSProperty aPropID
, PRBool aIsImportant
,
4003 PRBool aMustCallValueAppended
,
4006 if (nsCSSProps::IsShorthand(aPropID
)) {
4007 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
4008 DoTransferTempData(aDeclaration
, *p
, aIsImportant
,
4009 aMustCallValueAppended
, aChanged
);
4012 DoTransferTempData(aDeclaration
, aPropID
, aIsImportant
,
4013 aMustCallValueAppended
, aChanged
);
4015 mTempData
.AssertInitialState();
4018 // Perhaps the transferring code should be in nsCSSExpandedDataBlock, in
4019 // case some other caller wants to use it in the future (although I
4020 // can't think of why).
4022 CSSParserImpl::DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
4023 nsCSSProperty aPropID
, PRBool aIsImportant
,
4024 PRBool aMustCallValueAppended
,
4027 NS_ASSERTION(mTempData
.HasPropertyBit(aPropID
), "oops");
4029 if (!mData
.HasImportantBit(aPropID
))
4030 *aChanged
= PR_TRUE
;
4031 mData
.SetImportantBit(aPropID
);
4033 if (mData
.HasImportantBit(aPropID
)) {
4034 mTempData
.ClearProperty(aPropID
);
4039 if (aMustCallValueAppended
|| !mData
.HasPropertyBit(aPropID
)) {
4040 aDeclaration
->ValueAppended(aPropID
);
4043 mData
.SetPropertyBit(aPropID
);
4044 mTempData
.ClearPropertyBit(aPropID
);
4047 * Save needless copying and allocation by calling the destructor in
4048 * the destination, copying memory directly, and then using placement
4051 void *v_source
= mTempData
.PropertyAt(aPropID
);
4052 void *v_dest
= mData
.PropertyAt(aPropID
);
4053 switch (nsCSSProps::kTypeTable
[aPropID
]) {
4054 case eCSSType_Value
: {
4055 nsCSSValue
*source
= static_cast<nsCSSValue
*>(v_source
);
4056 nsCSSValue
*dest
= static_cast<nsCSSValue
*>(v_dest
);
4057 if (*source
!= *dest
)
4058 *aChanged
= PR_TRUE
;
4059 dest
->~nsCSSValue();
4060 memcpy(dest
, source
, sizeof(nsCSSValue
));
4061 new (source
) nsCSSValue();
4064 case eCSSType_Rect
: {
4065 nsCSSRect
*source
= static_cast<nsCSSRect
*>(v_source
);
4066 nsCSSRect
*dest
= static_cast<nsCSSRect
*>(v_dest
);
4067 if (*source
!= *dest
)
4068 *aChanged
= PR_TRUE
;
4070 memcpy(dest
, source
, sizeof(nsCSSRect
));
4071 new (source
) nsCSSRect();
4074 case eCSSType_ValuePair
: {
4075 nsCSSValuePair
*source
= static_cast<nsCSSValuePair
*>(v_source
);
4076 nsCSSValuePair
*dest
= static_cast<nsCSSValuePair
*>(v_dest
);
4077 if (*source
!= *dest
)
4078 *aChanged
= PR_TRUE
;
4079 dest
->~nsCSSValuePair();
4080 memcpy(dest
, source
, sizeof(nsCSSValuePair
));
4081 new (source
) nsCSSValuePair();
4084 case eCSSType_ValueList
: {
4085 nsCSSValueList
**source
= static_cast<nsCSSValueList
**>(v_source
);
4086 nsCSSValueList
**dest
= static_cast<nsCSSValueList
**>(v_dest
);
4087 if (!nsCSSValueList::Equal(*source
, *dest
))
4088 *aChanged
= PR_TRUE
;
4094 case eCSSType_ValuePairList
: {
4095 nsCSSValuePairList
**source
=
4096 static_cast<nsCSSValuePairList
**>(v_source
);
4097 nsCSSValuePairList
**dest
=
4098 static_cast<nsCSSValuePairList
**>(v_dest
);
4099 if (!nsCSSValuePairList::Equal(*source
, *dest
))
4100 *aChanged
= PR_TRUE
;
4108 static const nsCSSProperty kBorderTopIDs
[] = {
4109 eCSSProperty_border_top_width
,
4110 eCSSProperty_border_top_style
,
4111 eCSSProperty_border_top_color
4113 static const nsCSSProperty kBorderRightIDs
[] = {
4114 eCSSProperty_border_right_width_value
,
4115 eCSSProperty_border_right_style_value
,
4116 eCSSProperty_border_right_color_value
,
4117 eCSSProperty_border_right_width
,
4118 eCSSProperty_border_right_style
,
4119 eCSSProperty_border_right_color
4121 static const nsCSSProperty kBorderBottomIDs
[] = {
4122 eCSSProperty_border_bottom_width
,
4123 eCSSProperty_border_bottom_style
,
4124 eCSSProperty_border_bottom_color
4126 static const nsCSSProperty kBorderLeftIDs
[] = {
4127 eCSSProperty_border_left_width_value
,
4128 eCSSProperty_border_left_style_value
,
4129 eCSSProperty_border_left_color_value
,
4130 eCSSProperty_border_left_width
,
4131 eCSSProperty_border_left_style
,
4132 eCSSProperty_border_left_color
4134 static const nsCSSProperty kBorderStartIDs
[] = {
4135 eCSSProperty_border_start_width_value
,
4136 eCSSProperty_border_start_style_value
,
4137 eCSSProperty_border_start_color_value
,
4138 eCSSProperty_border_start_width
,
4139 eCSSProperty_border_start_style
,
4140 eCSSProperty_border_start_color
4142 static const nsCSSProperty kBorderEndIDs
[] = {
4143 eCSSProperty_border_end_width_value
,
4144 eCSSProperty_border_end_style_value
,
4145 eCSSProperty_border_end_color_value
,
4146 eCSSProperty_border_end_width
,
4147 eCSSProperty_border_end_style
,
4148 eCSSProperty_border_end_color
4150 static const nsCSSProperty kColumnRuleIDs
[] = {
4151 eCSSProperty__moz_column_rule_width
,
4152 eCSSProperty__moz_column_rule_style
,
4153 eCSSProperty__moz_column_rule_color
4157 CSSParserImpl::ParseEnum(nsCSSValue
& aValue
,
4158 const PRInt32 aKeywordTable
[])
4160 nsSubstring
* ident
= NextIdent();
4161 if (nsnull
== ident
) {
4164 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(*ident
);
4165 if (eCSSKeyword_UNKNOWN
< keyword
) {
4167 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4168 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4173 // Put the unknown identifier back and return
4180 char name
[5]; // needs to be long enough for the longest unit, with
4181 // terminating null.
4187 #define STR_WITH_LEN(_str) \
4188 _str, sizeof(_str) - 1
4190 const UnitInfo UnitData
[] = {
4191 { STR_WITH_LEN("px"), eCSSUnit_Pixel
, VARIANT_LENGTH
},
4192 { STR_WITH_LEN("em"), eCSSUnit_EM
, VARIANT_LENGTH
},
4193 { STR_WITH_LEN("ex"), eCSSUnit_XHeight
, VARIANT_LENGTH
},
4194 { STR_WITH_LEN("pt"), eCSSUnit_Point
, VARIANT_LENGTH
},
4195 { STR_WITH_LEN("in"), eCSSUnit_Inch
, VARIANT_LENGTH
},
4196 { STR_WITH_LEN("cm"), eCSSUnit_Centimeter
, VARIANT_LENGTH
},
4197 { STR_WITH_LEN("ch"), eCSSUnit_Char
, VARIANT_LENGTH
},
4198 { STR_WITH_LEN("mm"), eCSSUnit_Millimeter
, VARIANT_LENGTH
},
4199 { STR_WITH_LEN("pc"), eCSSUnit_Pica
, VARIANT_LENGTH
},
4200 { STR_WITH_LEN("deg"), eCSSUnit_Degree
, VARIANT_ANGLE
},
4201 { STR_WITH_LEN("grad"), eCSSUnit_Grad
, VARIANT_ANGLE
},
4202 { STR_WITH_LEN("rad"), eCSSUnit_Radian
, VARIANT_ANGLE
},
4203 { STR_WITH_LEN("hz"), eCSSUnit_Hertz
, VARIANT_FREQUENCY
},
4204 { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz
, VARIANT_FREQUENCY
},
4205 { STR_WITH_LEN("s"), eCSSUnit_Seconds
, VARIANT_TIME
},
4206 { STR_WITH_LEN("ms"), eCSSUnit_Milliseconds
, VARIANT_TIME
}
4212 CSSParserImpl::TranslateDimension(nsCSSValue
& aValue
,
4213 PRInt32 aVariantMask
,
4215 const nsString
& aUnit
)
4219 if (!aUnit
.IsEmpty()) {
4221 for (i
= 0; i
< NS_ARRAY_LENGTH(UnitData
); ++i
) {
4222 if (aUnit
.LowerCaseEqualsASCII(UnitData
[i
].name
,
4223 UnitData
[i
].length
)) {
4224 units
= UnitData
[i
].unit
;
4225 type
= UnitData
[i
].type
;
4230 if (i
== NS_ARRAY_LENGTH(UnitData
)) {
4235 // Must be a zero number...
4236 NS_ASSERTION(0 == aNumber
, "numbers without units must be 0");
4237 if ((VARIANT_LENGTH
& aVariantMask
) != 0) {
4238 units
= eCSSUnit_Point
;
4239 type
= VARIANT_LENGTH
;
4241 else if ((VARIANT_ANGLE
& aVariantMask
) != 0) {
4242 units
= eCSSUnit_Degree
;
4243 type
= VARIANT_ANGLE
;
4245 else if ((VARIANT_FREQUENCY
& aVariantMask
) != 0) {
4246 units
= eCSSUnit_Hertz
;
4247 type
= VARIANT_FREQUENCY
;
4249 else if ((VARIANT_TIME
& aVariantMask
) != 0) {
4250 units
= eCSSUnit_Seconds
;
4251 type
= VARIANT_TIME
;
4254 NS_ERROR("Variant mask does not include dimension; why were we called?");
4258 if ((type
& aVariantMask
) != 0) {
4259 aValue
.SetFloatValue(aNumber
, units
);
4266 CSSParserImpl::ParsePositiveVariant(nsCSSValue
& aValue
,
4267 PRInt32 aVariantMask
,
4268 const PRInt32 aKeywordTable
[])
4270 if (ParseVariant(aValue
, aVariantMask
, aKeywordTable
)) {
4271 if (eCSSUnit_Number
== aValue
.GetUnit() ||
4272 aValue
.IsLengthUnit()){
4273 if (aValue
.GetFloatValue() < 0) {
4278 else if (aValue
.GetUnit() == eCSSUnit_Percent
) {
4279 if (aValue
.GetPercentValue() < 0) {
4283 } else if (aValue
.GetUnit() == eCSSUnit_Integer
) {
4284 if (aValue
.GetIntValue() < 0) {
4294 // Assigns to aValue iff it returns PR_TRUE.
4296 CSSParserImpl::ParseVariant(nsCSSValue
& aValue
,
4297 PRInt32 aVariantMask
,
4298 const PRInt32 aKeywordTable
[])
4300 NS_ASSERTION(IsParsingCompoundProperty() ||
4301 ((~aVariantMask
) & (VARIANT_LENGTH
|VARIANT_COLOR
)),
4302 "cannot distinguish lengths and colors in quirks mode");
4304 if (!GetToken(PR_TRUE
)) {
4307 nsCSSToken
* tk
= &mToken
;
4308 if (((aVariantMask
& (VARIANT_AHK
| VARIANT_NORMAL
| VARIANT_NONE
)) != 0) &&
4309 (eCSSToken_Ident
== tk
->mType
)) {
4310 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
4311 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
4312 if ((aVariantMask
& VARIANT_AUTO
) != 0) {
4313 if (eCSSKeyword_auto
== keyword
) {
4314 aValue
.SetAutoValue();
4318 if ((aVariantMask
& VARIANT_INHERIT
) != 0) {
4319 // XXX Should we check IsParsingCompoundProperty, or do all
4320 // callers handle it? (Not all callers set it, though, since
4321 // they want the quirks that are disabled by setting it.)
4322 if (eCSSKeyword_inherit
== keyword
) {
4323 aValue
.SetInheritValue();
4326 else if (eCSSKeyword__moz_initial
== keyword
) { // anything that can inherit can also take an initial val.
4327 aValue
.SetInitialValue();
4331 if ((aVariantMask
& VARIANT_NONE
) != 0) {
4332 if (eCSSKeyword_none
== keyword
) {
4333 aValue
.SetNoneValue();
4337 if ((aVariantMask
& VARIANT_NORMAL
) != 0) {
4338 if (eCSSKeyword_normal
== keyword
) {
4339 aValue
.SetNormalValue();
4343 if ((aVariantMask
& VARIANT_SYSFONT
) != 0) {
4344 if (eCSSKeyword__moz_use_system_font
== keyword
&&
4345 !IsParsingCompoundProperty()) {
4346 aValue
.SetSystemFontValue();
4350 if ((aVariantMask
& VARIANT_KEYWORD
) != 0) {
4352 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4353 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4359 if (((aVariantMask
& (VARIANT_LENGTH
| VARIANT_ANGLE
| VARIANT_FREQUENCY
| VARIANT_TIME
)) != 0) &&
4360 tk
->IsDimension()) {
4361 if (TranslateDimension(aValue
, aVariantMask
, tk
->mNumber
, tk
->mIdent
)) {
4364 // Put the token back; we didn't parse it, so we shouldn't consume it
4368 if (((aVariantMask
& VARIANT_PERCENT
) != 0) &&
4369 (eCSSToken_Percentage
== tk
->mType
)) {
4370 aValue
.SetPercentValue(tk
->mNumber
);
4373 if (((aVariantMask
& VARIANT_NUMBER
) != 0) &&
4374 (eCSSToken_Number
== tk
->mType
)) {
4375 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Number
);
4378 if (((aVariantMask
& VARIANT_INTEGER
) != 0) &&
4379 (eCSSToken_Number
== tk
->mType
) && tk
->mIntegerValid
) {
4380 aValue
.SetIntValue(tk
->mInteger
, eCSSUnit_Integer
);
4383 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) { // NONSTANDARD: Nav interprets unitless numbers as px
4384 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4385 (eCSSToken_Number
== tk
->mType
)) {
4386 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4392 if (IsSVGMode() && !IsParsingCompoundProperty()) {
4393 // STANDARD: SVG Spec states that lengths and coordinates can be unitless
4394 // in which case they default to user-units (1 px = 1 user unit)
4395 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4396 (eCSSToken_Number
== tk
->mType
)) {
4397 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4403 if (((aVariantMask
& VARIANT_URL
) != 0) &&
4404 (eCSSToken_Function
== tk
->mType
) &&
4405 tk
->mIdent
.LowerCaseEqualsLiteral("url")) {
4406 if (ParseURL(aValue
)) {
4411 if ((aVariantMask
& VARIANT_COLOR
) != 0) {
4412 if ((mNavQuirkMode
&& !IsParsingCompoundProperty()) || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
4413 (eCSSToken_ID
== tk
->mType
) ||
4414 (eCSSToken_Ref
== tk
->mType
) ||
4415 (eCSSToken_Ident
== tk
->mType
) ||
4416 ((eCSSToken_Function
== tk
->mType
) &&
4417 (tk
->mIdent
.LowerCaseEqualsLiteral("rgb") ||
4418 tk
->mIdent
.LowerCaseEqualsLiteral("hsl") ||
4419 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
4420 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
4421 tk
->mIdent
.LowerCaseEqualsLiteral("rgba") ||
4422 tk
->mIdent
.LowerCaseEqualsLiteral("hsla"))))
4424 // Put token back so that parse color can get it
4426 if (ParseColor(aValue
)) {
4432 if (((aVariantMask
& VARIANT_STRING
) != 0) &&
4433 (eCSSToken_String
== tk
->mType
)) {
4434 nsAutoString buffer
;
4435 buffer
.Append(tk
->mSymbol
);
4436 buffer
.Append(tk
->mIdent
);
4437 buffer
.Append(tk
->mSymbol
);
4438 aValue
.SetStringValue(buffer
, eCSSUnit_String
);
4441 if (((aVariantMask
& VARIANT_IDENTIFIER
) != 0) &&
4442 (eCSSToken_Ident
== tk
->mType
)) {
4443 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
4446 if (((aVariantMask
& VARIANT_COUNTER
) != 0) &&
4447 (eCSSToken_Function
== tk
->mType
) &&
4448 (tk
->mIdent
.LowerCaseEqualsLiteral("counter") ||
4449 tk
->mIdent
.LowerCaseEqualsLiteral("counters"))) {
4450 return ParseCounter(aValue
);
4452 if (((aVariantMask
& VARIANT_ATTR
) != 0) &&
4453 (eCSSToken_Function
== tk
->mType
) &&
4454 tk
->mIdent
.LowerCaseEqualsLiteral("attr")) {
4455 return ParseAttr(aValue
);
4464 CSSParserImpl::ParseCounter(nsCSSValue
& aValue
)
4466 nsCSSUnit unit
= (mToken
.mIdent
.LowerCaseEqualsLiteral("counter") ?
4467 eCSSUnit_Counter
: eCSSUnit_Counters
);
4469 if (!ExpectSymbol('(', PR_FALSE
))
4472 if (!GetNonCloseParenToken(PR_TRUE
) ||
4473 eCSSToken_Ident
!= mToken
.mType
) {
4478 nsRefPtr
<nsCSSValue::Array
> val
=
4479 nsCSSValue::Array::Create(unit
== eCSSUnit_Counter
? 2 : 3);
4481 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4485 val
->Item(0).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4487 if (eCSSUnit_Counters
== unit
) {
4488 // get mandatory separator string
4489 if (!ExpectSymbol(',', PR_TRUE
) ||
4490 !(GetNonCloseParenToken(PR_TRUE
) &&
4491 eCSSToken_String
== mToken
.mType
)) {
4495 val
->Item(1).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4498 // get optional type
4499 PRInt32 type
= NS_STYLE_LIST_STYLE_DECIMAL
;
4500 if (ExpectSymbol(',', PR_TRUE
)) {
4501 nsCSSKeyword keyword
;
4502 PRBool success
= GetNonCloseParenToken(PR_TRUE
) &&
4503 eCSSToken_Ident
== mToken
.mType
&&
4504 (keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
)) !=
4505 eCSSKeyword_UNKNOWN
;
4507 if (keyword
== eCSSKeyword_none
) {
4508 type
= NS_STYLE_LIST_STYLE_NONE
;
4510 success
= nsCSSProps::FindKeyword(keyword
,
4511 nsCSSProps::kListStyleKTable
, type
);
4519 PRInt32 typeItem
= eCSSUnit_Counters
== unit
? 2 : 1;
4520 val
->Item(typeItem
).SetIntValue(type
, eCSSUnit_Enumerated
);
4522 if (!ExpectSymbol(')', PR_TRUE
)) {
4527 aValue
.SetArrayValue(val
, unit
);
4532 CSSParserImpl::ParseAttr(nsCSSValue
& aValue
)
4534 if (ExpectSymbol('(', PR_FALSE
)) {
4535 if (GetToken(PR_TRUE
)) {
4537 if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
4538 nsAutoString
holdIdent(mToken
.mIdent
);
4539 if (ExpectSymbol('|', PR_FALSE
)) { // namespace
4540 PRInt32 nameSpaceID
;
4541 if (!GetNamespaceIdForPrefix(holdIdent
, &nameSpaceID
)) {
4544 attr
.AppendInt(nameSpaceID
, 10);
4545 attr
.Append(PRUnichar('|'));
4546 if (! GetToken(PR_FALSE
)) {
4547 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4550 if (eCSSToken_Ident
== mToken
.mType
) {
4551 if (mCaseSensitive
) {
4552 attr
.Append(mToken
.mIdent
);
4554 nsAutoString buffer
;
4555 ToLowerCase(mToken
.mIdent
, buffer
);
4556 attr
.Append(buffer
);
4560 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4565 else { // no namespace
4566 if (mCaseSensitive
) {
4570 ToLowerCase(holdIdent
, attr
);
4574 else if (mToken
.IsSymbol('*')) { // namespace wildcard
4575 // Wildcard namespace makes no sense here and is not allowed
4576 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4580 else if (mToken
.IsSymbol('|')) { // explicit NO namespace
4581 if (! GetToken(PR_FALSE
)) {
4582 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4585 if (eCSSToken_Ident
== mToken
.mType
) {
4586 if (mCaseSensitive
) {
4587 attr
.Append(mToken
.mIdent
);
4589 nsAutoString buffer
;
4590 ToLowerCase(mToken
.mIdent
, buffer
);
4591 attr
.Append(buffer
);
4595 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4601 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
4605 if (ExpectSymbol(')', PR_TRUE
)) {
4606 aValue
.SetStringValue(attr
, eCSSUnit_Attr
);
4615 CSSParserImpl::ParseURL(nsCSSValue
& aValue
)
4617 if (!mSheetPrincipal
) {
4618 NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
4619 "origin principal");
4623 if (!ExpectSymbol('(', PR_FALSE
))
4628 nsCSSToken
* tk
= &mToken
;
4629 if (eCSSToken_String
!= tk
->mType
&& eCSSToken_URL
!= tk
->mType
)
4632 nsString url
= tk
->mIdent
;
4633 if (!ExpectSymbol(')', PR_TRUE
))
4636 // Translate url into an absolute url if the url is relative to the
4638 nsCOMPtr
<nsIURI
> uri
;
4639 NS_NewURI(getter_AddRefs(uri
), url
, nsnull
, mBaseURL
);
4641 nsStringBuffer
* buffer
= nsCSSValue::BufferFromString(url
);
4642 if (NS_UNLIKELY(!buffer
)) {
4643 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4646 nsCSSValue::URL
*urlVal
=
4647 new nsCSSValue::URL(uri
, buffer
, mSheetURL
, mSheetPrincipal
);
4650 if (NS_UNLIKELY(!urlVal
)) {
4651 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4654 aValue
.SetURLValue(urlVal
);
4659 CSSParserImpl::ParseChoice(nsCSSValue aValues
[],
4660 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
)
4663 nsAutoParseCompoundProperty
compound(this);
4666 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4667 // Try each property parser in order
4668 PRInt32 hadFound
= found
;
4670 for (index
= 0; index
< aNumIDs
; index
++) {
4671 PRInt32 bit
= 1 << index
;
4672 if ((found
& bit
) == 0) {
4673 if (ParseSingleValueProperty(aValues
[index
], aPropIDs
[index
])) {
4678 if (found
== hadFound
) { // found nothing new
4683 if (1 == found
) { // only first property
4684 if (eCSSUnit_Inherit
== aValues
[0].GetUnit()) { // one inherit, all inherit
4685 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4686 aValues
[loop
].SetInheritValue();
4688 found
= ((1 << aNumIDs
) - 1);
4690 else if (eCSSUnit_Initial
== aValues
[0].GetUnit()) { // one initial, all initial
4691 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4692 aValues
[loop
].SetInitialValue();
4694 found
= ((1 << aNumIDs
) - 1);
4697 else { // more than one value, verify no inherits or initials
4698 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4699 if (eCSSUnit_Inherit
== aValues
[loop
].GetUnit()) {
4703 else if (eCSSUnit_Initial
== aValues
[loop
].GetUnit()) {
4714 CSSParserImpl::AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
)
4716 NS_ASSERTION(0 <= aPropID
&& aPropID
< eCSSProperty_COUNT_no_shorthands
,
4717 "property out of range");
4718 NS_ASSERTION(nsCSSProps::kTypeTable
[aPropID
] == eCSSType_Value
,
4719 nsPrintfCString(64, "type error (property=\'%s\')",
4720 nsCSSProps::GetStringValue(aPropID
).get()).get());
4721 nsCSSValue
& storage
=
4722 *static_cast<nsCSSValue
*>(mTempData
.PropertyAt(aPropID
));
4724 mTempData
.SetPropertyBit(aPropID
);
4728 * Parse a "box" property. Box properties have 1 to 4 values. When less
4729 * than 4 values are provided a standard mapping is used to replicate
4733 CSSParserImpl::ParseBoxProperties(nsCSSRect
& aResult
,
4734 const nsCSSProperty aPropIDs
[])
4736 // Get up to four values for the property
4739 NS_FOR_CSS_SIDES (index
) {
4740 if (! ParseSingleValueProperty(result
.*(nsCSSRect::sides
[index
]),
4746 if ((count
== 0) || (PR_FALSE
== ExpectEndProperty())) {
4750 if (1 < count
) { // verify no more than single inherit or initial
4751 NS_FOR_CSS_SIDES (index
) {
4752 nsCSSUnit unit
= (result
.*(nsCSSRect::sides
[index
])).GetUnit();
4753 if (eCSSUnit_Inherit
== unit
|| eCSSUnit_Initial
== unit
) {
4759 // Provide missing values by replicating some of the values found
4761 case 1: // Make right == top
4762 result
.mRight
= result
.mTop
;
4763 case 2: // Make bottom == top
4764 result
.mBottom
= result
.mTop
;
4765 case 3: // Make left == right
4766 result
.mLeft
= result
.mRight
;
4769 NS_FOR_CSS_SIDES (index
) {
4770 mTempData
.SetPropertyBit(aPropIDs
[index
]);
4777 CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
4778 PRInt32 aSourceType
)
4780 const nsCSSProperty
* subprops
= nsCSSProps::SubpropertyEntryFor(aProperty
);
4781 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
4782 "not box property with physical vs. logical cascading");
4784 if (!ParseSingleValueProperty(value
, subprops
[0]) ||
4785 !ExpectEndProperty())
4788 AppendValue(subprops
[0], value
);
4789 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
4790 AppendValue(subprops
[1], typeVal
);
4791 AppendValue(subprops
[2], typeVal
);
4796 CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID
)
4798 nsCSSValue dimenX
, dimenY
;
4799 // required first value
4800 if (! ParsePositiveVariant(dimenX
, VARIANT_HLP
, nsnull
))
4802 // optional second value (forbidden if first value is inherit/initial)
4803 if (dimenX
.GetUnit() == eCSSUnit_Inherit
||
4804 dimenX
.GetUnit() == eCSSUnit_Initial
||
4805 ! ParsePositiveVariant(dimenY
, VARIANT_LP
, nsnull
))
4808 NS_ASSERTION(nsCSSProps::kTypeTable
[aPropID
] == eCSSType_ValuePair
,
4809 nsPrintfCString(64, "type error (property='%s')",
4810 nsCSSProps::GetStringValue(aPropID
).get())
4812 nsCSSValuePair
& storage
=
4813 *static_cast<nsCSSValuePair
*>(mTempData
.PropertyAt(aPropID
));
4814 storage
.mXValue
= dimenX
;
4815 storage
.mYValue
= dimenY
;
4816 mTempData
.SetPropertyBit(aPropID
);
4821 CSSParserImpl::ParseBoxCornerRadii(nsCSSCornerSizes
& aRadii
,
4822 const nsCSSProperty aPropIDs
[])
4824 // Rectangles are used as scratch storage.
4825 // top => top-left, right => top-right,
4826 // bottom => bottom-right, left => bottom-left.
4827 nsCSSRect dimenX
, dimenY
;
4828 PRInt32 countX
= 0, countY
= 0;
4830 NS_FOR_CSS_SIDES (side
) {
4831 if (! ParsePositiveVariant(dimenX
.*nsCSSRect::sides
[side
],
4832 side
> 0 ? VARIANT_LP
: VARIANT_HLP
, nsnull
))
4839 if (ExpectSymbol('/', PR_TRUE
)) {
4840 NS_FOR_CSS_SIDES (side
) {
4841 if (! ParsePositiveVariant(dimenY
.*nsCSSRect::sides
[side
],
4842 VARIANT_LP
, nsnull
))
4849 if (!ExpectEndProperty())
4852 // if 'initial' or 'inherit' was used, it must be the only value
4853 if (countX
> 1 || countY
> 0) {
4854 nsCSSUnit unit
= dimenX
.mTop
.GetUnit();
4855 if (eCSSUnit_Inherit
== unit
|| eCSSUnit_Initial
== unit
)
4859 // if we have no Y-values, use the X-values
4865 // Provide missing values by replicating some of the values found
4867 case 1: dimenX
.mRight
= dimenX
.mTop
; // top-right same as top-left, and
4868 case 2: dimenX
.mBottom
= dimenX
.mTop
; // bottom-right same as top-left, and
4869 case 3: dimenX
.mLeft
= dimenX
.mRight
; // bottom-left same as top-right
4873 case 1: dimenY
.mRight
= dimenY
.mTop
; // top-right same as top-left, and
4874 case 2: dimenY
.mBottom
= dimenY
.mTop
; // bottom-right same as top-left, and
4875 case 3: dimenY
.mLeft
= dimenY
.mRight
; // bottom-left same as top-right
4878 NS_FOR_CSS_SIDES(side
) {
4879 nsCSSValuePair
& corner
=
4880 aRadii
.GetFullCorner(NS_SIDE_TO_FULL_CORNER(side
, PR_FALSE
));
4881 corner
.mXValue
= dimenX
.*nsCSSRect::sides
[side
];
4882 corner
.mYValue
= dimenY
.*nsCSSRect::sides
[side
];
4883 mTempData
.SetPropertyBit(aPropIDs
[side
]);
4888 // These must be in CSS order (top,right,bottom,left) for indexing to work
4889 static const nsCSSProperty kBorderStyleIDs
[] = {
4890 eCSSProperty_border_top_style
,
4891 eCSSProperty_border_right_style_value
,
4892 eCSSProperty_border_bottom_style
,
4893 eCSSProperty_border_left_style_value
4895 static const nsCSSProperty kBorderWidthIDs
[] = {
4896 eCSSProperty_border_top_width
,
4897 eCSSProperty_border_right_width_value
,
4898 eCSSProperty_border_bottom_width
,
4899 eCSSProperty_border_left_width_value
4901 static const nsCSSProperty kBorderColorIDs
[] = {
4902 eCSSProperty_border_top_color
,
4903 eCSSProperty_border_right_color_value
,
4904 eCSSProperty_border_bottom_color
,
4905 eCSSProperty_border_left_color_value
4907 static const nsCSSProperty kBorderRadiusIDs
[] = {
4908 eCSSProperty__moz_border_radius_topLeft
,
4909 eCSSProperty__moz_border_radius_topRight
,
4910 eCSSProperty__moz_border_radius_bottomRight
,
4911 eCSSProperty__moz_border_radius_bottomLeft
4913 static const nsCSSProperty kOutlineRadiusIDs
[] = {
4914 eCSSProperty__moz_outline_radius_topLeft
,
4915 eCSSProperty__moz_outline_radius_topRight
,
4916 eCSSProperty__moz_outline_radius_bottomRight
,
4917 eCSSProperty__moz_outline_radius_bottomLeft
4921 CSSParserImpl::ParseProperty(nsCSSProperty aPropID
)
4923 NS_ASSERTION(aPropID
< eCSSProperty_COUNT
, "index out of range");
4925 switch (aPropID
) { // handle shorthand or multiple properties
4926 case eCSSProperty_background
:
4927 return ParseBackground();
4928 case eCSSProperty_background_position
:
4929 return ParseBackgroundPosition();
4930 case eCSSProperty_border
:
4931 return ParseBorderSide(kBorderTopIDs
, PR_TRUE
);
4932 case eCSSProperty_border_color
:
4933 return ParseBorderColor();
4934 case eCSSProperty_border_spacing
:
4935 return ParseBorderSpacing();
4936 case eCSSProperty_border_style
:
4937 return ParseBorderStyle();
4938 case eCSSProperty_border_bottom
:
4939 return ParseBorderSide(kBorderBottomIDs
, PR_FALSE
);
4940 case eCSSProperty_border_end
:
4941 return ParseDirectionalBorderSide(kBorderEndIDs
,
4942 NS_BOXPROP_SOURCE_LOGICAL
);
4943 case eCSSProperty_border_left
:
4944 return ParseDirectionalBorderSide(kBorderLeftIDs
,
4945 NS_BOXPROP_SOURCE_PHYSICAL
);
4946 case eCSSProperty_border_right
:
4947 return ParseDirectionalBorderSide(kBorderRightIDs
,
4948 NS_BOXPROP_SOURCE_PHYSICAL
);
4949 case eCSSProperty_border_start
:
4950 return ParseDirectionalBorderSide(kBorderStartIDs
,
4951 NS_BOXPROP_SOURCE_LOGICAL
);
4952 case eCSSProperty_border_top
:
4953 return ParseBorderSide(kBorderTopIDs
, PR_FALSE
);
4954 case eCSSProperty_border_bottom_colors
:
4955 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mBottom
,
4957 case eCSSProperty_border_left_colors
:
4958 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mLeft
,
4960 case eCSSProperty_border_right_colors
:
4961 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mRight
,
4963 case eCSSProperty_border_top_colors
:
4964 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mTop
,
4966 case eCSSProperty_border_image
:
4967 return ParseBorderImage();
4968 case eCSSProperty_border_width
:
4969 return ParseBorderWidth();
4970 case eCSSProperty_border_end_color
:
4971 return ParseDirectionalBoxProperty(eCSSProperty_border_end_color
,
4972 NS_BOXPROP_SOURCE_LOGICAL
);
4973 case eCSSProperty_border_left_color
:
4974 return ParseDirectionalBoxProperty(eCSSProperty_border_left_color
,
4975 NS_BOXPROP_SOURCE_PHYSICAL
);
4976 case eCSSProperty_border_right_color
:
4977 return ParseDirectionalBoxProperty(eCSSProperty_border_right_color
,
4978 NS_BOXPROP_SOURCE_PHYSICAL
);
4979 case eCSSProperty_border_start_color
:
4980 return ParseDirectionalBoxProperty(eCSSProperty_border_start_color
,
4981 NS_BOXPROP_SOURCE_LOGICAL
);
4982 case eCSSProperty_border_end_width
:
4983 return ParseDirectionalBoxProperty(eCSSProperty_border_end_width
,
4984 NS_BOXPROP_SOURCE_LOGICAL
);
4985 case eCSSProperty_border_left_width
:
4986 return ParseDirectionalBoxProperty(eCSSProperty_border_left_width
,
4987 NS_BOXPROP_SOURCE_PHYSICAL
);
4988 case eCSSProperty_border_right_width
:
4989 return ParseDirectionalBoxProperty(eCSSProperty_border_right_width
,
4990 NS_BOXPROP_SOURCE_PHYSICAL
);
4991 case eCSSProperty_border_start_width
:
4992 return ParseDirectionalBoxProperty(eCSSProperty_border_start_width
,
4993 NS_BOXPROP_SOURCE_LOGICAL
);
4994 case eCSSProperty_border_end_style
:
4995 return ParseDirectionalBoxProperty(eCSSProperty_border_end_style
,
4996 NS_BOXPROP_SOURCE_LOGICAL
);
4997 case eCSSProperty_border_left_style
:
4998 return ParseDirectionalBoxProperty(eCSSProperty_border_left_style
,
4999 NS_BOXPROP_SOURCE_PHYSICAL
);
5000 case eCSSProperty_border_right_style
:
5001 return ParseDirectionalBoxProperty(eCSSProperty_border_right_style
,
5002 NS_BOXPROP_SOURCE_PHYSICAL
);
5003 case eCSSProperty_border_start_style
:
5004 return ParseDirectionalBoxProperty(eCSSProperty_border_start_style
,
5005 NS_BOXPROP_SOURCE_LOGICAL
);
5006 case eCSSProperty__moz_border_radius
:
5007 return ParseBoxCornerRadii(mTempData
.mMargin
.mBorderRadius
,
5009 case eCSSProperty__moz_outline_radius
:
5010 return ParseBoxCornerRadii(mTempData
.mMargin
.mOutlineRadius
,
5013 case eCSSProperty__moz_border_radius_topLeft
:
5014 case eCSSProperty__moz_border_radius_topRight
:
5015 case eCSSProperty__moz_border_radius_bottomRight
:
5016 case eCSSProperty__moz_border_radius_bottomLeft
:
5017 case eCSSProperty__moz_outline_radius_topLeft
:
5018 case eCSSProperty__moz_outline_radius_topRight
:
5019 case eCSSProperty__moz_outline_radius_bottomRight
:
5020 case eCSSProperty__moz_outline_radius_bottomLeft
:
5021 return ParseBoxCornerRadius(aPropID
);
5023 case eCSSProperty_box_shadow
:
5024 return ParseBoxShadow();
5025 case eCSSProperty_clip
:
5026 return ParseRect(mTempData
.mDisplay
.mClip
, eCSSProperty_clip
);
5027 case eCSSProperty__moz_column_rule
:
5028 return ParseBorderSide(kColumnRuleIDs
, PR_FALSE
);
5029 case eCSSProperty_content
:
5030 return ParseContent();
5031 case eCSSProperty_counter_increment
:
5032 return ParseCounterData(&mTempData
.mContent
.mCounterIncrement
,
5034 case eCSSProperty_counter_reset
:
5035 return ParseCounterData(&mTempData
.mContent
.mCounterReset
,
5037 case eCSSProperty_cue
:
5039 case eCSSProperty_cursor
:
5040 return ParseCursor();
5041 case eCSSProperty_font
:
5043 case eCSSProperty_image_region
:
5044 return ParseRect(mTempData
.mList
.mImageRegion
,
5045 eCSSProperty_image_region
);
5046 case eCSSProperty_list_style
:
5047 return ParseListStyle();
5048 case eCSSProperty_margin
:
5049 return ParseMargin();
5050 case eCSSProperty_margin_end
:
5051 return ParseDirectionalBoxProperty(eCSSProperty_margin_end
,
5052 NS_BOXPROP_SOURCE_LOGICAL
);
5053 case eCSSProperty_margin_left
:
5054 return ParseDirectionalBoxProperty(eCSSProperty_margin_left
,
5055 NS_BOXPROP_SOURCE_PHYSICAL
);
5056 case eCSSProperty_margin_right
:
5057 return ParseDirectionalBoxProperty(eCSSProperty_margin_right
,
5058 NS_BOXPROP_SOURCE_PHYSICAL
);
5059 case eCSSProperty_margin_start
:
5060 return ParseDirectionalBoxProperty(eCSSProperty_margin_start
,
5061 NS_BOXPROP_SOURCE_LOGICAL
);
5062 case eCSSProperty_outline
:
5063 return ParseOutline();
5064 case eCSSProperty_overflow
:
5065 return ParseOverflow();
5066 case eCSSProperty_padding
:
5067 return ParsePadding();
5068 case eCSSProperty_padding_end
:
5069 return ParseDirectionalBoxProperty(eCSSProperty_padding_end
,
5070 NS_BOXPROP_SOURCE_LOGICAL
);
5071 case eCSSProperty_padding_left
:
5072 return ParseDirectionalBoxProperty(eCSSProperty_padding_left
,
5073 NS_BOXPROP_SOURCE_PHYSICAL
);
5074 case eCSSProperty_padding_right
:
5075 return ParseDirectionalBoxProperty(eCSSProperty_padding_right
,
5076 NS_BOXPROP_SOURCE_PHYSICAL
);
5077 case eCSSProperty_padding_start
:
5078 return ParseDirectionalBoxProperty(eCSSProperty_padding_start
,
5079 NS_BOXPROP_SOURCE_LOGICAL
);
5080 case eCSSProperty_pause
:
5081 return ParsePause();
5082 case eCSSProperty_quotes
:
5083 return ParseQuotes();
5084 case eCSSProperty_size
:
5086 case eCSSProperty_text_shadow
:
5087 return ParseTextShadow();
5088 case eCSSProperty__moz_transform
:
5089 return ParseMozTransform();
5090 case eCSSProperty__moz_transform_origin
:
5091 return ParseMozTransformOrigin();
5094 case eCSSProperty_fill
:
5095 return ParsePaint(&mTempData
.mSVG
.mFill
, eCSSProperty_fill
);
5096 case eCSSProperty_stroke
:
5097 return ParsePaint(&mTempData
.mSVG
.mStroke
, eCSSProperty_stroke
);
5098 case eCSSProperty_stroke_dasharray
:
5099 return ParseDasharray();
5100 case eCSSProperty_marker
:
5101 return ParseMarker();
5104 // Strip out properties we use internally.
5105 case eCSSProperty__x_system_font
:
5106 case eCSSProperty_margin_end_value
:
5107 case eCSSProperty_margin_left_value
:
5108 case eCSSProperty_margin_right_value
:
5109 case eCSSProperty_margin_start_value
:
5110 case eCSSProperty_margin_left_ltr_source
:
5111 case eCSSProperty_margin_left_rtl_source
:
5112 case eCSSProperty_margin_right_ltr_source
:
5113 case eCSSProperty_margin_right_rtl_source
:
5114 case eCSSProperty_padding_end_value
:
5115 case eCSSProperty_padding_left_value
:
5116 case eCSSProperty_padding_right_value
:
5117 case eCSSProperty_padding_start_value
:
5118 case eCSSProperty_padding_left_ltr_source
:
5119 case eCSSProperty_padding_left_rtl_source
:
5120 case eCSSProperty_padding_right_ltr_source
:
5121 case eCSSProperty_padding_right_rtl_source
:
5122 case eCSSProperty_border_end_color_value
:
5123 case eCSSProperty_border_left_color_value
:
5124 case eCSSProperty_border_right_color_value
:
5125 case eCSSProperty_border_start_color_value
:
5126 case eCSSProperty_border_left_color_ltr_source
:
5127 case eCSSProperty_border_left_color_rtl_source
:
5128 case eCSSProperty_border_right_color_ltr_source
:
5129 case eCSSProperty_border_right_color_rtl_source
:
5130 case eCSSProperty_border_end_style_value
:
5131 case eCSSProperty_border_left_style_value
:
5132 case eCSSProperty_border_right_style_value
:
5133 case eCSSProperty_border_start_style_value
:
5134 case eCSSProperty_border_left_style_ltr_source
:
5135 case eCSSProperty_border_left_style_rtl_source
:
5136 case eCSSProperty_border_right_style_ltr_source
:
5137 case eCSSProperty_border_right_style_rtl_source
:
5138 case eCSSProperty_border_end_width_value
:
5139 case eCSSProperty_border_left_width_value
:
5140 case eCSSProperty_border_right_width_value
:
5141 case eCSSProperty_border_start_width_value
:
5142 case eCSSProperty_border_left_width_ltr_source
:
5143 case eCSSProperty_border_left_width_rtl_source
:
5144 case eCSSProperty_border_right_width_ltr_source
:
5145 case eCSSProperty_border_right_width_rtl_source
:
5146 // The user can't use these
5147 REPORT_UNEXPECTED(PEInaccessibleProperty2
);
5149 default: // must be single property
5152 if (ParseSingleValueProperty(value
, aPropID
)) {
5153 if (ExpectEndProperty()) {
5154 AppendValue(aPropID
, value
);
5157 // XXX Report errors?
5159 // XXX Report errors?
5165 // Bits used in determining which background position info we have
5166 #define BG_CENTER NS_STYLE_BG_POSITION_CENTER
5167 #define BG_TOP NS_STYLE_BG_POSITION_TOP
5168 #define BG_BOTTOM NS_STYLE_BG_POSITION_BOTTOM
5169 #define BG_LEFT NS_STYLE_BG_POSITION_LEFT
5170 #define BG_RIGHT NS_STYLE_BG_POSITION_RIGHT
5171 #define BG_CTB (BG_CENTER | BG_TOP | BG_BOTTOM)
5172 #define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT)
5175 CSSParserImpl::ParseSingleValueProperty(nsCSSValue
& aValue
,
5176 nsCSSProperty aPropID
)
5179 case eCSSProperty_UNKNOWN
:
5180 case eCSSProperty_background
:
5181 case eCSSProperty_background_position
:
5182 case eCSSProperty_border
:
5183 case eCSSProperty_border_color
:
5184 case eCSSProperty_border_bottom_colors
:
5185 case eCSSProperty_border_image
:
5186 case eCSSProperty_border_left_colors
:
5187 case eCSSProperty_border_right_colors
:
5188 case eCSSProperty_border_end_color
:
5189 case eCSSProperty_border_left_color
:
5190 case eCSSProperty_border_right_color
:
5191 case eCSSProperty_border_start_color
:
5192 case eCSSProperty_border_end_style
:
5193 case eCSSProperty_border_left_style
:
5194 case eCSSProperty_border_right_style
:
5195 case eCSSProperty_border_start_style
:
5196 case eCSSProperty_border_end_width
:
5197 case eCSSProperty_border_left_width
:
5198 case eCSSProperty_border_right_width
:
5199 case eCSSProperty_border_start_width
:
5200 case eCSSProperty_border_top_colors
:
5201 case eCSSProperty_border_spacing
:
5202 case eCSSProperty_border_style
:
5203 case eCSSProperty_border_bottom
:
5204 case eCSSProperty_border_end
:
5205 case eCSSProperty_border_left
:
5206 case eCSSProperty_border_right
:
5207 case eCSSProperty_border_start
:
5208 case eCSSProperty_border_top
:
5209 case eCSSProperty_border_width
:
5210 case eCSSProperty__moz_border_radius
:
5211 case eCSSProperty__moz_border_radius_topLeft
:
5212 case eCSSProperty__moz_border_radius_topRight
:
5213 case eCSSProperty__moz_border_radius_bottomRight
:
5214 case eCSSProperty__moz_border_radius_bottomLeft
:
5215 case eCSSProperty_box_shadow
:
5216 case eCSSProperty_clip
:
5217 case eCSSProperty__moz_column_rule
:
5218 case eCSSProperty_content
:
5219 case eCSSProperty_counter_increment
:
5220 case eCSSProperty_counter_reset
:
5221 case eCSSProperty_cue
:
5222 case eCSSProperty_cursor
:
5223 case eCSSProperty_font
:
5224 case eCSSProperty_image_region
:
5225 case eCSSProperty_list_style
:
5226 case eCSSProperty_margin
:
5227 case eCSSProperty_margin_end
:
5228 case eCSSProperty_margin_left
:
5229 case eCSSProperty_margin_right
:
5230 case eCSSProperty_margin_start
:
5231 case eCSSProperty_outline
:
5232 case eCSSProperty__moz_outline_radius
:
5233 case eCSSProperty__moz_outline_radius_topLeft
:
5234 case eCSSProperty__moz_outline_radius_topRight
:
5235 case eCSSProperty__moz_outline_radius_bottomRight
:
5236 case eCSSProperty__moz_outline_radius_bottomLeft
:
5237 case eCSSProperty_overflow
:
5238 case eCSSProperty_padding
:
5239 case eCSSProperty_padding_end
:
5240 case eCSSProperty_padding_left
:
5241 case eCSSProperty_padding_right
:
5242 case eCSSProperty_padding_start
:
5243 case eCSSProperty_pause
:
5244 case eCSSProperty_quotes
:
5245 case eCSSProperty_size
:
5246 case eCSSProperty_text_shadow
:
5247 case eCSSProperty__moz_transform
:
5248 case eCSSProperty__moz_transform_origin
:
5249 case eCSSProperty_COUNT
:
5251 case eCSSProperty_fill
:
5252 case eCSSProperty_stroke
:
5253 case eCSSProperty_stroke_dasharray
:
5254 case eCSSProperty_marker
:
5256 NS_ERROR("not a single value property");
5259 case eCSSProperty__x_system_font
:
5260 case eCSSProperty_margin_left_ltr_source
:
5261 case eCSSProperty_margin_left_rtl_source
:
5262 case eCSSProperty_margin_right_ltr_source
:
5263 case eCSSProperty_margin_right_rtl_source
:
5264 case eCSSProperty_padding_left_ltr_source
:
5265 case eCSSProperty_padding_left_rtl_source
:
5266 case eCSSProperty_padding_right_ltr_source
:
5267 case eCSSProperty_padding_right_rtl_source
:
5268 case eCSSProperty_border_left_color_ltr_source
:
5269 case eCSSProperty_border_left_color_rtl_source
:
5270 case eCSSProperty_border_right_color_ltr_source
:
5271 case eCSSProperty_border_right_color_rtl_source
:
5272 case eCSSProperty_border_left_style_ltr_source
:
5273 case eCSSProperty_border_left_style_rtl_source
:
5274 case eCSSProperty_border_right_style_ltr_source
:
5275 case eCSSProperty_border_right_style_rtl_source
:
5276 case eCSSProperty_border_left_width_ltr_source
:
5277 case eCSSProperty_border_left_width_rtl_source
:
5278 case eCSSProperty_border_right_width_ltr_source
:
5279 case eCSSProperty_border_right_width_rtl_source
:
5281 case eCSSProperty_script_size_multiplier
:
5282 case eCSSProperty_script_min_size
:
5284 NS_ERROR("not currently parsed here");
5287 case eCSSProperty_appearance
:
5288 return ParseVariant(aValue
, VARIANT_HK
,
5289 nsCSSProps::kAppearanceKTable
);
5290 case eCSSProperty_azimuth
:
5291 return ParseAzimuth(aValue
);
5292 case eCSSProperty_background_attachment
:
5293 return ParseVariant(aValue
, VARIANT_HK
,
5294 nsCSSProps::kBackgroundAttachmentKTable
);
5295 case eCSSProperty__moz_background_clip
:
5296 return ParseVariant(aValue
, VARIANT_HK
,
5297 nsCSSProps::kBackgroundClipKTable
);
5298 case eCSSProperty_background_color
:
5299 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5300 case eCSSProperty_background_image
:
5301 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5302 case eCSSProperty__moz_background_inline_policy
:
5303 return ParseVariant(aValue
, VARIANT_HK
,
5304 nsCSSProps::kBackgroundInlinePolicyKTable
);
5305 case eCSSProperty__moz_background_origin
:
5306 return ParseVariant(aValue
, VARIANT_HK
,
5307 nsCSSProps::kBackgroundOriginKTable
);
5308 case eCSSProperty_background_repeat
:
5309 return ParseVariant(aValue
, VARIANT_HK
,
5310 nsCSSProps::kBackgroundRepeatKTable
);
5311 case eCSSProperty_binding
:
5312 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5313 case eCSSProperty_border_collapse
:
5314 return ParseVariant(aValue
, VARIANT_HK
,
5315 nsCSSProps::kBorderCollapseKTable
);
5316 case eCSSProperty_border_bottom_color
:
5317 case eCSSProperty_border_end_color_value
: // for internal use
5318 case eCSSProperty_border_left_color_value
: // for internal use
5319 case eCSSProperty_border_right_color_value
: // for internal use
5320 case eCSSProperty_border_start_color_value
: // for internal use
5321 case eCSSProperty_border_top_color
:
5322 case eCSSProperty__moz_column_rule_color
:
5323 return ParseVariant(aValue
, VARIANT_HCK
,
5324 nsCSSProps::kBorderColorKTable
);
5325 case eCSSProperty_border_bottom_style
:
5326 case eCSSProperty_border_end_style_value
: // for internal use
5327 case eCSSProperty_border_left_style_value
: // for internal use
5328 case eCSSProperty_border_right_style_value
: // for internal use
5329 case eCSSProperty_border_start_style_value
: // for internal use
5330 case eCSSProperty_border_top_style
:
5331 case eCSSProperty__moz_column_rule_style
:
5332 return ParseVariant(aValue
, VARIANT_HOK
,
5333 nsCSSProps::kBorderStyleKTable
);
5334 case eCSSProperty_border_bottom_width
:
5335 case eCSSProperty_border_end_width_value
: // for internal use
5336 case eCSSProperty_border_left_width_value
: // for internal use
5337 case eCSSProperty_border_right_width_value
: // for internal use
5338 case eCSSProperty_border_start_width_value
: // for internal use
5339 case eCSSProperty_border_top_width
:
5340 case eCSSProperty__moz_column_rule_width
:
5341 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5342 nsCSSProps::kBorderWidthKTable
);
5343 case eCSSProperty__moz_column_count
:
5344 return ParsePositiveVariant(aValue
, VARIANT_AHI
, nsnull
);
5345 case eCSSProperty__moz_column_width
:
5346 return ParsePositiveVariant(aValue
, VARIANT_AHL
, nsnull
);
5347 case eCSSProperty__moz_column_gap
:
5348 return ParsePositiveVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5349 case eCSSProperty_bottom
:
5350 case eCSSProperty_top
:
5351 case eCSSProperty_left
:
5352 case eCSSProperty_right
:
5353 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5354 case eCSSProperty_box_align
:
5355 return ParseVariant(aValue
, VARIANT_HK
,
5356 nsCSSProps::kBoxAlignKTable
);
5357 case eCSSProperty_box_direction
:
5358 return ParseVariant(aValue
, VARIANT_HK
,
5359 nsCSSProps::kBoxDirectionKTable
);
5360 case eCSSProperty_box_flex
:
5361 return ParsePositiveVariant(aValue
, VARIANT_HN
, nsnull
);
5362 case eCSSProperty_box_orient
:
5363 return ParseVariant(aValue
, VARIANT_HK
,
5364 nsCSSProps::kBoxOrientKTable
);
5365 case eCSSProperty_box_pack
:
5366 return ParseVariant(aValue
, VARIANT_HK
,
5367 nsCSSProps::kBoxPackKTable
);
5368 case eCSSProperty_box_ordinal_group
:
5369 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5371 case eCSSProperty_clip_path
:
5372 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5373 case eCSSProperty_clip_rule
:
5374 return ParseVariant(aValue
, VARIANT_HK
,
5375 nsCSSProps::kFillRuleKTable
);
5376 case eCSSProperty_color_interpolation
:
5377 case eCSSProperty_color_interpolation_filters
:
5378 return ParseVariant(aValue
, VARIANT_AHK
,
5379 nsCSSProps::kColorInterpolationKTable
);
5380 case eCSSProperty_dominant_baseline
:
5381 return ParseVariant(aValue
, VARIANT_AHK
,
5382 nsCSSProps::kDominantBaselineKTable
);
5383 case eCSSProperty_fill_opacity
:
5384 return ParseVariant(aValue
, VARIANT_HN
,
5386 case eCSSProperty_fill_rule
:
5387 return ParseVariant(aValue
, VARIANT_HK
,
5388 nsCSSProps::kFillRuleKTable
);
5389 case eCSSProperty_filter
:
5390 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5391 case eCSSProperty_flood_color
:
5392 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5393 case eCSSProperty_flood_opacity
:
5394 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5395 case eCSSProperty_lighting_color
:
5396 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5397 case eCSSProperty_marker_end
:
5398 case eCSSProperty_marker_mid
:
5399 case eCSSProperty_marker_start
:
5400 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5401 case eCSSProperty_mask
:
5402 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5403 case eCSSProperty_pointer_events
:
5404 return ParseVariant(aValue
, VARIANT_HOK
,
5405 nsCSSProps::kPointerEventsKTable
);
5406 case eCSSProperty_shape_rendering
:
5407 return ParseVariant(aValue
, VARIANT_AHK
,
5408 nsCSSProps::kShapeRenderingKTable
);
5409 case eCSSProperty_stop_color
:
5410 return ParseVariant(aValue
, VARIANT_HC
,
5412 case eCSSProperty_stop_opacity
:
5413 return ParseVariant(aValue
, VARIANT_HN
,
5415 case eCSSProperty_stroke_dashoffset
:
5416 return ParseVariant(aValue
, VARIANT_HLPN
,
5418 case eCSSProperty_stroke_linecap
:
5419 return ParseVariant(aValue
, VARIANT_HK
,
5420 nsCSSProps::kStrokeLinecapKTable
);
5421 case eCSSProperty_stroke_linejoin
:
5422 return ParseVariant(aValue
, VARIANT_HK
,
5423 nsCSSProps::kStrokeLinejoinKTable
);
5424 case eCSSProperty_stroke_miterlimit
:
5425 return ParsePositiveVariant(aValue
, VARIANT_HN
,
5427 case eCSSProperty_stroke_opacity
:
5428 return ParseVariant(aValue
, VARIANT_HN
,
5430 case eCSSProperty_stroke_width
:
5431 return ParsePositiveVariant(aValue
, VARIANT_HLPN
,
5433 case eCSSProperty_text_anchor
:
5434 return ParseVariant(aValue
, VARIANT_HK
,
5435 nsCSSProps::kTextAnchorKTable
);
5436 case eCSSProperty_text_rendering
:
5437 return ParseVariant(aValue
, VARIANT_AHK
,
5438 nsCSSProps::kTextRenderingKTable
);
5440 case eCSSProperty_box_sizing
:
5441 return ParseVariant(aValue
, VARIANT_HK
,
5442 nsCSSProps::kBoxSizingKTable
);
5443 case eCSSProperty_height
:
5444 return ParsePositiveVariant(aValue
, VARIANT_AHLP
, nsnull
);
5445 case eCSSProperty_width
:
5446 return ParsePositiveVariant(aValue
, VARIANT_AHKLP
,
5447 nsCSSProps::kWidthKTable
);
5448 case eCSSProperty_force_broken_image_icon
:
5449 return ParsePositiveVariant(aValue
, VARIANT_HI
, nsnull
);
5450 case eCSSProperty_caption_side
:
5451 return ParseVariant(aValue
, VARIANT_HK
,
5452 nsCSSProps::kCaptionSideKTable
);
5453 case eCSSProperty_clear
:
5454 return ParseVariant(aValue
, VARIANT_HOK
,
5455 nsCSSProps::kClearKTable
);
5456 case eCSSProperty_color
:
5457 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5458 case eCSSProperty_cue_after
:
5459 case eCSSProperty_cue_before
:
5460 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5461 case eCSSProperty_direction
:
5462 return ParseVariant(aValue
, VARIANT_HK
,
5463 nsCSSProps::kDirectionKTable
);
5464 case eCSSProperty_display
:
5465 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kDisplayKTable
)) {
5466 if (aValue
.GetUnit() == eCSSUnit_Enumerated
) {
5467 switch (aValue
.GetIntValue()) {
5468 case NS_STYLE_DISPLAY_MARKER
: // bug 2055
5469 case NS_STYLE_DISPLAY_RUN_IN
: // bug 2056
5470 case NS_STYLE_DISPLAY_COMPACT
: // bug 14983
5477 case eCSSProperty_elevation
:
5478 return ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5479 nsCSSProps::kElevationKTable
);
5480 case eCSSProperty_empty_cells
:
5481 return ParseVariant(aValue
, VARIANT_HK
,
5482 nsCSSProps::kEmptyCellsKTable
);
5483 case eCSSProperty_float
:
5484 return ParseVariant(aValue
, VARIANT_HOK
,
5485 nsCSSProps::kFloatKTable
);
5486 case eCSSProperty_float_edge
:
5487 return ParseVariant(aValue
, VARIANT_HK
,
5488 nsCSSProps::kFloatEdgeKTable
);
5489 case eCSSProperty_font_family
:
5490 return ParseFamily(aValue
);
5491 case eCSSProperty_font_size
:
5492 return ParsePositiveVariant(aValue
,
5493 VARIANT_HKLP
| VARIANT_SYSFONT
,
5494 nsCSSProps::kFontSizeKTable
);
5495 case eCSSProperty_font_size_adjust
:
5496 return ParseVariant(aValue
, VARIANT_HON
| VARIANT_SYSFONT
,
5498 case eCSSProperty_font_stretch
:
5499 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5500 nsCSSProps::kFontStretchKTable
);
5501 case eCSSProperty_font_style
:
5502 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5503 nsCSSProps::kFontStyleKTable
);
5504 case eCSSProperty_font_variant
:
5505 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5506 nsCSSProps::kFontVariantKTable
);
5507 case eCSSProperty_font_weight
:
5508 return ParseFontWeight(aValue
);
5509 case eCSSProperty_ime_mode
:
5510 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NORMAL
,
5511 nsCSSProps::kIMEModeKTable
);
5512 case eCSSProperty_letter_spacing
:
5513 case eCSSProperty_word_spacing
:
5514 return ParseVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5515 case eCSSProperty_line_height
:
5516 return ParsePositiveVariant(aValue
, VARIANT_HLPN
| VARIANT_NORMAL
| VARIANT_SYSFONT
, nsnull
);
5517 case eCSSProperty_list_style_image
:
5518 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5519 case eCSSProperty_list_style_position
:
5520 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kListStylePositionKTable
);
5521 case eCSSProperty_list_style_type
:
5522 return ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kListStyleKTable
);
5523 case eCSSProperty_margin_bottom
:
5524 case eCSSProperty_margin_end_value
: // for internal use
5525 case eCSSProperty_margin_left_value
: // for internal use
5526 case eCSSProperty_margin_right_value
: // for internal use
5527 case eCSSProperty_margin_start_value
: // for internal use
5528 case eCSSProperty_margin_top
:
5529 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5530 case eCSSProperty_marker_offset
:
5531 return ParseVariant(aValue
, VARIANT_AHL
, nsnull
);
5532 case eCSSProperty_marks
:
5533 return ParseMarks(aValue
);
5534 case eCSSProperty_max_height
:
5535 return ParsePositiveVariant(aValue
, VARIANT_HLPO
, nsnull
);
5536 case eCSSProperty_max_width
:
5537 return ParsePositiveVariant(aValue
, VARIANT_HKLPO
,
5538 nsCSSProps::kWidthKTable
);
5539 case eCSSProperty_min_height
:
5540 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5541 case eCSSProperty_min_width
:
5542 return ParsePositiveVariant(aValue
, VARIANT_HKLP
,
5543 nsCSSProps::kWidthKTable
);
5544 case eCSSProperty_opacity
:
5545 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5546 case eCSSProperty_orphans
:
5547 case eCSSProperty_widows
:
5548 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5549 case eCSSProperty_outline_color
:
5550 return ParseVariant(aValue
, VARIANT_HCK
,
5551 nsCSSProps::kOutlineColorKTable
);
5552 case eCSSProperty_outline_style
:
5553 return ParseVariant(aValue
, VARIANT_HOK
| VARIANT_AUTO
,
5554 nsCSSProps::kOutlineStyleKTable
);
5555 case eCSSProperty_outline_width
:
5556 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5557 nsCSSProps::kBorderWidthKTable
);
5558 case eCSSProperty_outline_offset
:
5559 return ParseVariant(aValue
, VARIANT_HL
, nsnull
);
5560 case eCSSProperty_overflow_x
:
5561 case eCSSProperty_overflow_y
:
5562 return ParseVariant(aValue
, VARIANT_AHK
,
5563 nsCSSProps::kOverflowSubKTable
);
5564 case eCSSProperty_padding_bottom
:
5565 case eCSSProperty_padding_end_value
: // for internal use
5566 case eCSSProperty_padding_left_value
: // for internal use
5567 case eCSSProperty_padding_right_value
: // for internal use
5568 case eCSSProperty_padding_start_value
: // for internal use
5569 case eCSSProperty_padding_top
:
5570 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5571 case eCSSProperty_page
:
5572 return ParseVariant(aValue
, VARIANT_AUTO
| VARIANT_IDENTIFIER
, nsnull
);
5573 case eCSSProperty_page_break_after
:
5574 case eCSSProperty_page_break_before
:
5575 return ParseVariant(aValue
, VARIANT_AHK
,
5576 nsCSSProps::kPageBreakKTable
);
5577 case eCSSProperty_page_break_inside
:
5578 return ParseVariant(aValue
, VARIANT_AHK
,
5579 nsCSSProps::kPageBreakInsideKTable
);
5580 case eCSSProperty_pause_after
:
5581 case eCSSProperty_pause_before
:
5582 return ParseVariant(aValue
, VARIANT_HTP
, nsnull
);
5583 case eCSSProperty_pitch
:
5584 return ParseVariant(aValue
, VARIANT_HKF
, nsCSSProps::kPitchKTable
);
5585 case eCSSProperty_pitch_range
:
5586 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5587 case eCSSProperty_position
:
5588 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kPositionKTable
);
5589 case eCSSProperty_richness
:
5590 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5592 // script-level can take Integer or Number values, but only Integer ("relative")
5593 // values can be specified in a style sheet. Also we only allow this property
5594 // when unsafe rules are enabled, because otherwise it could interfere
5595 // with rulenode optimizations if used in a non-MathML-enabled document.
5596 case eCSSProperty_script_level
:
5597 if (!mUnsafeRulesEnabled
)
5599 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5601 case eCSSProperty_speak
:
5602 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5603 nsCSSProps::kSpeakKTable
);
5604 case eCSSProperty_speak_header
:
5605 return ParseVariant(aValue
, VARIANT_HK
,
5606 nsCSSProps::kSpeakHeaderKTable
);
5607 case eCSSProperty_speak_numeral
:
5608 return ParseVariant(aValue
, VARIANT_HK
,
5609 nsCSSProps::kSpeakNumeralKTable
);
5610 case eCSSProperty_speak_punctuation
:
5611 return ParseVariant(aValue
, VARIANT_HOK
,
5612 nsCSSProps::kSpeakPunctuationKTable
);
5613 case eCSSProperty_speech_rate
:
5614 return ParseVariant(aValue
, VARIANT_HN
| VARIANT_KEYWORD
,
5615 nsCSSProps::kSpeechRateKTable
);
5616 case eCSSProperty_stack_sizing
:
5617 return ParseVariant(aValue
, VARIANT_HK
,
5618 nsCSSProps::kStackSizingKTable
);
5619 case eCSSProperty_stress
:
5620 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5621 case eCSSProperty_table_layout
:
5622 return ParseVariant(aValue
, VARIANT_AHK
,
5623 nsCSSProps::kTableLayoutKTable
);
5624 case eCSSProperty_text_align
:
5625 // When we support aligning on a string, we can parse text-align
5627 return ParseVariant(aValue
, VARIANT_HK
/* | VARIANT_STRING */,
5628 nsCSSProps::kTextAlignKTable
);
5629 case eCSSProperty_text_decoration
:
5630 return ParseTextDecoration(aValue
);
5631 case eCSSProperty_text_indent
:
5632 return ParseVariant(aValue
, VARIANT_HLP
, nsnull
);
5633 case eCSSProperty_text_transform
:
5634 return ParseVariant(aValue
, VARIANT_HOK
,
5635 nsCSSProps::kTextTransformKTable
);
5636 case eCSSProperty_unicode_bidi
:
5637 return ParseVariant(aValue
, VARIANT_HMK
,
5638 nsCSSProps::kUnicodeBidiKTable
);
5639 case eCSSProperty_user_focus
:
5640 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5641 nsCSSProps::kUserFocusKTable
);
5642 case eCSSProperty_user_input
:
5643 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5644 nsCSSProps::kUserInputKTable
);
5645 case eCSSProperty_user_modify
:
5646 return ParseVariant(aValue
, VARIANT_HK
,
5647 nsCSSProps::kUserModifyKTable
);
5648 case eCSSProperty_user_select
:
5649 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5650 nsCSSProps::kUserSelectKTable
);
5651 case eCSSProperty_vertical_align
:
5652 return ParseVariant(aValue
, VARIANT_HKLP
,
5653 nsCSSProps::kVerticalAlignKTable
);
5654 case eCSSProperty_visibility
:
5655 return ParseVariant(aValue
, VARIANT_HK
,
5656 nsCSSProps::kVisibilityKTable
);
5657 case eCSSProperty_voice_family
:
5658 return ParseFamily(aValue
);
5659 case eCSSProperty_volume
:
5660 return ParseVariant(aValue
, VARIANT_HPN
| VARIANT_KEYWORD
,
5661 nsCSSProps::kVolumeKTable
);
5662 case eCSSProperty_white_space
:
5663 return ParseVariant(aValue
, VARIANT_HMK
,
5664 nsCSSProps::kWhitespaceKTable
);
5665 case eCSSProperty__moz_window_shadow
:
5666 return ParseVariant(aValue
, VARIANT_HOK
,
5667 nsCSSProps::kWindowShadowKTable
);
5668 case eCSSProperty_word_wrap
:
5669 return ParseVariant(aValue
, VARIANT_HMK
,
5670 nsCSSProps::kWordwrapKTable
);
5671 case eCSSProperty_z_index
:
5672 return ParseVariant(aValue
, VARIANT_AHI
, nsnull
);
5674 // explicitly do NOT have a default case to let the compiler
5675 // help find missing properties
5679 // nsFont::EnumerateFamilies callback for ParseFontDescriptorValue
5680 struct NS_STACK_CLASS ExtractFirstFamilyData
{
5681 nsAutoString mFamilyName
;
5683 ExtractFirstFamilyData() : mFamilyName(), mGood(PR_FALSE
) {}
5687 ExtractFirstFamily(const nsString
& aFamily
,
5691 ExtractFirstFamilyData
* realData
= (ExtractFirstFamilyData
*) aData
;
5692 if (aGeneric
|| realData
->mFamilyName
.Length() > 0) {
5693 realData
->mGood
= PR_FALSE
;
5696 realData
->mFamilyName
.Assign(aFamily
);
5697 realData
->mGood
= PR_TRUE
;
5701 // font-descriptor: descriptor ':' value ';'
5702 // caller has advanced mToken to point at the descriptor
5704 CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
5708 // These four are similar to the properties of the same name,
5709 // possibly with more restrictions on the values they can take.
5710 case eCSSFontDesc_Family
: {
5711 if (!ParseFamily(aValue
) ||
5712 aValue
.GetUnit() != eCSSUnit_String
)
5715 // the style parameters to the nsFont constructor are ignored,
5716 // because it's only being used to call EnumerateFamilies
5717 nsAutoString valueStr
;
5718 aValue
.GetStringValue(valueStr
);
5719 nsFont
font(valueStr
, 0, 0, 0, 0, 0);
5720 ExtractFirstFamilyData dat
;
5722 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
5726 aValue
.SetStringValue(dat
.mFamilyName
, eCSSUnit_String
);
5730 case eCSSFontDesc_Style
:
5731 // property is VARIANT_HMK|VARIANT_SYSFONT
5732 return ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5733 nsCSSProps::kFontStyleKTable
);
5735 case eCSSFontDesc_Weight
:
5736 return (ParseFontWeight(aValue
) &&
5737 aValue
.GetUnit() != eCSSUnit_Inherit
&&
5738 aValue
.GetUnit() != eCSSUnit_Initial
&&
5739 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5740 (aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER
&&
5741 aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER
)));
5743 case eCSSFontDesc_Stretch
:
5744 // property is VARIANT_HMK|VARIANT_SYSFONT
5745 return (ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5746 nsCSSProps::kFontStretchKTable
) &&
5747 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5748 (aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_WIDER
&&
5749 aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_NARROWER
)));
5751 // These two are unique to @font-face and have their own special grammar.
5752 case eCSSFontDesc_Src
:
5753 return ParseFontSrc(aValue
);
5755 case eCSSFontDesc_UnicodeRange
:
5756 return ParseFontRanges(aValue
);
5758 case eCSSFontDesc_UNKNOWN
:
5759 case eCSSFontDesc_COUNT
:
5760 NS_NOTREACHED("bad nsCSSFontDesc code");
5762 // explicitly do NOT have a default case to let the compiler
5763 // help find missing descriptors
5768 CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
)
5770 nsCSSValue
physical(NS_BOXPROP_SOURCE_PHYSICAL
, eCSSUnit_Enumerated
);
5771 for (const nsCSSProperty
*prop
= aSourceProperties
;
5772 *prop
!= eCSSProperty_UNKNOWN
; ++prop
) {
5773 AppendValue(*prop
, physical
);
5778 CSSParserImpl::ParseAzimuth(nsCSSValue
& aValue
)
5780 if (ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5781 nsCSSProps::kAzimuthKTable
)) {
5782 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
5783 PRInt32 intValue
= aValue
.GetIntValue();
5784 if ((NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) &&
5785 (intValue
<= NS_STYLE_AZIMUTH_BEHIND
)) { // look for optional modifier
5786 nsCSSValue modifier
;
5787 if (ParseEnum(modifier
, nsCSSProps::kAzimuthKTable
)) {
5788 PRInt32 enumValue
= modifier
.GetIntValue();
5789 if (((intValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5790 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= enumValue
) && (enumValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
)) ||
5791 ((enumValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5792 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) && (intValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
))) {
5793 aValue
.SetIntValue(intValue
| enumValue
, eCSSUnit_Enumerated
);
5796 // Put the unknown identifier back and return
5808 BoxPositionMaskToCSSValue(PRInt32 aMask
, PRBool isX
)
5810 PRInt32 val
= NS_STYLE_BG_POSITION_CENTER
;
5812 if (aMask
& BG_LEFT
) {
5813 val
= NS_STYLE_BG_POSITION_LEFT
;
5815 else if (aMask
& BG_RIGHT
) {
5816 val
= NS_STYLE_BG_POSITION_RIGHT
;
5820 if (aMask
& BG_TOP
) {
5821 val
= NS_STYLE_BG_POSITION_TOP
;
5823 else if (aMask
& BG_BOTTOM
) {
5824 val
= NS_STYLE_BG_POSITION_BOTTOM
;
5828 return nsCSSValue(val
, eCSSUnit_Enumerated
);
5832 CSSParserImpl::ParseBackground()
5834 nsAutoParseCompoundProperty
compound(this);
5836 // Fill in the values that the shorthand will set if we don't find
5838 mTempData
.mColor
.mBackColor
.SetColorValue(NS_RGBA(0, 0, 0, 0));
5839 mTempData
.SetPropertyBit(eCSSProperty_background_color
);
5840 mTempData
.mColor
.mBackImage
.SetNoneValue();
5841 mTempData
.SetPropertyBit(eCSSProperty_background_image
);
5842 mTempData
.mColor
.mBackRepeat
.SetIntValue(NS_STYLE_BG_REPEAT_XY
,
5843 eCSSUnit_Enumerated
);
5844 mTempData
.SetPropertyBit(eCSSProperty_background_repeat
);
5845 mTempData
.mColor
.mBackAttachment
.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL
,
5846 eCSSUnit_Enumerated
);
5847 mTempData
.SetPropertyBit(eCSSProperty_background_attachment
);
5848 mTempData
.mColor
.mBackPosition
.mXValue
.SetPercentValue(0.0f
);
5849 mTempData
.mColor
.mBackPosition
.mYValue
.SetPercentValue(0.0f
);
5850 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
5851 // including the ones that we can't set from the shorthand.
5852 mTempData
.mColor
.mBackClip
.SetIntValue(NS_STYLE_BG_CLIP_BORDER
,
5853 eCSSUnit_Enumerated
);
5854 mTempData
.SetPropertyBit(eCSSProperty__moz_background_clip
);
5855 mTempData
.mColor
.mBackOrigin
.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING
,
5856 eCSSUnit_Enumerated
);
5857 mTempData
.SetPropertyBit(eCSSProperty__moz_background_origin
);
5858 mTempData
.mColor
.mBackInlinePolicy
.SetIntValue(
5859 NS_STYLE_BG_INLINE_POLICY_CONTINUOUS
, eCSSUnit_Enumerated
);
5860 mTempData
.SetPropertyBit(eCSSProperty__moz_background_inline_policy
);
5862 // XXX If ParseSingleValueProperty were table-driven (bug 376079) and
5863 // automatically filled in the right field of mTempData, we could move
5864 // ParseBackgroundPosition to it (as a special case) and switch back
5865 // to using ParseChoice here.
5867 PRBool haveColor
= PR_FALSE
,
5868 haveImage
= PR_FALSE
,
5869 haveRepeat
= PR_FALSE
,
5870 haveAttach
= PR_FALSE
,
5871 havePosition
= PR_FALSE
;
5872 while (GetToken(PR_TRUE
)) {
5873 nsCSSTokenType tt
= mToken
.mType
;
5874 UngetToken(); // ...but we'll still cheat and use mToken
5875 if (tt
== eCSSToken_Symbol
) {
5876 // ExpectEndProperty only looks for symbols, and nothing else will
5881 if (tt
== eCSSToken_Ident
) {
5882 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
5884 if (keyword
== eCSSKeyword_inherit
||
5885 keyword
== eCSSKeyword__moz_initial
) {
5886 if (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
)
5888 haveColor
= haveImage
= haveRepeat
= haveAttach
= havePosition
=
5890 GetToken(PR_TRUE
); // undo the UngetToken above
5892 if (keyword
== eCSSKeyword_inherit
) {
5893 val
.SetInheritValue();
5895 val
.SetInitialValue();
5897 mTempData
.mColor
.mBackColor
= val
;
5898 mTempData
.mColor
.mBackImage
= val
;
5899 mTempData
.mColor
.mBackRepeat
= val
;
5900 mTempData
.mColor
.mBackAttachment
= val
;
5901 mTempData
.mColor
.mBackPosition
.mXValue
= val
;
5902 mTempData
.mColor
.mBackPosition
.mYValue
= val
;
5903 // Reset (for 'inherit') the 3 properties that can't be
5904 // specified, although it's not entirely clear in the spec:
5905 // http://lists.w3.org/Archives/Public/www-style/2007Mar/0110
5906 mTempData
.mColor
.mBackClip
= val
;
5907 mTempData
.mColor
.mBackOrigin
= val
;
5908 mTempData
.mColor
.mBackInlinePolicy
= val
;
5910 } else if (keyword
== eCSSKeyword_none
) {
5913 haveImage
= PR_TRUE
;
5914 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5915 eCSSProperty_background_image
)) {
5916 NS_NOTREACHED("should be able to parse");
5919 } else if (nsCSSProps::FindKeyword(keyword
,
5920 nsCSSProps::kBackgroundAttachmentKTable
, dummy
)) {
5923 haveAttach
= PR_TRUE
;
5924 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackAttachment
,
5925 eCSSProperty_background_attachment
)) {
5926 NS_NOTREACHED("should be able to parse");
5929 } else if (nsCSSProps::FindKeyword(keyword
,
5930 nsCSSProps::kBackgroundRepeatKTable
, dummy
)) {
5933 haveRepeat
= PR_TRUE
;
5934 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackRepeat
,
5935 eCSSProperty_background_repeat
)) {
5936 NS_NOTREACHED("should be able to parse");
5939 } else if (nsCSSProps::FindKeyword(keyword
,
5940 nsCSSProps::kBackgroundPositionKTable
, dummy
)) {
5943 havePosition
= PR_TRUE
;
5944 if (!ParseBackgroundPositionValues()) {
5950 haveColor
= PR_TRUE
;
5951 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5952 eCSSProperty_background_color
)) {
5956 } else if (eCSSToken_Function
== tt
&&
5957 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
5960 haveImage
= PR_TRUE
;
5961 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5962 eCSSProperty_background_image
)) {
5965 } else if (mToken
.IsDimension() || tt
== eCSSToken_Percentage
) {
5968 havePosition
= PR_TRUE
;
5969 if (!ParseBackgroundPositionValues()) {
5975 haveColor
= PR_TRUE
;
5976 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5977 eCSSProperty_background_color
)) {
5983 return ExpectEndProperty() &&
5984 (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
);
5988 CSSParserImpl::ParseBackgroundPosition()
5990 if (!ParseBoxPosition(mTempData
.mColor
.mBackPosition
))
5992 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
5997 CSSParserImpl::ParseBackgroundPositionValues()
5999 return ParseBoxPositionValues(mTempData
.mColor
.mBackPosition
);
6003 * Parses two values that correspond to positions in a box. These can be
6004 * values corresponding to percentages of the box, raw offsets, or keywords
6005 * like "top," "left center," etc.
6007 * @param aOut The nsCSSValuePair where to place the result.
6008 * @return Whether or not the operation succeeded.
6010 PRBool
CSSParserImpl::ParseBoxPosition(nsCSSValuePair
&aOut
)
6012 // Need to read the box positions and the end of the property.
6013 return ParseBoxPositionValues(aOut
) && ExpectEndProperty();
6016 PRBool
CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair
&aOut
)
6018 // First try a percentage or a length value
6019 nsCSSValue
&xValue
= aOut
.mXValue
,
6020 &yValue
= aOut
.mYValue
;
6021 if (ParseVariant(xValue
, VARIANT_HLP
, nsnull
)) {
6022 if (eCSSUnit_Inherit
== xValue
.GetUnit() ||
6023 eCSSUnit_Initial
== xValue
.GetUnit()) { // both are inherited or both are set to initial
6027 // We have one percentage/length. Get the optional second
6028 // percentage/length/keyword.
6029 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
6030 // We have two numbers
6034 if (ParseEnum(yValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6035 PRInt32 yVal
= yValue
.GetIntValue();
6036 if (!(yVal
& BG_CTB
)) {
6037 // The second keyword can only be 'center', 'top', or 'bottom'
6040 yValue
= BoxPositionMaskToCSSValue(yVal
, PR_FALSE
);
6044 // If only one percentage or length value is given, it sets the
6045 // horizontal position only, and the vertical position will be 50%.
6046 yValue
.SetPercentValue(0.5f
);
6050 // Now try keywords. We do this manually to allow for the first
6051 // appearance of "center" to apply to the either the x or y
6052 // position (it's ambiguous so we have to disambiguate). Each
6053 // allowed keyword value is assigned it's own bit. We don't allow
6054 // any duplicate keywords other than center. We try to get two
6055 // keywords but it's okay if there is only one.
6057 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6058 PRInt32 bit
= xValue
.GetIntValue();
6060 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6061 bit
= xValue
.GetIntValue();
6062 if (mask
& (bit
& ~BG_CENTER
)) {
6063 // Only the 'center' keyword can be duplicated.
6069 // Only one keyword. See if we have a length or percentage.
6070 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
6071 if (!(mask
& BG_CLR
)) {
6072 // The first keyword can only be 'center', 'left', or 'right'
6076 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
6082 // Check for bad input. Bad input consists of no matching keywords,
6083 // or pairs of x keywords or pairs of y keywords.
6084 if ((mask
== 0) || (mask
== (BG_TOP
| BG_BOTTOM
)) ||
6085 (mask
== (BG_LEFT
| BG_RIGHT
))) {
6089 // Create style values
6090 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
6091 yValue
= BoxPositionMaskToCSSValue(mask
, PR_FALSE
);
6096 CSSParserImpl::ParseBorderColor()
6098 static const nsCSSProperty kBorderColorSources
[] = {
6099 eCSSProperty_border_left_color_ltr_source
,
6100 eCSSProperty_border_left_color_rtl_source
,
6101 eCSSProperty_border_right_color_ltr_source
,
6102 eCSSProperty_border_right_color_rtl_source
,
6103 eCSSProperty_UNKNOWN
6106 // do this now, in case 4 values weren't specified
6107 InitBoxPropsAsPhysical(kBorderColorSources
);
6108 return ParseBoxProperties(mTempData
.mMargin
.mBorderColor
,
6113 CSSParserImpl::ParseBorderImage()
6115 if (ParseVariant(mTempData
.mMargin
.mBorderImage
,
6116 VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
6117 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
6121 // <uri> [<number> | <percentage>]{1,4} [ / <border-width>{1,4} ]? [stretch | repeat | round]{0,2}
6122 nsRefPtr
<nsCSSValue::Array
> arr
= nsCSSValue::Array::Create(11);
6124 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6128 nsCSSValue
& url
= arr
->Item(0);
6129 nsCSSValue
& splitTop
= arr
->Item(1);
6130 nsCSSValue
& splitRight
= arr
->Item(2);
6131 nsCSSValue
& splitBottom
= arr
->Item(3);
6132 nsCSSValue
& splitLeft
= arr
->Item(4);
6133 nsCSSValue
& borderWidthTop
= arr
->Item(5);
6134 nsCSSValue
& borderWidthRight
= arr
->Item(6);
6135 nsCSSValue
& borderWidthBottom
= arr
->Item(7);
6136 nsCSSValue
& borderWidthLeft
= arr
->Item(8);
6137 nsCSSValue
& horizontalKeyword
= arr
->Item(9);
6138 nsCSSValue
& verticalKeyword
= arr
->Item(10);
6141 if (!ParseVariant(url
, VARIANT_URL
, nsnull
)) {
6145 // [<number> | <percentage>]{1,4}
6146 if (!ParsePositiveVariant(splitTop
,
6147 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6150 if (!ParsePositiveVariant(splitRight
,
6151 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6152 splitRight
= splitTop
;
6154 if (!ParsePositiveVariant(splitBottom
,
6155 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6156 splitBottom
= splitTop
;
6158 if (!ParsePositiveVariant(splitLeft
,
6159 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6160 splitLeft
= splitRight
;
6163 // [ / <border-width>{1,4} ]?
6164 if (ExpectSymbol('/', PR_TRUE
)) {
6165 // if have '/', at least one value is required
6166 if (!ParsePositiveVariant(borderWidthTop
, VARIANT_LENGTH
, nsnull
)) {
6169 if (!ParsePositiveVariant(borderWidthRight
, VARIANT_LENGTH
, nsnull
)) {
6170 borderWidthRight
= borderWidthTop
;
6172 if (!ParsePositiveVariant(borderWidthBottom
, VARIANT_LENGTH
, nsnull
)) {
6173 borderWidthBottom
= borderWidthTop
;
6175 if (!ParsePositiveVariant(borderWidthLeft
, VARIANT_LENGTH
, nsnull
)) {
6176 borderWidthLeft
= borderWidthRight
;
6180 // [stretch | repeat | round]{0,2}
6181 // missing keywords are handled in nsRuleNode::ComputeBorderData()
6182 if (ParseEnum(horizontalKeyword
, nsCSSProps::kBorderImageKTable
)) {
6183 ParseEnum(verticalKeyword
, nsCSSProps::kBorderImageKTable
);
6186 if (!ExpectEndProperty()) {
6190 mTempData
.mMargin
.mBorderImage
.SetArrayValue(arr
, eCSSUnit_Array
);
6191 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
6197 CSSParserImpl::ParseBorderSpacing()
6200 if (ParsePositiveVariant(xValue
, VARIANT_HL
, nsnull
)) {
6201 if (xValue
.IsLengthUnit()) {
6202 // We have one length. Get the optional second length.
6204 if (ParsePositiveVariant(yValue
, VARIANT_LENGTH
, nsnull
)) {
6205 // We have two numbers
6206 if (ExpectEndProperty()) {
6207 mTempData
.mTable
.mBorderSpacing
.mXValue
= xValue
;
6208 mTempData
.mTable
.mBorderSpacing
.mYValue
= yValue
;
6209 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6216 // We have one length which is the horizontal spacing. Create a value for
6217 // the vertical spacing which is equal
6218 if (ExpectEndProperty()) {
6219 mTempData
.mTable
.mBorderSpacing
.SetBothValuesTo(xValue
);
6220 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6228 CSSParserImpl::ParseBorderSide(const nsCSSProperty aPropIDs
[],
6229 PRBool aSetAllSides
)
6231 const PRInt32 numProps
= 3;
6232 nsCSSValue values
[numProps
];
6234 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6235 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6239 if ((found
& 1) == 0) { // Provide default border-width
6240 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6242 if ((found
& 2) == 0) { // Provide default border-style
6243 values
[1].SetNoneValue();
6245 if ((found
& 4) == 0) { // text color will be used
6246 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6250 static const nsCSSProperty kBorderSources
[] = {
6251 eCSSProperty_border_left_color_ltr_source
,
6252 eCSSProperty_border_left_color_rtl_source
,
6253 eCSSProperty_border_right_color_ltr_source
,
6254 eCSSProperty_border_right_color_rtl_source
,
6255 eCSSProperty_border_left_style_ltr_source
,
6256 eCSSProperty_border_left_style_rtl_source
,
6257 eCSSProperty_border_right_style_ltr_source
,
6258 eCSSProperty_border_right_style_rtl_source
,
6259 eCSSProperty_border_left_width_ltr_source
,
6260 eCSSProperty_border_left_width_rtl_source
,
6261 eCSSProperty_border_right_width_ltr_source
,
6262 eCSSProperty_border_right_width_rtl_source
,
6263 eCSSProperty_UNKNOWN
6266 InitBoxPropsAsPhysical(kBorderSources
);
6268 // Parsing "border" shorthand; set all four sides to the same thing
6269 for (PRInt32 index
= 0; index
< 4; index
++) {
6270 NS_ASSERTION(numProps
== 3, "This code needs updating");
6271 AppendValue(kBorderWidthIDs
[index
], values
[0]);
6272 AppendValue(kBorderStyleIDs
[index
], values
[1]);
6273 AppendValue(kBorderColorIDs
[index
], values
[2]);
6277 // Just set our one side
6278 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6279 AppendValue(aPropIDs
[index
], values
[index
]);
6286 CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
6287 PRInt32 aSourceType
)
6289 const PRInt32 numProps
= 3;
6290 nsCSSValue values
[numProps
];
6292 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6293 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6297 if ((found
& 1) == 0) { // Provide default border-width
6298 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6300 if ((found
& 2) == 0) { // Provide default border-style
6301 values
[1].SetNoneValue();
6303 if ((found
& 4) == 0) { // text color will be used
6304 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6306 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6307 const nsCSSProperty
* subprops
=
6308 nsCSSProps::SubpropertyEntryFor(aPropIDs
[index
+ numProps
]);
6309 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
6310 "not box property with physical vs. logical cascading");
6311 AppendValue(subprops
[0], values
[index
]);
6312 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
6313 AppendValue(subprops
[1], typeVal
);
6314 AppendValue(subprops
[2], typeVal
);
6320 CSSParserImpl::ParseBorderStyle()
6322 static const nsCSSProperty kBorderStyleSources
[] = {
6323 eCSSProperty_border_left_style_ltr_source
,
6324 eCSSProperty_border_left_style_rtl_source
,
6325 eCSSProperty_border_right_style_ltr_source
,
6326 eCSSProperty_border_right_style_rtl_source
,
6327 eCSSProperty_UNKNOWN
6330 // do this now, in case 4 values weren't specified
6331 InitBoxPropsAsPhysical(kBorderStyleSources
);
6332 return ParseBoxProperties(mTempData
.mMargin
.mBorderStyle
,
6337 CSSParserImpl::ParseBorderWidth()
6339 static const nsCSSProperty kBorderWidthSources
[] = {
6340 eCSSProperty_border_left_width_ltr_source
,
6341 eCSSProperty_border_left_width_rtl_source
,
6342 eCSSProperty_border_right_width_ltr_source
,
6343 eCSSProperty_border_right_width_rtl_source
,
6344 eCSSProperty_UNKNOWN
6347 // do this now, in case 4 values weren't specified
6348 InitBoxPropsAsPhysical(kBorderWidthSources
);
6349 return ParseBoxProperties(mTempData
.mMargin
.mBorderWidth
,
6354 CSSParserImpl::ParseBorderColors(nsCSSValueList
** aResult
,
6355 nsCSSProperty aProperty
)
6358 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6359 nsCSSValueList
* listHead
= new nsCSSValueList();
6360 nsCSSValueList
* list
= listHead
;
6362 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6365 list
->mValue
= value
;
6368 if (ExpectEndProperty()) {
6369 mTempData
.SetPropertyBit(aProperty
);
6370 *aResult
= listHead
;
6373 // FIXME Bug 389404: We should not accept inherit, -moz-initial,
6374 // or none as anything other than the first value.
6375 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6376 list
->mNext
= new nsCSSValueList();
6379 list
->mValue
= value
;
6381 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6392 CSSParserImpl::ParseRect(nsCSSRect
& aRect
, nsCSSProperty aPropID
)
6396 if ((result
= DoParseRect(rect
)) &&
6399 mTempData
.SetPropertyBit(aPropID
);
6405 CSSParserImpl::DoParseRect(nsCSSRect
& aRect
)
6407 if (! GetToken(PR_TRUE
)) {
6410 if (eCSSToken_Ident
== mToken
.mType
) {
6411 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
6413 case eCSSKeyword_auto
:
6414 if (ExpectEndProperty()) {
6415 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Auto
));
6419 case eCSSKeyword_inherit
:
6420 if (ExpectEndProperty()) {
6421 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Inherit
));
6425 case eCSSKeyword__moz_initial
:
6426 if (ExpectEndProperty()) {
6427 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Initial
));
6435 } else if ((eCSSToken_Function
== mToken
.mType
) &&
6436 mToken
.mIdent
.LowerCaseEqualsLiteral("rect")) {
6437 if (!ExpectSymbol('(', PR_TRUE
)) {
6440 NS_FOR_CSS_SIDES(side
) {
6441 if (! ParseVariant(aRect
.*(nsCSSRect::sides
[side
]),
6442 VARIANT_AL
, nsnull
)) {
6446 // skip optional commas between elements
6447 ExpectSymbol(',', PR_TRUE
);
6450 if (!ExpectSymbol(')', PR_TRUE
)) {
6453 if (ExpectEndProperty()) {
6462 #define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
6465 CSSParserImpl::ParseContent()
6467 // XXX Rewrite to make it look more like ParseCursor or ParseCounterData?
6469 if (ParseVariant(value
,
6470 VARIANT_CONTENT
| VARIANT_INHERIT
| VARIANT_NORMAL
|
6472 nsCSSProps::kContentKTable
)) {
6473 nsCSSValueList
* listHead
= new nsCSSValueList();
6474 nsCSSValueList
* list
= listHead
;
6475 if (nsnull
== list
) {
6476 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6479 list
->mValue
= value
;
6481 while (nsnull
!= list
) {
6482 if (ExpectEndProperty()) {
6483 mTempData
.SetPropertyBit(eCSSProperty_content
);
6484 mTempData
.mContent
.mContent
= listHead
;
6487 if (eCSSUnit_Inherit
== value
.GetUnit() ||
6488 eCSSUnit_Initial
== value
.GetUnit() ||
6489 eCSSUnit_Normal
== value
.GetUnit() ||
6490 eCSSUnit_None
== value
.GetUnit() ||
6491 (eCSSUnit_Enumerated
== value
.GetUnit() &&
6492 NS_STYLE_CONTENT_ALT_CONTENT
== value
.GetIntValue())) {
6493 // This only matters the first time through the loop.
6497 if (ParseVariant(value
, VARIANT_CONTENT
, nsCSSProps::kContentKTable
) &&
6498 // Make sure we didn't end up with NS_STYLE_CONTENT_ALT_CONTENT here
6499 (value
.GetUnit() != eCSSUnit_Enumerated
||
6500 value
.GetIntValue() != NS_STYLE_CONTENT_ALT_CONTENT
)) {
6501 list
->mNext
= new nsCSSValueList();
6503 if (nsnull
!= list
) {
6504 list
->mValue
= value
;
6507 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6519 struct SingleCounterPropValue
{
6525 CSSParserImpl::ParseCounterData(nsCSSValuePairList
** aResult
,
6526 nsCSSProperty aPropID
)
6528 nsSubstring
* ident
= NextIdent();
6529 if (nsnull
== ident
) {
6532 static const SingleCounterPropValue singleValues
[] = {
6533 { "none", eCSSUnit_None
},
6534 { "inherit", eCSSUnit_Inherit
},
6535 { "-moz-initial", eCSSUnit_Initial
}
6537 for (const SingleCounterPropValue
*sv
= singleValues
,
6538 *sv_end
= singleValues
+ NS_ARRAY_LENGTH(singleValues
);
6539 sv
!= sv_end
; ++sv
) {
6540 if (ident
->LowerCaseEqualsASCII(sv
->str
)) {
6541 if (CheckEndProperty()) {
6542 nsCSSValuePairList
* dataHead
= new nsCSSValuePairList();
6544 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6547 dataHead
->mXValue
= nsCSSValue(sv
->unit
);
6548 *aResult
= dataHead
;
6549 mTempData
.SetPropertyBit(aPropID
);
6555 UngetToken(); // undo NextIdent
6557 nsCSSValuePairList
* dataHead
= nsnull
;
6558 nsCSSValuePairList
**next
= &dataHead
;
6560 if (!GetToken(PR_TRUE
) || mToken
.mType
!= eCSSToken_Ident
) {
6563 nsCSSValuePairList
*data
= *next
= new nsCSSValuePairList();
6565 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6568 next
= &data
->mNext
;
6569 data
->mXValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
6570 if (GetToken(PR_TRUE
)) {
6571 if (eCSSToken_Number
== mToken
.mType
&& mToken
.mIntegerValid
) {
6572 data
->mYValue
.SetIntValue(mToken
.mInteger
, eCSSUnit_Integer
);
6577 if (ExpectEndProperty()) {
6578 mTempData
.SetPropertyBit(aPropID
);
6579 *aResult
= dataHead
;
6588 CSSParserImpl::ParseCue()
6591 if (ParseSingleValueProperty(before
, eCSSProperty_cue_before
)) {
6592 if (eCSSUnit_Inherit
!= before
.GetUnit() &&
6593 eCSSUnit_Initial
!= before
.GetUnit()) {
6595 if (ParseSingleValueProperty(after
, eCSSProperty_cue_after
)) {
6596 if (ExpectEndProperty()) {
6597 AppendValue(eCSSProperty_cue_before
, before
);
6598 AppendValue(eCSSProperty_cue_after
, after
);
6604 if (ExpectEndProperty()) {
6605 AppendValue(eCSSProperty_cue_before
, before
);
6606 AppendValue(eCSSProperty_cue_after
, before
);
6614 CSSParserImpl::ParseCursor()
6616 nsCSSValueList
*list
= nsnull
;
6617 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
6618 cur
= *curp
= new nsCSSValueList();
6620 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6623 if (!ParseVariant(cur
->mValue
,
6624 (cur
== list
) ? VARIANT_AHUK
: VARIANT_AUK
,
6625 nsCSSProps::kCursorKTable
)) {
6628 if (cur
->mValue
.GetUnit() != eCSSUnit_URL
) {
6629 if (!ExpectEndProperty()) {
6632 // Only success case here, since having the failure case at the
6633 // end allows more sharing of code.
6634 mTempData
.SetPropertyBit(eCSSProperty_cursor
);
6635 mTempData
.mUserInterface
.mCursor
= list
;
6638 // We have a URL, so make a value array with three values.
6639 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(3);
6641 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6644 val
->Item(0) = cur
->mValue
;
6645 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
6647 // Parse optional x and y position of cursor hotspot (css3-ui).
6648 if (ParseVariant(val
->Item(1), VARIANT_NUMBER
, nsnull
)) {
6649 // If we have one number, we must have two.
6650 if (!ParseVariant(val
->Item(2), VARIANT_NUMBER
, nsnull
)) {
6655 if (!ExpectSymbol(',', PR_TRUE
)) {
6659 // Have failure case at the end so we can |break| to get to it.
6666 CSSParserImpl::ParseFont()
6668 static const nsCSSProperty fontIDs
[] = {
6669 eCSSProperty_font_style
,
6670 eCSSProperty_font_variant
,
6671 eCSSProperty_font_weight
6675 if (ParseVariant(family
, VARIANT_HK
, nsCSSProps::kFontKTable
)) {
6676 if (ExpectEndProperty()) {
6677 if (eCSSUnit_Inherit
== family
.GetUnit() ||
6678 eCSSUnit_Initial
== family
.GetUnit()) {
6679 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6680 AppendValue(eCSSProperty_font_family
, family
);
6681 AppendValue(eCSSProperty_font_style
, family
);
6682 AppendValue(eCSSProperty_font_variant
, family
);
6683 AppendValue(eCSSProperty_font_weight
, family
);
6684 AppendValue(eCSSProperty_font_size
, family
);
6685 AppendValue(eCSSProperty_line_height
, family
);
6686 AppendValue(eCSSProperty_font_stretch
, family
);
6687 AppendValue(eCSSProperty_font_size_adjust
, family
);
6690 AppendValue(eCSSProperty__x_system_font
, family
);
6691 nsCSSValue
systemFont(eCSSUnit_System_Font
);
6692 AppendValue(eCSSProperty_font_family
, systemFont
);
6693 AppendValue(eCSSProperty_font_style
, systemFont
);
6694 AppendValue(eCSSProperty_font_variant
, systemFont
);
6695 AppendValue(eCSSProperty_font_weight
, systemFont
);
6696 AppendValue(eCSSProperty_font_size
, systemFont
);
6697 AppendValue(eCSSProperty_line_height
, systemFont
);
6698 AppendValue(eCSSProperty_font_stretch
, systemFont
);
6699 AppendValue(eCSSProperty_font_size_adjust
, systemFont
);
6706 // Get optional font-style, font-variant and font-weight (in any order)
6707 const PRInt32 numProps
= 3;
6708 nsCSSValue values
[numProps
];
6709 PRInt32 found
= ParseChoice(values
, fontIDs
, numProps
);
6710 if ((found
< 0) || (eCSSUnit_Inherit
== values
[0].GetUnit()) ||
6711 (eCSSUnit_Initial
== values
[0].GetUnit())) { // illegal data
6714 if ((found
& 1) == 0) {
6715 // Provide default font-style
6716 values
[0].SetNormalValue();
6718 if ((found
& 2) == 0) {
6719 // Provide default font-variant
6720 values
[1].SetNormalValue();
6722 if ((found
& 4) == 0) {
6723 // Provide default font-weight
6724 values
[2].SetNormalValue();
6727 // Get mandatory font-size
6729 if (! ParseVariant(size
, VARIANT_KEYWORD
| VARIANT_LP
, nsCSSProps::kFontSizeKTable
)) {
6733 // Get optional "/" line-height
6734 nsCSSValue lineHeight
;
6735 if (ExpectSymbol('/', PR_TRUE
)) {
6736 if (! ParsePositiveVariant(lineHeight
,
6737 VARIANT_NUMBER
| VARIANT_LP
| VARIANT_NORMAL
,
6743 lineHeight
.SetNormalValue();
6746 // Get final mandatory font-family
6747 nsAutoParseCompoundProperty
compound(this);
6748 if (ParseFamily(family
)) {
6749 if ((eCSSUnit_Inherit
!= family
.GetUnit()) && (eCSSUnit_Initial
!= family
.GetUnit()) &&
6750 ExpectEndProperty()) {
6751 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6752 AppendValue(eCSSProperty_font_family
, family
);
6753 AppendValue(eCSSProperty_font_style
, values
[0]);
6754 AppendValue(eCSSProperty_font_variant
, values
[1]);
6755 AppendValue(eCSSProperty_font_weight
, values
[2]);
6756 AppendValue(eCSSProperty_font_size
, size
);
6757 AppendValue(eCSSProperty_line_height
, lineHeight
);
6758 AppendValue(eCSSProperty_font_stretch
, nsCSSValue(eCSSUnit_Normal
));
6759 AppendValue(eCSSProperty_font_size_adjust
, nsCSSValue(eCSSUnit_None
));
6767 CSSParserImpl::ParseFontWeight(nsCSSValue
& aValue
)
6769 if (ParseVariant(aValue
, VARIANT_HMKI
| VARIANT_SYSFONT
, nsCSSProps::kFontWeightKTable
)) {
6770 if (eCSSUnit_Integer
== aValue
.GetUnit()) { // ensure unit value
6771 PRInt32 intValue
= aValue
.GetIntValue();
6772 if ((100 <= intValue
) &&
6773 (intValue
<= 900) &&
6774 (0 == (intValue
% 100))) {
6787 CSSParserImpl::ParseOneFamily(nsAString
& aFamily
)
6789 if (!GetToken(PR_TRUE
))
6792 nsCSSToken
* tk
= &mToken
;
6794 if (eCSSToken_Ident
== tk
->mType
) {
6795 aFamily
.Append(tk
->mIdent
);
6797 if (!GetToken(PR_FALSE
))
6800 if (eCSSToken_Ident
== tk
->mType
) {
6801 aFamily
.Append(tk
->mIdent
);
6802 } else if (eCSSToken_WhiteSpace
== tk
->mType
) {
6803 // Lookahead one token and drop whitespace if we are ending the
6805 if (!GetToken(PR_TRUE
))
6809 if (eCSSToken_Ident
== tk
->mType
)
6810 aFamily
.Append(PRUnichar(' '));
6820 } else if (eCSSToken_String
== tk
->mType
) {
6821 aFamily
.Append(tk
->mSymbol
); // replace the quotes
6822 aFamily
.Append(tk
->mIdent
); // XXX What if it had escaped quotes?
6823 aFamily
.Append(tk
->mSymbol
);
6832 ///////////////////////////////////////////////////////
6833 // -moz-transform Parsing Implementation
6835 /* Reads a function list of arguments. Do not call this function
6836 * directly; it's mean to be caled from ParseFunction.
6839 CSSParserImpl::ParseFunctionInternals(const PRInt32 aVariantMask
[],
6842 nsTArray
<nsCSSValue
> &aOutput
)
6844 for (PRUint16 index
= 0; index
< aMaxElems
; ++index
) {
6845 nsCSSValue newValue
;
6846 if (!ParseVariant(newValue
, aVariantMask
[index
], nsnull
))
6849 if (!aOutput
.AppendElement(newValue
)) {
6850 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6854 // See whether to continue or whether to look for end of function.
6855 if (!ExpectSymbol(',', PR_TRUE
)) {
6856 // We need to read the closing parenthesis, and also must take care
6857 // that we haven't read too few symbols.
6858 return ExpectSymbol(')', PR_TRUE
) && (index
+ 1) >= aMinElems
;
6862 // If we're here, we finished looping without hitting the end, so we read too
6867 /* Parses a function [ input of the form (a [, b]*) ] and stores it
6868 * as an nsCSSValue that holds a function of the form
6869 * function-name arg1 arg2 ... argN
6871 * On error, the return value is PR_FALSE.
6873 * @param aFunction The name of the function that we're reading.
6874 * @param aAllowedTypes An array of values corresponding to the legal
6875 * types for each element in the function. The zeroth element in the
6876 * array corresponds to the first function parameter, etc. The length
6877 * of this array _must_ be greater than or equal to aMaxElems or the
6878 * behavior is undefined.
6879 * @param aMinElems Minimum number of elements to read. Reading fewer than
6880 * this many elements will result in the function failing.
6881 * @param aMaxElems Maximum number of elements to read. Reading more than
6882 * this many elements will result in the function failing.
6883 * @param aValue (out) The value that was parsed.
6886 CSSParserImpl::ParseFunction(const nsString
&aFunction
,
6887 const PRInt32 aAllowedTypes
[],
6888 PRUint16 aMinElems
, PRUint16 aMaxElems
,
6891 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
6893 /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
6894 * elements stored in the the nsCSSValue::Array.
6896 static const arrlen_t MAX_ALLOWED_ELEMS
= 0xFFFE;
6898 /* Make a copy of the function name, since the reference is _probably_ to
6899 * mToken.mIdent, which is going to get overwritten during the course of this
6902 nsString
functionName(aFunction
);
6904 /* First things first... read the parenthesis. If it fails, abort. */
6905 if (!ExpectSymbol('(', PR_TRUE
))
6908 /* Read in a list of values as an nsTArray, failing if we can't or if
6909 * it's out of bounds.
6911 nsTArray
<nsCSSValue
> foundValues
;
6912 if (!ParseFunctionInternals(aAllowedTypes
, aMinElems
, aMaxElems
,
6916 /* Now, convert this nsTArray into an nsCSSValue::Array object.
6917 * We'll need N + 1 spots, one for the function name and the rest for the
6918 * arguments. In case the user has given us more than 2^16 - 2 arguments,
6919 * we'll truncate them at 2^16 - 2 arguments.
6921 PRUint16 numElements
= (foundValues
.Length() <= MAX_ALLOWED_ELEMS
?
6922 foundValues
.Length() + 1 : MAX_ALLOWED_ELEMS
);
6923 nsRefPtr
<nsCSSValue::Array
> convertedArray
=
6924 nsCSSValue::Array::Create(numElements
);
6925 if (!convertedArray
) {
6926 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6930 /* Copy things over. */
6931 convertedArray
->Item(0).SetStringValue(functionName
, eCSSUnit_String
);
6932 for (PRUint16 index
= 0; index
+ 1 < numElements
; ++index
)
6933 convertedArray
->Item(index
+ 1) = foundValues
[static_cast<arrlen_t
>(index
)];
6935 /* Fill in the outparam value with the array. */
6936 aValue
.SetArrayValue(convertedArray
, eCSSUnit_Function
);
6943 * Given a token, determines the minimum and maximum number of function
6944 * parameters to read, along with the mask that should be used to read
6945 * those function parameters. If the token isn't a transform function,
6948 * @param aToken The token identifying the function.
6949 * @param aMinElems [out] The minimum number of elements to read.
6950 * @param aMaxElems [out] The maximum number of elements to read
6951 * @param aVariantMask [out] The variant mask to use during parsing
6952 * @return Whether the information was loaded successfully.
6954 static PRBool
GetFunctionParseInformation(nsCSSKeyword aToken
,
6955 PRUint16
&aMinElems
,
6956 PRUint16
&aMaxElems
,
6957 const PRInt32
*& aVariantMask
)
6959 /* These types represent the common variant masks that will be used to
6960 * parse out the individual functions. The order in the enumeration
6961 * must match the order in which the masks are declared.
6963 enum { eLengthPercent
,
6971 static const PRInt32 kMaxElemsPerFunction
= 6;
6972 static const PRInt32 kVariantMasks
[eNumVariantMasks
][kMaxElemsPerFunction
] = {
6973 {VARIANT_LENGTH
| VARIANT_PERCENT
},
6974 {VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
},
6976 {VARIANT_ANGLE
, VARIANT_ANGLE
},
6978 {VARIANT_NUMBER
, VARIANT_NUMBER
},
6979 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
6980 VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
}};
6983 static const PRUint8 kVariantMaskLengths
[eNumVariantMasks
] =
6984 {1, 2, 1, 2, 1, 2, 6};
6987 PRInt32 variantIndex
= eNumVariantMasks
;
6990 case eCSSKeyword_translatex
:
6991 /* Exactly one length or percent. */
6992 variantIndex
= eLengthPercent
;
6996 case eCSSKeyword_translatey
:
6997 /* Exactly one length or percent. */
6998 variantIndex
= eLengthPercent
;
7002 case eCSSKeyword_scalex
:
7003 /* Exactly one scale factor. */
7004 variantIndex
= eNumber
;
7008 case eCSSKeyword_scaley
:
7009 /* Exactly one scale factor. */
7010 variantIndex
= eNumber
;
7014 case eCSSKeyword_rotate
:
7015 /* Exactly one angle. */
7016 variantIndex
= eAngle
;
7020 case eCSSKeyword_translate
:
7021 /* One or two lengths or percents. */
7022 variantIndex
= eTwoLengthPercents
;
7026 case eCSSKeyword_skew
:
7027 /* Exactly one or two angles. */
7028 variantIndex
= eTwoAngles
;
7032 case eCSSKeyword_scale
:
7033 /* One or two scale factors. */
7034 variantIndex
= eTwoNumbers
;
7038 case eCSSKeyword_skewx
:
7039 /* Exactly one angle. */
7040 variantIndex
= eAngle
;
7044 case eCSSKeyword_skewy
:
7045 /* Exactly one angle. */
7046 variantIndex
= eAngle
;
7050 case eCSSKeyword_matrix
:
7051 /* Six values, which can be numbers, lengths, or percents. */
7052 variantIndex
= eMatrix
;
7057 /* Oh dear, we didn't match. Report an error. */
7061 NS_ASSERTION(aMinElems
> 0, "Didn't update minimum elements!");
7062 NS_ASSERTION(aMaxElems
> 0, "Didn't update maximum elements!");
7063 NS_ASSERTION(aMinElems
<= aMaxElems
, "aMinElems > aMaxElems!");
7064 NS_ASSERTION(variantIndex
>= 0, "Invalid variant mask!");
7065 NS_ASSERTION(variantIndex
< eNumVariantMasks
, "Invalid variant mask!");
7067 NS_ASSERTION(aMaxElems
<= kVariantMaskLengths
[variantIndex
],
7068 "Invalid aMaxElems for this variant mask.");
7071 // Convert the index into a mask.
7072 aVariantMask
= kVariantMasks
[variantIndex
];
7078 /* Reads a single transform function from the tokenizer stream, reporting an
7079 * error if something goes wrong.
7081 PRBool
CSSParserImpl::ReadSingleTransform(nsCSSValueList
**& aTail
)
7083 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
7085 if (!GetToken(PR_TRUE
))
7088 /* Check to make sure that we've read a function. */
7089 if (mToken
.mType
!= eCSSToken_Function
) {
7094 /* Load up the variant mask information for ParseFunction. If we can't,
7097 const PRInt32
* variantMask
;
7098 PRUint16 minElems
, maxElems
;
7099 if (!GetFunctionParseInformation(nsCSSKeywords::LookupKeyword(mToken
.mIdent
),
7100 minElems
, maxElems
, variantMask
))
7103 /* Create a cell to populate, fail if we're out of memory. */
7104 nsAutoPtr
<nsCSSValue
> newCell(new nsCSSValue
);
7106 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7110 /* Try reading things in, failing if we can't */
7111 if (!ParseFunction(mToken
.mIdent
, variantMask
, minElems
, maxElems
, *newCell
))
7114 /* Wrap up our result in an nsCSSValueList cell. */
7115 nsAutoPtr
<nsCSSValueList
> toAppend(new nsCSSValueList
);
7119 toAppend
->mValue
= *newCell
;
7121 /* Chain the element to the end of the transform list, then update the
7124 *aTail
= toAppend
.forget();
7125 aTail
= &(*aTail
)->mNext
;
7127 /* It worked! Return true. */
7131 /* Parses a -moz-transform property list by continuously reading in properties
7132 * and constructing a matrix from it.
7134 PRBool
CSSParserImpl::ParseMozTransform()
7136 mTempData
.mDisplay
.mTransform
= nsnull
;
7138 /* First, check to see if this is some sort of keyword - none, inherit,
7141 nsCSSValue keywordValue
;
7142 if (ParseVariant(keywordValue
, VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
7143 /* Looks like it is. Make a new value list and fill it in, failing if
7146 mTempData
.mDisplay
.mTransform
= new nsCSSValueList
;
7147 if (!mTempData
.mDisplay
.mTransform
) {
7148 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7152 /* Inform the parser that everything worked. */
7153 mTempData
.mDisplay
.mTransform
->mValue
= keywordValue
;
7154 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7158 /* We will read a nonempty list of transforms. Thus we'll read in a
7159 * transform, then continuously read transforms until we're no longer
7162 nsCSSValueList
*transformList
= nsnull
;
7163 nsCSSValueList
**tail
= &transformList
;
7165 /* Try reading a transform. If we fail to do so, abort. */
7166 if (!ReadSingleTransform(tail
)) {
7167 delete transformList
;
7171 while (!CheckEndProperty());
7173 /* Confirm that this is the end of the property and set error code
7174 * appropriately otherwise.
7176 if (!ExpectEndProperty()) {
7177 delete transformList
;
7181 /* Validate our data. */
7182 NS_ASSERTION(transformList
, "Didn't read any transforms!");
7184 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7185 mTempData
.mDisplay
.mTransform
= transformList
;
7190 PRBool
CSSParserImpl::ParseMozTransformOrigin()
7192 /* Read in a box position, fail if we can't. */
7193 if (!ParseBoxPosition(mTempData
.mDisplay
.mTransformOrigin
))
7196 /* Set the property bit and return. */
7197 mTempData
.SetPropertyBit(eCSSProperty__moz_transform_origin
);
7202 CSSParserImpl::ParseFamily(nsCSSValue
& aValue
)
7204 if (!GetToken(PR_TRUE
))
7207 if (eCSSToken_Ident
== mToken
.mType
) {
7208 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
7209 if (keyword
== eCSSKeyword_inherit
) {
7210 aValue
.SetInheritValue();
7213 if (keyword
== eCSSKeyword__moz_initial
) {
7214 aValue
.SetInitialValue();
7217 if (keyword
== eCSSKeyword__moz_use_system_font
&&
7218 !IsParsingCompoundProperty()) {
7219 aValue
.SetSystemFontValue();
7226 nsAutoString family
;
7228 if (!ParseOneFamily(family
))
7231 if (!ExpectSymbol(',', PR_TRUE
))
7234 family
.Append(PRUnichar(','));
7237 if (family
.IsEmpty()) {
7240 aValue
.SetStringValue(family
, eCSSUnit_String
);
7244 // src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*
7245 // uri-src: uri [ 'format(' string ( ',' string )* ')' ]
7246 // local-src: 'local(' ( string | ident ) ')'
7249 CSSParserImpl::ParseFontSrc(nsCSSValue
& aValue
)
7251 // could we maybe turn nsCSSValue::Array into nsTArray<nsCSSValue>?
7252 nsTArray
<nsCSSValue
> values
;
7255 if (!GetToken(PR_TRUE
))
7258 if (mToken
.mType
== eCSSToken_Function
&&
7259 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
7262 values
.AppendElement(cur
);
7263 if (!ParseFontSrcFormat(values
))
7266 } else if (mToken
.mType
== eCSSToken_Function
&&
7267 mToken
.mIdent
.LowerCaseEqualsLiteral("local")) {
7268 // css3-fonts does not specify a formal grammar for local().
7269 // The text permits both unquoted identifiers and quoted
7270 // strings. We resolve this ambiguity in the spec by
7271 // assuming that the appropriate production is a single
7272 // <family-name>, possibly surrounded by whitespace.
7274 nsAutoString family
;
7275 if (!ExpectSymbol('(', PR_FALSE
))
7277 if (!ParseOneFamily(family
))
7279 if (!ExpectSymbol(')', PR_TRUE
))
7282 // the style parameters to the nsFont constructor are ignored,
7283 // because it's only being used to call EnumerateFamilies
7284 nsFont
font(family
, 0, 0, 0, 0, 0);
7285 ExtractFirstFamilyData dat
;
7287 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
7291 cur
.SetStringValue(dat
.mFamilyName
, eCSSUnit_Local_Font
);
7292 values
.AppendElement(cur
);
7297 if (!ExpectSymbol(',', PR_TRUE
))
7301 nsRefPtr
<nsCSSValue::Array
> srcVals
7302 = nsCSSValue::Array::Create(values
.Length());
7307 for (i
= 0; i
< values
.Length(); i
++)
7308 srcVals
->Item(i
) = values
[i
];
7309 aValue
.SetArrayValue(srcVals
, eCSSUnit_Array
);
7314 CSSParserImpl::ParseFontSrcFormat(nsTArray
<nsCSSValue
> & values
)
7316 if (!GetToken(PR_TRUE
))
7317 return PR_TRUE
; // EOF harmless here
7318 if (mToken
.mType
!= eCSSToken_Function
||
7319 !mToken
.mIdent
.LowerCaseEqualsLiteral("format")) {
7323 if (!ExpectSymbol('(', PR_FALSE
))
7327 if (!GetToken(PR_TRUE
))
7330 if (mToken
.mType
!= eCSSToken_String
)
7333 nsCSSValue
cur(mToken
.mIdent
, eCSSUnit_Font_Format
);
7334 values
.AppendElement(cur
);
7335 } while (ExpectSymbol(',', PR_TRUE
));
7337 return ExpectSymbol(')', PR_TRUE
);
7340 // font-ranges: urange ( ',' urange )*
7342 CSSParserImpl::ParseFontRanges(nsCSSValue
& aValue
)
7344 // not currently implemented (bug 443976)
7349 CSSParserImpl::ParseListStyle()
7351 const PRInt32 numProps
= 3;
7352 static const nsCSSProperty listStyleIDs
[] = {
7353 eCSSProperty_list_style_type
,
7354 eCSSProperty_list_style_position
,
7355 eCSSProperty_list_style_image
7358 nsCSSValue values
[numProps
];
7360 PRInt32 found
= ParseChoice(values
, listStyleIDs
, numProps
);
7361 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7365 // Provide default values
7366 if ((found
& 1) == 0) {
7367 values
[0].SetIntValue(NS_STYLE_LIST_STYLE_DISC
, eCSSUnit_Enumerated
);
7369 if ((found
& 2) == 0) {
7370 values
[1].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE
, eCSSUnit_Enumerated
);
7372 if ((found
& 4) == 0) {
7373 values
[2].SetNoneValue();
7376 for (index
= 0; index
< numProps
; index
++) {
7377 AppendValue(listStyleIDs
[index
], values
[index
]);
7383 CSSParserImpl::ParseMargin()
7385 static const nsCSSProperty kMarginSideIDs
[] = {
7386 eCSSProperty_margin_top
,
7387 eCSSProperty_margin_right_value
,
7388 eCSSProperty_margin_bottom
,
7389 eCSSProperty_margin_left_value
7391 static const nsCSSProperty kMarginSources
[] = {
7392 eCSSProperty_margin_left_ltr_source
,
7393 eCSSProperty_margin_left_rtl_source
,
7394 eCSSProperty_margin_right_ltr_source
,
7395 eCSSProperty_margin_right_rtl_source
,
7396 eCSSProperty_UNKNOWN
7399 // do this now, in case 4 values weren't specified
7400 InitBoxPropsAsPhysical(kMarginSources
);
7401 return ParseBoxProperties(mTempData
.mMargin
.mMargin
,
7406 CSSParserImpl::ParseMarks(nsCSSValue
& aValue
)
7408 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kPageMarksKTable
)) {
7409 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
7410 if (PR_FALSE
== CheckEndProperty()) {
7412 if (ParseEnum(second
, nsCSSProps::kPageMarksKTable
)) {
7413 aValue
.SetIntValue(aValue
.GetIntValue() | second
.GetIntValue(), eCSSUnit_Enumerated
);
7425 CSSParserImpl::ParseOutline()
7427 const PRInt32 numProps
= 3;
7428 static const nsCSSProperty kOutlineIDs
[] = {
7429 eCSSProperty_outline_color
,
7430 eCSSProperty_outline_style
,
7431 eCSSProperty_outline_width
7434 nsCSSValue values
[numProps
];
7435 PRInt32 found
= ParseChoice(values
, kOutlineIDs
, numProps
);
7436 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7440 // Provide default values
7441 if ((found
& 1) == 0) {
7442 #ifdef GFX_HAS_INVERT
7443 values
[0].SetIntValue(NS_STYLE_COLOR_INVERT
, eCSSUnit_Enumerated
);
7445 values
[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
7448 if ((found
& 2) == 0) {
7449 values
[1].SetNoneValue();
7451 if ((found
& 4) == 0) {
7452 values
[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
7456 for (index
= 0; index
< numProps
; index
++) {
7457 AppendValue(kOutlineIDs
[index
], values
[index
]);
7463 CSSParserImpl::ParseOverflow()
7465 nsCSSValue overflow
;
7466 if (!ParseVariant(overflow
, VARIANT_AHK
,
7467 nsCSSProps::kOverflowKTable
) ||
7468 !ExpectEndProperty())
7471 nsCSSValue
overflowX(overflow
);
7472 nsCSSValue
overflowY(overflow
);
7473 if (eCSSUnit_Enumerated
== overflow
.GetUnit())
7474 switch(overflow
.GetIntValue()) {
7475 case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL
:
7476 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7477 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7479 case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL
:
7480 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7481 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7484 AppendValue(eCSSProperty_overflow_x
, overflowX
);
7485 AppendValue(eCSSProperty_overflow_y
, overflowY
);
7490 CSSParserImpl::ParsePadding()
7492 static const nsCSSProperty kPaddingSideIDs
[] = {
7493 eCSSProperty_padding_top
,
7494 eCSSProperty_padding_right_value
,
7495 eCSSProperty_padding_bottom
,
7496 eCSSProperty_padding_left_value
7498 static const nsCSSProperty kPaddingSources
[] = {
7499 eCSSProperty_padding_left_ltr_source
,
7500 eCSSProperty_padding_left_rtl_source
,
7501 eCSSProperty_padding_right_ltr_source
,
7502 eCSSProperty_padding_right_rtl_source
,
7503 eCSSProperty_UNKNOWN
7506 // do this now, in case 4 values weren't specified
7507 InitBoxPropsAsPhysical(kPaddingSources
);
7508 return ParseBoxProperties(mTempData
.mMargin
.mPadding
,
7513 CSSParserImpl::ParsePause()
7516 if (ParseSingleValueProperty(before
, eCSSProperty_pause_before
)) {
7517 if (eCSSUnit_Inherit
!= before
.GetUnit() && eCSSUnit_Initial
!= before
.GetUnit()) {
7519 if (ParseSingleValueProperty(after
, eCSSProperty_pause_after
)) {
7520 if (ExpectEndProperty()) {
7521 AppendValue(eCSSProperty_pause_before
, before
);
7522 AppendValue(eCSSProperty_pause_after
, after
);
7528 if (ExpectEndProperty()) {
7529 AppendValue(eCSSProperty_pause_before
, before
);
7530 AppendValue(eCSSProperty_pause_after
, before
);
7538 CSSParserImpl::ParseQuotes()
7541 if (ParseVariant(open
, VARIANT_HOS
, nsnull
)) {
7542 if (eCSSUnit_String
== open
.GetUnit()) {
7543 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7544 nsCSSValuePairList
* quotes
= quotesHead
;
7545 if (nsnull
== quotes
) {
7546 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7549 quotes
->mXValue
= open
;
7550 while (nsnull
!= quotes
) {
7551 // get mandatory close
7552 if (ParseVariant(quotes
->mYValue
, VARIANT_STRING
,
7554 if (CheckEndProperty()) {
7555 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7556 mTempData
.mContent
.mQuotes
= quotesHead
;
7559 // look for another open
7560 if (ParseVariant(open
, VARIANT_STRING
, nsnull
)) {
7561 quotes
->mNext
= new nsCSSValuePairList();
7562 quotes
= quotes
->mNext
;
7563 if (nsnull
!= quotes
) {
7564 quotes
->mXValue
= open
;
7567 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7575 if (ExpectEndProperty()) {
7576 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7577 quotesHead
->mXValue
= open
;
7578 mTempData
.mContent
.mQuotes
= quotesHead
;
7579 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7587 CSSParserImpl::ParseSize()
7590 if (ParseVariant(width
, VARIANT_AHKL
, nsCSSProps::kPageSizeKTable
)) {
7591 if (width
.IsLengthUnit()) {
7593 if (ParseVariant(height
, VARIANT_LENGTH
, nsnull
)) {
7594 if (ExpectEndProperty()) {
7595 mTempData
.mPage
.mSize
.mXValue
= width
;
7596 mTempData
.mPage
.mSize
.mYValue
= height
;
7597 mTempData
.SetPropertyBit(eCSSProperty_size
);
7603 if (ExpectEndProperty()) {
7604 mTempData
.mPage
.mSize
.SetBothValuesTo(width
);
7605 mTempData
.SetPropertyBit(eCSSProperty_size
);
7613 CSSParserImpl::ParseTextDecoration(nsCSSValue
& aValue
)
7615 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kTextDecorationKTable
)) {
7616 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) { // look for more keywords
7617 PRInt32 intValue
= aValue
.GetIntValue();
7620 for (index
= 0; index
< 3; index
++) {
7621 if (ParseEnum(keyword
, nsCSSProps::kTextDecorationKTable
)) {
7622 intValue
|= keyword
.GetIntValue();
7628 aValue
.SetIntValue(intValue
, eCSSUnit_Enumerated
);
7636 CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread
)
7638 nsAutoParseCompoundProperty
compound(this);
7640 // Parses x, y, radius, color (in two possible orders)
7641 // This parses the input into a list. Either it contains just a "none" or
7642 // "inherit" value, or a list of arrays.
7643 // The resulting arrays will always contain the above order, with color and
7644 // radius as null values as needed
7653 nsCSSValueList
*list
= nsnull
;
7654 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
7655 cur
= *curp
= new nsCSSValueList();
7657 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7660 if (!ParseVariant(cur
->mValue
,
7661 (cur
== list
) ? VARIANT_HC
| VARIANT_LENGTH
| VARIANT_NONE
7662 : VARIANT_COLOR
| VARIANT_LENGTH
,
7667 nsCSSUnit unit
= cur
->mValue
.GetUnit();
7668 if (unit
!= eCSSUnit_None
&& unit
!= eCSSUnit_Inherit
&&
7669 unit
!= eCSSUnit_Initial
) {
7670 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(5);
7672 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7675 PRBool haveColor
= PR_FALSE
;
7676 if (cur
->mValue
.IsLengthUnit()) {
7677 val
->Item(IndexX
) = cur
->mValue
;
7679 // Must be a color (as string or color value)
7680 NS_ASSERTION(unit
== eCSSUnit_String
|| unit
== eCSSUnit_Color
||
7681 unit
== eCSSUnit_EnumColor
,
7682 "Must be a color value (named color, numeric color, "
7683 "or system color)");
7684 haveColor
= PR_TRUE
;
7685 val
->Item(IndexColor
) = cur
->mValue
;
7687 // Parse the X coordinate
7688 if (!ParseVariant(val
->Item(IndexX
), VARIANT_LENGTH
,
7693 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
7695 // Y coordinate; this one is not optional
7696 if (!ParseVariant(val
->Item(IndexY
), VARIANT_LENGTH
, nsnull
)) {
7700 // Optional radius. Ignore errors except if they pass a negative
7701 // value which we must reject. If we use ParsePositiveVariant we can't
7702 // tell the difference between an unspecified radius and a negative
7703 // radius, so that's why we don't use it.
7704 if (ParseVariant(val
->Item(IndexRadius
), VARIANT_LENGTH
, nsnull
) &&
7705 val
->Item(IndexRadius
).GetFloatValue() < 0) {
7710 // Optional spread (ignore errors)
7711 ParseVariant(val
->Item(IndexSpread
), VARIANT_LENGTH
,
7716 // Optional color (ignore errors)
7717 ParseVariant(val
->Item(IndexColor
), VARIANT_COLOR
,
7721 // Might be at a comma now
7722 if (ExpectSymbol(',', PR_TRUE
)) {
7728 if (!ExpectEndProperty()) {
7729 // If we don't have a comma to delimit the next value, we
7730 // must be at the end of the property. Otherwise we've hit
7731 // something else, which is an error.
7735 // Only success case here, since having the failure case at the
7736 // end allows more sharing of code.
7739 // Have failure case at the end so we can |break| to get to it.
7745 CSSParserImpl::ParseTextShadow()
7747 nsCSSValueList
* list
= ParseCSSShadowList(PR_FALSE
);
7751 mTempData
.SetPropertyBit(eCSSProperty_text_shadow
);
7752 mTempData
.mText
.mTextShadow
= list
;
7757 CSSParserImpl::ParseBoxShadow()
7759 nsCSSValueList
* list
= ParseCSSShadowList(PR_TRUE
);
7763 mTempData
.SetPropertyBit(eCSSProperty_box_shadow
);
7764 mTempData
.mMargin
.mBoxShadow
= list
;
7769 CSSParserImpl::GetNamespaceIdForPrefix(const nsString
& aPrefix
,
7770 PRInt32
* aNameSpaceID
)
7772 NS_PRECONDITION(!aPrefix
.IsEmpty(), "Must have a prefix here");
7774 PRInt32 nameSpaceID
= kNameSpaceID_Unknown
;
7775 if (mNameSpaceMap
) {
7776 // user-specified identifiers are case-sensitive (bug 416106)
7777 nsCOMPtr
<nsIAtom
> prefix
= do_GetAtom(aPrefix
);
7778 nameSpaceID
= mNameSpaceMap
->FindNameSpaceID(prefix
);
7780 // else no declared namespaces
7782 if (kNameSpaceID_Unknown
== nameSpaceID
) { // unknown prefix, dump it
7783 const PRUnichar
*params
[] = {
7786 REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix
, params
);
7787 if (mUnresolvablePrefixException
)
7788 mScanner
.SetLowLevelError(NS_ERROR_DOM_NAMESPACE_ERR
);
7792 *aNameSpaceID
= nameSpaceID
;
7797 CSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
)
7799 if (mNameSpaceMap
) {
7800 aSelector
.SetNameSpace(mNameSpaceMap
->FindNameSpaceID(nsnull
));
7802 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // wildcard
7808 CSSParserImpl::ParsePaint(nsCSSValuePair
* aResult
,
7809 nsCSSProperty aPropID
)
7811 if (!ParseVariant(aResult
->mXValue
,
7812 VARIANT_HC
| VARIANT_NONE
| VARIANT_URL
,
7816 if (aResult
->mXValue
.GetUnit() == eCSSUnit_URL
) {
7817 if (!ParseVariant(aResult
->mYValue
, VARIANT_COLOR
| VARIANT_NONE
,
7819 aResult
->mYValue
.SetColorValue(NS_RGB(0, 0, 0));
7821 aResult
->mYValue
= aResult
->mXValue
;
7824 if (!ExpectEndProperty())
7827 mTempData
.SetPropertyBit(aPropID
);
7832 CSSParserImpl::ParseDasharray()
7835 if (ParseVariant(value
, VARIANT_HLPN
| VARIANT_NONE
, nsnull
)) {
7836 nsCSSValueList
*listHead
= new nsCSSValueList
;
7837 nsCSSValueList
*list
= listHead
;
7839 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7843 list
->mValue
= value
;
7846 if (CheckEndProperty()) {
7847 mTempData
.SetPropertyBit(eCSSProperty_stroke_dasharray
);
7848 mTempData
.mSVG
.mStrokeDasharray
= listHead
;
7852 if (eCSSUnit_Inherit
== value
.GetUnit() ||
7853 eCSSUnit_Initial
== value
.GetUnit() ||
7854 eCSSUnit_None
== value
.GetUnit())
7857 if (!ExpectSymbol(',', PR_TRUE
))
7860 if (!ParseVariant(value
,
7861 VARIANT_LENGTH
| VARIANT_PERCENT
| VARIANT_NUMBER
,
7865 list
->mNext
= new nsCSSValueList
;
7868 list
->mValue
= value
;
7870 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7880 CSSParserImpl::ParseMarker()
7883 if (ParseSingleValueProperty(marker
, eCSSProperty_marker_end
)) {
7884 if (ExpectEndProperty()) {
7885 AppendValue(eCSSProperty_marker_end
, marker
);
7886 AppendValue(eCSSProperty_marker_mid
, marker
);
7887 AppendValue(eCSSProperty_marker_start
, marker
);