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
);
278 PRBool
SkipDeclaration(PRBool aCheckForBraces
);
279 PRBool
GetNonCloseParenToken(PRBool aSkipWS
);
281 PRBool
PushGroup(nsICSSGroupRule
* aRule
);
284 PRBool
ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aProcessData
);
285 PRBool
ParseAtRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
286 PRBool
ParseCharsetRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
287 PRBool
ParseImportRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
288 PRBool
GatherURL(nsString
& aURL
);
289 PRBool
GatherMedia(nsMediaList
* aMedia
,
290 PRUnichar aStopSymbol
);
291 PRBool
ParseMediaQuery(PRUnichar aStopSymbol
, nsMediaQuery
**aQuery
,
292 PRBool
*aParsedSomething
, PRBool
*aHitStop
);
293 PRBool
ParseMediaQueryExpression(nsMediaQuery
* aQuery
);
294 PRBool
ProcessImport(const nsString
& aURLSpec
,
296 RuleAppendFunc aAppendFunc
,
298 PRBool
ParseGroupRule(nsICSSGroupRule
* aRule
, RuleAppendFunc aAppendFunc
,
300 PRBool
ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
301 PRBool
ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
302 PRBool
ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
303 PRBool
ProcessNameSpace(const nsString
& aPrefix
,
304 const nsString
& aURLSpec
, RuleAppendFunc aAppendFunc
,
307 PRBool
ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
308 PRBool
ParseFontDescriptor(nsCSSFontFaceRule
* aRule
);
309 PRBool
ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
312 PRBool
ParsePageRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
314 enum nsSelectorParsingStatus
{
315 // we have parsed a selector and we saw a token that cannot be
316 // part of a selector:
317 eSelectorParsingStatus_Done
,
318 // we should continue parsing the selector:
319 eSelectorParsingStatus_Continue
,
320 // same as "Done" but we did not find a selector:
321 eSelectorParsingStatus_Empty
,
322 // we saw an unexpected token or token value,
323 // or we saw end-of-file with an unfinished selector:
324 eSelectorParsingStatus_Error
326 nsSelectorParsingStatus
ParseIDSelector(PRInt32
& aDataMask
,
327 nsCSSSelector
& aSelector
);
329 nsSelectorParsingStatus
ParseClassSelector(PRInt32
& aDataMask
,
330 nsCSSSelector
& aSelector
);
332 nsSelectorParsingStatus
ParsePseudoSelector(PRInt32
& aDataMask
,
333 nsCSSSelector
& aSelector
,
336 nsSelectorParsingStatus
ParseAttributeSelector(PRInt32
& aDataMask
,
337 nsCSSSelector
& aSelector
);
339 nsSelectorParsingStatus
ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
340 nsCSSSelector
& aSelector
,
343 nsSelectorParsingStatus
ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
346 nsSelectorParsingStatus
ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
349 nsSelectorParsingStatus
ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
350 nsCSSSelector
& aSelector
);
352 nsSelectorParsingStatus
ParseSelector(nsCSSSelector
& aSelectorResult
);
354 // If aTerminateAtBrace is true, the selector list is done when we
355 // hit a '{'. Otherwise, it's done when we hit EOF.
356 PRBool
ParseSelectorList(nsCSSSelectorList
*& aListHead
,
357 PRBool aTerminateAtBrace
);
358 PRBool
ParseSelectorGroup(nsCSSSelectorList
*& aListHead
);
359 nsCSSDeclaration
* ParseDeclarationBlock(PRBool aCheckForBraces
);
360 PRBool
ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
361 PRBool aCheckForBraces
,
362 PRBool aMustCallValueAppended
,
364 // After a parse error parsing |aPropID|, clear the data in
366 void ClearTempData(nsCSSProperty aPropID
);
367 // After a successful parse of |aPropID|, transfer data from
368 // |mTempData| to |mData|. Set |*aChanged| to true if something
369 // changed, but leave it unmodified otherwise. If aMustCallValueAppended
370 // is false, will not call ValueAppended on aDeclaration if the property
371 // is already set in it.
372 void TransferTempData(nsCSSDeclaration
* aDeclaration
,
373 nsCSSProperty aPropID
, PRBool aIsImportant
,
374 PRBool aMustCallValueAppended
,
376 void DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
377 nsCSSProperty aPropID
, PRBool aIsImportant
,
378 PRBool aMustCallValueAppended
,
380 PRBool
ParseProperty(nsCSSProperty aPropID
);
381 PRBool
ParseSingleValueProperty(nsCSSValue
& aValue
,
382 nsCSSProperty aPropID
);
385 PRBool
ParseTreePseudoElement(nsCSSSelector
& aSelector
);
388 void InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
);
390 // Property specific parsing routines
391 PRBool
ParseAzimuth(nsCSSValue
& aValue
);
392 PRBool
ParseBackground();
393 PRBool
ParseBackgroundPosition();
394 PRBool
ParseBackgroundPositionValues();
395 PRBool
ParseBoxPosition(nsCSSValuePair
& aOut
);
396 PRBool
ParseBoxPositionValues(nsCSSValuePair
& aOut
);
397 PRBool
ParseBorderColor();
398 PRBool
ParseBorderColors(nsCSSValueList
** aResult
,
399 nsCSSProperty aProperty
);
400 PRBool
ParseBorderImage();
401 PRBool
ParseBorderSpacing();
402 PRBool
ParseBorderSide(const nsCSSProperty aPropIDs
[],
403 PRBool aSetAllSides
);
404 PRBool
ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
405 PRInt32 aSourceType
);
406 PRBool
ParseBorderStyle();
407 PRBool
ParseBorderWidth();
408 // for 'clip' and '-moz-image-region'
409 PRBool
ParseRect(nsCSSRect
& aRect
,
410 nsCSSProperty aPropID
);
411 PRBool
DoParseRect(nsCSSRect
& aRect
);
412 PRBool
ParseContent();
413 PRBool
ParseCounterData(nsCSSValuePairList
** aResult
,
414 nsCSSProperty aPropID
);
416 PRBool
ParseCursor();
418 PRBool
ParseFontWeight(nsCSSValue
& aValue
);
419 PRBool
ParseOneFamily(nsAString
& aValue
);
420 PRBool
ParseFamily(nsCSSValue
& aValue
);
421 PRBool
ParseFontSrc(nsCSSValue
& aValue
);
422 PRBool
ParseFontSrcFormat(nsTArray
<nsCSSValue
>& values
);
423 PRBool
ParseFontRanges(nsCSSValue
& aValue
);
424 PRBool
ParseListStyle();
425 PRBool
ParseMargin();
426 PRBool
ParseMarks(nsCSSValue
& aValue
);
427 PRBool
ParseMozTransform();
428 PRBool
ParseOutline();
429 PRBool
ParseOverflow();
430 PRBool
ParsePadding();
432 PRBool
ParseQuotes();
434 PRBool
ParseTextDecoration(nsCSSValue
& aValue
);
436 nsCSSValueList
* ParseCSSShadowList(PRBool aUsesSpread
);
437 PRBool
ParseTextShadow();
438 PRBool
ParseBoxShadow();
441 PRBool
ParsePaint(nsCSSValuePair
* aResult
,
442 nsCSSProperty aPropID
);
443 PRBool
ParseDasharray();
444 PRBool
ParseMarker();
447 // Reused utility parsing routines
448 void AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
);
449 PRBool
ParseBoxProperties(nsCSSRect
& aResult
,
450 const nsCSSProperty aPropIDs
[]);
451 PRBool
ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
452 PRInt32 aSourceType
);
453 PRBool
ParseBoxCornerRadius(const nsCSSProperty aPropID
);
454 PRBool
ParseBoxCornerRadii(nsCSSCornerSizes
& aRadii
,
455 const nsCSSProperty aPropIDs
[]);
456 PRInt32
ParseChoice(nsCSSValue aValues
[],
457 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
);
458 PRBool
ParseColor(nsCSSValue
& aValue
);
459 PRBool
ParseColorComponent(PRUint8
& aComponent
,
460 PRInt32
& aType
, char aStop
);
461 // ParseHSLColor parses everything starting with the opening '('
462 // up through and including the aStop char.
463 PRBool
ParseHSLColor(nscolor
& aColor
, char aStop
);
464 // ParseColorOpacity will enforce that the color ends with a ')'
466 PRBool
ParseColorOpacity(PRUint8
& aOpacity
);
467 PRBool
ParseEnum(nsCSSValue
& aValue
, const PRInt32 aKeywordTable
[]);
468 PRBool
ParseVariant(nsCSSValue
& aValue
,
469 PRInt32 aVariantMask
,
470 const PRInt32 aKeywordTable
[]);
471 PRBool
ParsePositiveVariant(nsCSSValue
& aValue
,
472 PRInt32 aVariantMask
,
473 const PRInt32 aKeywordTable
[]);
474 PRBool
ParseCounter(nsCSSValue
& aValue
);
475 PRBool
ParseAttr(nsCSSValue
& aValue
);
476 PRBool
ParseURL(nsCSSValue
& aValue
);
477 PRBool
TranslateDimension(nsCSSValue
& aValue
, PRInt32 aVariantMask
,
478 float aNumber
, const nsString
& aUnit
);
480 void SetParsingCompoundProperty(PRBool aBool
) {
481 NS_ASSERTION(aBool
== PR_TRUE
|| aBool
== PR_FALSE
, "bad PRBool value");
482 mParsingCompoundProperty
= aBool
;
484 PRBool
IsParsingCompoundProperty(void) const {
485 return mParsingCompoundProperty
;
488 /* Functions for -moz-transform Parsing */
489 PRBool
ReadSingleTransform(nsCSSValueList
**& aTail
);
490 PRBool
ParseFunction(const nsString
&aFunction
, const PRInt32 aAllowedTypes
[],
491 PRUint16 aMinElems
, PRUint16 aMaxElems
,
493 PRBool
ParseFunctionInternals(const PRInt32 aVariantMask
[],
496 nsTArray
<nsCSSValue
>& aOutput
);
498 /* Functions for -moz-transform-origin Parsing */
499 PRBool
ParseMozTransformOrigin();
502 /* Find and return the correct namespace ID for the prefix aPrefix.
503 If the prefix cannot be resolved to a namespace, this method will
504 return false. Otherwise it will return true. When returning
505 false, it may set the low-level error code, depending on the
506 value of mUnresolvablePrefixException.
508 This method never returns kNameSpaceID_Unknown or
509 kNameSpaceID_None for aNameSpaceID while returning true.
511 PRBool
GetNamespaceIdForPrefix(const nsString
& aPrefix
,
512 PRInt32
* aNameSpaceID
);
514 /* Find the correct default namespace, and set it on aSelector. */
515 void SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
);
517 // Current token. The value is valid after calling GetToken and invalidated
522 nsCSSScanner mScanner
;
524 // The URI to be used as a base for relative URIs.
525 nsCOMPtr
<nsIURI
> mBaseURL
;
527 // The URI to be used as an HTTP "Referer" and for error reporting.
528 nsCOMPtr
<nsIURI
> mSheetURL
;
530 // The principal of the sheet involved
531 nsCOMPtr
<nsIPrincipal
> mSheetPrincipal
;
533 // The sheet we're parsing into
534 nsCOMPtr
<nsICSSStyleSheet
> mSheet
;
536 // Used for @import rules
537 nsICSSLoader
* mChildLoader
; // not ref counted, it owns us
539 // Sheet section we're in. This is used to enforce correct ordering of the
540 // various rule types (eg the fact that a @charset rule must come before
541 // anything else). Note that there are checks of similar things in various
542 // places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
546 eCSSSection_NameSpace
,
549 nsCSSSection mSection
;
551 nsXMLNameSpaceMap
*mNameSpaceMap
; // weak, mSheet owns it
553 // After an UngetToken is done this flag is true. The next call to
554 // GetToken clears the flag.
555 PRPackedBool mHavePushBack
: 1;
557 // True if we are in quirks mode; false in standards or almost standards mode
558 PRPackedBool mNavQuirkMode
: 1;
560 // True if unsafe rules should be allowed
561 PRPackedBool mUnsafeRulesEnabled
: 1;
563 // True for parsing media lists for HTML attributes, where we have to
564 // ignore CSS comments.
565 PRPackedBool mHTMLMediaMode
: 1;
567 // True if tagnames and attributes are case-sensitive
568 PRPackedBool mCaseSensitive
: 1;
570 // This flag is set when parsing a non-box shorthand; it's used to not apply
571 // some quirks during shorthand parsing
572 PRPackedBool mParsingCompoundProperty
: 1;
574 // If this flag is true, failure to resolve a namespace prefix
575 // should set the low-level error to NS_ERROR_DOM_NAMESPACE_ERR
576 PRPackedBool mUnresolvablePrefixException
: 1;
578 // Stack of rule groups; used for @media and such.
579 nsCOMArray
<nsICSSGroupRule
> mGroupStack
;
581 // During the parsing of a property (which may be a shorthand), the data
582 // are stored in |mTempData|. (It is needed to ensure that parser
583 // errors cause the data to be ignored, and to ensure that a
584 // non-'!important' declaration does not override an '!important'
586 nsCSSExpandedDataBlock mTempData
;
588 // All data from successfully parsed properties are placed into |mData|.
589 nsCSSExpandedDataBlock mData
;
592 PRPackedBool mScannerInited
;
596 static void AppendRuleToArray(nsICSSRule
* aRule
, void* aArray
)
598 static_cast<nsCOMArray
<nsICSSRule
>*>(aArray
)->AppendObject(aRule
);
601 static void AppendRuleToSheet(nsICSSRule
* aRule
, void* aParser
)
603 CSSParserImpl
* parser
= (CSSParserImpl
*) aParser
;
604 parser
->AppendRule(aRule
);
608 NS_NewCSSParser(nsICSSParser
** aInstancePtrResult
)
610 CSSParserImpl
*it
= new CSSParserImpl();
613 return NS_ERROR_OUT_OF_MEMORY
;
616 return it
->QueryInterface(NS_GET_IID(nsICSSParser
), (void **) aInstancePtrResult
);
619 #ifdef CSS_REPORT_PARSE_ERRORS
621 #define REPORT_UNEXPECTED(msg_) \
622 mScanner.ReportUnexpected(#msg_)
624 #define REPORT_UNEXPECTED_P(msg_, params_) \
625 mScanner.ReportUnexpectedParams(#msg_, params_, NS_ARRAY_LENGTH(params_))
627 #define REPORT_UNEXPECTED_EOF(lf_) \
628 mScanner.ReportUnexpectedEOF(#lf_)
630 #define REPORT_UNEXPECTED_EOF_CHAR(ch_) \
631 mScanner.ReportUnexpectedEOF(ch_)
633 #define REPORT_UNEXPECTED_TOKEN(msg_) \
634 mScanner.ReportUnexpectedToken(mToken, #msg_)
636 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_) \
637 mScanner.ReportUnexpectedTokenParams(mToken, #msg_, \
638 params_, NS_ARRAY_LENGTH(params_))
641 #define OUTPUT_ERROR() \
642 mScanner.OutputError()
644 #define CLEAR_ERROR() \
645 mScanner.ClearError()
649 #define REPORT_UNEXPECTED(msg_)
650 #define REPORT_UNEXPECTED_P(msg_, params_)
651 #define REPORT_UNEXPECTED_EOF(lf_)
652 #define REPORT_UNEXPECTED_EOF_CHAR(ch_)
653 #define REPORT_UNEXPECTED_TOKEN(msg_)
654 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_)
655 #define OUTPUT_ERROR()
656 #define CLEAR_ERROR()
660 CSSParserImpl::CSSParserImpl()
663 mChildLoader(nsnull
),
664 mSection(eCSSSection_Charset
),
665 mNameSpaceMap(nsnull
),
666 mHavePushBack(PR_FALSE
),
667 mNavQuirkMode(PR_FALSE
),
668 mUnsafeRulesEnabled(PR_FALSE
),
669 mHTMLMediaMode(PR_FALSE
),
670 mCaseSensitive(PR_FALSE
),
671 mParsingCompoundProperty(PR_FALSE
),
672 mUnresolvablePrefixException(PR_FALSE
)
674 , mScannerInited(PR_FALSE
)
679 NS_IMPL_ISUPPORTS1(CSSParserImpl
, nsICSSParser
)
681 CSSParserImpl::~CSSParserImpl()
683 mData
.AssertInitialState();
684 mTempData
.AssertInitialState();
688 CSSParserImpl::SetStyleSheet(nsICSSStyleSheet
* aSheet
)
690 if (aSheet
!= mSheet
) {
691 // Switch to using the new sheet, if any
695 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
697 mNameSpaceMap
= nsnull
;
705 CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive
)
707 NS_ASSERTION(aCaseSensitive
== PR_TRUE
|| aCaseSensitive
== PR_FALSE
, "bad PRBool value");
708 mCaseSensitive
= aCaseSensitive
;
713 CSSParserImpl::SetQuirkMode(PRBool aQuirkMode
)
715 NS_ASSERTION(aQuirkMode
== PR_TRUE
|| aQuirkMode
== PR_FALSE
, "bad PRBool value");
716 mNavQuirkMode
= aQuirkMode
;
722 CSSParserImpl::SetSVGMode(PRBool aSVGMode
)
724 NS_ASSERTION(aSVGMode
== PR_TRUE
|| aSVGMode
== PR_FALSE
,
726 mScanner
.SetSVGMode(aSVGMode
);
732 CSSParserImpl::SetChildLoader(nsICSSLoader
* aChildLoader
)
734 mChildLoader
= aChildLoader
; // not ref counted, it owns us
739 CSSParserImpl::InitScanner(nsIUnicharInputStream
* aInput
, nsIURI
* aSheetURI
,
740 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
741 nsIPrincipal
* aSheetPrincipal
)
743 NS_ASSERTION(! mScannerInited
, "already have scanner");
745 mScanner
.Init(aInput
, nsnull
, 0, aSheetURI
, aLineNumber
);
747 mScannerInited
= PR_TRUE
;
750 mSheetURL
= aSheetURI
;
751 mSheetPrincipal
= aSheetPrincipal
;
753 mHavePushBack
= PR_FALSE
;
757 CSSParserImpl::InitScanner(const nsSubstring
& aString
, nsIURI
* aSheetURI
,
758 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
759 nsIPrincipal
* aSheetPrincipal
)
761 // Having it not own the string is OK since the caller will hold on to
762 // the stream until we're done parsing.
763 NS_ASSERTION(! mScannerInited
, "already have scanner");
765 mScanner
.Init(nsnull
, aString
.BeginReading(), aString
.Length(), aSheetURI
, aLineNumber
);
768 mScannerInited
= PR_TRUE
;
771 mSheetURL
= aSheetURI
;
772 mSheetPrincipal
= aSheetPrincipal
;
774 mHavePushBack
= PR_FALSE
;
778 CSSParserImpl::ReleaseScanner(void)
782 mScannerInited
= PR_FALSE
;
786 mSheetPrincipal
= nsnull
;
791 CSSParserImpl::Parse(nsIUnicharInputStream
* aInput
,
794 nsIPrincipal
* aSheetPrincipal
,
795 PRUint32 aLineNumber
,
796 PRBool aAllowUnsafeRules
)
798 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
800 NS_ASSERTION(nsnull
!= aBaseURI
, "need base URL");
801 NS_ASSERTION(nsnull
!= aSheetURI
, "need sheet URL");
802 AssertInitialState();
804 NS_PRECONDITION(mSheet
, "Must have sheet to parse into");
805 NS_ENSURE_STATE(mSheet
);
808 nsCOMPtr
<nsIURI
> uri
;
809 mSheet
->GetSheetURI(getter_AddRefs(uri
));
811 NS_ASSERTION(NS_SUCCEEDED(aSheetURI
->Equals(uri
, &equal
)) && equal
,
812 "Sheet URI does not match passed URI");
813 NS_ASSERTION(NS_SUCCEEDED(mSheet
->Principal()->Equals(aSheetPrincipal
,
816 "Sheet principal does not match passed principal");
819 InitScanner(aInput
, aSheetURI
, aLineNumber
, aBaseURI
, aSheetPrincipal
);
821 PRInt32 ruleCount
= 0;
822 mSheet
->StyleRuleCount(ruleCount
);
824 nsICSSRule
* lastRule
= nsnull
;
825 mSheet
->GetStyleRuleAt(ruleCount
- 1, lastRule
);
828 lastRule
->GetType(type
);
830 case nsICSSRule::CHARSET_RULE
:
831 case nsICSSRule::IMPORT_RULE
:
832 mSection
= eCSSSection_Import
;
834 case nsICSSRule::NAMESPACE_RULE
:
835 mSection
= eCSSSection_NameSpace
;
838 mSection
= eCSSSection_General
;
841 NS_RELEASE(lastRule
);
845 mSection
= eCSSSection_Charset
; // sheet is empty, any rules are fair
848 mUnsafeRulesEnabled
= aAllowUnsafeRules
;
850 nsCSSToken
* tk
= &mToken
;
852 // Get next non-whitespace token
853 if (!GetToken(PR_TRUE
)) {
857 if (eCSSToken_HTMLComment
== tk
->mType
) {
858 continue; // legal here only
860 if (eCSSToken_AtKeyword
== tk
->mType
) {
861 ParseAtRule(AppendRuleToSheet
, this);
865 if (ParseRuleSet(AppendRuleToSheet
, this)) {
866 mSection
= eCSSSection_General
;
871 mUnsafeRulesEnabled
= PR_FALSE
;
873 // XXX check for low level errors
878 * Determines whether the identifier contained in the given string is a
879 * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1.
882 NonMozillaVendorIdentifier(const nsAString
& ident
)
884 return (ident
.First() == PRUnichar('-') &&
885 !StringBeginsWith(ident
, NS_LITERAL_STRING("-moz-"))) ||
886 ident
.First() == PRUnichar('_');
891 CSSParserImpl::ParseStyleAttribute(const nsAString
& aAttributeValue
,
894 nsIPrincipal
* aNodePrincipal
,
895 nsICSSStyleRule
** aResult
)
897 NS_PRECONDITION(aNodePrincipal
, "Must have principal here!");
898 AssertInitialState();
900 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
903 InitScanner(aAttributeValue
, aDocURL
, 0, aBaseURL
, aNodePrincipal
);
905 mSection
= eCSSSection_General
;
907 // In quirks mode, allow style declarations to have braces or not
910 if (mNavQuirkMode
&& GetToken(PR_TRUE
)) {
911 haveBraces
= eCSSToken_Symbol
== mToken
.mType
&&
912 '{' == mToken
.mSymbol
;
916 haveBraces
= PR_FALSE
;
919 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(haveBraces
);
921 // Create a style rule for the declaration
922 nsICSSStyleRule
* rule
= nsnull
;
923 nsresult rv
= NS_NewCSSStyleRule(&rule
, nsnull
, declaration
);
925 declaration
->RuleAbort();
937 // XXX check for low level errors
942 CSSParserImpl::ParseAndAppendDeclaration(const nsAString
& aBuffer
,
945 nsIPrincipal
* aSheetPrincipal
,
946 nsCSSDeclaration
* aDeclaration
,
947 PRBool aParseOnlyOneDecl
,
949 PRBool aClearOldDecl
)
951 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
952 AssertInitialState();
954 *aChanged
= PR_FALSE
;
956 InitScanner(aBuffer
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
958 mSection
= eCSSSection_General
;
961 mData
.AssertInitialState();
962 aDeclaration
->ClearData();
963 // We could check if it was already empty, but...
966 aDeclaration
->ExpandTo(&mData
);
971 // If we cleared the old decl, then we want to be calling
972 // ValueAppended as we parse.
973 if (!ParseDeclaration(aDeclaration
, PR_FALSE
, aClearOldDecl
, aChanged
)) {
974 rv
= mScanner
.GetLowLevelError();
978 if (!SkipDeclaration(PR_FALSE
)) {
979 rv
= mScanner
.GetLowLevelError();
983 } while (!aParseOnlyOneDecl
);
984 aDeclaration
->CompressFrom(&mData
);
991 CSSParserImpl::ParseRule(const nsAString
& aRule
,
994 nsIPrincipal
* aSheetPrincipal
,
995 nsCOMArray
<nsICSSRule
>& aResult
)
997 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
998 AssertInitialState();
1000 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1002 InitScanner(aRule
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1004 mSection
= eCSSSection_Charset
; // callers are responsible for rejecting invalid rules.
1006 nsCSSToken
* tk
= &mToken
;
1007 // Get first non-whitespace token
1008 if (!GetToken(PR_TRUE
)) {
1009 REPORT_UNEXPECTED(PEParseRuleWSOnly
);
1011 } else if (eCSSToken_AtKeyword
== tk
->mType
) {
1012 ParseAtRule(AppendRuleToArray
, &aResult
);
1016 ParseRuleSet(AppendRuleToArray
, &aResult
);
1020 // XXX check for low-level errors
1025 CSSParserImpl::ParseProperty(const nsCSSProperty aPropID
,
1026 const nsAString
& aPropValue
,
1029 nsIPrincipal
* aSheetPrincipal
,
1030 nsCSSDeclaration
* aDeclaration
,
1033 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1034 AssertInitialState();
1036 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1037 NS_ASSERTION(nsnull
!= aDeclaration
, "Need declaration to parse into!");
1038 *aChanged
= PR_FALSE
;
1040 InitScanner(aPropValue
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1042 mSection
= eCSSSection_General
;
1044 if (eCSSProperty_UNKNOWN
== aPropID
) { // unknown property
1045 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1046 const PRUnichar
*params
[] = {
1049 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
1050 REPORT_UNEXPECTED(PEDeclDropped
);
1056 mData
.AssertInitialState();
1057 mTempData
.AssertInitialState();
1058 aDeclaration
->ExpandTo(&mData
);
1059 nsresult result
= NS_OK
;
1060 PRBool parsedOK
= ParseProperty(aPropID
);
1061 if (parsedOK
&& !GetToken(PR_TRUE
)) {
1062 TransferTempData(aDeclaration
, aPropID
, PR_FALSE
, PR_FALSE
, aChanged
);
1065 // Junk at end of property value.
1066 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
1068 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1069 const PRUnichar
*params
[] = {
1072 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
1073 REPORT_UNEXPECTED(PEDeclDropped
);
1075 ClearTempData(aPropID
);
1076 result
= mScanner
.GetLowLevelError();
1080 aDeclaration
->CompressFrom(&mData
);
1087 CSSParserImpl::ParseMediaList(const nsSubstring
& aBuffer
,
1088 nsIURI
* aURL
, // for error reporting
1089 PRUint32 aLineNumber
, // for error reporting
1090 nsMediaList
* aMediaList
,
1093 // XXX Are there cases where the caller wants to keep what it already
1094 // has in case of parser error?
1095 aMediaList
->Clear();
1097 // fake base URL since media lists don't have URLs in them
1098 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1100 AssertInitialState();
1101 NS_ASSERTION(aHTMLMode
== PR_TRUE
|| aHTMLMode
== PR_FALSE
,
1103 mHTMLMediaMode
= aHTMLMode
;
1105 // XXXldb We need to make the scanner not skip CSS comments! (Or
1108 // For aHTMLMode, we used to follow the parsing rules in
1109 // http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors
1110 // which wouldn't work for media queries since they remove all but the
1111 // first word. However, they're changed in
1112 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2
1113 // (as of 2008-05-29) which says that the media attribute just points
1114 // to a media query. (The main substative difference is the relative
1115 // precedence of commas and paretheses.)
1117 if (!GatherMedia(aMediaList
, PRUnichar(0))) {
1118 aMediaList
->Clear();
1119 aMediaList
->SetNonEmpty(); // don't match anything
1120 if (!mHTMLMediaMode
) {
1124 nsresult rv
= mScanner
.GetLowLevelError();
1127 mHTMLMediaMode
= PR_FALSE
;
1133 CSSParserImpl::ParseColorString(const nsSubstring
& aBuffer
,
1134 nsIURI
* aURL
, // for error reporting
1135 PRUint32 aLineNumber
, // for error reporting
1138 AssertInitialState();
1139 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1142 PRBool colorParsed
= ParseColor(value
);
1143 nsresult rv
= mScanner
.GetLowLevelError();
1148 return NS_FAILED(rv
) ? rv
: NS_ERROR_FAILURE
;
1151 if (value
.GetUnit() == eCSSUnit_String
) {
1153 if (NS_ColorNameToRGB(nsDependentString(value
.GetStringBufferValue()), &rgba
)) {
1157 } else if (value
.GetUnit() == eCSSUnit_Color
) {
1158 (*aColor
) = value
.GetColorValue();
1160 } else if (value
.GetUnit() == eCSSUnit_EnumColor
) {
1161 PRInt32 intValue
= value
.GetIntValue();
1162 if (intValue
>= 0) {
1163 nsCOMPtr
<nsILookAndFeel
> lfSvc
= do_GetService("@mozilla.org/widget/lookandfeel;1");
1166 rv
= lfSvc
->GetColor((nsILookAndFeel::nsColorID
) value
.GetIntValue(), rgba
);
1167 if (NS_SUCCEEDED(rv
))
1171 // XXX - this is NS_COLOR_CURRENTCOLOR, NS_COLOR_MOZ_HYPERLINKTEXT, etc.
1172 // which we don't handle as per the ParseColorString definition. Should
1173 // remove this limitation at some point.
1174 rv
= NS_ERROR_FAILURE
;
1182 CSSParserImpl::ParseSelectorString(const nsSubstring
& aSelectorString
,
1183 nsIURI
* aURL
, // for error reporting
1184 PRUint32 aLineNumber
, // for error reporting
1185 nsCSSSelectorList
**aSelectorList
)
1187 InitScanner(aSelectorString
, aURL
, aLineNumber
, aURL
, nsnull
);
1189 AssertInitialState();
1191 mUnresolvablePrefixException
= PR_TRUE
;
1193 PRBool success
= ParseSelectorList(*aSelectorList
, PR_FALSE
);
1194 nsresult rv
= mScanner
.GetLowLevelError();
1198 mUnresolvablePrefixException
= PR_FALSE
;
1201 NS_ASSERTION(*aSelectorList
, "Should have list!");
1205 NS_ASSERTION(!*aSelectorList
, "Shouldn't have list!");
1206 if (NS_SUCCEEDED(rv
)) {
1207 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
1212 //----------------------------------------------------------------------
1215 CSSParserImpl::GetToken(PRBool aSkipWS
)
1218 if (!mHavePushBack
) {
1219 if (!mScanner
.Next(mToken
)) {
1223 mHavePushBack
= PR_FALSE
;
1224 if (aSkipWS
&& (eCSSToken_WhiteSpace
== mToken
.mType
)) {
1233 CSSParserImpl::GetURLToken()
1236 // XXXldb This pushback code doesn't make sense.
1237 if (! mHavePushBack
) {
1238 if (! mScanner
.NextURL(mToken
)) {
1242 mHavePushBack
= PR_FALSE
;
1243 if (eCSSToken_WhiteSpace
!= mToken
.mType
) {
1251 CSSParserImpl::UngetToken()
1253 NS_PRECONDITION(mHavePushBack
== PR_FALSE
, "double pushback");
1254 mHavePushBack
= PR_TRUE
;
1258 CSSParserImpl::ExpectSymbol(PRUnichar aSymbol
,
1261 if (!GetToken(aSkipWS
)) {
1262 // CSS2.1 specifies that all "open constructs" are to be closed at
1263 // EOF. It simplifies higher layers if we claim to have found an
1264 // ), ], }, or ; if we encounter EOF while looking for one of them.
1265 // Do still issue a diagnostic, to aid debugging.
1266 if (aSymbol
== ')' || aSymbol
== ']' ||
1267 aSymbol
== '}' || aSymbol
== ';') {
1268 REPORT_UNEXPECTED_EOF_CHAR(aSymbol
);
1274 if (mToken
.IsSymbol(aSymbol
)) {
1281 // Checks to see if we're at the end of a property. If an error occurs during
1282 // the check, does not signal a parse error.
1284 CSSParserImpl::CheckEndProperty()
1286 if (!GetToken(PR_TRUE
)) {
1287 return PR_TRUE
; // properties may end with eof
1289 if ((eCSSToken_Symbol
== mToken
.mType
) &&
1290 ((';' == mToken
.mSymbol
) ||
1291 ('!' == mToken
.mSymbol
) ||
1292 ('}' == mToken
.mSymbol
))) {
1293 // XXX need to verify that ! is only followed by "important [;|}]
1294 // XXX this requires a multi-token pushback buffer
1302 // Checks if we're at the end of a property, raising an error if we're not.
1304 CSSParserImpl::ExpectEndProperty()
1306 if (CheckEndProperty())
1309 // If we're here, we read something incorrect, so we should report it.
1310 REPORT_UNEXPECTED_TOKEN(PRExpectEndValue
);
1316 CSSParserImpl::NextIdent()
1318 // XXX Error reporting?
1319 if (!GetToken(PR_TRUE
)) {
1322 if (eCSSToken_Ident
!= mToken
.mType
) {
1326 return &mToken
.mIdent
;
1330 CSSParserImpl::SkipAtRule()
1333 if (!GetToken(PR_TRUE
)) {
1334 REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF
);
1337 if (eCSSToken_Symbol
== mToken
.mType
) {
1338 PRUnichar symbol
= mToken
.mSymbol
;
1339 if (symbol
== ';') {
1342 if (symbol
== '{') {
1345 } else if (symbol
== '(') {
1347 } else if (symbol
== '[') {
1356 CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc
,
1359 if ((mSection
<= eCSSSection_Charset
) &&
1360 (mToken
.mIdent
.LowerCaseEqualsLiteral("charset"))) {
1361 if (ParseCharsetRule(aAppendFunc
, aData
)) {
1362 mSection
= eCSSSection_Import
; // only one charset allowed
1366 if ((mSection
<= eCSSSection_Import
) &&
1367 mToken
.mIdent
.LowerCaseEqualsLiteral("import")) {
1368 if (ParseImportRule(aAppendFunc
, aData
)) {
1369 mSection
= eCSSSection_Import
;
1373 if ((mSection
<= eCSSSection_NameSpace
) &&
1374 mToken
.mIdent
.LowerCaseEqualsLiteral("namespace")) {
1375 if (ParseNameSpaceRule(aAppendFunc
, aData
)) {
1376 mSection
= eCSSSection_NameSpace
;
1380 if (mToken
.mIdent
.LowerCaseEqualsLiteral("media")) {
1381 if (ParseMediaRule(aAppendFunc
, aData
)) {
1382 mSection
= eCSSSection_General
;
1386 if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-document")) {
1387 if (ParseMozDocumentRule(aAppendFunc
, aData
)) {
1388 mSection
= eCSSSection_General
;
1392 if (mToken
.mIdent
.LowerCaseEqualsLiteral("font-face")) {
1393 if (ParseFontFaceRule(aAppendFunc
, aData
)) {
1394 mSection
= eCSSSection_General
;
1398 if (mToken
.mIdent
.LowerCaseEqualsLiteral("page")) {
1399 if (ParsePageRule(aAppendFunc
, aData
)) {
1400 mSection
= eCSSSection_General
;
1405 if (!NonMozillaVendorIdentifier(mToken
.mIdent
)) {
1406 REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule
);
1410 // Skip over unsupported at rule, don't advance section
1411 return SkipAtRule();
1415 CSSParserImpl::ParseCharsetRule(RuleAppendFunc aAppendFunc
,
1418 if (!GetToken(PR_TRUE
)) {
1419 REPORT_UNEXPECTED_EOF(PECharsetRuleEOF
);
1423 if (eCSSToken_String
!= mToken
.mType
) {
1424 REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString
);
1428 nsAutoString charset
= mToken
.mIdent
;
1430 if (!ExpectSymbol(';', PR_TRUE
)) {
1434 nsCOMPtr
<nsICSSRule
> rule
;
1435 NS_NewCSSCharsetRule(getter_AddRefs(rule
), charset
);
1438 (*aAppendFunc
)(rule
, aData
);
1445 CSSParserImpl::GatherURL(nsString
& aURL
)
1447 if (!GetToken(PR_TRUE
)) {
1450 if (eCSSToken_String
== mToken
.mType
) {
1451 aURL
= mToken
.mIdent
;
1454 else if (eCSSToken_Function
== mToken
.mType
&&
1455 mToken
.mIdent
.LowerCaseEqualsLiteral("url") &&
1456 ExpectSymbol('(', PR_FALSE
) &&
1458 (eCSSToken_String
== mToken
.mType
||
1459 eCSSToken_URL
== mToken
.mType
)) {
1460 aURL
= mToken
.mIdent
;
1461 if (ExpectSymbol(')', PR_TRUE
)) {
1469 CSSParserImpl::ParseMediaQuery(PRUnichar aStopSymbol
,
1470 nsMediaQuery
**aQuery
,
1471 PRBool
*aParsedSomething
,
1475 *aParsedSomething
= PR_FALSE
;
1476 *aHitStop
= PR_FALSE
;
1478 // "If the comma-separated list is the empty list it is assumed to
1479 // specify the media query 'all'." (css3-mediaqueries, section
1481 if (!GetToken(PR_TRUE
)) {
1482 *aHitStop
= PR_TRUE
;
1483 // expected termination by EOF
1484 if (aStopSymbol
== PRUnichar(0))
1487 // unexpected termination by EOF
1488 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1492 if (eCSSToken_Symbol
== mToken
.mType
&&
1493 mToken
.mSymbol
== aStopSymbol
) {
1494 *aHitStop
= PR_TRUE
;
1500 *aParsedSomething
= PR_TRUE
;
1502 nsAutoPtr
<nsMediaQuery
> query(new nsMediaQuery
);
1504 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1508 if (ExpectSymbol('(', PR_TRUE
)) {
1509 // we got an expression without a media type
1510 UngetToken(); // so ParseMediaQueryExpression can handle it
1511 query
->SetType(nsGkAtoms::all
);
1512 query
->SetTypeOmitted();
1513 // Just parse the first expression here.
1514 if (!ParseMediaQueryExpression(query
)) {
1516 query
->SetHadUnknownExpression();
1519 nsCOMPtr
<nsIAtom
> mediaType
;
1520 PRBool gotNotOrOnly
= PR_FALSE
;
1522 if (!GetToken(PR_TRUE
)) {
1523 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1526 if (eCSSToken_Ident
!= mToken
.mType
) {
1527 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent
);
1531 // case insensitive from CSS - must be lower cased
1532 ToLowerCase(mToken
.mIdent
);
1533 mediaType
= do_GetAtom(mToken
.mIdent
);
1535 (mediaType
!= nsGkAtoms::_not
&& mediaType
!= nsGkAtoms::only
))
1537 gotNotOrOnly
= PR_TRUE
;
1538 if (mediaType
== nsGkAtoms::_not
)
1539 query
->SetNegated();
1541 query
->SetHasOnly();
1543 query
->SetType(mediaType
);
1547 if (!GetToken(PR_TRUE
)) {
1548 *aHitStop
= PR_TRUE
;
1549 // expected termination by EOF
1550 if (aStopSymbol
== PRUnichar(0))
1553 // unexpected termination by EOF
1554 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1558 if (eCSSToken_Symbol
== mToken
.mType
&&
1559 mToken
.mSymbol
== aStopSymbol
) {
1560 *aHitStop
= PR_TRUE
;
1564 if (eCSSToken_Symbol
== mToken
.mType
&& mToken
.mSymbol
== ',') {
1565 // Done with the expressions for this query
1568 if (eCSSToken_Ident
!= mToken
.mType
||
1569 !mToken
.mIdent
.LowerCaseEqualsLiteral("and")) {
1570 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma
);
1574 if (!ParseMediaQueryExpression(query
)) {
1576 query
->SetHadUnknownExpression();
1579 *aQuery
= query
.forget();
1583 // Returns false only when there is a low-level error in the scanner
1586 CSSParserImpl::GatherMedia(nsMediaList
* aMedia
,
1587 PRUnichar aStopSymbol
)
1590 nsAutoPtr
<nsMediaQuery
> query
;
1591 PRBool parsedSomething
, hitStop
;
1592 if (!ParseMediaQuery(aStopSymbol
, getter_Transfers(query
),
1593 &parsedSomething
, &hitStop
)) {
1594 if (NS_FAILED(mScanner
.GetLowLevelError())) {
1599 if (parsedSomething
) {
1600 aMedia
->SetNonEmpty();
1603 nsresult rv
= aMedia
->AppendQuery(query
);
1604 if (NS_FAILED(rv
)) {
1605 mScanner
.SetLowLevelError(rv
);
1617 CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery
* aQuery
)
1619 if (!ExpectSymbol('(', PR_TRUE
)) {
1620 REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart
);
1623 if (! GetToken(PR_TRUE
)) {
1624 REPORT_UNEXPECTED_EOF(PEMQExpressionEOF
);
1627 if (eCSSToken_Ident
!= mToken
.mType
) {
1628 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1633 nsMediaExpression
*expr
= aQuery
->NewExpression();
1635 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1640 // case insensitive from CSS - must be lower cased
1641 ToLowerCase(mToken
.mIdent
);
1642 const PRUnichar
*featureString
;
1643 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("min-"))) {
1644 expr
->mRange
= nsMediaExpression::eMin
;
1645 featureString
= mToken
.mIdent
.get() + 4;
1646 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("max-"))) {
1647 expr
->mRange
= nsMediaExpression::eMax
;
1648 featureString
= mToken
.mIdent
.get() + 4;
1650 expr
->mRange
= nsMediaExpression::eEqual
;
1651 featureString
= mToken
.mIdent
.get();
1654 nsCOMPtr
<nsIAtom
> mediaFeatureAtom
= do_GetAtom(featureString
);
1655 const nsMediaFeature
*feature
= nsMediaFeatures::features
;
1656 for (; feature
->mName
; ++feature
) {
1657 if (*(feature
->mName
) == mediaFeatureAtom
) {
1661 if (!feature
->mName
||
1662 (expr
->mRange
!= nsMediaExpression::eEqual
&&
1663 feature
->mRangeType
!= nsMediaFeature::eMinMaxAllowed
)) {
1664 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1668 expr
->mFeature
= feature
;
1670 if (!GetToken(PR_TRUE
) || mToken
.IsSymbol(')')) {
1671 // Query expressions for any feature can be given without a value.
1672 // However, min/max prefixes are not allowed.
1673 if (expr
->mRange
!= nsMediaExpression::eEqual
) {
1674 REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue
);
1677 expr
->mValue
.Reset();
1681 if (!mToken
.IsSymbol(':')) {
1682 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd
);
1688 switch (feature
->mValueType
) {
1689 case nsMediaFeature::eLength
:
1690 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_LENGTH
, nsnull
);
1692 case nsMediaFeature::eInteger
:
1693 case nsMediaFeature::eBoolInteger
:
1694 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_INTEGER
, nsnull
);
1695 // Enforce extra restrictions for eBoolInteger
1697 feature
->mValueType
== nsMediaFeature::eBoolInteger
&&
1698 expr
->mValue
.GetIntValue() > 1)
1701 case nsMediaFeature::eIntRatio
:
1703 // Two integers separated by '/', with optional whitespace on
1704 // either side of the '/'.
1705 nsRefPtr
<nsCSSValue::Array
> a
= nsCSSValue::Array::Create(2);
1707 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1711 expr
->mValue
.SetArrayValue(a
, eCSSUnit_Array
);
1712 // We don't bother with ParsePositiveVariant since we have to
1713 // check for != 0 as well; no need to worry about the UngetToken
1714 // since we're throwing out up to the next ')' anyway.
1715 rv
= ParseVariant(a
->Item(0), VARIANT_INTEGER
, nsnull
) &&
1716 a
->Item(0).GetIntValue() > 0 &&
1717 ExpectSymbol('/', PR_TRUE
) &&
1718 ParseVariant(a
->Item(1), VARIANT_INTEGER
, nsnull
) &&
1719 a
->Item(1).GetIntValue() > 0;
1722 case nsMediaFeature::eResolution
:
1723 rv
= GetToken(PR_TRUE
) && mToken
.IsDimension() &&
1724 mToken
.mIntegerValid
&& mToken
.mNumber
> 0.0f
;
1726 // No worries about whether unitless zero is allowed, since the
1727 // value must be positive (and we checked that above).
1728 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(), "IsDimension lied");
1729 if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpi")) {
1730 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Inch
);
1731 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpcm")) {
1732 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Centimeter
);
1738 case nsMediaFeature::eEnumerated
:
1739 rv
= ParseVariant(expr
->mValue
, VARIANT_KEYWORD
,
1740 feature
->mKeywordTable
);
1743 if (!rv
|| !ExpectSymbol(')', PR_TRUE
)) {
1744 REPORT_UNEXPECTED(PEMQExpectedFeatureValue
);
1752 // Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"
1754 CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc
, void* aData
)
1756 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1758 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1763 if (!GatherURL(url
)) {
1764 REPORT_UNEXPECTED_TOKEN(PEImportNotURI
);
1768 if (!ExpectSymbol(';', PR_TRUE
)) {
1769 if (!GatherMedia(media
, ';') ||
1770 !ExpectSymbol(';', PR_TRUE
)) {
1771 REPORT_UNEXPECTED_TOKEN(PEImportUnexpected
);
1772 // don't advance section, simply ignore invalid @import
1776 // Safe to assert this, since we ensured that there is something
1777 // other than the ';' coming after the @import's url() token.
1778 NS_ASSERTION(media
->Count() != 0, "media list must be nonempty");
1781 ProcessImport(url
, media
, aAppendFunc
, aData
);
1787 CSSParserImpl::ProcessImport(const nsString
& aURLSpec
,
1788 nsMediaList
* aMedia
,
1789 RuleAppendFunc aAppendFunc
,
1792 nsCOMPtr
<nsICSSImportRule
> rule
;
1793 nsresult rv
= NS_NewCSSImportRule(getter_AddRefs(rule
), aURLSpec
, aMedia
);
1794 if (NS_FAILED(rv
)) {
1795 mScanner
.SetLowLevelError(rv
);
1798 (*aAppendFunc
)(rule
, aData
);
1801 nsCOMPtr
<nsIURI
> url
;
1802 // XXX should pass a charset!
1803 rv
= NS_NewURI(getter_AddRefs(url
), aURLSpec
, nsnull
, mBaseURL
);
1805 if (NS_FAILED(rv
)) {
1806 // import url is bad
1807 // XXX log this somewhere for easier web page debugging
1808 mScanner
.SetLowLevelError(rv
);
1812 mChildLoader
->LoadChildSheet(mSheet
, url
, aMedia
, rule
);
1818 // Parse the {} part of an @media or @-moz-document rule.
1820 CSSParserImpl::ParseGroupRule(nsICSSGroupRule
* aRule
,
1821 RuleAppendFunc aAppendFunc
,
1824 // XXXbz this could use better error reporting throughout the method
1825 if (!ExpectSymbol('{', PR_TRUE
)) {
1829 // push rule on stack, loop over children
1830 if (!PushGroup(aRule
)) {
1831 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1834 nsCSSSection holdSection
= mSection
;
1835 mSection
= eCSSSection_General
;
1838 // Get next non-whitespace token
1839 if (! GetToken(PR_TRUE
)) {
1840 REPORT_UNEXPECTED_EOF(PEGroupRuleEOF
);
1843 if (mToken
.IsSymbol('}')) { // done!
1847 if (eCSSToken_AtKeyword
== mToken
.mType
) {
1848 SkipAtRule(); // group rules cannot contain @rules
1852 ParseRuleSet(AppendRuleToSheet
, this);
1856 if (!ExpectSymbol('}', PR_TRUE
)) {
1857 mSection
= holdSection
;
1860 (*aAppendFunc
)(aRule
, aData
);
1864 // Parse a CSS2 media rule: "@media medium [, medium] { ... }"
1866 CSSParserImpl::ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aData
)
1868 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1870 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1874 if (GatherMedia(media
, '{')) {
1875 // XXXbz this could use better error reporting throughout the method
1876 nsRefPtr
<nsCSSMediaRule
> rule(new nsCSSMediaRule());
1877 // Append first, so when we do SetMedia() the rule
1878 // knows what its stylesheet is.
1879 if (rule
&& ParseGroupRule(rule
, aAppendFunc
, aData
)) {
1880 rule
->SetMedia(media
);
1888 // Parse a @-moz-document rule. This is like an @media rule, but instead
1889 // of a medium it has a nonempty list of items where each item is either
1890 // url(), url-prefix(), or domain().
1892 CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aData
)
1894 nsCSSDocumentRule::URL
*urls
= nsnull
;
1895 nsCSSDocumentRule::URL
**next
= &urls
;
1897 if (!GetToken(PR_TRUE
) ||
1898 eCSSToken_Function
!= mToken
.mType
||
1899 !(mToken
.mIdent
.LowerCaseEqualsLiteral("url") ||
1900 mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix") ||
1901 mToken
.mIdent
.LowerCaseEqualsLiteral("domain"))) {
1902 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc
);
1906 nsCSSDocumentRule::URL
*cur
= *next
= new nsCSSDocumentRule::URL
;
1908 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1913 if (mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
1914 cur
->func
= nsCSSDocumentRule::eURL
;
1915 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix")) {
1916 cur
->func
= nsCSSDocumentRule::eURLPrefix
;
1917 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("domain")) {
1918 cur
->func
= nsCSSDocumentRule::eDomain
;
1921 if (!ExpectSymbol('(', PR_FALSE
) ||
1923 (eCSSToken_String
!= mToken
.mType
&&
1924 eCSSToken_URL
!= mToken
.mType
)) {
1925 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI
);
1929 if (!ExpectSymbol(')', PR_TRUE
)) {
1934 // We could try to make the URL (as long as it's not domain())
1935 // canonical and absolute with NS_NewURI and GetSpec, but I'm
1936 // inclined to think we shouldn't.
1937 CopyUTF16toUTF8(mToken
.mIdent
, cur
->url
);
1938 } while (ExpectSymbol(',', PR_TRUE
));
1940 nsRefPtr
<nsCSSDocumentRule
> rule(new nsCSSDocumentRule());
1942 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1946 rule
->SetURLs(urls
);
1948 return ParseGroupRule(rule
, aAppendFunc
, aData
);
1951 // Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"
1953 CSSParserImpl::ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
1955 if (!GetToken(PR_TRUE
)) {
1956 REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF
);
1960 nsAutoString prefix
;
1963 if (eCSSToken_Ident
== mToken
.mType
) {
1964 prefix
= mToken
.mIdent
;
1965 // user-specified identifiers are case-sensitive (bug 416106)
1966 if (! GetToken(PR_TRUE
)) {
1967 REPORT_UNEXPECTED_EOF(PEAtNSURIEOF
);
1972 if (eCSSToken_String
== mToken
.mType
) {
1973 url
= mToken
.mIdent
;
1974 if (ExpectSymbol(';', PR_TRUE
)) {
1975 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
1979 else if ((eCSSToken_Function
== mToken
.mType
) &&
1980 (mToken
.mIdent
.LowerCaseEqualsLiteral("url"))) {
1981 if (ExpectSymbol('(', PR_FALSE
)) {
1982 if (GetURLToken()) {
1983 if ((eCSSToken_String
== mToken
.mType
) || (eCSSToken_URL
== mToken
.mType
)) {
1984 url
= mToken
.mIdent
;
1985 if (ExpectSymbol(')', PR_TRUE
)) {
1986 if (ExpectSymbol(';', PR_TRUE
)) {
1987 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
1995 REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected
);
2001 CSSParserImpl::ProcessNameSpace(const nsString
& aPrefix
,
2002 const nsString
& aURLSpec
,
2003 RuleAppendFunc aAppendFunc
,
2006 PRBool result
= PR_FALSE
;
2008 nsCOMPtr
<nsICSSNameSpaceRule
> rule
;
2009 nsCOMPtr
<nsIAtom
> prefix
;
2011 if (!aPrefix
.IsEmpty()) {
2012 prefix
= do_GetAtom(aPrefix
);
2015 NS_NewCSSNameSpaceRule(getter_AddRefs(rule
), prefix
, aURLSpec
);
2017 (*aAppendFunc
)(rule
, aData
);
2019 // If this was the first namespace rule encountered, it will trigger
2020 // creation of a namespace map.
2021 if (!mNameSpaceMap
) {
2022 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
2029 // font-face-rule: '@font-face' '{' font-description '}'
2030 // font-description: font-descriptor+
2032 CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
2034 if (!ExpectSymbol('{', PR_TRUE
))
2037 nsRefPtr
<nsCSSFontFaceRule
> rule(new nsCSSFontFaceRule());
2039 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2044 if (!GetToken(PR_TRUE
)) {
2045 REPORT_UNEXPECTED_EOF(PEFontFaceEOF
);
2048 if (mToken
.IsSymbol('}')) { // done!
2053 // ignore extra semicolons
2054 if (mToken
.IsSymbol(';'))
2057 if (!ParseFontDescriptor(rule
)) {
2058 REPORT_UNEXPECTED(PEDeclSkipped
);
2060 if (!SkipDeclaration(PR_TRUE
))
2064 if (!ExpectSymbol('}', PR_TRUE
))
2066 (*aAppendFunc
)(rule
, aData
);
2070 // font-descriptor: font-family-desc
2071 // | font-style-desc
2072 // | font-weight-desc
2073 // | font-stretch-desc
2075 // | unicode-range-desc
2077 // All font-*-desc productions follow the pattern
2078 // IDENT ':' value ';'
2080 // On entry to this function, mToken is the IDENT.
2083 CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule
* aRule
)
2085 if (eCSSToken_Ident
!= mToken
.mType
) {
2086 REPORT_UNEXPECTED_TOKEN(PEFontDescExpected
);
2090 nsString descName
= mToken
.mIdent
;
2091 if (!ExpectSymbol(':', PR_TRUE
)) {
2092 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
2097 nsCSSFontDesc descID
= nsCSSProps::LookupFontDesc(descName
);
2100 if (descID
== eCSSFontDesc_UNKNOWN
) {
2101 if (NonMozillaVendorIdentifier(descName
)) {
2102 // silently skip other vendors' extensions
2103 SkipDeclaration(PR_TRUE
);
2106 const PRUnichar
*params
[] = {
2109 REPORT_UNEXPECTED_P(PEUnknownFontDesc
, params
);
2114 if (!ParseFontDescriptorValue(descID
, value
)) {
2115 const PRUnichar
*params
[] = {
2118 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
2122 if (!ExpectEndProperty())
2125 aRule
->SetDesc(descID
, value
);
2131 CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc
, void* aData
)
2133 // XXX not yet implemented
2138 CSSParserImpl::SkipUntil(PRUnichar aStopSymbol
)
2140 nsCSSToken
* tk
= &mToken
;
2142 if (!GetToken(PR_TRUE
)) {
2145 if (eCSSToken_Symbol
== tk
->mType
) {
2146 PRUnichar symbol
= tk
->mSymbol
;
2147 if (symbol
== aStopSymbol
) {
2149 } else if ('{' == symbol
) {
2151 } else if ('[' == symbol
) {
2153 } else if ('(' == symbol
) {
2161 CSSParserImpl::GetNonCloseParenToken(PRBool aSkipWS
)
2163 if (!GetToken(aSkipWS
))
2165 if (mToken
.mType
== eCSSToken_Symbol
&& mToken
.mSymbol
== ')') {
2173 CSSParserImpl::SkipDeclaration(PRBool aCheckForBraces
)
2175 nsCSSToken
* tk
= &mToken
;
2177 if (!GetToken(PR_TRUE
)) {
2178 if (aCheckForBraces
) {
2179 REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF
);
2183 if (eCSSToken_Symbol
== tk
->mType
) {
2184 PRUnichar symbol
= tk
->mSymbol
;
2185 if (';' == symbol
) {
2188 if (aCheckForBraces
) {
2189 if ('}' == symbol
) {
2194 if ('{' == symbol
) {
2196 } else if ('(' == symbol
) {
2198 } else if ('[' == symbol
) {
2207 CSSParserImpl::SkipRuleSet()
2209 nsCSSToken
* tk
= &mToken
;
2211 if (!GetToken(PR_TRUE
)) {
2212 REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF
);
2215 if (eCSSToken_Symbol
== tk
->mType
) {
2216 PRUnichar symbol
= tk
->mSymbol
;
2217 if ('{' == symbol
) {
2221 if ('(' == symbol
) {
2223 } else if ('[' == symbol
) {
2231 CSSParserImpl::PushGroup(nsICSSGroupRule
* aRule
)
2233 if (mGroupStack
.AppendObject(aRule
))
2240 CSSParserImpl::PopGroup(void)
2242 PRInt32 count
= mGroupStack
.Count();
2244 mGroupStack
.RemoveObjectAt(count
- 1);
2249 CSSParserImpl::AppendRule(nsICSSRule
* aRule
)
2251 PRInt32 count
= mGroupStack
.Count();
2253 mGroupStack
[count
- 1]->AppendStyleRule(aRule
);
2256 mSheet
->AppendStyleRule(aRule
);
2261 CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aData
)
2263 // First get the list of selectors for the rule
2264 nsCSSSelectorList
* slist
= nsnull
;
2265 PRUint32 linenum
= mScanner
.GetLineNumber();
2266 if (! ParseSelectorList(slist
, PR_TRUE
)) {
2267 REPORT_UNEXPECTED(PEBadSelectorRSIgnored
);
2272 NS_ASSERTION(nsnull
!= slist
, "null selector list");
2275 // Next parse the declaration block
2276 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(PR_TRUE
);
2277 if (nsnull
== declaration
) {
2278 // XXX skip something here
2285 fputs("{\n", stdout
);
2286 declaration
->List();
2287 fputs("}\n", stdout
);
2290 // Translate the selector list and declaration block into style data
2292 nsCOMPtr
<nsICSSStyleRule
> rule
;
2293 NS_NewCSSStyleRule(getter_AddRefs(rule
), slist
, declaration
);
2295 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2299 rule
->SetLineNumber(linenum
);
2300 (*aAppendFunc
)(rule
, aData
);
2306 CSSParserImpl::ParseSelectorList(nsCSSSelectorList
*& aListHead
,
2307 PRBool aTerminateAtBrace
)
2309 nsCSSSelectorList
* list
= nsnull
;
2310 if (! ParseSelectorGroup(list
)) {
2311 // must have at least one selector group
2315 NS_ASSERTION(nsnull
!= list
, "no selector list");
2318 // After that there must either be a "," or a "{" (the latter if
2319 // aTerminateAtBrace is true)
2320 nsCSSToken
* tk
= &mToken
;
2322 if (! GetToken(PR_TRUE
)) {
2323 if (!aTerminateAtBrace
) {
2327 REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF
);
2331 if (eCSSToken_Symbol
== tk
->mType
) {
2332 if (',' == tk
->mSymbol
) {
2333 nsCSSSelectorList
* newList
= nsnull
;
2334 // Another selector group must follow
2335 if (! ParseSelectorGroup(newList
)) {
2338 // add new list to the end of the selector list
2339 list
->mNext
= newList
;
2342 } else if ('{' == tk
->mSymbol
&& aTerminateAtBrace
) {
2347 REPORT_UNEXPECTED_TOKEN(PESelectorListExtra
);
2357 static PRBool
IsSinglePseudoClass(const nsCSSSelector
& aSelector
)
2359 return PRBool((aSelector
.mNameSpace
== kNameSpaceID_Unknown
) &&
2360 (aSelector
.mTag
== nsnull
) &&
2361 (aSelector
.mIDList
== nsnull
) &&
2362 (aSelector
.mClassList
== nsnull
) &&
2363 (aSelector
.mAttrList
== nsnull
) &&
2364 (aSelector
.mNegations
== nsnull
) &&
2365 (aSelector
.mPseudoClassList
!= nsnull
) &&
2366 (aSelector
.mPseudoClassList
->mNext
== nsnull
));
2370 static PRBool
IsTreePseudoElement(nsIAtom
* aPseudo
)
2373 aPseudo
->GetUTF8String(&str
);
2374 static const char moz_tree
[] = ":-moz-tree-";
2375 return nsCRT::strncmp(str
, moz_tree
, PRInt32(sizeof(moz_tree
)-1)) == 0;
2380 CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList
*& aList
)
2382 nsAutoPtr
<nsCSSSelectorList
> list
;
2383 PRUnichar combinator
= PRUnichar(0);
2385 PRBool havePseudoElement
= PR_FALSE
;
2386 PRBool done
= PR_FALSE
;
2388 nsAutoPtr
<nsCSSSelector
> newSelector(new nsCSSSelector());
2390 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2393 nsSelectorParsingStatus parsingStatus
=
2394 ParseSelector(*newSelector
);
2395 if (parsingStatus
== eSelectorParsingStatus_Empty
) {
2397 REPORT_UNEXPECTED(PESelectorGroupNoSelector
);
2401 if (parsingStatus
== eSelectorParsingStatus_Error
) {
2405 if (nsnull
== list
) {
2406 list
= new nsCSSSelectorList();
2407 if (nsnull
== list
) {
2408 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2412 list
->AddSelector(newSelector
);
2413 nsCSSSelector
* listSel
= list
->mSelectors
;
2415 // pull out pseudo elements here
2416 nsPseudoClassList
* prevList
= nsnull
;
2417 nsPseudoClassList
* pseudoClassList
= listSel
->mPseudoClassList
;
2418 while (nsnull
!= pseudoClassList
) {
2419 if (! nsCSSPseudoClasses::IsPseudoClass(pseudoClassList
->mAtom
)) {
2420 havePseudoElement
= PR_TRUE
;
2421 if (IsSinglePseudoClass(*listSel
)) { // convert to pseudo element selector
2422 nsIAtom
* pseudoElement
= pseudoClassList
->mAtom
; // steal ref count
2423 pseudoClassList
->mAtom
= nsnull
;
2425 if (listSel
->mNext
) {// more to the selector
2426 listSel
->mOperator
= PRUnichar('>');
2427 nsAutoPtr
<nsCSSSelector
> empty(new nsCSSSelector());
2429 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2432 list
->AddSelector(empty
); // leave a blank (universal) selector in the middle
2433 listSel
= list
->mSelectors
; // use the new one for the pseudo
2435 listSel
->mTag
= pseudoElement
;
2437 else { // append new pseudo element selector
2438 nsAutoPtr
<nsCSSSelector
> pseudoTagSelector(new nsCSSSelector());
2439 if (!pseudoTagSelector
) {
2440 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2443 pseudoTagSelector
->mTag
= pseudoClassList
->mAtom
; // steal ref count
2445 if (IsTreePseudoElement(pseudoTagSelector
->mTag
)) {
2446 // Take the remaining "pseudoclasses" that we parsed
2447 // inside the tree pseudoelement's ()-list, and
2448 // make our new selector have these pseudoclasses
2449 // in its pseudoclass list.
2450 pseudoTagSelector
->mPseudoClassList
= pseudoClassList
->mNext
;
2451 pseudoClassList
->mNext
= nsnull
;
2454 list
->AddSelector(pseudoTagSelector
);
2455 pseudoClassList
->mAtom
= nsnull
;
2456 listSel
->mOperator
= PRUnichar('>');
2457 if (nsnull
== prevList
) { // delete list entry
2458 listSel
->mPseudoClassList
= pseudoClassList
->mNext
;
2461 prevList
->mNext
= pseudoClassList
->mNext
;
2463 pseudoClassList
->mNext
= nsnull
;
2464 delete pseudoClassList
;
2465 weight
+= listSel
->CalcWeight(); // capture weight from remainder
2467 break; // only one pseudo element per selector
2469 prevList
= pseudoClassList
;
2470 pseudoClassList
= pseudoClassList
->mNext
;
2473 combinator
= PRUnichar(0);
2474 if (!GetToken(PR_FALSE
)) {
2478 // Assume we are done unless we find a combinator here.
2480 if (eCSSToken_WhiteSpace
== mToken
.mType
) {
2481 if (!GetToken(PR_TRUE
)) {
2487 if (eCSSToken_Symbol
== mToken
.mType
&&
2488 ('+' == mToken
.mSymbol
||
2489 '>' == mToken
.mSymbol
||
2490 '~' == mToken
.mSymbol
)) {
2492 combinator
= mToken
.mSymbol
;
2493 list
->mSelectors
->SetOperator(combinator
);
2496 if (eCSSToken_Symbol
== mToken
.mType
&&
2497 ('{' == mToken
.mSymbol
||
2498 ',' == mToken
.mSymbol
)) {
2499 // End of this selector group
2502 UngetToken(); // give it back to selector if we're not done, or make sure
2503 // we see it as the end of the selector if we are.
2506 if (havePseudoElement
) {
2510 weight
+= listSel
->CalcWeight();
2514 if (PRUnichar(0) != combinator
) { // no dangling combinators
2516 // This should report the problematic combinator
2517 REPORT_UNEXPECTED(PESelectorGroupExtraCombinator
);
2519 aList
= list
.forget();
2521 aList
->mWeight
= weight
;
2523 return PRBool(nsnull
!= aList
);
2526 #define SEL_MASK_NSPACE 0x01
2527 #define SEL_MASK_ELEM 0x02
2528 #define SEL_MASK_ID 0x04
2529 #define SEL_MASK_CLASS 0x08
2530 #define SEL_MASK_ATTRIB 0x10
2531 #define SEL_MASK_PCLASS 0x20
2532 #define SEL_MASK_PELEM 0x40
2535 // Parses an ID selector #name
2537 CSSParserImpl::nsSelectorParsingStatus
2538 CSSParserImpl::ParseIDSelector(PRInt32
& aDataMask
,
2539 nsCSSSelector
& aSelector
)
2541 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(),
2542 "Empty mIdent in eCSSToken_ID token?");
2543 aDataMask
|= SEL_MASK_ID
;
2544 aSelector
.AddID(mToken
.mIdent
);
2545 return eSelectorParsingStatus_Continue
;
2549 // Parses a class selector .name
2551 CSSParserImpl::nsSelectorParsingStatus
2552 CSSParserImpl::ParseClassSelector(PRInt32
& aDataMask
,
2553 nsCSSSelector
& aSelector
)
2555 if (! GetToken(PR_FALSE
)) { // get ident
2556 REPORT_UNEXPECTED_EOF(PEClassSelEOF
);
2557 return eSelectorParsingStatus_Error
;
2559 if (eCSSToken_Ident
!= mToken
.mType
) { // malformed selector
2560 REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent
);
2562 return eSelectorParsingStatus_Error
;
2564 aDataMask
|= SEL_MASK_CLASS
;
2566 aSelector
.AddClass(mToken
.mIdent
);
2568 return eSelectorParsingStatus_Continue
;
2572 // Parse a type element selector or a universal selector
2573 // namespace|type or namespace|* or *|* or *
2575 CSSParserImpl::nsSelectorParsingStatus
2576 CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
2577 nsCSSSelector
& aSelector
,
2580 nsAutoString buffer
;
2581 if (mToken
.IsSymbol('*')) { // universal element selector, or universal namespace
2582 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2583 aDataMask
|= SEL_MASK_NSPACE
;
2584 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // namespace wildcard
2586 if (! GetToken(PR_FALSE
)) {
2587 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2588 return eSelectorParsingStatus_Error
;
2590 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2591 aDataMask
|= SEL_MASK_ELEM
;
2592 if (mCaseSensitive
) {
2593 aSelector
.SetTag(mToken
.mIdent
);
2596 ToLowerCase(mToken
.mIdent
, buffer
);
2597 aSelector
.SetTag(buffer
);
2600 else if (mToken
.IsSymbol('*')) { // universal selector
2601 aDataMask
|= SEL_MASK_ELEM
;
2605 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2607 return eSelectorParsingStatus_Error
;
2610 else { // was universal element selector
2611 SetDefaultNamespaceOnSelector(aSelector
);
2612 aDataMask
|= SEL_MASK_ELEM
;
2613 // don't set any tag in the selector
2615 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2616 return eSelectorParsingStatus_Done
;
2619 else if (eCSSToken_Ident
== mToken
.mType
) { // element name or namespace name
2620 buffer
= mToken
.mIdent
; // hang on to ident
2622 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2623 aDataMask
|= SEL_MASK_NSPACE
;
2624 PRInt32 nameSpaceID
;
2625 if (!GetNamespaceIdForPrefix(buffer
, &nameSpaceID
)) {
2626 return eSelectorParsingStatus_Error
;
2628 aSelector
.SetNameSpace(nameSpaceID
);
2630 if (! GetToken(PR_FALSE
)) {
2631 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2632 return eSelectorParsingStatus_Error
;
2634 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2635 aDataMask
|= SEL_MASK_ELEM
;
2636 if (mCaseSensitive
) {
2637 aSelector
.SetTag(mToken
.mIdent
);
2640 ToLowerCase(mToken
.mIdent
, buffer
);
2641 aSelector
.SetTag(buffer
);
2644 else if (mToken
.IsSymbol('*')) { // universal selector
2645 aDataMask
|= SEL_MASK_ELEM
;
2649 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2651 return eSelectorParsingStatus_Error
;
2654 else { // was element name
2655 SetDefaultNamespaceOnSelector(aSelector
);
2656 if (mCaseSensitive
) {
2657 aSelector
.SetTag(buffer
);
2660 ToLowerCase(buffer
);
2661 aSelector
.SetTag(buffer
);
2663 aDataMask
|= SEL_MASK_ELEM
;
2665 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2666 return eSelectorParsingStatus_Done
;
2669 else if (mToken
.IsSymbol('|')) { // No namespace
2670 aDataMask
|= SEL_MASK_NSPACE
;
2671 aSelector
.SetNameSpace(kNameSpaceID_None
); // explicit NO namespace
2673 // get mandatory tag
2674 if (! GetToken(PR_FALSE
)) {
2675 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2676 return eSelectorParsingStatus_Error
;
2678 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2679 aDataMask
|= SEL_MASK_ELEM
;
2680 if (mCaseSensitive
) {
2681 aSelector
.SetTag(mToken
.mIdent
);
2684 ToLowerCase(mToken
.mIdent
, buffer
);
2685 aSelector
.SetTag(buffer
);
2688 else if (mToken
.IsSymbol('*')) { // universal selector
2689 aDataMask
|= SEL_MASK_ELEM
;
2693 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2695 return eSelectorParsingStatus_Error
;
2697 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2698 return eSelectorParsingStatus_Done
;
2702 SetDefaultNamespaceOnSelector(aSelector
);
2706 // restore last token read in case of a negated type selector
2709 return eSelectorParsingStatus_Continue
;
2713 // Parse attribute selectors [attr], [attr=value], [attr|=value],
2714 // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
2716 CSSParserImpl::nsSelectorParsingStatus
2717 CSSParserImpl::ParseAttributeSelector(PRInt32
& aDataMask
,
2718 nsCSSSelector
& aSelector
)
2720 if (! GetToken(PR_TRUE
)) { // premature EOF
2721 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2722 return eSelectorParsingStatus_Error
;
2725 PRInt32 nameSpaceID
= kNameSpaceID_None
;
2727 if (mToken
.IsSymbol('*')) { // wildcard namespace
2728 nameSpaceID
= kNameSpaceID_Unknown
;
2729 if (ExpectSymbol('|', PR_FALSE
)) {
2730 if (! GetToken(PR_FALSE
)) { // premature EOF
2731 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2732 return eSelectorParsingStatus_Error
;
2734 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2735 attr
= mToken
.mIdent
;
2738 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2740 return eSelectorParsingStatus_Error
;
2744 REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar
);
2745 return eSelectorParsingStatus_Error
;
2748 else if (mToken
.IsSymbol('|')) { // NO namespace
2749 if (! GetToken(PR_FALSE
)) { // premature EOF
2750 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2751 return eSelectorParsingStatus_Error
;
2753 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2754 attr
= mToken
.mIdent
;
2757 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2759 return eSelectorParsingStatus_Error
;
2762 else if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
2763 attr
= mToken
.mIdent
; // hang on to it
2764 if (ExpectSymbol('|', PR_FALSE
)) { // was a namespace
2765 if (!GetNamespaceIdForPrefix(attr
, &nameSpaceID
)) {
2766 return eSelectorParsingStatus_Error
;
2768 if (! GetToken(PR_FALSE
)) { // premature EOF
2769 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2770 return eSelectorParsingStatus_Error
;
2772 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2773 attr
= mToken
.mIdent
;
2776 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2778 return eSelectorParsingStatus_Error
;
2783 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
2785 return eSelectorParsingStatus_Error
;
2788 if (! mCaseSensitive
) {
2791 if (! GetToken(PR_TRUE
)) { // premature EOF
2792 REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF
);
2793 return eSelectorParsingStatus_Error
;
2795 if ((eCSSToken_Symbol
== mToken
.mType
) ||
2796 (eCSSToken_Includes
== mToken
.mType
) ||
2797 (eCSSToken_Dashmatch
== mToken
.mType
) ||
2798 (eCSSToken_Beginsmatch
== mToken
.mType
) ||
2799 (eCSSToken_Endsmatch
== mToken
.mType
) ||
2800 (eCSSToken_Containsmatch
== mToken
.mType
)) {
2802 if (eCSSToken_Includes
== mToken
.mType
) {
2803 func
= NS_ATTR_FUNC_INCLUDES
;
2805 else if (eCSSToken_Dashmatch
== mToken
.mType
) {
2806 func
= NS_ATTR_FUNC_DASHMATCH
;
2808 else if (eCSSToken_Beginsmatch
== mToken
.mType
) {
2809 func
= NS_ATTR_FUNC_BEGINSMATCH
;
2811 else if (eCSSToken_Endsmatch
== mToken
.mType
) {
2812 func
= NS_ATTR_FUNC_ENDSMATCH
;
2814 else if (eCSSToken_Containsmatch
== mToken
.mType
) {
2815 func
= NS_ATTR_FUNC_CONTAINSMATCH
;
2817 else if (']' == mToken
.mSymbol
) {
2818 aDataMask
|= SEL_MASK_ATTRIB
;
2819 aSelector
.AddAttribute(nameSpaceID
, attr
);
2820 func
= NS_ATTR_FUNC_SET
;
2822 else if ('=' == mToken
.mSymbol
) {
2823 func
= NS_ATTR_FUNC_EQUALS
;
2826 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2827 UngetToken(); // bad function
2828 return eSelectorParsingStatus_Error
;
2830 if (NS_ATTR_FUNC_SET
!= func
) { // get value
2831 if (! GetToken(PR_TRUE
)) { // premature EOF
2832 REPORT_UNEXPECTED_EOF(PEAttSelValueEOF
);
2833 return eSelectorParsingStatus_Error
;
2835 if ((eCSSToken_Ident
== mToken
.mType
) || (eCSSToken_String
== mToken
.mType
)) {
2836 nsAutoString
value(mToken
.mIdent
);
2837 if (! GetToken(PR_TRUE
)) { // premature EOF
2838 REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF
);
2839 return eSelectorParsingStatus_Error
;
2841 if (mToken
.IsSymbol(']')) {
2842 PRBool isCaseSensitive
= PR_TRUE
;
2844 // If we're parsing a style sheet for an HTML document, and
2845 // the attribute selector is for a non-namespaced attribute,
2846 // then check to see if it's one of the known attributes whose
2847 // VALUE is case-insensitive.
2848 if (!mCaseSensitive
&& nameSpaceID
== kNameSpaceID_None
) {
2849 static const char* caseInsensitiveHTMLAttribute
[] = {
2850 // list based on http://www.w3.org/TR/html4/
2896 // additional attributes not in HTML4
2897 "direction", // marquee
2901 const char* htmlAttr
;
2902 while ((htmlAttr
= caseInsensitiveHTMLAttribute
[i
++])) {
2903 if (attr
.EqualsIgnoreCase(htmlAttr
)) {
2904 isCaseSensitive
= PR_FALSE
;
2909 aDataMask
|= SEL_MASK_ATTRIB
;
2910 aSelector
.AddAttribute(nameSpaceID
, attr
, func
, value
, isCaseSensitive
);
2913 REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose
);
2915 return eSelectorParsingStatus_Error
;
2919 REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue
);
2921 return eSelectorParsingStatus_Error
;
2926 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2927 UngetToken(); // bad dog, no biscut!
2928 return eSelectorParsingStatus_Error
;
2930 return eSelectorParsingStatus_Continue
;
2934 // Parse pseudo-classes and pseudo-elements
2936 CSSParserImpl::nsSelectorParsingStatus
2937 CSSParserImpl::ParsePseudoSelector(PRInt32
& aDataMask
,
2938 nsCSSSelector
& aSelector
,
2941 if (! GetToken(PR_FALSE
)) { // premature eof
2942 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2943 return eSelectorParsingStatus_Error
;
2946 // First, find out whether we are parsing a CSS3 pseudo-element
2947 PRBool parsingPseudoElement
= PR_FALSE
;
2948 if (mToken
.IsSymbol(':')) {
2949 parsingPseudoElement
= PR_TRUE
;
2950 if (! GetToken(PR_FALSE
)) { // premature eof
2951 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2952 return eSelectorParsingStatus_Error
;
2956 // Do some sanity-checking on the token
2957 if (eCSSToken_Ident
!= mToken
.mType
&& eCSSToken_Function
!= mToken
.mType
) {
2958 // malformed selector
2959 REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName
);
2961 return eSelectorParsingStatus_Error
;
2964 // OK, now we know we have an mIdent. Atomize it. All the atoms, for
2965 // pseudo-classes as well as pseudo-elements, start with a single ':'.
2966 nsAutoString buffer
;
2967 buffer
.Append(PRUnichar(':'));
2968 buffer
.Append(mToken
.mIdent
);
2969 ToLowerCase(buffer
);
2970 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(buffer
);
2972 // stash away some info about this pseudo so we only have to get it once.
2973 PRBool isTreePseudo
= PR_FALSE
;
2975 isTreePseudo
= IsTreePseudoElement(pseudo
);
2976 // If a tree pseudo-element is using the function syntax, it will
2977 // get isTree set here and will pass the check below that only
2978 // allows functions if they are in our list of things allowed to be
2979 // functions. If it is _not_ using the function syntax, isTree will
2980 // be false, and it will still pass that check. So the tree
2981 // pseudo-elements are allowed to be either functions or not, as
2983 PRBool isTree
= (eCSSToken_Function
== mToken
.mType
) && isTreePseudo
;
2985 PRBool isPseudoElement
= nsCSSPseudoElements::IsPseudoElement(pseudo
);
2986 // anonymous boxes are only allowed if they're the tree boxes or we have
2987 // enabled unsafe rules
2988 PRBool isAnonBox
= nsCSSAnonBoxes::IsAnonBox(pseudo
) &&
2989 (mUnsafeRulesEnabled
|| isTreePseudo
);
2990 PRBool isPseudoClass
= nsCSSPseudoClasses::IsPseudoClass(pseudo
);
2992 if (!isPseudoClass
&& !isPseudoElement
&& !isAnonBox
) {
2993 // Not a pseudo-class, not a pseudo-element.... forget it
2994 REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown
);
2996 return eSelectorParsingStatus_Error
;
2999 // If it's a function token, it better be on our "ok" list, and if the name
3000 // is that of a function pseudo it better be a function token
3001 if ((eCSSToken_Function
== mToken
.mType
) !=
3006 nsCSSPseudoClasses::notPseudo
== pseudo
||
3007 nsCSSPseudoClasses::HasStringArg(pseudo
) ||
3008 nsCSSPseudoClasses::HasNthPairArg(pseudo
))) {
3009 // There are no other function pseudos
3010 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc
);
3012 return eSelectorParsingStatus_Error
;
3015 // If it starts with "::", it better be a pseudo-element
3016 if (parsingPseudoElement
&&
3019 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE
);
3021 return eSelectorParsingStatus_Error
;
3024 if (!parsingPseudoElement
&& nsCSSPseudoClasses::notPseudo
== pseudo
) {
3025 if (aIsNegated
) { // :not() can't be itself negated
3026 REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot
);
3028 return eSelectorParsingStatus_Error
;
3030 // CSS 3 Negation pseudo-class takes one simple selector as argument
3031 nsSelectorParsingStatus parsingStatus
=
3032 ParseNegatedSimpleSelector(aDataMask
, aSelector
);
3033 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3034 return parsingStatus
;
3037 else if (!parsingPseudoElement
&& isPseudoClass
) {
3038 aDataMask
|= SEL_MASK_PCLASS
;
3039 if (nsCSSPseudoClasses::HasStringArg(pseudo
)) {
3040 nsSelectorParsingStatus parsingStatus
=
3041 ParsePseudoClassWithIdentArg(aSelector
, pseudo
);
3042 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3043 return parsingStatus
;
3046 else if (nsCSSPseudoClasses::HasNthPairArg(pseudo
)) {
3047 nsSelectorParsingStatus parsingStatus
=
3048 ParsePseudoClassWithNthPairArg(aSelector
, pseudo
);
3049 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3050 return parsingStatus
;
3054 aSelector
.AddPseudoClass(pseudo
);
3057 else if (isPseudoElement
|| isAnonBox
) {
3058 // Pseudo-element. Make some more sanity checks.
3060 if (aIsNegated
) { // pseudo-elements can't be negated
3061 REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot
);
3063 return eSelectorParsingStatus_Error
;
3065 // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
3066 // to have a single ':' on them. Others (CSS3+ pseudo-elements and
3067 // various -moz-* pseudo-elements) must have |parsingPseudoElement|
3069 if (!parsingPseudoElement
&&
3070 !nsCSSPseudoElements::IsCSS2PseudoElement(pseudo
)
3075 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly
);
3077 return eSelectorParsingStatus_Error
;
3080 if (0 == (aDataMask
& SEL_MASK_PELEM
)) {
3081 aDataMask
|= SEL_MASK_PELEM
;
3082 aSelector
.AddPseudoClass(pseudo
); // store it here, it gets pulled later
3086 // We have encountered a pseudoelement of the form
3087 // -moz-tree-xxxx(a,b,c). We parse (a,b,c) and add each
3088 // item in the list to the pseudoclass list. They will be pulled
3089 // from the list later along with the pseudo-element.
3090 if (!ParseTreePseudoElement(aSelector
)) {
3091 return eSelectorParsingStatus_Error
;
3096 // ensure selector ends here, must be followed by EOF, space, '{' or ','
3097 if (GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3098 if ((eCSSToken_WhiteSpace
== mToken
.mType
) ||
3099 (mToken
.IsSymbol('{') || mToken
.IsSymbol(','))) {
3101 return eSelectorParsingStatus_Done
;
3103 REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing
);
3105 return eSelectorParsingStatus_Error
;
3108 else { // multiple pseudo elements, not legal
3109 REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE
);
3111 return eSelectorParsingStatus_Error
;
3116 // We should never end up here. Indeed, if we ended up here, we know (from
3117 // the current if/else cascade) that !isPseudoElement and !isAnonBox. But
3118 // then due to our earlier check we know that isPseudoClass. Since we
3119 // didn't fall into the isPseudoClass case in this cascade, we must have
3120 // parsingPseudoElement. But we've already checked the
3121 // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if
3123 NS_NOTREACHED("How did this happen?");
3126 return eSelectorParsingStatus_Continue
;
3130 // Parse the argument of a negation pseudo-class :not()
3132 CSSParserImpl::nsSelectorParsingStatus
3133 CSSParserImpl::ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
3134 nsCSSSelector
& aSelector
)
3136 // Check if we have the first parenthesis
3137 if (!ExpectSymbol('(', PR_FALSE
)) {
3138 REPORT_UNEXPECTED_TOKEN(PENegationBadArg
);
3139 return eSelectorParsingStatus_Error
;
3142 if (! GetToken(PR_TRUE
)) { // premature eof
3143 REPORT_UNEXPECTED_EOF(PENegationEOF
);
3144 return eSelectorParsingStatus_Error
;
3147 // Create a new nsCSSSelector and add it to the end of
3148 // aSelector.mNegations.
3149 // Given the current parsing rules, every selector in mNegations
3150 // contains only one simple selector (css3 definition) within it.
3151 // This could easily change in future versions of CSS, and the only
3152 // thing we need to change to support that is this parsing code.
3153 nsCSSSelector
*newSel
= new nsCSSSelector();
3155 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
3156 return eSelectorParsingStatus_Error
;
3158 nsCSSSelector
* negations
= &aSelector
;
3159 while (negations
->mNegations
) {
3160 negations
= negations
->mNegations
;
3162 negations
->mNegations
= newSel
;
3164 nsSelectorParsingStatus parsingStatus
;
3165 if (eCSSToken_ID
== mToken
.mType
) { // #id
3166 parsingStatus
= ParseIDSelector(aDataMask
, *newSel
);
3168 else if (mToken
.IsSymbol('.')) { // .class
3169 parsingStatus
= ParseClassSelector(aDataMask
, *newSel
);
3171 else if (mToken
.IsSymbol(':')) { // :pseudo
3172 parsingStatus
= ParsePseudoSelector(aDataMask
, *newSel
, PR_TRUE
);
3174 else if (mToken
.IsSymbol('[')) { // [attribute
3175 parsingStatus
= ParseAttributeSelector(aDataMask
, *newSel
);
3178 // then it should be a type element or universal selector
3179 parsingStatus
= ParseTypeOrUniversalSelector(aDataMask
, *newSel
, PR_TRUE
);
3181 if (eSelectorParsingStatus_Error
== parsingStatus
) {
3182 REPORT_UNEXPECTED_TOKEN(PENegationBadInner
);
3183 return parsingStatus
;
3185 // close the parenthesis
3186 if (!ExpectSymbol(')', PR_TRUE
)) {
3187 REPORT_UNEXPECTED_TOKEN(PENegationNoClose
);
3188 return eSelectorParsingStatus_Error
;
3191 return eSelectorParsingStatus_Continue
;
3195 // Parse the argument of a pseudo-class that has an ident arg
3197 CSSParserImpl::nsSelectorParsingStatus
3198 CSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
3201 // Check if we have the first parenthesis
3202 if (!ExpectSymbol('(', PR_FALSE
)) {
3203 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3204 return eSelectorParsingStatus_Error
;
3207 if (! GetToken(PR_TRUE
)) { // premature eof
3208 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3209 return eSelectorParsingStatus_Error
;
3211 // We expect an identifier with a language abbreviation
3212 if (eCSSToken_Ident
!= mToken
.mType
) {
3213 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent
);
3215 // XXX Call SkipUntil to the next ")"?
3216 return eSelectorParsingStatus_Error
;
3219 // Add the pseudo with the language parameter
3220 aSelector
.AddPseudoClass(aPseudo
, mToken
.mIdent
.get());
3222 // close the parenthesis
3223 if (!ExpectSymbol(')', PR_TRUE
)) {
3224 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3225 // XXX Call SkipUntil to the next ")"?
3226 return eSelectorParsingStatus_Error
;
3229 return eSelectorParsingStatus_Continue
;
3232 CSSParserImpl::nsSelectorParsingStatus
3233 CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
3236 PRInt32 numbers
[2] = { 0, 0 };
3237 PRBool lookForB
= PR_TRUE
;
3239 // Check whether we have the first parenthesis
3240 if (!ExpectSymbol('(', PR_FALSE
)) {
3241 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3242 return eSelectorParsingStatus_Error
;
3245 // Follow the whitespace rules as proposed in
3246 // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
3248 if (! GetToken(PR_TRUE
)) {
3249 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3250 return eSelectorParsingStatus_Error
;
3253 if (eCSSToken_Ident
== mToken
.mType
|| eCSSToken_Dimension
== mToken
.mType
) {
3254 // The CSS tokenization doesn't handle :nth-child() containing - well:
3255 // 2n-1 is a dimension
3256 // n-1 is an identifier
3257 // The easiest way to deal with that is to push everything from the
3258 // minus on back onto the scanner's pushback buffer.
3259 PRUint32 truncAt
= 0;
3260 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("n-"))) {
3262 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("-n-"))) {
3266 for (PRUint32 i
= mToken
.mIdent
.Length() - 1; i
>= truncAt
; --i
) {
3267 mScanner
.Pushback(mToken
.mIdent
[i
]);
3269 mToken
.mIdent
.Truncate(truncAt
);
3273 if (eCSSToken_Ident
== mToken
.mType
) {
3274 if (mToken
.mIdent
.EqualsIgnoreCase("odd")) {
3277 lookForB
= PR_FALSE
;
3279 else if (mToken
.mIdent
.EqualsIgnoreCase("even")) {
3282 lookForB
= PR_FALSE
;
3284 else if (mToken
.mIdent
.EqualsIgnoreCase("n")) {
3287 else if (mToken
.mIdent
.EqualsIgnoreCase("-n")) {
3291 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3292 // XXX Call SkipUntil to the next ")"?
3293 return eSelectorParsingStatus_Error
;
3296 else if (eCSSToken_Number
== mToken
.mType
) {
3297 if (!mToken
.mIntegerValid
) {
3298 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3299 // XXX Call SkipUntil to the next ")"?
3300 return eSelectorParsingStatus_Error
;
3302 numbers
[1] = mToken
.mInteger
;
3303 lookForB
= PR_FALSE
;
3305 else if (eCSSToken_Dimension
== mToken
.mType
) {
3306 if (!mToken
.mIntegerValid
|| !mToken
.mIdent
.EqualsIgnoreCase("n")) {
3307 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3308 // XXX Call SkipUntil to the next ")"?
3309 return eSelectorParsingStatus_Error
;
3311 numbers
[0] = mToken
.mInteger
;
3313 // XXX If it's a ')', is that valid? (as 0n+0)
3315 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3316 // XXX Call SkipUntil to the next ")" (unless this is one already)?
3317 return eSelectorParsingStatus_Error
;
3320 if (! GetToken(PR_TRUE
)) {
3321 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3322 return eSelectorParsingStatus_Error
;
3324 if (lookForB
&& !mToken
.IsSymbol(')')) {
3325 // The '+' or '-' sign can optionally be separated by whitespace.
3326 // If it is separated by whitespace from what follows it, it appears
3327 // as a separate token rather than part of the number token.
3328 PRBool haveSign
= PR_FALSE
;
3330 if (mToken
.IsSymbol('+') || mToken
.IsSymbol('-')) {
3332 if (mToken
.IsSymbol('-')) {
3335 if (! GetToken(PR_TRUE
)) {
3336 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3337 return eSelectorParsingStatus_Error
;
3340 if (eCSSToken_Number
!= mToken
.mType
||
3341 !mToken
.mIntegerValid
|| mToken
.mHasSign
== haveSign
) {
3342 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3343 // XXX Call SkipUntil to the next ")"?
3344 return eSelectorParsingStatus_Error
;
3346 numbers
[1] = mToken
.mInteger
* sign
;
3347 if (! GetToken(PR_TRUE
)) {
3348 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3349 return eSelectorParsingStatus_Error
;
3352 if (!mToken
.IsSymbol(')')) {
3353 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3354 // XXX Call SkipUntil to the next ")"?
3355 return eSelectorParsingStatus_Error
;
3357 aSelector
.AddPseudoClass(aPseudo
, numbers
);
3358 return eSelectorParsingStatus_Continue
;
3363 * This is the format for selectors:
3364 * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
3366 CSSParserImpl::nsSelectorParsingStatus
3367 CSSParserImpl::ParseSelector(nsCSSSelector
& aSelector
)
3369 if (! GetToken(PR_TRUE
)) {
3370 REPORT_UNEXPECTED_EOF(PESelectorEOF
);
3371 return eSelectorParsingStatus_Error
;
3374 PRInt32 dataMask
= 0;
3375 nsSelectorParsingStatus parsingStatus
=
3376 ParseTypeOrUniversalSelector(dataMask
, aSelector
, PR_FALSE
);
3377 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3378 return parsingStatus
;
3382 if (eCSSToken_ID
== mToken
.mType
) { // #id
3383 parsingStatus
= ParseIDSelector(dataMask
, aSelector
);
3385 else if (mToken
.IsSymbol('.')) { // .class
3386 parsingStatus
= ParseClassSelector(dataMask
, aSelector
);
3388 else if (mToken
.IsSymbol(':')) { // :pseudo
3389 parsingStatus
= ParsePseudoSelector(dataMask
, aSelector
, PR_FALSE
);
3391 else if (mToken
.IsSymbol('[')) { // [attribute
3392 parsingStatus
= ParseAttributeSelector(dataMask
, aSelector
);
3394 else { // not a selector token, we're done
3395 parsingStatus
= eSelectorParsingStatus_Done
;
3399 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3400 return parsingStatus
;
3403 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3404 return eSelectorParsingStatus_Done
;
3408 return dataMask
? parsingStatus
: eSelectorParsingStatus_Empty
;
3412 CSSParserImpl::ParseDeclarationBlock(PRBool aCheckForBraces
)
3414 if (aCheckForBraces
) {
3415 if (!ExpectSymbol('{', PR_TRUE
)) {
3416 REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart
);
3421 nsCSSDeclaration
* declaration
= new nsCSSDeclaration();
3422 mData
.AssertInitialState();
3426 if (!ParseDeclaration(declaration
, aCheckForBraces
,
3427 PR_TRUE
, &changed
)) {
3428 if (!SkipDeclaration(aCheckForBraces
)) {
3431 if (aCheckForBraces
) {
3432 if (ExpectSymbol('}', PR_TRUE
)) {
3436 // Since the skipped declaration didn't end the block we parse
3437 // the next declaration.
3440 declaration
->CompressFrom(&mData
);
3445 // The types to pass to ParseColorComponent. These correspond to the
3446 // various datatypes that can go within rgb().
3447 #define COLOR_TYPE_UNKNOWN 0
3448 #define COLOR_TYPE_INTEGERS 1
3449 #define COLOR_TYPE_PERCENTAGES 2
3452 CSSParserImpl::ParseColor(nsCSSValue
& aValue
)
3454 if (!GetToken(PR_TRUE
)) {
3455 REPORT_UNEXPECTED_EOF(PEColorEOF
);
3459 nsCSSToken
* tk
= &mToken
;
3461 switch (tk
->mType
) {
3465 if (NS_HexToRGB(tk
->mIdent
, &rgba
)) {
3466 aValue
.SetColorValue(rgba
);
3471 case eCSSToken_Ident
:
3472 if (NS_ColorNameToRGB(tk
->mIdent
, &rgba
)) {
3473 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
3477 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
3478 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
3480 if (nsCSSProps::FindKeyword(keyword
, nsCSSProps::kColorKTable
, value
)) {
3481 aValue
.SetIntValue(value
, eCSSUnit_EnumColor
);
3487 case eCSSToken_Function
:
3488 if (mToken
.mIdent
.LowerCaseEqualsLiteral("rgb")) {
3489 // rgb ( component , component , component )
3491 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3492 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3493 ParseColorComponent(r
, type
, ',') &&
3494 ParseColorComponent(g
, type
, ',') &&
3495 ParseColorComponent(b
, type
, ')')) {
3496 aValue
.SetColorValue(NS_RGB(r
,g
,b
));
3499 return PR_FALSE
; // already pushed back
3501 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
3502 mToken
.mIdent
.LowerCaseEqualsLiteral("rgba")) {
3503 // rgba ( component , component , component , opacity )
3505 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3506 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3507 ParseColorComponent(r
, type
, ',') &&
3508 ParseColorComponent(g
, type
, ',') &&
3509 ParseColorComponent(b
, type
, ',') &&
3510 ParseColorOpacity(a
)) {
3511 aValue
.SetColorValue(NS_RGBA(r
, g
, b
, a
));
3514 return PR_FALSE
; // already pushed back
3516 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("hsl")) {
3517 // hsl ( hue , saturation , lightness )
3518 // "hue" is a number, "saturation" and "lightness" are percentages.
3519 if (ParseHSLColor(rgba
, ')')) {
3520 aValue
.SetColorValue(rgba
);
3525 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
3526 mToken
.mIdent
.LowerCaseEqualsLiteral("hsla")) {
3527 // hsla ( hue , saturation , lightness , opacity )
3528 // "hue" is a number, "saturation" and "lightness" are percentages,
3529 // "opacity" is a number.
3531 if (ParseHSLColor(rgba
, ',') &&
3532 ParseColorOpacity(a
)) {
3533 aValue
.SetColorValue(NS_RGBA(NS_GET_R(rgba
), NS_GET_G(rgba
),
3534 NS_GET_B(rgba
), a
));
3544 // try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)
3545 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) {
3546 // - If the string starts with 'a-f', the nsCSSScanner builds the
3547 // token as a eCSSToken_Ident and we can parse the string as a
3548 // 'xxyyzz' RGB color.
3549 // - If it only contains '0-9' digits, the token is a
3550 // eCSSToken_Number and it must be converted back to a 6
3551 // characters string to be parsed as a RGB color.
3552 // - If it starts with '0-9' and contains any 'a-f', the token is a
3553 // eCSSToken_Dimension, the mNumber part must be converted back to
3554 // a string and the mIdent part must be appended to that string so
3555 // that the resulting string has 6 characters.
3556 // Note: This is a hack for Nav compatibility. Do not attempt to
3557 // simplify it by hacking into the ncCSSScanner. This would be very
3561 switch (tk
->mType
) {
3562 case eCSSToken_Ident
:
3563 str
.Assign(tk
->mIdent
);
3566 case eCSSToken_Number
:
3567 if (tk
->mIntegerValid
) {
3568 PR_snprintf(buffer
, sizeof(buffer
), "%06d", tk
->mInteger
);
3569 str
.AssignWithConversion(buffer
);
3573 case eCSSToken_Dimension
:
3574 if (tk
->mIdent
.Length() <= 6) {
3575 PR_snprintf(buffer
, sizeof(buffer
), "%06.0f", tk
->mNumber
);
3577 temp
.AssignWithConversion(buffer
);
3578 temp
.Right(str
, 6 - tk
->mIdent
.Length());
3579 str
.Append(tk
->mIdent
);
3583 // There is a whole bunch of cases that are
3584 // not handled by this switch. Ignore them.
3587 if (NS_HexToRGB(str
, &rgba
)) {
3588 aValue
.SetColorValue(rgba
);
3594 REPORT_UNEXPECTED_TOKEN(PEColorNotColor
);
3599 // aType will be set if we have already parsed other color components
3600 // in this color spec
3602 CSSParserImpl::ParseColorComponent(PRUint8
& aComponent
,
3606 if (!GetToken(PR_TRUE
)) {
3607 REPORT_UNEXPECTED_EOF(PEColorComponentEOF
);
3611 nsCSSToken
* tk
= &mToken
;
3612 switch (tk
->mType
) {
3613 case eCSSToken_Number
:
3615 case COLOR_TYPE_UNKNOWN
:
3616 aType
= COLOR_TYPE_INTEGERS
;
3618 case COLOR_TYPE_INTEGERS
:
3620 case COLOR_TYPE_PERCENTAGES
:
3621 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3625 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3628 if (!mToken
.mIntegerValid
) {
3629 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3633 value
= tk
->mNumber
;
3635 case eCSSToken_Percentage
:
3637 case COLOR_TYPE_UNKNOWN
:
3638 aType
= COLOR_TYPE_PERCENTAGES
;
3640 case COLOR_TYPE_INTEGERS
:
3641 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3644 case COLOR_TYPE_PERCENTAGES
:
3647 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3649 value
= tk
->mNumber
* 255.0f
;
3652 REPORT_UNEXPECTED_TOKEN(PEColorBadRGBContents
);
3656 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3657 if (value
< 0.0f
) value
= 0.0f
;
3658 if (value
> 255.0f
) value
= 255.0f
;
3659 aComponent
= NSToIntRound(value
);
3662 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3663 const PRUnichar
*params
[] = {
3667 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3673 CSSParserImpl::ParseHSLColor(nscolor
& aColor
,
3677 if (!ExpectSymbol('(', PR_FALSE
)) {
3678 NS_ERROR("How did this get to be a function token?");
3683 if (!GetToken(PR_TRUE
)) {
3684 REPORT_UNEXPECTED_EOF(PEColorHueEOF
);
3687 if (mToken
.mType
!= eCSSToken_Number
) {
3688 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3694 // hue values are wraparound
3697 if (!ExpectSymbol(',', PR_TRUE
)) {
3698 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3702 // Get the saturation
3703 if (!GetToken(PR_TRUE
)) {
3704 REPORT_UNEXPECTED_EOF(PEColorSaturationEOF
);
3707 if (mToken
.mType
!= eCSSToken_Percentage
) {
3708 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3713 if (s
< 0.0f
) s
= 0.0f
;
3714 if (s
> 1.0f
) s
= 1.0f
;
3716 if (!ExpectSymbol(',', PR_TRUE
)) {
3717 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3721 // Get the lightness
3722 if (!GetToken(PR_TRUE
)) {
3723 REPORT_UNEXPECTED_EOF(PEColorLightnessEOF
);
3726 if (mToken
.mType
!= eCSSToken_Percentage
) {
3727 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3732 if (l
< 0.0f
) l
= 0.0f
;
3733 if (l
> 1.0f
) l
= 1.0f
;
3735 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3736 aColor
= NS_HSL2RGB(h
, s
, l
);
3740 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3741 const PRUnichar
*params
[] = {
3745 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3751 CSSParserImpl::ParseColorOpacity(PRUint8
& aOpacity
)
3753 if (!GetToken(PR_TRUE
)) {
3754 REPORT_UNEXPECTED_EOF(PEColorOpacityEOF
);
3758 if (mToken
.mType
!= eCSSToken_Number
) {
3759 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3764 if (mToken
.mNumber
< 0.0f
) {
3765 mToken
.mNumber
= 0.0f
;
3766 } else if (mToken
.mNumber
> 1.0f
) {
3767 mToken
.mNumber
= 1.0f
;
3770 PRUint8 value
= nsStyleUtil::FloatToColorComponent(mToken
.mNumber
);
3771 NS_ASSERTION(fabs(mToken
.mNumber
- value
/255.0f
) <= 0.5f
,
3772 "FloatToColorComponent did something weird");
3774 if (!ExpectSymbol(')', PR_TRUE
)) {
3775 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
3786 CSSParserImpl::ParseTreePseudoElement(nsCSSSelector
& aSelector
)
3788 if (ExpectSymbol('(', PR_FALSE
)) {
3789 while (!ExpectSymbol(')', PR_TRUE
)) {
3790 if (!GetToken(PR_TRUE
)) {
3793 else if (eCSSToken_Ident
== mToken
.mType
) {
3794 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(mToken
.mIdent
);
3795 aSelector
.AddPseudoClass(pseudo
);
3797 else if (eCSSToken_Symbol
== mToken
.mType
) {
3798 if (!mToken
.IsSymbol(','))
3801 else return PR_FALSE
;
3809 //----------------------------------------------------------------------
3812 CSSParserImpl::ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
3813 PRBool aCheckForBraces
,
3814 PRBool aMustCallValueAppended
,
3817 mTempData
.AssertInitialState();
3819 // Get property name
3820 nsCSSToken
* tk
= &mToken
;
3821 nsAutoString propertyName
;
3823 if (!GetToken(PR_TRUE
)) {
3824 if (aCheckForBraces
) {
3825 REPORT_UNEXPECTED_EOF(PEDeclEndEOF
);
3829 if (eCSSToken_Ident
== tk
->mType
) {
3830 propertyName
= tk
->mIdent
;
3831 // grab the ident before the ExpectSymbol trashes the token
3832 if (!ExpectSymbol(':', PR_TRUE
)) {
3833 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
3834 REPORT_UNEXPECTED(PEDeclDropped
);
3840 if (tk
->IsSymbol(';')) {
3841 // dangling semicolons are skipped
3845 if (!tk
->IsSymbol('}')) {
3846 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected
);
3847 REPORT_UNEXPECTED(PEDeclSkipped
);
3850 // Not a declaration...
3855 // Map property name to its ID and then parse the property
3856 nsCSSProperty propID
= nsCSSProps::LookupProperty(propertyName
);
3857 if (eCSSProperty_UNKNOWN
== propID
) { // unknown property
3858 if (!NonMozillaVendorIdentifier(propertyName
)) {
3859 const PRUnichar
*params
[] = {
3862 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
3863 REPORT_UNEXPECTED(PEDeclDropped
);
3869 if (! ParseProperty(propID
)) {
3870 // XXX Much better to put stuff in the value parsers instead...
3871 const PRUnichar
*params
[] = {
3874 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
3875 REPORT_UNEXPECTED(PEDeclDropped
);
3877 ClearTempData(propID
);
3882 // See if the declaration is followed by a "!important" declaration
3883 PRBool isImportant
= PR_FALSE
;
3884 if (!GetToken(PR_TRUE
)) {
3885 // EOF is a perfectly good way to end a declaration and declaration block
3886 TransferTempData(aDeclaration
, propID
, isImportant
,
3887 aMustCallValueAppended
, aChanged
);
3891 if (eCSSToken_Symbol
== tk
->mType
&& '!' == tk
->mSymbol
) {
3892 // Look for important ident
3893 if (!GetToken(PR_TRUE
)) {
3894 // Premature eof is not ok
3895 REPORT_UNEXPECTED_EOF(PEImportantEOF
);
3896 ClearTempData(propID
);
3899 if ((eCSSToken_Ident
!= tk
->mType
) ||
3900 !tk
->mIdent
.LowerCaseEqualsLiteral("important")) {
3901 REPORT_UNEXPECTED_TOKEN(PEExpectedImportant
);
3904 ClearTempData(propID
);
3907 isImportant
= PR_TRUE
;
3910 // Not a !important declaration
3914 // Make sure valid property declaration is terminated with either a
3915 // semicolon, EOF or a right-curly-brace (this last only when
3916 // aCheckForBraces is true).
3917 if (!GetToken(PR_TRUE
)) {
3918 // EOF is a perfectly good way to end a declaration and declaration block
3919 TransferTempData(aDeclaration
, propID
, isImportant
,
3920 aMustCallValueAppended
, aChanged
);
3923 if (eCSSToken_Symbol
== tk
->mType
) {
3924 if (';' == tk
->mSymbol
) {
3925 TransferTempData(aDeclaration
, propID
, isImportant
,
3926 aMustCallValueAppended
, aChanged
);
3929 if (aCheckForBraces
&& '}' == tk
->mSymbol
) {
3930 // Unget the '}' so we'll be able to tell that this is the end
3931 // of the declaration block when we unwind from here.
3933 TransferTempData(aDeclaration
, propID
, isImportant
,
3934 aMustCallValueAppended
, aChanged
);
3938 if (aCheckForBraces
)
3939 REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2
);
3941 REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd
);
3942 REPORT_UNEXPECTED(PEDeclDropped
);
3944 ClearTempData(propID
);
3949 CSSParserImpl::ClearTempData(nsCSSProperty aPropID
)
3951 if (nsCSSProps::IsShorthand(aPropID
)) {
3952 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
3953 mTempData
.ClearProperty(*p
);
3956 mTempData
.ClearProperty(aPropID
);
3958 mTempData
.AssertInitialState();
3962 CSSParserImpl::TransferTempData(nsCSSDeclaration
* aDeclaration
,
3963 nsCSSProperty aPropID
, PRBool aIsImportant
,
3964 PRBool aMustCallValueAppended
,
3967 if (nsCSSProps::IsShorthand(aPropID
)) {
3968 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
3969 DoTransferTempData(aDeclaration
, *p
, aIsImportant
,
3970 aMustCallValueAppended
, aChanged
);
3973 DoTransferTempData(aDeclaration
, aPropID
, aIsImportant
,
3974 aMustCallValueAppended
, aChanged
);
3976 mTempData
.AssertInitialState();
3979 // Perhaps the transferring code should be in nsCSSExpandedDataBlock, in
3980 // case some other caller wants to use it in the future (although I
3981 // can't think of why).
3983 CSSParserImpl::DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
3984 nsCSSProperty aPropID
, PRBool aIsImportant
,
3985 PRBool aMustCallValueAppended
,
3988 NS_ASSERTION(mTempData
.HasPropertyBit(aPropID
), "oops");
3990 if (!mData
.HasImportantBit(aPropID
))
3991 *aChanged
= PR_TRUE
;
3992 mData
.SetImportantBit(aPropID
);
3994 if (mData
.HasImportantBit(aPropID
)) {
3995 mTempData
.ClearProperty(aPropID
);
4000 if (aMustCallValueAppended
|| !mData
.HasPropertyBit(aPropID
)) {
4001 aDeclaration
->ValueAppended(aPropID
);
4004 mData
.SetPropertyBit(aPropID
);
4005 mTempData
.ClearPropertyBit(aPropID
);
4008 * Save needless copying and allocation by calling the destructor in
4009 * the destination, copying memory directly, and then using placement
4012 void *v_source
= mTempData
.PropertyAt(aPropID
);
4013 void *v_dest
= mData
.PropertyAt(aPropID
);
4014 switch (nsCSSProps::kTypeTable
[aPropID
]) {
4015 case eCSSType_Value
: {
4016 nsCSSValue
*source
= static_cast<nsCSSValue
*>(v_source
);
4017 nsCSSValue
*dest
= static_cast<nsCSSValue
*>(v_dest
);
4018 if (*source
!= *dest
)
4019 *aChanged
= PR_TRUE
;
4020 dest
->~nsCSSValue();
4021 memcpy(dest
, source
, sizeof(nsCSSValue
));
4022 new (source
) nsCSSValue();
4025 case eCSSType_Rect
: {
4026 nsCSSRect
*source
= static_cast<nsCSSRect
*>(v_source
);
4027 nsCSSRect
*dest
= static_cast<nsCSSRect
*>(v_dest
);
4028 if (*source
!= *dest
)
4029 *aChanged
= PR_TRUE
;
4031 memcpy(dest
, source
, sizeof(nsCSSRect
));
4032 new (source
) nsCSSRect();
4035 case eCSSType_ValuePair
: {
4036 nsCSSValuePair
*source
= static_cast<nsCSSValuePair
*>(v_source
);
4037 nsCSSValuePair
*dest
= static_cast<nsCSSValuePair
*>(v_dest
);
4038 if (*source
!= *dest
)
4039 *aChanged
= PR_TRUE
;
4040 dest
->~nsCSSValuePair();
4041 memcpy(dest
, source
, sizeof(nsCSSValuePair
));
4042 new (source
) nsCSSValuePair();
4045 case eCSSType_ValueList
: {
4046 nsCSSValueList
**source
= static_cast<nsCSSValueList
**>(v_source
);
4047 nsCSSValueList
**dest
= static_cast<nsCSSValueList
**>(v_dest
);
4048 if (!nsCSSValueList::Equal(*source
, *dest
))
4049 *aChanged
= PR_TRUE
;
4055 case eCSSType_ValuePairList
: {
4056 nsCSSValuePairList
**source
=
4057 static_cast<nsCSSValuePairList
**>(v_source
);
4058 nsCSSValuePairList
**dest
=
4059 static_cast<nsCSSValuePairList
**>(v_dest
);
4060 if (!nsCSSValuePairList::Equal(*source
, *dest
))
4061 *aChanged
= PR_TRUE
;
4069 static const nsCSSProperty kBorderTopIDs
[] = {
4070 eCSSProperty_border_top_width
,
4071 eCSSProperty_border_top_style
,
4072 eCSSProperty_border_top_color
4074 static const nsCSSProperty kBorderRightIDs
[] = {
4075 eCSSProperty_border_right_width_value
,
4076 eCSSProperty_border_right_style_value
,
4077 eCSSProperty_border_right_color_value
,
4078 eCSSProperty_border_right_width
,
4079 eCSSProperty_border_right_style
,
4080 eCSSProperty_border_right_color
4082 static const nsCSSProperty kBorderBottomIDs
[] = {
4083 eCSSProperty_border_bottom_width
,
4084 eCSSProperty_border_bottom_style
,
4085 eCSSProperty_border_bottom_color
4087 static const nsCSSProperty kBorderLeftIDs
[] = {
4088 eCSSProperty_border_left_width_value
,
4089 eCSSProperty_border_left_style_value
,
4090 eCSSProperty_border_left_color_value
,
4091 eCSSProperty_border_left_width
,
4092 eCSSProperty_border_left_style
,
4093 eCSSProperty_border_left_color
4095 static const nsCSSProperty kBorderStartIDs
[] = {
4096 eCSSProperty_border_start_width_value
,
4097 eCSSProperty_border_start_style_value
,
4098 eCSSProperty_border_start_color_value
,
4099 eCSSProperty_border_start_width
,
4100 eCSSProperty_border_start_style
,
4101 eCSSProperty_border_start_color
4103 static const nsCSSProperty kBorderEndIDs
[] = {
4104 eCSSProperty_border_end_width_value
,
4105 eCSSProperty_border_end_style_value
,
4106 eCSSProperty_border_end_color_value
,
4107 eCSSProperty_border_end_width
,
4108 eCSSProperty_border_end_style
,
4109 eCSSProperty_border_end_color
4111 static const nsCSSProperty kColumnRuleIDs
[] = {
4112 eCSSProperty__moz_column_rule_width
,
4113 eCSSProperty__moz_column_rule_style
,
4114 eCSSProperty__moz_column_rule_color
4118 CSSParserImpl::ParseEnum(nsCSSValue
& aValue
,
4119 const PRInt32 aKeywordTable
[])
4121 nsSubstring
* ident
= NextIdent();
4122 if (nsnull
== ident
) {
4125 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(*ident
);
4126 if (eCSSKeyword_UNKNOWN
< keyword
) {
4128 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4129 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4134 // Put the unknown identifier back and return
4141 char name
[5]; // needs to be long enough for the longest unit, with
4142 // terminating null.
4148 #define STR_WITH_LEN(_str) \
4149 _str, sizeof(_str) - 1
4151 const UnitInfo UnitData
[] = {
4152 { STR_WITH_LEN("px"), eCSSUnit_Pixel
, VARIANT_LENGTH
},
4153 { STR_WITH_LEN("em"), eCSSUnit_EM
, VARIANT_LENGTH
},
4154 { STR_WITH_LEN("ex"), eCSSUnit_XHeight
, VARIANT_LENGTH
},
4155 { STR_WITH_LEN("pt"), eCSSUnit_Point
, VARIANT_LENGTH
},
4156 { STR_WITH_LEN("in"), eCSSUnit_Inch
, VARIANT_LENGTH
},
4157 { STR_WITH_LEN("cm"), eCSSUnit_Centimeter
, VARIANT_LENGTH
},
4158 { STR_WITH_LEN("ch"), eCSSUnit_Char
, VARIANT_LENGTH
},
4159 { STR_WITH_LEN("mm"), eCSSUnit_Millimeter
, VARIANT_LENGTH
},
4160 { STR_WITH_LEN("pc"), eCSSUnit_Pica
, VARIANT_LENGTH
},
4161 { STR_WITH_LEN("deg"), eCSSUnit_Degree
, VARIANT_ANGLE
},
4162 { STR_WITH_LEN("grad"), eCSSUnit_Grad
, VARIANT_ANGLE
},
4163 { STR_WITH_LEN("rad"), eCSSUnit_Radian
, VARIANT_ANGLE
},
4164 { STR_WITH_LEN("hz"), eCSSUnit_Hertz
, VARIANT_FREQUENCY
},
4165 { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz
, VARIANT_FREQUENCY
},
4166 { STR_WITH_LEN("s"), eCSSUnit_Seconds
, VARIANT_TIME
},
4167 { STR_WITH_LEN("ms"), eCSSUnit_Milliseconds
, VARIANT_TIME
}
4173 CSSParserImpl::TranslateDimension(nsCSSValue
& aValue
,
4174 PRInt32 aVariantMask
,
4176 const nsString
& aUnit
)
4180 if (!aUnit
.IsEmpty()) {
4182 for (i
= 0; i
< NS_ARRAY_LENGTH(UnitData
); ++i
) {
4183 if (aUnit
.LowerCaseEqualsASCII(UnitData
[i
].name
,
4184 UnitData
[i
].length
)) {
4185 units
= UnitData
[i
].unit
;
4186 type
= UnitData
[i
].type
;
4191 if (i
== NS_ARRAY_LENGTH(UnitData
)) {
4196 // Must be a zero number...
4197 NS_ASSERTION(0 == aNumber
, "numbers without units must be 0");
4198 if ((VARIANT_LENGTH
& aVariantMask
) != 0) {
4199 units
= eCSSUnit_Point
;
4200 type
= VARIANT_LENGTH
;
4202 else if ((VARIANT_ANGLE
& aVariantMask
) != 0) {
4203 units
= eCSSUnit_Degree
;
4204 type
= VARIANT_ANGLE
;
4206 else if ((VARIANT_FREQUENCY
& aVariantMask
) != 0) {
4207 units
= eCSSUnit_Hertz
;
4208 type
= VARIANT_FREQUENCY
;
4210 else if ((VARIANT_TIME
& aVariantMask
) != 0) {
4211 units
= eCSSUnit_Seconds
;
4212 type
= VARIANT_TIME
;
4215 NS_ERROR("Variant mask does not include dimension; why were we called?");
4219 if ((type
& aVariantMask
) != 0) {
4220 aValue
.SetFloatValue(aNumber
, units
);
4227 CSSParserImpl::ParsePositiveVariant(nsCSSValue
& aValue
,
4228 PRInt32 aVariantMask
,
4229 const PRInt32 aKeywordTable
[])
4231 if (ParseVariant(aValue
, aVariantMask
, aKeywordTable
)) {
4232 if (eCSSUnit_Number
== aValue
.GetUnit() ||
4233 aValue
.IsLengthUnit()){
4234 if (aValue
.GetFloatValue() < 0) {
4239 else if (aValue
.GetUnit() == eCSSUnit_Percent
) {
4240 if (aValue
.GetPercentValue() < 0) {
4244 } else if (aValue
.GetUnit() == eCSSUnit_Integer
) {
4245 if (aValue
.GetIntValue() < 0) {
4255 // Assigns to aValue iff it returns PR_TRUE.
4257 CSSParserImpl::ParseVariant(nsCSSValue
& aValue
,
4258 PRInt32 aVariantMask
,
4259 const PRInt32 aKeywordTable
[])
4261 NS_ASSERTION(IsParsingCompoundProperty() ||
4262 ((~aVariantMask
) & (VARIANT_LENGTH
|VARIANT_COLOR
)),
4263 "cannot distinguish lengths and colors in quirks mode");
4265 if (!GetToken(PR_TRUE
)) {
4268 nsCSSToken
* tk
= &mToken
;
4269 if (((aVariantMask
& (VARIANT_AHK
| VARIANT_NORMAL
| VARIANT_NONE
)) != 0) &&
4270 (eCSSToken_Ident
== tk
->mType
)) {
4271 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
4272 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
4273 if ((aVariantMask
& VARIANT_AUTO
) != 0) {
4274 if (eCSSKeyword_auto
== keyword
) {
4275 aValue
.SetAutoValue();
4279 if ((aVariantMask
& VARIANT_INHERIT
) != 0) {
4280 // XXX Should we check IsParsingCompoundProperty, or do all
4281 // callers handle it? (Not all callers set it, though, since
4282 // they want the quirks that are disabled by setting it.)
4283 if (eCSSKeyword_inherit
== keyword
) {
4284 aValue
.SetInheritValue();
4287 else if (eCSSKeyword__moz_initial
== keyword
) { // anything that can inherit can also take an initial val.
4288 aValue
.SetInitialValue();
4292 if ((aVariantMask
& VARIANT_NONE
) != 0) {
4293 if (eCSSKeyword_none
== keyword
) {
4294 aValue
.SetNoneValue();
4298 if ((aVariantMask
& VARIANT_NORMAL
) != 0) {
4299 if (eCSSKeyword_normal
== keyword
) {
4300 aValue
.SetNormalValue();
4304 if ((aVariantMask
& VARIANT_SYSFONT
) != 0) {
4305 if (eCSSKeyword__moz_use_system_font
== keyword
&&
4306 !IsParsingCompoundProperty()) {
4307 aValue
.SetSystemFontValue();
4311 if ((aVariantMask
& VARIANT_KEYWORD
) != 0) {
4313 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4314 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4320 if (((aVariantMask
& (VARIANT_LENGTH
| VARIANT_ANGLE
| VARIANT_FREQUENCY
| VARIANT_TIME
)) != 0) &&
4321 tk
->IsDimension()) {
4322 if (TranslateDimension(aValue
, aVariantMask
, tk
->mNumber
, tk
->mIdent
)) {
4325 // Put the token back; we didn't parse it, so we shouldn't consume it
4329 if (((aVariantMask
& VARIANT_PERCENT
) != 0) &&
4330 (eCSSToken_Percentage
== tk
->mType
)) {
4331 aValue
.SetPercentValue(tk
->mNumber
);
4334 if (((aVariantMask
& VARIANT_NUMBER
) != 0) &&
4335 (eCSSToken_Number
== tk
->mType
)) {
4336 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Number
);
4339 if (((aVariantMask
& VARIANT_INTEGER
) != 0) &&
4340 (eCSSToken_Number
== tk
->mType
) && tk
->mIntegerValid
) {
4341 aValue
.SetIntValue(tk
->mInteger
, eCSSUnit_Integer
);
4344 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) { // NONSTANDARD: Nav interprets unitless numbers as px
4345 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4346 (eCSSToken_Number
== tk
->mType
)) {
4347 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4353 if (IsSVGMode() && !IsParsingCompoundProperty()) {
4354 // STANDARD: SVG Spec states that lengths and coordinates can be unitless
4355 // in which case they default to user-units (1 px = 1 user unit)
4356 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4357 (eCSSToken_Number
== tk
->mType
)) {
4358 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4364 if (((aVariantMask
& VARIANT_URL
) != 0) &&
4365 (eCSSToken_Function
== tk
->mType
) &&
4366 tk
->mIdent
.LowerCaseEqualsLiteral("url")) {
4367 if (ParseURL(aValue
)) {
4372 if ((aVariantMask
& VARIANT_COLOR
) != 0) {
4373 if ((mNavQuirkMode
&& !IsParsingCompoundProperty()) || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
4374 (eCSSToken_ID
== tk
->mType
) ||
4375 (eCSSToken_Ref
== tk
->mType
) ||
4376 (eCSSToken_Ident
== tk
->mType
) ||
4377 ((eCSSToken_Function
== tk
->mType
) &&
4378 (tk
->mIdent
.LowerCaseEqualsLiteral("rgb") ||
4379 tk
->mIdent
.LowerCaseEqualsLiteral("hsl") ||
4380 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
4381 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
4382 tk
->mIdent
.LowerCaseEqualsLiteral("rgba") ||
4383 tk
->mIdent
.LowerCaseEqualsLiteral("hsla"))))
4385 // Put token back so that parse color can get it
4387 if (ParseColor(aValue
)) {
4393 if (((aVariantMask
& VARIANT_STRING
) != 0) &&
4394 (eCSSToken_String
== tk
->mType
)) {
4395 nsAutoString buffer
;
4396 buffer
.Append(tk
->mSymbol
);
4397 buffer
.Append(tk
->mIdent
);
4398 buffer
.Append(tk
->mSymbol
);
4399 aValue
.SetStringValue(buffer
, eCSSUnit_String
);
4402 if (((aVariantMask
& VARIANT_IDENTIFIER
) != 0) &&
4403 (eCSSToken_Ident
== tk
->mType
)) {
4404 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
4407 if (((aVariantMask
& VARIANT_COUNTER
) != 0) &&
4408 (eCSSToken_Function
== tk
->mType
) &&
4409 (tk
->mIdent
.LowerCaseEqualsLiteral("counter") ||
4410 tk
->mIdent
.LowerCaseEqualsLiteral("counters"))) {
4411 return ParseCounter(aValue
);
4413 if (((aVariantMask
& VARIANT_ATTR
) != 0) &&
4414 (eCSSToken_Function
== tk
->mType
) &&
4415 tk
->mIdent
.LowerCaseEqualsLiteral("attr")) {
4416 return ParseAttr(aValue
);
4425 CSSParserImpl::ParseCounter(nsCSSValue
& aValue
)
4427 nsCSSUnit unit
= (mToken
.mIdent
.LowerCaseEqualsLiteral("counter") ?
4428 eCSSUnit_Counter
: eCSSUnit_Counters
);
4430 if (!ExpectSymbol('(', PR_FALSE
))
4433 if (!GetNonCloseParenToken(PR_TRUE
) ||
4434 eCSSToken_Ident
!= mToken
.mType
) {
4439 nsRefPtr
<nsCSSValue::Array
> val
=
4440 nsCSSValue::Array::Create(unit
== eCSSUnit_Counter
? 2 : 3);
4442 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4446 val
->Item(0).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4448 if (eCSSUnit_Counters
== unit
) {
4449 // get mandatory separator string
4450 if (!ExpectSymbol(',', PR_TRUE
) ||
4451 !(GetNonCloseParenToken(PR_TRUE
) &&
4452 eCSSToken_String
== mToken
.mType
)) {
4456 val
->Item(1).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4459 // get optional type
4460 PRInt32 type
= NS_STYLE_LIST_STYLE_DECIMAL
;
4461 if (ExpectSymbol(',', PR_TRUE
)) {
4462 nsCSSKeyword keyword
;
4463 PRBool success
= GetNonCloseParenToken(PR_TRUE
) &&
4464 eCSSToken_Ident
== mToken
.mType
&&
4465 (keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
)) !=
4466 eCSSKeyword_UNKNOWN
;
4468 if (keyword
== eCSSKeyword_none
) {
4469 type
= NS_STYLE_LIST_STYLE_NONE
;
4471 success
= nsCSSProps::FindKeyword(keyword
,
4472 nsCSSProps::kListStyleKTable
, type
);
4480 PRInt32 typeItem
= eCSSUnit_Counters
== unit
? 2 : 1;
4481 val
->Item(typeItem
).SetIntValue(type
, eCSSUnit_Enumerated
);
4483 if (!ExpectSymbol(')', PR_TRUE
)) {
4488 aValue
.SetArrayValue(val
, unit
);
4493 CSSParserImpl::ParseAttr(nsCSSValue
& aValue
)
4495 if (ExpectSymbol('(', PR_FALSE
)) {
4496 if (GetToken(PR_TRUE
)) {
4498 if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
4499 nsAutoString
holdIdent(mToken
.mIdent
);
4500 if (ExpectSymbol('|', PR_FALSE
)) { // namespace
4501 PRInt32 nameSpaceID
;
4502 if (!GetNamespaceIdForPrefix(holdIdent
, &nameSpaceID
)) {
4505 attr
.AppendInt(nameSpaceID
, 10);
4506 attr
.Append(PRUnichar('|'));
4507 if (! GetToken(PR_FALSE
)) {
4508 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4511 if (eCSSToken_Ident
== mToken
.mType
) {
4512 if (mCaseSensitive
) {
4513 attr
.Append(mToken
.mIdent
);
4515 nsAutoString buffer
;
4516 ToLowerCase(mToken
.mIdent
, buffer
);
4517 attr
.Append(buffer
);
4521 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4526 else { // no namespace
4527 if (mCaseSensitive
) {
4531 ToLowerCase(holdIdent
, attr
);
4535 else if (mToken
.IsSymbol('*')) { // namespace wildcard
4536 // Wildcard namespace makes no sense here and is not allowed
4537 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4541 else if (mToken
.IsSymbol('|')) { // explicit NO namespace
4542 if (! GetToken(PR_FALSE
)) {
4543 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4546 if (eCSSToken_Ident
== mToken
.mType
) {
4547 if (mCaseSensitive
) {
4548 attr
.Append(mToken
.mIdent
);
4550 nsAutoString buffer
;
4551 ToLowerCase(mToken
.mIdent
, buffer
);
4552 attr
.Append(buffer
);
4556 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4562 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
4566 if (ExpectSymbol(')', PR_TRUE
)) {
4567 aValue
.SetStringValue(attr
, eCSSUnit_Attr
);
4576 CSSParserImpl::ParseURL(nsCSSValue
& aValue
)
4578 if (!mSheetPrincipal
) {
4579 NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
4580 "origin principal");
4584 if (!ExpectSymbol('(', PR_FALSE
))
4589 nsCSSToken
* tk
= &mToken
;
4590 if (eCSSToken_String
!= tk
->mType
&& eCSSToken_URL
!= tk
->mType
)
4593 nsString url
= tk
->mIdent
;
4594 if (!ExpectSymbol(')', PR_TRUE
))
4597 // Translate url into an absolute url if the url is relative to the
4599 nsCOMPtr
<nsIURI
> uri
;
4600 NS_NewURI(getter_AddRefs(uri
), url
, nsnull
, mBaseURL
);
4602 nsStringBuffer
* buffer
= nsCSSValue::BufferFromString(url
);
4603 if (NS_UNLIKELY(!buffer
)) {
4604 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4607 nsCSSValue::URL
*urlVal
=
4608 new nsCSSValue::URL(uri
, buffer
, mSheetURL
, mSheetPrincipal
);
4611 if (NS_UNLIKELY(!urlVal
)) {
4612 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4615 aValue
.SetURLValue(urlVal
);
4620 CSSParserImpl::ParseChoice(nsCSSValue aValues
[],
4621 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
)
4624 nsAutoParseCompoundProperty
compound(this);
4627 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4628 // Try each property parser in order
4629 PRInt32 hadFound
= found
;
4631 for (index
= 0; index
< aNumIDs
; index
++) {
4632 PRInt32 bit
= 1 << index
;
4633 if ((found
& bit
) == 0) {
4634 if (ParseSingleValueProperty(aValues
[index
], aPropIDs
[index
])) {
4639 if (found
== hadFound
) { // found nothing new
4644 if (1 == found
) { // only first property
4645 if (eCSSUnit_Inherit
== aValues
[0].GetUnit()) { // one inherit, all inherit
4646 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4647 aValues
[loop
].SetInheritValue();
4649 found
= ((1 << aNumIDs
) - 1);
4651 else if (eCSSUnit_Initial
== aValues
[0].GetUnit()) { // one initial, all initial
4652 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4653 aValues
[loop
].SetInitialValue();
4655 found
= ((1 << aNumIDs
) - 1);
4658 else { // more than one value, verify no inherits or initials
4659 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4660 if (eCSSUnit_Inherit
== aValues
[loop
].GetUnit()) {
4664 else if (eCSSUnit_Initial
== aValues
[loop
].GetUnit()) {
4675 CSSParserImpl::AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
)
4677 NS_ASSERTION(0 <= aPropID
&& aPropID
< eCSSProperty_COUNT_no_shorthands
,
4678 "property out of range");
4679 NS_ASSERTION(nsCSSProps::kTypeTable
[aPropID
] == eCSSType_Value
,
4680 nsPrintfCString(64, "type error (property=\'%s\')",
4681 nsCSSProps::GetStringValue(aPropID
).get()).get());
4682 nsCSSValue
& storage
=
4683 *static_cast<nsCSSValue
*>(mTempData
.PropertyAt(aPropID
));
4685 mTempData
.SetPropertyBit(aPropID
);
4689 * Parse a "box" property. Box properties have 1 to 4 values. When less
4690 * than 4 values are provided a standard mapping is used to replicate
4694 CSSParserImpl::ParseBoxProperties(nsCSSRect
& aResult
,
4695 const nsCSSProperty aPropIDs
[])
4697 // Get up to four values for the property
4700 NS_FOR_CSS_SIDES (index
) {
4701 if (! ParseSingleValueProperty(result
.*(nsCSSRect::sides
[index
]),
4707 if ((count
== 0) || (PR_FALSE
== ExpectEndProperty())) {
4711 if (1 < count
) { // verify no more than single inherit or initial
4712 NS_FOR_CSS_SIDES (index
) {
4713 nsCSSUnit unit
= (result
.*(nsCSSRect::sides
[index
])).GetUnit();
4714 if (eCSSUnit_Inherit
== unit
|| eCSSUnit_Initial
== unit
) {
4720 // Provide missing values by replicating some of the values found
4722 case 1: // Make right == top
4723 result
.mRight
= result
.mTop
;
4724 case 2: // Make bottom == top
4725 result
.mBottom
= result
.mTop
;
4726 case 3: // Make left == right
4727 result
.mLeft
= result
.mRight
;
4730 NS_FOR_CSS_SIDES (index
) {
4731 mTempData
.SetPropertyBit(aPropIDs
[index
]);
4738 CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
4739 PRInt32 aSourceType
)
4741 const nsCSSProperty
* subprops
= nsCSSProps::SubpropertyEntryFor(aProperty
);
4742 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
4743 "not box property with physical vs. logical cascading");
4745 if (!ParseSingleValueProperty(value
, subprops
[0]) ||
4746 !ExpectEndProperty())
4749 AppendValue(subprops
[0], value
);
4750 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
4751 AppendValue(subprops
[1], typeVal
);
4752 AppendValue(subprops
[2], typeVal
);
4757 CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID
)
4759 nsCSSValue dimenX
, dimenY
;
4760 // required first value
4761 if (! ParsePositiveVariant(dimenX
, VARIANT_HLP
, nsnull
))
4763 // optional second value (forbidden if first value is inherit/initial)
4764 if (dimenX
.GetUnit() == eCSSUnit_Inherit
||
4765 dimenX
.GetUnit() == eCSSUnit_Initial
||
4766 ! ParsePositiveVariant(dimenY
, VARIANT_LP
, nsnull
))
4769 NS_ASSERTION(nsCSSProps::kTypeTable
[aPropID
] == eCSSType_ValuePair
,
4770 nsPrintfCString(64, "type error (property='%s')",
4771 nsCSSProps::GetStringValue(aPropID
).get())
4773 nsCSSValuePair
& storage
=
4774 *static_cast<nsCSSValuePair
*>(mTempData
.PropertyAt(aPropID
));
4775 storage
.mXValue
= dimenX
;
4776 storage
.mYValue
= dimenY
;
4777 mTempData
.SetPropertyBit(aPropID
);
4782 CSSParserImpl::ParseBoxCornerRadii(nsCSSCornerSizes
& aRadii
,
4783 const nsCSSProperty aPropIDs
[])
4785 // Rectangles are used as scratch storage.
4786 // top => top-left, right => top-right,
4787 // bottom => bottom-right, left => bottom-left.
4788 nsCSSRect dimenX
, dimenY
;
4789 PRInt32 countX
= 0, countY
= 0;
4791 NS_FOR_CSS_SIDES (side
) {
4792 if (! ParsePositiveVariant(dimenX
.*nsCSSRect::sides
[side
],
4793 side
> 0 ? VARIANT_LP
: VARIANT_HLP
, nsnull
))
4800 if (ExpectSymbol('/', PR_TRUE
)) {
4801 NS_FOR_CSS_SIDES (side
) {
4802 if (! ParsePositiveVariant(dimenY
.*nsCSSRect::sides
[side
],
4803 VARIANT_LP
, nsnull
))
4810 if (!ExpectEndProperty())
4813 // if 'initial' or 'inherit' was used, it must be the only value
4814 if (countX
> 1 || countY
> 0) {
4815 nsCSSUnit unit
= dimenX
.mTop
.GetUnit();
4816 if (eCSSUnit_Inherit
== unit
|| eCSSUnit_Initial
== unit
)
4820 // if we have no Y-values, use the X-values
4826 // Provide missing values by replicating some of the values found
4828 case 1: dimenX
.mRight
= dimenX
.mTop
; // top-right same as top-left, and
4829 case 2: dimenX
.mBottom
= dimenX
.mTop
; // bottom-right same as top-left, and
4830 case 3: dimenX
.mLeft
= dimenX
.mRight
; // bottom-left same as top-right
4834 case 1: dimenY
.mRight
= dimenY
.mTop
; // top-right same as top-left, and
4835 case 2: dimenY
.mBottom
= dimenY
.mTop
; // bottom-right same as top-left, and
4836 case 3: dimenY
.mLeft
= dimenY
.mRight
; // bottom-left same as top-right
4839 NS_FOR_CSS_SIDES(side
) {
4840 nsCSSValuePair
& corner
=
4841 aRadii
.GetFullCorner(NS_SIDE_TO_FULL_CORNER(side
, PR_FALSE
));
4842 corner
.mXValue
= dimenX
.*nsCSSRect::sides
[side
];
4843 corner
.mYValue
= dimenY
.*nsCSSRect::sides
[side
];
4844 mTempData
.SetPropertyBit(aPropIDs
[side
]);
4849 // These must be in CSS order (top,right,bottom,left) for indexing to work
4850 static const nsCSSProperty kBorderStyleIDs
[] = {
4851 eCSSProperty_border_top_style
,
4852 eCSSProperty_border_right_style_value
,
4853 eCSSProperty_border_bottom_style
,
4854 eCSSProperty_border_left_style_value
4856 static const nsCSSProperty kBorderWidthIDs
[] = {
4857 eCSSProperty_border_top_width
,
4858 eCSSProperty_border_right_width_value
,
4859 eCSSProperty_border_bottom_width
,
4860 eCSSProperty_border_left_width_value
4862 static const nsCSSProperty kBorderColorIDs
[] = {
4863 eCSSProperty_border_top_color
,
4864 eCSSProperty_border_right_color_value
,
4865 eCSSProperty_border_bottom_color
,
4866 eCSSProperty_border_left_color_value
4868 static const nsCSSProperty kBorderRadiusIDs
[] = {
4869 eCSSProperty__moz_border_radius_topLeft
,
4870 eCSSProperty__moz_border_radius_topRight
,
4871 eCSSProperty__moz_border_radius_bottomRight
,
4872 eCSSProperty__moz_border_radius_bottomLeft
4874 static const nsCSSProperty kOutlineRadiusIDs
[] = {
4875 eCSSProperty__moz_outline_radius_topLeft
,
4876 eCSSProperty__moz_outline_radius_topRight
,
4877 eCSSProperty__moz_outline_radius_bottomRight
,
4878 eCSSProperty__moz_outline_radius_bottomLeft
4882 CSSParserImpl::ParseProperty(nsCSSProperty aPropID
)
4884 NS_ASSERTION(aPropID
< eCSSProperty_COUNT
, "index out of range");
4886 switch (aPropID
) { // handle shorthand or multiple properties
4887 case eCSSProperty_background
:
4888 return ParseBackground();
4889 case eCSSProperty_background_position
:
4890 return ParseBackgroundPosition();
4891 case eCSSProperty_border
:
4892 return ParseBorderSide(kBorderTopIDs
, PR_TRUE
);
4893 case eCSSProperty_border_color
:
4894 return ParseBorderColor();
4895 case eCSSProperty_border_spacing
:
4896 return ParseBorderSpacing();
4897 case eCSSProperty_border_style
:
4898 return ParseBorderStyle();
4899 case eCSSProperty_border_bottom
:
4900 return ParseBorderSide(kBorderBottomIDs
, PR_FALSE
);
4901 case eCSSProperty_border_end
:
4902 return ParseDirectionalBorderSide(kBorderEndIDs
,
4903 NS_BOXPROP_SOURCE_LOGICAL
);
4904 case eCSSProperty_border_left
:
4905 return ParseDirectionalBorderSide(kBorderLeftIDs
,
4906 NS_BOXPROP_SOURCE_PHYSICAL
);
4907 case eCSSProperty_border_right
:
4908 return ParseDirectionalBorderSide(kBorderRightIDs
,
4909 NS_BOXPROP_SOURCE_PHYSICAL
);
4910 case eCSSProperty_border_start
:
4911 return ParseDirectionalBorderSide(kBorderStartIDs
,
4912 NS_BOXPROP_SOURCE_LOGICAL
);
4913 case eCSSProperty_border_top
:
4914 return ParseBorderSide(kBorderTopIDs
, PR_FALSE
);
4915 case eCSSProperty_border_bottom_colors
:
4916 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mBottom
,
4918 case eCSSProperty_border_left_colors
:
4919 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mLeft
,
4921 case eCSSProperty_border_right_colors
:
4922 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mRight
,
4924 case eCSSProperty_border_top_colors
:
4925 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mTop
,
4927 case eCSSProperty_border_image
:
4928 return ParseBorderImage();
4929 case eCSSProperty_border_width
:
4930 return ParseBorderWidth();
4931 case eCSSProperty_border_end_color
:
4932 return ParseDirectionalBoxProperty(eCSSProperty_border_end_color
,
4933 NS_BOXPROP_SOURCE_LOGICAL
);
4934 case eCSSProperty_border_left_color
:
4935 return ParseDirectionalBoxProperty(eCSSProperty_border_left_color
,
4936 NS_BOXPROP_SOURCE_PHYSICAL
);
4937 case eCSSProperty_border_right_color
:
4938 return ParseDirectionalBoxProperty(eCSSProperty_border_right_color
,
4939 NS_BOXPROP_SOURCE_PHYSICAL
);
4940 case eCSSProperty_border_start_color
:
4941 return ParseDirectionalBoxProperty(eCSSProperty_border_start_color
,
4942 NS_BOXPROP_SOURCE_LOGICAL
);
4943 case eCSSProperty_border_end_width
:
4944 return ParseDirectionalBoxProperty(eCSSProperty_border_end_width
,
4945 NS_BOXPROP_SOURCE_LOGICAL
);
4946 case eCSSProperty_border_left_width
:
4947 return ParseDirectionalBoxProperty(eCSSProperty_border_left_width
,
4948 NS_BOXPROP_SOURCE_PHYSICAL
);
4949 case eCSSProperty_border_right_width
:
4950 return ParseDirectionalBoxProperty(eCSSProperty_border_right_width
,
4951 NS_BOXPROP_SOURCE_PHYSICAL
);
4952 case eCSSProperty_border_start_width
:
4953 return ParseDirectionalBoxProperty(eCSSProperty_border_start_width
,
4954 NS_BOXPROP_SOURCE_LOGICAL
);
4955 case eCSSProperty_border_end_style
:
4956 return ParseDirectionalBoxProperty(eCSSProperty_border_end_style
,
4957 NS_BOXPROP_SOURCE_LOGICAL
);
4958 case eCSSProperty_border_left_style
:
4959 return ParseDirectionalBoxProperty(eCSSProperty_border_left_style
,
4960 NS_BOXPROP_SOURCE_PHYSICAL
);
4961 case eCSSProperty_border_right_style
:
4962 return ParseDirectionalBoxProperty(eCSSProperty_border_right_style
,
4963 NS_BOXPROP_SOURCE_PHYSICAL
);
4964 case eCSSProperty_border_start_style
:
4965 return ParseDirectionalBoxProperty(eCSSProperty_border_start_style
,
4966 NS_BOXPROP_SOURCE_LOGICAL
);
4967 case eCSSProperty__moz_border_radius
:
4968 return ParseBoxCornerRadii(mTempData
.mMargin
.mBorderRadius
,
4970 case eCSSProperty__moz_outline_radius
:
4971 return ParseBoxCornerRadii(mTempData
.mMargin
.mOutlineRadius
,
4974 case eCSSProperty__moz_border_radius_topLeft
:
4975 case eCSSProperty__moz_border_radius_topRight
:
4976 case eCSSProperty__moz_border_radius_bottomRight
:
4977 case eCSSProperty__moz_border_radius_bottomLeft
:
4978 case eCSSProperty__moz_outline_radius_topLeft
:
4979 case eCSSProperty__moz_outline_radius_topRight
:
4980 case eCSSProperty__moz_outline_radius_bottomRight
:
4981 case eCSSProperty__moz_outline_radius_bottomLeft
:
4982 return ParseBoxCornerRadius(aPropID
);
4984 case eCSSProperty_box_shadow
:
4985 return ParseBoxShadow();
4986 case eCSSProperty_clip
:
4987 return ParseRect(mTempData
.mDisplay
.mClip
, eCSSProperty_clip
);
4988 case eCSSProperty__moz_column_rule
:
4989 return ParseBorderSide(kColumnRuleIDs
, PR_FALSE
);
4990 case eCSSProperty_content
:
4991 return ParseContent();
4992 case eCSSProperty_counter_increment
:
4993 return ParseCounterData(&mTempData
.mContent
.mCounterIncrement
,
4995 case eCSSProperty_counter_reset
:
4996 return ParseCounterData(&mTempData
.mContent
.mCounterReset
,
4998 case eCSSProperty_cue
:
5000 case eCSSProperty_cursor
:
5001 return ParseCursor();
5002 case eCSSProperty_font
:
5004 case eCSSProperty_image_region
:
5005 return ParseRect(mTempData
.mList
.mImageRegion
,
5006 eCSSProperty_image_region
);
5007 case eCSSProperty_list_style
:
5008 return ParseListStyle();
5009 case eCSSProperty_margin
:
5010 return ParseMargin();
5011 case eCSSProperty_margin_end
:
5012 return ParseDirectionalBoxProperty(eCSSProperty_margin_end
,
5013 NS_BOXPROP_SOURCE_LOGICAL
);
5014 case eCSSProperty_margin_left
:
5015 return ParseDirectionalBoxProperty(eCSSProperty_margin_left
,
5016 NS_BOXPROP_SOURCE_PHYSICAL
);
5017 case eCSSProperty_margin_right
:
5018 return ParseDirectionalBoxProperty(eCSSProperty_margin_right
,
5019 NS_BOXPROP_SOURCE_PHYSICAL
);
5020 case eCSSProperty_margin_start
:
5021 return ParseDirectionalBoxProperty(eCSSProperty_margin_start
,
5022 NS_BOXPROP_SOURCE_LOGICAL
);
5023 case eCSSProperty_outline
:
5024 return ParseOutline();
5025 case eCSSProperty_overflow
:
5026 return ParseOverflow();
5027 case eCSSProperty_padding
:
5028 return ParsePadding();
5029 case eCSSProperty_padding_end
:
5030 return ParseDirectionalBoxProperty(eCSSProperty_padding_end
,
5031 NS_BOXPROP_SOURCE_LOGICAL
);
5032 case eCSSProperty_padding_left
:
5033 return ParseDirectionalBoxProperty(eCSSProperty_padding_left
,
5034 NS_BOXPROP_SOURCE_PHYSICAL
);
5035 case eCSSProperty_padding_right
:
5036 return ParseDirectionalBoxProperty(eCSSProperty_padding_right
,
5037 NS_BOXPROP_SOURCE_PHYSICAL
);
5038 case eCSSProperty_padding_start
:
5039 return ParseDirectionalBoxProperty(eCSSProperty_padding_start
,
5040 NS_BOXPROP_SOURCE_LOGICAL
);
5041 case eCSSProperty_pause
:
5042 return ParsePause();
5043 case eCSSProperty_quotes
:
5044 return ParseQuotes();
5045 case eCSSProperty_size
:
5047 case eCSSProperty_text_shadow
:
5048 return ParseTextShadow();
5049 case eCSSProperty__moz_transform
:
5050 return ParseMozTransform();
5051 case eCSSProperty__moz_transform_origin
:
5052 return ParseMozTransformOrigin();
5055 case eCSSProperty_fill
:
5056 return ParsePaint(&mTempData
.mSVG
.mFill
, eCSSProperty_fill
);
5057 case eCSSProperty_stroke
:
5058 return ParsePaint(&mTempData
.mSVG
.mStroke
, eCSSProperty_stroke
);
5059 case eCSSProperty_stroke_dasharray
:
5060 return ParseDasharray();
5061 case eCSSProperty_marker
:
5062 return ParseMarker();
5065 // Strip out properties we use internally.
5066 case eCSSProperty__x_system_font
:
5067 case eCSSProperty_margin_end_value
:
5068 case eCSSProperty_margin_left_value
:
5069 case eCSSProperty_margin_right_value
:
5070 case eCSSProperty_margin_start_value
:
5071 case eCSSProperty_margin_left_ltr_source
:
5072 case eCSSProperty_margin_left_rtl_source
:
5073 case eCSSProperty_margin_right_ltr_source
:
5074 case eCSSProperty_margin_right_rtl_source
:
5075 case eCSSProperty_padding_end_value
:
5076 case eCSSProperty_padding_left_value
:
5077 case eCSSProperty_padding_right_value
:
5078 case eCSSProperty_padding_start_value
:
5079 case eCSSProperty_padding_left_ltr_source
:
5080 case eCSSProperty_padding_left_rtl_source
:
5081 case eCSSProperty_padding_right_ltr_source
:
5082 case eCSSProperty_padding_right_rtl_source
:
5083 case eCSSProperty_border_end_color_value
:
5084 case eCSSProperty_border_left_color_value
:
5085 case eCSSProperty_border_right_color_value
:
5086 case eCSSProperty_border_start_color_value
:
5087 case eCSSProperty_border_left_color_ltr_source
:
5088 case eCSSProperty_border_left_color_rtl_source
:
5089 case eCSSProperty_border_right_color_ltr_source
:
5090 case eCSSProperty_border_right_color_rtl_source
:
5091 case eCSSProperty_border_end_style_value
:
5092 case eCSSProperty_border_left_style_value
:
5093 case eCSSProperty_border_right_style_value
:
5094 case eCSSProperty_border_start_style_value
:
5095 case eCSSProperty_border_left_style_ltr_source
:
5096 case eCSSProperty_border_left_style_rtl_source
:
5097 case eCSSProperty_border_right_style_ltr_source
:
5098 case eCSSProperty_border_right_style_rtl_source
:
5099 case eCSSProperty_border_end_width_value
:
5100 case eCSSProperty_border_left_width_value
:
5101 case eCSSProperty_border_right_width_value
:
5102 case eCSSProperty_border_start_width_value
:
5103 case eCSSProperty_border_left_width_ltr_source
:
5104 case eCSSProperty_border_left_width_rtl_source
:
5105 case eCSSProperty_border_right_width_ltr_source
:
5106 case eCSSProperty_border_right_width_rtl_source
:
5107 // The user can't use these
5108 REPORT_UNEXPECTED(PEInaccessibleProperty2
);
5110 default: // must be single property
5113 if (ParseSingleValueProperty(value
, aPropID
)) {
5114 if (ExpectEndProperty()) {
5115 AppendValue(aPropID
, value
);
5118 // XXX Report errors?
5120 // XXX Report errors?
5126 // Bits used in determining which background position info we have
5127 #define BG_CENTER NS_STYLE_BG_POSITION_CENTER
5128 #define BG_TOP NS_STYLE_BG_POSITION_TOP
5129 #define BG_BOTTOM NS_STYLE_BG_POSITION_BOTTOM
5130 #define BG_LEFT NS_STYLE_BG_POSITION_LEFT
5131 #define BG_RIGHT NS_STYLE_BG_POSITION_RIGHT
5132 #define BG_CTB (BG_CENTER | BG_TOP | BG_BOTTOM)
5133 #define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT)
5136 CSSParserImpl::ParseSingleValueProperty(nsCSSValue
& aValue
,
5137 nsCSSProperty aPropID
)
5140 case eCSSProperty_UNKNOWN
:
5141 case eCSSProperty_background
:
5142 case eCSSProperty_background_position
:
5143 case eCSSProperty_border
:
5144 case eCSSProperty_border_color
:
5145 case eCSSProperty_border_bottom_colors
:
5146 case eCSSProperty_border_image
:
5147 case eCSSProperty_border_left_colors
:
5148 case eCSSProperty_border_right_colors
:
5149 case eCSSProperty_border_end_color
:
5150 case eCSSProperty_border_left_color
:
5151 case eCSSProperty_border_right_color
:
5152 case eCSSProperty_border_start_color
:
5153 case eCSSProperty_border_end_style
:
5154 case eCSSProperty_border_left_style
:
5155 case eCSSProperty_border_right_style
:
5156 case eCSSProperty_border_start_style
:
5157 case eCSSProperty_border_end_width
:
5158 case eCSSProperty_border_left_width
:
5159 case eCSSProperty_border_right_width
:
5160 case eCSSProperty_border_start_width
:
5161 case eCSSProperty_border_top_colors
:
5162 case eCSSProperty_border_spacing
:
5163 case eCSSProperty_border_style
:
5164 case eCSSProperty_border_bottom
:
5165 case eCSSProperty_border_end
:
5166 case eCSSProperty_border_left
:
5167 case eCSSProperty_border_right
:
5168 case eCSSProperty_border_start
:
5169 case eCSSProperty_border_top
:
5170 case eCSSProperty_border_width
:
5171 case eCSSProperty__moz_border_radius
:
5172 case eCSSProperty__moz_border_radius_topLeft
:
5173 case eCSSProperty__moz_border_radius_topRight
:
5174 case eCSSProperty__moz_border_radius_bottomRight
:
5175 case eCSSProperty__moz_border_radius_bottomLeft
:
5176 case eCSSProperty_box_shadow
:
5177 case eCSSProperty_clip
:
5178 case eCSSProperty__moz_column_rule
:
5179 case eCSSProperty_content
:
5180 case eCSSProperty_counter_increment
:
5181 case eCSSProperty_counter_reset
:
5182 case eCSSProperty_cue
:
5183 case eCSSProperty_cursor
:
5184 case eCSSProperty_font
:
5185 case eCSSProperty_image_region
:
5186 case eCSSProperty_list_style
:
5187 case eCSSProperty_margin
:
5188 case eCSSProperty_margin_end
:
5189 case eCSSProperty_margin_left
:
5190 case eCSSProperty_margin_right
:
5191 case eCSSProperty_margin_start
:
5192 case eCSSProperty_outline
:
5193 case eCSSProperty__moz_outline_radius
:
5194 case eCSSProperty__moz_outline_radius_topLeft
:
5195 case eCSSProperty__moz_outline_radius_topRight
:
5196 case eCSSProperty__moz_outline_radius_bottomRight
:
5197 case eCSSProperty__moz_outline_radius_bottomLeft
:
5198 case eCSSProperty_overflow
:
5199 case eCSSProperty_padding
:
5200 case eCSSProperty_padding_end
:
5201 case eCSSProperty_padding_left
:
5202 case eCSSProperty_padding_right
:
5203 case eCSSProperty_padding_start
:
5204 case eCSSProperty_pause
:
5205 case eCSSProperty_quotes
:
5206 case eCSSProperty_size
:
5207 case eCSSProperty_text_shadow
:
5208 case eCSSProperty__moz_transform
:
5209 case eCSSProperty__moz_transform_origin
:
5210 case eCSSProperty_COUNT
:
5212 case eCSSProperty_fill
:
5213 case eCSSProperty_stroke
:
5214 case eCSSProperty_stroke_dasharray
:
5215 case eCSSProperty_marker
:
5217 NS_ERROR("not a single value property");
5220 case eCSSProperty__x_system_font
:
5221 case eCSSProperty_margin_left_ltr_source
:
5222 case eCSSProperty_margin_left_rtl_source
:
5223 case eCSSProperty_margin_right_ltr_source
:
5224 case eCSSProperty_margin_right_rtl_source
:
5225 case eCSSProperty_padding_left_ltr_source
:
5226 case eCSSProperty_padding_left_rtl_source
:
5227 case eCSSProperty_padding_right_ltr_source
:
5228 case eCSSProperty_padding_right_rtl_source
:
5229 case eCSSProperty_border_left_color_ltr_source
:
5230 case eCSSProperty_border_left_color_rtl_source
:
5231 case eCSSProperty_border_right_color_ltr_source
:
5232 case eCSSProperty_border_right_color_rtl_source
:
5233 case eCSSProperty_border_left_style_ltr_source
:
5234 case eCSSProperty_border_left_style_rtl_source
:
5235 case eCSSProperty_border_right_style_ltr_source
:
5236 case eCSSProperty_border_right_style_rtl_source
:
5237 case eCSSProperty_border_left_width_ltr_source
:
5238 case eCSSProperty_border_left_width_rtl_source
:
5239 case eCSSProperty_border_right_width_ltr_source
:
5240 case eCSSProperty_border_right_width_rtl_source
:
5242 case eCSSProperty_script_size_multiplier
:
5243 case eCSSProperty_script_min_size
:
5245 NS_ERROR("not currently parsed here");
5248 case eCSSProperty_appearance
:
5249 return ParseVariant(aValue
, VARIANT_HK
,
5250 nsCSSProps::kAppearanceKTable
);
5251 case eCSSProperty_azimuth
:
5252 return ParseAzimuth(aValue
);
5253 case eCSSProperty_background_attachment
:
5254 return ParseVariant(aValue
, VARIANT_HK
,
5255 nsCSSProps::kBackgroundAttachmentKTable
);
5256 case eCSSProperty__moz_background_clip
:
5257 return ParseVariant(aValue
, VARIANT_HK
,
5258 nsCSSProps::kBackgroundClipKTable
);
5259 case eCSSProperty_background_color
:
5260 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5261 case eCSSProperty_background_image
:
5262 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5263 case eCSSProperty__moz_background_inline_policy
:
5264 return ParseVariant(aValue
, VARIANT_HK
,
5265 nsCSSProps::kBackgroundInlinePolicyKTable
);
5266 case eCSSProperty__moz_background_origin
:
5267 return ParseVariant(aValue
, VARIANT_HK
,
5268 nsCSSProps::kBackgroundOriginKTable
);
5269 case eCSSProperty_background_repeat
:
5270 return ParseVariant(aValue
, VARIANT_HK
,
5271 nsCSSProps::kBackgroundRepeatKTable
);
5272 case eCSSProperty_binding
:
5273 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5274 case eCSSProperty_border_collapse
:
5275 return ParseVariant(aValue
, VARIANT_HK
,
5276 nsCSSProps::kBorderCollapseKTable
);
5277 case eCSSProperty_border_bottom_color
:
5278 case eCSSProperty_border_end_color_value
: // for internal use
5279 case eCSSProperty_border_left_color_value
: // for internal use
5280 case eCSSProperty_border_right_color_value
: // for internal use
5281 case eCSSProperty_border_start_color_value
: // for internal use
5282 case eCSSProperty_border_top_color
:
5283 case eCSSProperty__moz_column_rule_color
:
5284 return ParseVariant(aValue
, VARIANT_HCK
,
5285 nsCSSProps::kBorderColorKTable
);
5286 case eCSSProperty_border_bottom_style
:
5287 case eCSSProperty_border_end_style_value
: // for internal use
5288 case eCSSProperty_border_left_style_value
: // for internal use
5289 case eCSSProperty_border_right_style_value
: // for internal use
5290 case eCSSProperty_border_start_style_value
: // for internal use
5291 case eCSSProperty_border_top_style
:
5292 case eCSSProperty__moz_column_rule_style
:
5293 return ParseVariant(aValue
, VARIANT_HOK
,
5294 nsCSSProps::kBorderStyleKTable
);
5295 case eCSSProperty_border_bottom_width
:
5296 case eCSSProperty_border_end_width_value
: // for internal use
5297 case eCSSProperty_border_left_width_value
: // for internal use
5298 case eCSSProperty_border_right_width_value
: // for internal use
5299 case eCSSProperty_border_start_width_value
: // for internal use
5300 case eCSSProperty_border_top_width
:
5301 case eCSSProperty__moz_column_rule_width
:
5302 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5303 nsCSSProps::kBorderWidthKTable
);
5304 case eCSSProperty__moz_column_count
:
5305 return ParsePositiveVariant(aValue
, VARIANT_AHI
, nsnull
);
5306 case eCSSProperty__moz_column_width
:
5307 return ParsePositiveVariant(aValue
, VARIANT_AHL
, nsnull
);
5308 case eCSSProperty__moz_column_gap
:
5309 return ParsePositiveVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5310 case eCSSProperty_bottom
:
5311 case eCSSProperty_top
:
5312 case eCSSProperty_left
:
5313 case eCSSProperty_right
:
5314 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5315 case eCSSProperty_box_align
:
5316 return ParseVariant(aValue
, VARIANT_HK
,
5317 nsCSSProps::kBoxAlignKTable
);
5318 case eCSSProperty_box_direction
:
5319 return ParseVariant(aValue
, VARIANT_HK
,
5320 nsCSSProps::kBoxDirectionKTable
);
5321 case eCSSProperty_box_flex
:
5322 return ParsePositiveVariant(aValue
, VARIANT_HN
, nsnull
);
5323 case eCSSProperty_box_orient
:
5324 return ParseVariant(aValue
, VARIANT_HK
,
5325 nsCSSProps::kBoxOrientKTable
);
5326 case eCSSProperty_box_pack
:
5327 return ParseVariant(aValue
, VARIANT_HK
,
5328 nsCSSProps::kBoxPackKTable
);
5329 case eCSSProperty_box_ordinal_group
:
5330 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5332 case eCSSProperty_clip_path
:
5333 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5334 case eCSSProperty_clip_rule
:
5335 return ParseVariant(aValue
, VARIANT_HK
,
5336 nsCSSProps::kFillRuleKTable
);
5337 case eCSSProperty_color_interpolation
:
5338 case eCSSProperty_color_interpolation_filters
:
5339 return ParseVariant(aValue
, VARIANT_AHK
,
5340 nsCSSProps::kColorInterpolationKTable
);
5341 case eCSSProperty_dominant_baseline
:
5342 return ParseVariant(aValue
, VARIANT_AHK
,
5343 nsCSSProps::kDominantBaselineKTable
);
5344 case eCSSProperty_fill_opacity
:
5345 return ParseVariant(aValue
, VARIANT_HN
,
5347 case eCSSProperty_fill_rule
:
5348 return ParseVariant(aValue
, VARIANT_HK
,
5349 nsCSSProps::kFillRuleKTable
);
5350 case eCSSProperty_filter
:
5351 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5352 case eCSSProperty_flood_color
:
5353 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5354 case eCSSProperty_flood_opacity
:
5355 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5356 case eCSSProperty_lighting_color
:
5357 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5358 case eCSSProperty_marker_end
:
5359 case eCSSProperty_marker_mid
:
5360 case eCSSProperty_marker_start
:
5361 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5362 case eCSSProperty_mask
:
5363 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5364 case eCSSProperty_pointer_events
:
5365 return ParseVariant(aValue
, VARIANT_HOK
,
5366 nsCSSProps::kPointerEventsKTable
);
5367 case eCSSProperty_shape_rendering
:
5368 return ParseVariant(aValue
, VARIANT_AHK
,
5369 nsCSSProps::kShapeRenderingKTable
);
5370 case eCSSProperty_stop_color
:
5371 return ParseVariant(aValue
, VARIANT_HC
,
5373 case eCSSProperty_stop_opacity
:
5374 return ParseVariant(aValue
, VARIANT_HN
,
5376 case eCSSProperty_stroke_dashoffset
:
5377 return ParseVariant(aValue
, VARIANT_HLPN
,
5379 case eCSSProperty_stroke_linecap
:
5380 return ParseVariant(aValue
, VARIANT_HK
,
5381 nsCSSProps::kStrokeLinecapKTable
);
5382 case eCSSProperty_stroke_linejoin
:
5383 return ParseVariant(aValue
, VARIANT_HK
,
5384 nsCSSProps::kStrokeLinejoinKTable
);
5385 case eCSSProperty_stroke_miterlimit
:
5386 return ParsePositiveVariant(aValue
, VARIANT_HN
,
5388 case eCSSProperty_stroke_opacity
:
5389 return ParseVariant(aValue
, VARIANT_HN
,
5391 case eCSSProperty_stroke_width
:
5392 return ParsePositiveVariant(aValue
, VARIANT_HLPN
,
5394 case eCSSProperty_text_anchor
:
5395 return ParseVariant(aValue
, VARIANT_HK
,
5396 nsCSSProps::kTextAnchorKTable
);
5397 case eCSSProperty_text_rendering
:
5398 return ParseVariant(aValue
, VARIANT_AHK
,
5399 nsCSSProps::kTextRenderingKTable
);
5401 case eCSSProperty_box_sizing
:
5402 return ParseVariant(aValue
, VARIANT_HK
,
5403 nsCSSProps::kBoxSizingKTable
);
5404 case eCSSProperty_height
:
5405 return ParsePositiveVariant(aValue
, VARIANT_AHLP
, nsnull
);
5406 case eCSSProperty_width
:
5407 return ParsePositiveVariant(aValue
, VARIANT_AHKLP
,
5408 nsCSSProps::kWidthKTable
);
5409 case eCSSProperty_force_broken_image_icon
:
5410 return ParsePositiveVariant(aValue
, VARIANT_HI
, nsnull
);
5411 case eCSSProperty_caption_side
:
5412 return ParseVariant(aValue
, VARIANT_HK
,
5413 nsCSSProps::kCaptionSideKTable
);
5414 case eCSSProperty_clear
:
5415 return ParseVariant(aValue
, VARIANT_HOK
,
5416 nsCSSProps::kClearKTable
);
5417 case eCSSProperty_color
:
5418 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5419 case eCSSProperty_cue_after
:
5420 case eCSSProperty_cue_before
:
5421 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5422 case eCSSProperty_direction
:
5423 return ParseVariant(aValue
, VARIANT_HK
,
5424 nsCSSProps::kDirectionKTable
);
5425 case eCSSProperty_display
:
5426 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kDisplayKTable
)) {
5427 if (aValue
.GetUnit() == eCSSUnit_Enumerated
) {
5428 switch (aValue
.GetIntValue()) {
5429 case NS_STYLE_DISPLAY_MARKER
: // bug 2055
5430 case NS_STYLE_DISPLAY_RUN_IN
: // bug 2056
5431 case NS_STYLE_DISPLAY_COMPACT
: // bug 14983
5438 case eCSSProperty_elevation
:
5439 return ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5440 nsCSSProps::kElevationKTable
);
5441 case eCSSProperty_empty_cells
:
5442 return ParseVariant(aValue
, VARIANT_HK
,
5443 nsCSSProps::kEmptyCellsKTable
);
5444 case eCSSProperty_float
:
5445 return ParseVariant(aValue
, VARIANT_HOK
,
5446 nsCSSProps::kFloatKTable
);
5447 case eCSSProperty_float_edge
:
5448 return ParseVariant(aValue
, VARIANT_HK
,
5449 nsCSSProps::kFloatEdgeKTable
);
5450 case eCSSProperty_font_family
:
5451 return ParseFamily(aValue
);
5452 case eCSSProperty_font_size
:
5453 return ParsePositiveVariant(aValue
,
5454 VARIANT_HKLP
| VARIANT_SYSFONT
,
5455 nsCSSProps::kFontSizeKTable
);
5456 case eCSSProperty_font_size_adjust
:
5457 return ParseVariant(aValue
, VARIANT_HON
| VARIANT_SYSFONT
,
5459 case eCSSProperty_font_stretch
:
5460 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5461 nsCSSProps::kFontStretchKTable
);
5462 case eCSSProperty_font_style
:
5463 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5464 nsCSSProps::kFontStyleKTable
);
5465 case eCSSProperty_font_variant
:
5466 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5467 nsCSSProps::kFontVariantKTable
);
5468 case eCSSProperty_font_weight
:
5469 return ParseFontWeight(aValue
);
5470 case eCSSProperty_ime_mode
:
5471 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NORMAL
,
5472 nsCSSProps::kIMEModeKTable
);
5473 case eCSSProperty_letter_spacing
:
5474 case eCSSProperty_word_spacing
:
5475 return ParseVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5476 case eCSSProperty_line_height
:
5477 return ParsePositiveVariant(aValue
, VARIANT_HLPN
| VARIANT_NORMAL
| VARIANT_SYSFONT
, nsnull
);
5478 case eCSSProperty_list_style_image
:
5479 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5480 case eCSSProperty_list_style_position
:
5481 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kListStylePositionKTable
);
5482 case eCSSProperty_list_style_type
:
5483 return ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kListStyleKTable
);
5484 case eCSSProperty_margin_bottom
:
5485 case eCSSProperty_margin_end_value
: // for internal use
5486 case eCSSProperty_margin_left_value
: // for internal use
5487 case eCSSProperty_margin_right_value
: // for internal use
5488 case eCSSProperty_margin_start_value
: // for internal use
5489 case eCSSProperty_margin_top
:
5490 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5491 case eCSSProperty_marker_offset
:
5492 return ParseVariant(aValue
, VARIANT_AHL
, nsnull
);
5493 case eCSSProperty_marks
:
5494 return ParseMarks(aValue
);
5495 case eCSSProperty_max_height
:
5496 return ParsePositiveVariant(aValue
, VARIANT_HLPO
, nsnull
);
5497 case eCSSProperty_max_width
:
5498 return ParsePositiveVariant(aValue
, VARIANT_HKLPO
,
5499 nsCSSProps::kWidthKTable
);
5500 case eCSSProperty_min_height
:
5501 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5502 case eCSSProperty_min_width
:
5503 return ParsePositiveVariant(aValue
, VARIANT_HKLP
,
5504 nsCSSProps::kWidthKTable
);
5505 case eCSSProperty_opacity
:
5506 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5507 case eCSSProperty_orphans
:
5508 case eCSSProperty_widows
:
5509 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5510 case eCSSProperty_outline_color
:
5511 return ParseVariant(aValue
, VARIANT_HCK
,
5512 nsCSSProps::kOutlineColorKTable
);
5513 case eCSSProperty_outline_style
:
5514 return ParseVariant(aValue
, VARIANT_HOK
| VARIANT_AUTO
,
5515 nsCSSProps::kOutlineStyleKTable
);
5516 case eCSSProperty_outline_width
:
5517 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5518 nsCSSProps::kBorderWidthKTable
);
5519 case eCSSProperty_outline_offset
:
5520 return ParseVariant(aValue
, VARIANT_HL
, nsnull
);
5521 case eCSSProperty_overflow_x
:
5522 case eCSSProperty_overflow_y
:
5523 return ParseVariant(aValue
, VARIANT_AHK
,
5524 nsCSSProps::kOverflowSubKTable
);
5525 case eCSSProperty_padding_bottom
:
5526 case eCSSProperty_padding_end_value
: // for internal use
5527 case eCSSProperty_padding_left_value
: // for internal use
5528 case eCSSProperty_padding_right_value
: // for internal use
5529 case eCSSProperty_padding_start_value
: // for internal use
5530 case eCSSProperty_padding_top
:
5531 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5532 case eCSSProperty_page
:
5533 return ParseVariant(aValue
, VARIANT_AUTO
| VARIANT_IDENTIFIER
, nsnull
);
5534 case eCSSProperty_page_break_after
:
5535 case eCSSProperty_page_break_before
:
5536 return ParseVariant(aValue
, VARIANT_AHK
,
5537 nsCSSProps::kPageBreakKTable
);
5538 case eCSSProperty_page_break_inside
:
5539 return ParseVariant(aValue
, VARIANT_AHK
,
5540 nsCSSProps::kPageBreakInsideKTable
);
5541 case eCSSProperty_pause_after
:
5542 case eCSSProperty_pause_before
:
5543 return ParseVariant(aValue
, VARIANT_HTP
, nsnull
);
5544 case eCSSProperty_pitch
:
5545 return ParseVariant(aValue
, VARIANT_HKF
, nsCSSProps::kPitchKTable
);
5546 case eCSSProperty_pitch_range
:
5547 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5548 case eCSSProperty_position
:
5549 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kPositionKTable
);
5550 case eCSSProperty_richness
:
5551 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5553 // script-level can take Integer or Number values, but only Integer ("relative")
5554 // values can be specified in a style sheet. Also we only allow this property
5555 // when unsafe rules are enabled, because otherwise it could interfere
5556 // with rulenode optimizations if used in a non-MathML-enabled document.
5557 case eCSSProperty_script_level
:
5558 if (!mUnsafeRulesEnabled
)
5560 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5562 case eCSSProperty_speak
:
5563 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5564 nsCSSProps::kSpeakKTable
);
5565 case eCSSProperty_speak_header
:
5566 return ParseVariant(aValue
, VARIANT_HK
,
5567 nsCSSProps::kSpeakHeaderKTable
);
5568 case eCSSProperty_speak_numeral
:
5569 return ParseVariant(aValue
, VARIANT_HK
,
5570 nsCSSProps::kSpeakNumeralKTable
);
5571 case eCSSProperty_speak_punctuation
:
5572 return ParseVariant(aValue
, VARIANT_HOK
,
5573 nsCSSProps::kSpeakPunctuationKTable
);
5574 case eCSSProperty_speech_rate
:
5575 return ParseVariant(aValue
, VARIANT_HN
| VARIANT_KEYWORD
,
5576 nsCSSProps::kSpeechRateKTable
);
5577 case eCSSProperty_stack_sizing
:
5578 return ParseVariant(aValue
, VARIANT_HK
,
5579 nsCSSProps::kStackSizingKTable
);
5580 case eCSSProperty_stress
:
5581 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5582 case eCSSProperty_table_layout
:
5583 return ParseVariant(aValue
, VARIANT_AHK
,
5584 nsCSSProps::kTableLayoutKTable
);
5585 case eCSSProperty_text_align
:
5586 // When we support aligning on a string, we can parse text-align
5588 return ParseVariant(aValue
, VARIANT_HK
/* | VARIANT_STRING */,
5589 nsCSSProps::kTextAlignKTable
);
5590 case eCSSProperty_text_decoration
:
5591 return ParseTextDecoration(aValue
);
5592 case eCSSProperty_text_indent
:
5593 return ParseVariant(aValue
, VARIANT_HLP
, nsnull
);
5594 case eCSSProperty_text_transform
:
5595 return ParseVariant(aValue
, VARIANT_HOK
,
5596 nsCSSProps::kTextTransformKTable
);
5597 case eCSSProperty_unicode_bidi
:
5598 return ParseVariant(aValue
, VARIANT_HMK
,
5599 nsCSSProps::kUnicodeBidiKTable
);
5600 case eCSSProperty_user_focus
:
5601 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5602 nsCSSProps::kUserFocusKTable
);
5603 case eCSSProperty_user_input
:
5604 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5605 nsCSSProps::kUserInputKTable
);
5606 case eCSSProperty_user_modify
:
5607 return ParseVariant(aValue
, VARIANT_HK
,
5608 nsCSSProps::kUserModifyKTable
);
5609 case eCSSProperty_user_select
:
5610 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5611 nsCSSProps::kUserSelectKTable
);
5612 case eCSSProperty_vertical_align
:
5613 return ParseVariant(aValue
, VARIANT_HKLP
,
5614 nsCSSProps::kVerticalAlignKTable
);
5615 case eCSSProperty_visibility
:
5616 return ParseVariant(aValue
, VARIANT_HK
,
5617 nsCSSProps::kVisibilityKTable
);
5618 case eCSSProperty_voice_family
:
5619 return ParseFamily(aValue
);
5620 case eCSSProperty_volume
:
5621 return ParseVariant(aValue
, VARIANT_HPN
| VARIANT_KEYWORD
,
5622 nsCSSProps::kVolumeKTable
);
5623 case eCSSProperty_white_space
:
5624 return ParseVariant(aValue
, VARIANT_HMK
,
5625 nsCSSProps::kWhitespaceKTable
);
5626 case eCSSProperty__moz_window_shadow
:
5627 return ParseVariant(aValue
, VARIANT_HOK
,
5628 nsCSSProps::kWindowShadowKTable
);
5629 case eCSSProperty_word_wrap
:
5630 return ParseVariant(aValue
, VARIANT_HMK
,
5631 nsCSSProps::kWordwrapKTable
);
5632 case eCSSProperty_z_index
:
5633 return ParseVariant(aValue
, VARIANT_AHI
, nsnull
);
5635 // explicitly do NOT have a default case to let the compiler
5636 // help find missing properties
5640 // nsFont::EnumerateFamilies callback for ParseFontDescriptorValue
5641 struct NS_STACK_CLASS ExtractFirstFamilyData
{
5642 nsAutoString mFamilyName
;
5644 ExtractFirstFamilyData() : mFamilyName(), mGood(PR_FALSE
) {}
5648 ExtractFirstFamily(const nsString
& aFamily
,
5652 ExtractFirstFamilyData
* realData
= (ExtractFirstFamilyData
*) aData
;
5653 if (aGeneric
|| realData
->mFamilyName
.Length() > 0) {
5654 realData
->mGood
= PR_FALSE
;
5657 realData
->mFamilyName
.Assign(aFamily
);
5658 realData
->mGood
= PR_TRUE
;
5662 // font-descriptor: descriptor ':' value ';'
5663 // caller has advanced mToken to point at the descriptor
5665 CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
5669 // These four are similar to the properties of the same name,
5670 // possibly with more restrictions on the values they can take.
5671 case eCSSFontDesc_Family
: {
5672 if (!ParseFamily(aValue
) ||
5673 aValue
.GetUnit() != eCSSUnit_String
)
5676 // the style parameters to the nsFont constructor are ignored,
5677 // because it's only being used to call EnumerateFamilies
5678 nsAutoString valueStr
;
5679 aValue
.GetStringValue(valueStr
);
5680 nsFont
font(valueStr
, 0, 0, 0, 0, 0);
5681 ExtractFirstFamilyData dat
;
5683 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
5687 aValue
.SetStringValue(dat
.mFamilyName
, eCSSUnit_String
);
5691 case eCSSFontDesc_Style
:
5692 // property is VARIANT_HMK|VARIANT_SYSFONT
5693 return ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5694 nsCSSProps::kFontStyleKTable
);
5696 case eCSSFontDesc_Weight
:
5697 return (ParseFontWeight(aValue
) &&
5698 aValue
.GetUnit() != eCSSUnit_Inherit
&&
5699 aValue
.GetUnit() != eCSSUnit_Initial
&&
5700 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5701 (aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER
&&
5702 aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER
)));
5704 case eCSSFontDesc_Stretch
:
5705 // property is VARIANT_HMK|VARIANT_SYSFONT
5706 return (ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5707 nsCSSProps::kFontStretchKTable
) &&
5708 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5709 (aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_WIDER
&&
5710 aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_NARROWER
)));
5712 // These two are unique to @font-face and have their own special grammar.
5713 case eCSSFontDesc_Src
:
5714 return ParseFontSrc(aValue
);
5716 case eCSSFontDesc_UnicodeRange
:
5717 return ParseFontRanges(aValue
);
5719 case eCSSFontDesc_UNKNOWN
:
5720 case eCSSFontDesc_COUNT
:
5721 NS_NOTREACHED("bad nsCSSFontDesc code");
5723 // explicitly do NOT have a default case to let the compiler
5724 // help find missing descriptors
5729 CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
)
5731 nsCSSValue
physical(NS_BOXPROP_SOURCE_PHYSICAL
, eCSSUnit_Enumerated
);
5732 for (const nsCSSProperty
*prop
= aSourceProperties
;
5733 *prop
!= eCSSProperty_UNKNOWN
; ++prop
) {
5734 AppendValue(*prop
, physical
);
5739 CSSParserImpl::ParseAzimuth(nsCSSValue
& aValue
)
5741 if (ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5742 nsCSSProps::kAzimuthKTable
)) {
5743 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
5744 PRInt32 intValue
= aValue
.GetIntValue();
5745 if ((NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) &&
5746 (intValue
<= NS_STYLE_AZIMUTH_BEHIND
)) { // look for optional modifier
5747 nsCSSValue modifier
;
5748 if (ParseEnum(modifier
, nsCSSProps::kAzimuthKTable
)) {
5749 PRInt32 enumValue
= modifier
.GetIntValue();
5750 if (((intValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5751 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= enumValue
) && (enumValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
)) ||
5752 ((enumValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5753 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) && (intValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
))) {
5754 aValue
.SetIntValue(intValue
| enumValue
, eCSSUnit_Enumerated
);
5757 // Put the unknown identifier back and return
5769 BoxPositionMaskToCSSValue(PRInt32 aMask
, PRBool isX
)
5771 PRInt32 val
= NS_STYLE_BG_POSITION_CENTER
;
5773 if (aMask
& BG_LEFT
) {
5774 val
= NS_STYLE_BG_POSITION_LEFT
;
5776 else if (aMask
& BG_RIGHT
) {
5777 val
= NS_STYLE_BG_POSITION_RIGHT
;
5781 if (aMask
& BG_TOP
) {
5782 val
= NS_STYLE_BG_POSITION_TOP
;
5784 else if (aMask
& BG_BOTTOM
) {
5785 val
= NS_STYLE_BG_POSITION_BOTTOM
;
5789 return nsCSSValue(val
, eCSSUnit_Enumerated
);
5793 CSSParserImpl::ParseBackground()
5795 nsAutoParseCompoundProperty
compound(this);
5797 // Fill in the values that the shorthand will set if we don't find
5799 mTempData
.mColor
.mBackColor
.SetColorValue(NS_RGBA(0, 0, 0, 0));
5800 mTempData
.SetPropertyBit(eCSSProperty_background_color
);
5801 mTempData
.mColor
.mBackImage
.SetNoneValue();
5802 mTempData
.SetPropertyBit(eCSSProperty_background_image
);
5803 mTempData
.mColor
.mBackRepeat
.SetIntValue(NS_STYLE_BG_REPEAT_XY
,
5804 eCSSUnit_Enumerated
);
5805 mTempData
.SetPropertyBit(eCSSProperty_background_repeat
);
5806 mTempData
.mColor
.mBackAttachment
.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL
,
5807 eCSSUnit_Enumerated
);
5808 mTempData
.SetPropertyBit(eCSSProperty_background_attachment
);
5809 mTempData
.mColor
.mBackPosition
.mXValue
.SetPercentValue(0.0f
);
5810 mTempData
.mColor
.mBackPosition
.mYValue
.SetPercentValue(0.0f
);
5811 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
5812 // including the ones that we can't set from the shorthand.
5813 mTempData
.mColor
.mBackClip
.SetIntValue(NS_STYLE_BG_CLIP_BORDER
,
5814 eCSSUnit_Enumerated
);
5815 mTempData
.SetPropertyBit(eCSSProperty__moz_background_clip
);
5816 mTempData
.mColor
.mBackOrigin
.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING
,
5817 eCSSUnit_Enumerated
);
5818 mTempData
.SetPropertyBit(eCSSProperty__moz_background_origin
);
5819 mTempData
.mColor
.mBackInlinePolicy
.SetIntValue(
5820 NS_STYLE_BG_INLINE_POLICY_CONTINUOUS
, eCSSUnit_Enumerated
);
5821 mTempData
.SetPropertyBit(eCSSProperty__moz_background_inline_policy
);
5823 // XXX If ParseSingleValueProperty were table-driven (bug 376079) and
5824 // automatically filled in the right field of mTempData, we could move
5825 // ParseBackgroundPosition to it (as a special case) and switch back
5826 // to using ParseChoice here.
5828 PRBool haveColor
= PR_FALSE
,
5829 haveImage
= PR_FALSE
,
5830 haveRepeat
= PR_FALSE
,
5831 haveAttach
= PR_FALSE
,
5832 havePosition
= PR_FALSE
;
5833 while (GetToken(PR_TRUE
)) {
5834 nsCSSTokenType tt
= mToken
.mType
;
5835 UngetToken(); // ...but we'll still cheat and use mToken
5836 if (tt
== eCSSToken_Symbol
) {
5837 // ExpectEndProperty only looks for symbols, and nothing else will
5842 if (tt
== eCSSToken_Ident
) {
5843 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
5845 if (keyword
== eCSSKeyword_inherit
||
5846 keyword
== eCSSKeyword__moz_initial
) {
5847 if (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
)
5849 haveColor
= haveImage
= haveRepeat
= haveAttach
= havePosition
=
5851 GetToken(PR_TRUE
); // undo the UngetToken above
5853 if (keyword
== eCSSKeyword_inherit
) {
5854 val
.SetInheritValue();
5856 val
.SetInitialValue();
5858 mTempData
.mColor
.mBackColor
= val
;
5859 mTempData
.mColor
.mBackImage
= val
;
5860 mTempData
.mColor
.mBackRepeat
= val
;
5861 mTempData
.mColor
.mBackAttachment
= val
;
5862 mTempData
.mColor
.mBackPosition
.mXValue
= val
;
5863 mTempData
.mColor
.mBackPosition
.mYValue
= val
;
5864 // Reset (for 'inherit') the 3 properties that can't be
5865 // specified, although it's not entirely clear in the spec:
5866 // http://lists.w3.org/Archives/Public/www-style/2007Mar/0110
5867 mTempData
.mColor
.mBackClip
= val
;
5868 mTempData
.mColor
.mBackOrigin
= val
;
5869 mTempData
.mColor
.mBackInlinePolicy
= val
;
5871 } else if (keyword
== eCSSKeyword_none
) {
5874 haveImage
= PR_TRUE
;
5875 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5876 eCSSProperty_background_image
)) {
5877 NS_NOTREACHED("should be able to parse");
5880 } else if (nsCSSProps::FindKeyword(keyword
,
5881 nsCSSProps::kBackgroundAttachmentKTable
, dummy
)) {
5884 haveAttach
= PR_TRUE
;
5885 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackAttachment
,
5886 eCSSProperty_background_attachment
)) {
5887 NS_NOTREACHED("should be able to parse");
5890 } else if (nsCSSProps::FindKeyword(keyword
,
5891 nsCSSProps::kBackgroundRepeatKTable
, dummy
)) {
5894 haveRepeat
= PR_TRUE
;
5895 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackRepeat
,
5896 eCSSProperty_background_repeat
)) {
5897 NS_NOTREACHED("should be able to parse");
5900 } else if (nsCSSProps::FindKeyword(keyword
,
5901 nsCSSProps::kBackgroundPositionKTable
, dummy
)) {
5904 havePosition
= PR_TRUE
;
5905 if (!ParseBackgroundPositionValues()) {
5911 haveColor
= PR_TRUE
;
5912 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5913 eCSSProperty_background_color
)) {
5917 } else if (eCSSToken_Function
== tt
&&
5918 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
5921 haveImage
= PR_TRUE
;
5922 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5923 eCSSProperty_background_image
)) {
5926 } else if (mToken
.IsDimension() || tt
== eCSSToken_Percentage
) {
5929 havePosition
= PR_TRUE
;
5930 if (!ParseBackgroundPositionValues()) {
5936 haveColor
= PR_TRUE
;
5937 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5938 eCSSProperty_background_color
)) {
5944 return ExpectEndProperty() &&
5945 (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
);
5949 CSSParserImpl::ParseBackgroundPosition()
5951 if (!ParseBoxPosition(mTempData
.mColor
.mBackPosition
))
5953 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
5958 CSSParserImpl::ParseBackgroundPositionValues()
5960 return ParseBoxPositionValues(mTempData
.mColor
.mBackPosition
);
5964 * Parses two values that correspond to positions in a box. These can be
5965 * values corresponding to percentages of the box, raw offsets, or keywords
5966 * like "top," "left center," etc.
5968 * @param aOut The nsCSSValuePair where to place the result.
5969 * @return Whether or not the operation succeeded.
5971 PRBool
CSSParserImpl::ParseBoxPosition(nsCSSValuePair
&aOut
)
5973 // Need to read the box positions and the end of the property.
5974 return ParseBoxPositionValues(aOut
) && ExpectEndProperty();
5977 PRBool
CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair
&aOut
)
5979 // First try a percentage or a length value
5980 nsCSSValue
&xValue
= aOut
.mXValue
,
5981 &yValue
= aOut
.mYValue
;
5982 if (ParseVariant(xValue
, VARIANT_HLP
, nsnull
)) {
5983 if (eCSSUnit_Inherit
== xValue
.GetUnit() ||
5984 eCSSUnit_Initial
== xValue
.GetUnit()) { // both are inherited or both are set to initial
5988 // We have one percentage/length. Get the optional second
5989 // percentage/length/keyword.
5990 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
5991 // We have two numbers
5995 if (ParseEnum(yValue
, nsCSSProps::kBackgroundPositionKTable
)) {
5996 PRInt32 yVal
= yValue
.GetIntValue();
5997 if (!(yVal
& BG_CTB
)) {
5998 // The second keyword can only be 'center', 'top', or 'bottom'
6001 yValue
= BoxPositionMaskToCSSValue(yVal
, PR_FALSE
);
6005 // If only one percentage or length value is given, it sets the
6006 // horizontal position only, and the vertical position will be 50%.
6007 yValue
.SetPercentValue(0.5f
);
6011 // Now try keywords. We do this manually to allow for the first
6012 // appearance of "center" to apply to the either the x or y
6013 // position (it's ambiguous so we have to disambiguate). Each
6014 // allowed keyword value is assigned it's own bit. We don't allow
6015 // any duplicate keywords other than center. We try to get two
6016 // keywords but it's okay if there is only one.
6018 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6019 PRInt32 bit
= xValue
.GetIntValue();
6021 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6022 bit
= xValue
.GetIntValue();
6023 if (mask
& (bit
& ~BG_CENTER
)) {
6024 // Only the 'center' keyword can be duplicated.
6030 // Only one keyword. See if we have a length or percentage.
6031 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
6032 if (!(mask
& BG_CLR
)) {
6033 // The first keyword can only be 'center', 'left', or 'right'
6037 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
6043 // Check for bad input. Bad input consists of no matching keywords,
6044 // or pairs of x keywords or pairs of y keywords.
6045 if ((mask
== 0) || (mask
== (BG_TOP
| BG_BOTTOM
)) ||
6046 (mask
== (BG_LEFT
| BG_RIGHT
))) {
6050 // Create style values
6051 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
6052 yValue
= BoxPositionMaskToCSSValue(mask
, PR_FALSE
);
6057 CSSParserImpl::ParseBorderColor()
6059 static const nsCSSProperty kBorderColorSources
[] = {
6060 eCSSProperty_border_left_color_ltr_source
,
6061 eCSSProperty_border_left_color_rtl_source
,
6062 eCSSProperty_border_right_color_ltr_source
,
6063 eCSSProperty_border_right_color_rtl_source
,
6064 eCSSProperty_UNKNOWN
6067 // do this now, in case 4 values weren't specified
6068 InitBoxPropsAsPhysical(kBorderColorSources
);
6069 return ParseBoxProperties(mTempData
.mMargin
.mBorderColor
,
6074 CSSParserImpl::ParseBorderImage()
6076 if (ParseVariant(mTempData
.mMargin
.mBorderImage
,
6077 VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
6078 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
6082 // <uri> [<number> | <percentage>]{1,4} [ / <border-width>{1,4} ]? [stretch | repeat | round]{0,2}
6083 nsRefPtr
<nsCSSValue::Array
> arr
= nsCSSValue::Array::Create(11);
6085 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6089 nsCSSValue
& url
= arr
->Item(0);
6090 nsCSSValue
& splitTop
= arr
->Item(1);
6091 nsCSSValue
& splitRight
= arr
->Item(2);
6092 nsCSSValue
& splitBottom
= arr
->Item(3);
6093 nsCSSValue
& splitLeft
= arr
->Item(4);
6094 nsCSSValue
& borderWidthTop
= arr
->Item(5);
6095 nsCSSValue
& borderWidthRight
= arr
->Item(6);
6096 nsCSSValue
& borderWidthBottom
= arr
->Item(7);
6097 nsCSSValue
& borderWidthLeft
= arr
->Item(8);
6098 nsCSSValue
& horizontalKeyword
= arr
->Item(9);
6099 nsCSSValue
& verticalKeyword
= arr
->Item(10);
6102 if (!ParseVariant(url
, VARIANT_URL
, nsnull
)) {
6106 // [<number> | <percentage>]{1,4}
6107 if (!ParsePositiveVariant(splitTop
,
6108 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6111 if (!ParsePositiveVariant(splitRight
,
6112 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6113 splitRight
= splitTop
;
6115 if (!ParsePositiveVariant(splitBottom
,
6116 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6117 splitBottom
= splitTop
;
6119 if (!ParsePositiveVariant(splitLeft
,
6120 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6121 splitLeft
= splitRight
;
6124 // [ / <border-width>{1,4} ]?
6125 if (ExpectSymbol('/', PR_TRUE
)) {
6126 // if have '/', at least one value is required
6127 if (!ParsePositiveVariant(borderWidthTop
, VARIANT_LENGTH
, nsnull
)) {
6130 if (!ParsePositiveVariant(borderWidthRight
, VARIANT_LENGTH
, nsnull
)) {
6131 borderWidthRight
= borderWidthTop
;
6133 if (!ParsePositiveVariant(borderWidthBottom
, VARIANT_LENGTH
, nsnull
)) {
6134 borderWidthBottom
= borderWidthTop
;
6136 if (!ParsePositiveVariant(borderWidthLeft
, VARIANT_LENGTH
, nsnull
)) {
6137 borderWidthLeft
= borderWidthRight
;
6141 // [stretch | repeat | round]{0,2}
6142 // missing keywords are handled in nsRuleNode::ComputeBorderData()
6143 if (ParseEnum(horizontalKeyword
, nsCSSProps::kBorderImageKTable
)) {
6144 ParseEnum(verticalKeyword
, nsCSSProps::kBorderImageKTable
);
6147 if (!ExpectEndProperty()) {
6151 mTempData
.mMargin
.mBorderImage
.SetArrayValue(arr
, eCSSUnit_Array
);
6152 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
6158 CSSParserImpl::ParseBorderSpacing()
6161 if (ParsePositiveVariant(xValue
, VARIANT_HL
, nsnull
)) {
6162 if (xValue
.IsLengthUnit()) {
6163 // We have one length. Get the optional second length.
6165 if (ParsePositiveVariant(yValue
, VARIANT_LENGTH
, nsnull
)) {
6166 // We have two numbers
6167 if (ExpectEndProperty()) {
6168 mTempData
.mTable
.mBorderSpacing
.mXValue
= xValue
;
6169 mTempData
.mTable
.mBorderSpacing
.mYValue
= yValue
;
6170 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6177 // We have one length which is the horizontal spacing. Create a value for
6178 // the vertical spacing which is equal
6179 if (ExpectEndProperty()) {
6180 mTempData
.mTable
.mBorderSpacing
.SetBothValuesTo(xValue
);
6181 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6189 CSSParserImpl::ParseBorderSide(const nsCSSProperty aPropIDs
[],
6190 PRBool aSetAllSides
)
6192 const PRInt32 numProps
= 3;
6193 nsCSSValue values
[numProps
];
6195 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6196 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6200 if ((found
& 1) == 0) { // Provide default border-width
6201 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6203 if ((found
& 2) == 0) { // Provide default border-style
6204 values
[1].SetNoneValue();
6206 if ((found
& 4) == 0) { // text color will be used
6207 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6211 static const nsCSSProperty kBorderSources
[] = {
6212 eCSSProperty_border_left_color_ltr_source
,
6213 eCSSProperty_border_left_color_rtl_source
,
6214 eCSSProperty_border_right_color_ltr_source
,
6215 eCSSProperty_border_right_color_rtl_source
,
6216 eCSSProperty_border_left_style_ltr_source
,
6217 eCSSProperty_border_left_style_rtl_source
,
6218 eCSSProperty_border_right_style_ltr_source
,
6219 eCSSProperty_border_right_style_rtl_source
,
6220 eCSSProperty_border_left_width_ltr_source
,
6221 eCSSProperty_border_left_width_rtl_source
,
6222 eCSSProperty_border_right_width_ltr_source
,
6223 eCSSProperty_border_right_width_rtl_source
,
6224 eCSSProperty_UNKNOWN
6227 InitBoxPropsAsPhysical(kBorderSources
);
6229 // Parsing "border" shorthand; set all four sides to the same thing
6230 for (PRInt32 index
= 0; index
< 4; index
++) {
6231 NS_ASSERTION(numProps
== 3, "This code needs updating");
6232 AppendValue(kBorderWidthIDs
[index
], values
[0]);
6233 AppendValue(kBorderStyleIDs
[index
], values
[1]);
6234 AppendValue(kBorderColorIDs
[index
], values
[2]);
6238 // Just set our one side
6239 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6240 AppendValue(aPropIDs
[index
], values
[index
]);
6247 CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
6248 PRInt32 aSourceType
)
6250 const PRInt32 numProps
= 3;
6251 nsCSSValue values
[numProps
];
6253 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6254 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6258 if ((found
& 1) == 0) { // Provide default border-width
6259 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6261 if ((found
& 2) == 0) { // Provide default border-style
6262 values
[1].SetNoneValue();
6264 if ((found
& 4) == 0) { // text color will be used
6265 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6267 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6268 const nsCSSProperty
* subprops
=
6269 nsCSSProps::SubpropertyEntryFor(aPropIDs
[index
+ numProps
]);
6270 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
6271 "not box property with physical vs. logical cascading");
6272 AppendValue(subprops
[0], values
[index
]);
6273 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
6274 AppendValue(subprops
[1], typeVal
);
6275 AppendValue(subprops
[2], typeVal
);
6281 CSSParserImpl::ParseBorderStyle()
6283 static const nsCSSProperty kBorderStyleSources
[] = {
6284 eCSSProperty_border_left_style_ltr_source
,
6285 eCSSProperty_border_left_style_rtl_source
,
6286 eCSSProperty_border_right_style_ltr_source
,
6287 eCSSProperty_border_right_style_rtl_source
,
6288 eCSSProperty_UNKNOWN
6291 // do this now, in case 4 values weren't specified
6292 InitBoxPropsAsPhysical(kBorderStyleSources
);
6293 return ParseBoxProperties(mTempData
.mMargin
.mBorderStyle
,
6298 CSSParserImpl::ParseBorderWidth()
6300 static const nsCSSProperty kBorderWidthSources
[] = {
6301 eCSSProperty_border_left_width_ltr_source
,
6302 eCSSProperty_border_left_width_rtl_source
,
6303 eCSSProperty_border_right_width_ltr_source
,
6304 eCSSProperty_border_right_width_rtl_source
,
6305 eCSSProperty_UNKNOWN
6308 // do this now, in case 4 values weren't specified
6309 InitBoxPropsAsPhysical(kBorderWidthSources
);
6310 return ParseBoxProperties(mTempData
.mMargin
.mBorderWidth
,
6315 CSSParserImpl::ParseBorderColors(nsCSSValueList
** aResult
,
6316 nsCSSProperty aProperty
)
6319 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6320 nsCSSValueList
* listHead
= new nsCSSValueList();
6321 nsCSSValueList
* list
= listHead
;
6323 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6326 list
->mValue
= value
;
6329 if (ExpectEndProperty()) {
6330 mTempData
.SetPropertyBit(aProperty
);
6331 *aResult
= listHead
;
6334 // FIXME Bug 389404: We should not accept inherit, -moz-initial,
6335 // or none as anything other than the first value.
6336 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6337 list
->mNext
= new nsCSSValueList();
6340 list
->mValue
= value
;
6342 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6353 CSSParserImpl::ParseRect(nsCSSRect
& aRect
, nsCSSProperty aPropID
)
6357 if ((result
= DoParseRect(rect
)) &&
6360 mTempData
.SetPropertyBit(aPropID
);
6366 CSSParserImpl::DoParseRect(nsCSSRect
& aRect
)
6368 if (! GetToken(PR_TRUE
)) {
6371 if (eCSSToken_Ident
== mToken
.mType
) {
6372 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
6374 case eCSSKeyword_auto
:
6375 if (ExpectEndProperty()) {
6376 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Auto
));
6380 case eCSSKeyword_inherit
:
6381 if (ExpectEndProperty()) {
6382 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Inherit
));
6386 case eCSSKeyword__moz_initial
:
6387 if (ExpectEndProperty()) {
6388 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Initial
));
6396 } else if ((eCSSToken_Function
== mToken
.mType
) &&
6397 mToken
.mIdent
.LowerCaseEqualsLiteral("rect")) {
6398 if (!ExpectSymbol('(', PR_TRUE
)) {
6401 NS_FOR_CSS_SIDES(side
) {
6402 if (! ParseVariant(aRect
.*(nsCSSRect::sides
[side
]),
6403 VARIANT_AL
, nsnull
)) {
6407 // skip optional commas between elements
6408 ExpectSymbol(',', PR_TRUE
);
6411 if (!ExpectSymbol(')', PR_TRUE
)) {
6414 if (ExpectEndProperty()) {
6423 #define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
6426 CSSParserImpl::ParseContent()
6428 // XXX Rewrite to make it look more like ParseCursor or ParseCounterData?
6430 if (ParseVariant(value
,
6431 VARIANT_CONTENT
| VARIANT_INHERIT
| VARIANT_NORMAL
|
6433 nsCSSProps::kContentKTable
)) {
6434 nsCSSValueList
* listHead
= new nsCSSValueList();
6435 nsCSSValueList
* list
= listHead
;
6436 if (nsnull
== list
) {
6437 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6440 list
->mValue
= value
;
6442 while (nsnull
!= list
) {
6443 if (ExpectEndProperty()) {
6444 mTempData
.SetPropertyBit(eCSSProperty_content
);
6445 mTempData
.mContent
.mContent
= listHead
;
6448 if (eCSSUnit_Inherit
== value
.GetUnit() ||
6449 eCSSUnit_Initial
== value
.GetUnit() ||
6450 eCSSUnit_Normal
== value
.GetUnit() ||
6451 eCSSUnit_None
== value
.GetUnit() ||
6452 (eCSSUnit_Enumerated
== value
.GetUnit() &&
6453 NS_STYLE_CONTENT_ALT_CONTENT
== value
.GetIntValue())) {
6454 // This only matters the first time through the loop.
6458 if (ParseVariant(value
, VARIANT_CONTENT
, nsCSSProps::kContentKTable
) &&
6459 // Make sure we didn't end up with NS_STYLE_CONTENT_ALT_CONTENT here
6460 (value
.GetUnit() != eCSSUnit_Enumerated
||
6461 value
.GetIntValue() != NS_STYLE_CONTENT_ALT_CONTENT
)) {
6462 list
->mNext
= new nsCSSValueList();
6464 if (nsnull
!= list
) {
6465 list
->mValue
= value
;
6468 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6480 struct SingleCounterPropValue
{
6486 CSSParserImpl::ParseCounterData(nsCSSValuePairList
** aResult
,
6487 nsCSSProperty aPropID
)
6489 nsSubstring
* ident
= NextIdent();
6490 if (nsnull
== ident
) {
6493 static const SingleCounterPropValue singleValues
[] = {
6494 { "none", eCSSUnit_None
},
6495 { "inherit", eCSSUnit_Inherit
},
6496 { "-moz-initial", eCSSUnit_Initial
}
6498 for (const SingleCounterPropValue
*sv
= singleValues
,
6499 *sv_end
= singleValues
+ NS_ARRAY_LENGTH(singleValues
);
6500 sv
!= sv_end
; ++sv
) {
6501 if (ident
->LowerCaseEqualsASCII(sv
->str
)) {
6502 if (CheckEndProperty()) {
6503 nsCSSValuePairList
* dataHead
= new nsCSSValuePairList();
6505 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6508 dataHead
->mXValue
= nsCSSValue(sv
->unit
);
6509 *aResult
= dataHead
;
6510 mTempData
.SetPropertyBit(aPropID
);
6516 UngetToken(); // undo NextIdent
6518 nsCSSValuePairList
* dataHead
= nsnull
;
6519 nsCSSValuePairList
**next
= &dataHead
;
6521 if (!GetToken(PR_TRUE
) || mToken
.mType
!= eCSSToken_Ident
) {
6524 nsCSSValuePairList
*data
= *next
= new nsCSSValuePairList();
6526 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6529 next
= &data
->mNext
;
6530 data
->mXValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
6531 if (GetToken(PR_TRUE
)) {
6532 if (eCSSToken_Number
== mToken
.mType
&& mToken
.mIntegerValid
) {
6533 data
->mYValue
.SetIntValue(mToken
.mInteger
, eCSSUnit_Integer
);
6538 if (ExpectEndProperty()) {
6539 mTempData
.SetPropertyBit(aPropID
);
6540 *aResult
= dataHead
;
6549 CSSParserImpl::ParseCue()
6552 if (ParseSingleValueProperty(before
, eCSSProperty_cue_before
)) {
6553 if (eCSSUnit_Inherit
!= before
.GetUnit() &&
6554 eCSSUnit_Initial
!= before
.GetUnit()) {
6556 if (ParseSingleValueProperty(after
, eCSSProperty_cue_after
)) {
6557 if (ExpectEndProperty()) {
6558 AppendValue(eCSSProperty_cue_before
, before
);
6559 AppendValue(eCSSProperty_cue_after
, after
);
6565 if (ExpectEndProperty()) {
6566 AppendValue(eCSSProperty_cue_before
, before
);
6567 AppendValue(eCSSProperty_cue_after
, before
);
6575 CSSParserImpl::ParseCursor()
6577 nsCSSValueList
*list
= nsnull
;
6578 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
6579 cur
= *curp
= new nsCSSValueList();
6581 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6584 if (!ParseVariant(cur
->mValue
,
6585 (cur
== list
) ? VARIANT_AHUK
: VARIANT_AUK
,
6586 nsCSSProps::kCursorKTable
)) {
6589 if (cur
->mValue
.GetUnit() != eCSSUnit_URL
) {
6590 if (!ExpectEndProperty()) {
6593 // Only success case here, since having the failure case at the
6594 // end allows more sharing of code.
6595 mTempData
.SetPropertyBit(eCSSProperty_cursor
);
6596 mTempData
.mUserInterface
.mCursor
= list
;
6599 // We have a URL, so make a value array with three values.
6600 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(3);
6602 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6605 val
->Item(0) = cur
->mValue
;
6606 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
6608 // Parse optional x and y position of cursor hotspot (css3-ui).
6609 if (ParseVariant(val
->Item(1), VARIANT_NUMBER
, nsnull
)) {
6610 // If we have one number, we must have two.
6611 if (!ParseVariant(val
->Item(2), VARIANT_NUMBER
, nsnull
)) {
6616 if (!ExpectSymbol(',', PR_TRUE
)) {
6620 // Have failure case at the end so we can |break| to get to it.
6627 CSSParserImpl::ParseFont()
6629 static const nsCSSProperty fontIDs
[] = {
6630 eCSSProperty_font_style
,
6631 eCSSProperty_font_variant
,
6632 eCSSProperty_font_weight
6636 if (ParseVariant(family
, VARIANT_HK
, nsCSSProps::kFontKTable
)) {
6637 if (ExpectEndProperty()) {
6638 if (eCSSUnit_Inherit
== family
.GetUnit() ||
6639 eCSSUnit_Initial
== family
.GetUnit()) {
6640 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6641 AppendValue(eCSSProperty_font_family
, family
);
6642 AppendValue(eCSSProperty_font_style
, family
);
6643 AppendValue(eCSSProperty_font_variant
, family
);
6644 AppendValue(eCSSProperty_font_weight
, family
);
6645 AppendValue(eCSSProperty_font_size
, family
);
6646 AppendValue(eCSSProperty_line_height
, family
);
6647 AppendValue(eCSSProperty_font_stretch
, family
);
6648 AppendValue(eCSSProperty_font_size_adjust
, family
);
6651 AppendValue(eCSSProperty__x_system_font
, family
);
6652 nsCSSValue
systemFont(eCSSUnit_System_Font
);
6653 AppendValue(eCSSProperty_font_family
, systemFont
);
6654 AppendValue(eCSSProperty_font_style
, systemFont
);
6655 AppendValue(eCSSProperty_font_variant
, systemFont
);
6656 AppendValue(eCSSProperty_font_weight
, systemFont
);
6657 AppendValue(eCSSProperty_font_size
, systemFont
);
6658 AppendValue(eCSSProperty_line_height
, systemFont
);
6659 AppendValue(eCSSProperty_font_stretch
, systemFont
);
6660 AppendValue(eCSSProperty_font_size_adjust
, systemFont
);
6667 // Get optional font-style, font-variant and font-weight (in any order)
6668 const PRInt32 numProps
= 3;
6669 nsCSSValue values
[numProps
];
6670 PRInt32 found
= ParseChoice(values
, fontIDs
, numProps
);
6671 if ((found
< 0) || (eCSSUnit_Inherit
== values
[0].GetUnit()) ||
6672 (eCSSUnit_Initial
== values
[0].GetUnit())) { // illegal data
6675 if ((found
& 1) == 0) {
6676 // Provide default font-style
6677 values
[0].SetNormalValue();
6679 if ((found
& 2) == 0) {
6680 // Provide default font-variant
6681 values
[1].SetNormalValue();
6683 if ((found
& 4) == 0) {
6684 // Provide default font-weight
6685 values
[2].SetNormalValue();
6688 // Get mandatory font-size
6690 if (! ParseVariant(size
, VARIANT_KEYWORD
| VARIANT_LP
, nsCSSProps::kFontSizeKTable
)) {
6694 // Get optional "/" line-height
6695 nsCSSValue lineHeight
;
6696 if (ExpectSymbol('/', PR_TRUE
)) {
6697 if (! ParsePositiveVariant(lineHeight
,
6698 VARIANT_NUMBER
| VARIANT_LP
| VARIANT_NORMAL
,
6704 lineHeight
.SetNormalValue();
6707 // Get final mandatory font-family
6708 nsAutoParseCompoundProperty
compound(this);
6709 if (ParseFamily(family
)) {
6710 if ((eCSSUnit_Inherit
!= family
.GetUnit()) && (eCSSUnit_Initial
!= family
.GetUnit()) &&
6711 ExpectEndProperty()) {
6712 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6713 AppendValue(eCSSProperty_font_family
, family
);
6714 AppendValue(eCSSProperty_font_style
, values
[0]);
6715 AppendValue(eCSSProperty_font_variant
, values
[1]);
6716 AppendValue(eCSSProperty_font_weight
, values
[2]);
6717 AppendValue(eCSSProperty_font_size
, size
);
6718 AppendValue(eCSSProperty_line_height
, lineHeight
);
6719 AppendValue(eCSSProperty_font_stretch
, nsCSSValue(eCSSUnit_Normal
));
6720 AppendValue(eCSSProperty_font_size_adjust
, nsCSSValue(eCSSUnit_None
));
6728 CSSParserImpl::ParseFontWeight(nsCSSValue
& aValue
)
6730 if (ParseVariant(aValue
, VARIANT_HMKI
| VARIANT_SYSFONT
, nsCSSProps::kFontWeightKTable
)) {
6731 if (eCSSUnit_Integer
== aValue
.GetUnit()) { // ensure unit value
6732 PRInt32 intValue
= aValue
.GetIntValue();
6733 if ((100 <= intValue
) &&
6734 (intValue
<= 900) &&
6735 (0 == (intValue
% 100))) {
6748 CSSParserImpl::ParseOneFamily(nsAString
& aFamily
)
6750 if (!GetToken(PR_TRUE
))
6753 nsCSSToken
* tk
= &mToken
;
6755 if (eCSSToken_Ident
== tk
->mType
) {
6756 aFamily
.Append(tk
->mIdent
);
6758 if (!GetToken(PR_FALSE
))
6761 if (eCSSToken_Ident
== tk
->mType
) {
6762 aFamily
.Append(tk
->mIdent
);
6763 } else if (eCSSToken_WhiteSpace
== tk
->mType
) {
6764 // Lookahead one token and drop whitespace if we are ending the
6766 if (!GetToken(PR_TRUE
))
6770 if (eCSSToken_Ident
== tk
->mType
)
6771 aFamily
.Append(PRUnichar(' '));
6781 } else if (eCSSToken_String
== tk
->mType
) {
6782 aFamily
.Append(tk
->mSymbol
); // replace the quotes
6783 aFamily
.Append(tk
->mIdent
); // XXX What if it had escaped quotes?
6784 aFamily
.Append(tk
->mSymbol
);
6793 ///////////////////////////////////////////////////////
6794 // -moz-transform Parsing Implementation
6796 /* Reads a function list of arguments. Do not call this function
6797 * directly; it's mean to be caled from ParseFunction.
6800 CSSParserImpl::ParseFunctionInternals(const PRInt32 aVariantMask
[],
6803 nsTArray
<nsCSSValue
> &aOutput
)
6805 for (PRUint16 index
= 0; index
< aMaxElems
; ++index
) {
6806 nsCSSValue newValue
;
6807 if (!ParseVariant(newValue
, aVariantMask
[index
], nsnull
))
6810 if (!aOutput
.AppendElement(newValue
)) {
6811 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6815 // See whether to continue or whether to look for end of function.
6816 if (!ExpectSymbol(',', PR_TRUE
)) {
6817 // We need to read the closing parenthesis, and also must take care
6818 // that we haven't read too few symbols.
6819 return ExpectSymbol(')', PR_TRUE
) && (index
+ 1) >= aMinElems
;
6823 // If we're here, we finished looping without hitting the end, so we read too
6828 /* Parses a function [ input of the form (a [, b]*) ] and stores it
6829 * as an nsCSSValue that holds a function of the form
6830 * function-name arg1 arg2 ... argN
6832 * On error, the return value is PR_FALSE.
6834 * @param aFunction The name of the function that we're reading.
6835 * @param aAllowedTypes An array of values corresponding to the legal
6836 * types for each element in the function. The zeroth element in the
6837 * array corresponds to the first function parameter, etc. The length
6838 * of this array _must_ be greater than or equal to aMaxElems or the
6839 * behavior is undefined.
6840 * @param aMinElems Minimum number of elements to read. Reading fewer than
6841 * this many elements will result in the function failing.
6842 * @param aMaxElems Maximum number of elements to read. Reading more than
6843 * this many elements will result in the function failing.
6844 * @param aValue (out) The value that was parsed.
6847 CSSParserImpl::ParseFunction(const nsString
&aFunction
,
6848 const PRInt32 aAllowedTypes
[],
6849 PRUint16 aMinElems
, PRUint16 aMaxElems
,
6852 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
6854 /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
6855 * elements stored in the the nsCSSValue::Array.
6857 static const arrlen_t MAX_ALLOWED_ELEMS
= 0xFFFE;
6859 /* Make a copy of the function name, since the reference is _probably_ to
6860 * mToken.mIdent, which is going to get overwritten during the course of this
6863 nsString
functionName(aFunction
);
6865 /* First things first... read the parenthesis. If it fails, abort. */
6866 if (!ExpectSymbol('(', PR_TRUE
))
6869 /* Read in a list of values as an nsTArray, failing if we can't or if
6870 * it's out of bounds.
6872 nsTArray
<nsCSSValue
> foundValues
;
6873 if (!ParseFunctionInternals(aAllowedTypes
, aMinElems
, aMaxElems
,
6877 /* Now, convert this nsTArray into an nsCSSValue::Array object.
6878 * We'll need N + 1 spots, one for the function name and the rest for the
6879 * arguments. In case the user has given us more than 2^16 - 2 arguments,
6880 * we'll truncate them at 2^16 - 2 arguments.
6882 PRUint16 numElements
= (foundValues
.Length() <= MAX_ALLOWED_ELEMS
?
6883 foundValues
.Length() + 1 : MAX_ALLOWED_ELEMS
);
6884 nsRefPtr
<nsCSSValue::Array
> convertedArray
=
6885 nsCSSValue::Array::Create(numElements
);
6886 if (!convertedArray
) {
6887 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6891 /* Copy things over. */
6892 convertedArray
->Item(0).SetStringValue(functionName
, eCSSUnit_String
);
6893 for (PRUint16 index
= 0; index
+ 1 < numElements
; ++index
)
6894 convertedArray
->Item(index
+ 1) = foundValues
[static_cast<arrlen_t
>(index
)];
6896 /* Fill in the outparam value with the array. */
6897 aValue
.SetArrayValue(convertedArray
, eCSSUnit_Function
);
6904 * Given a token, determines the minimum and maximum number of function
6905 * parameters to read, along with the mask that should be used to read
6906 * those function parameters. If the token isn't a transform function,
6909 * @param aToken The token identifying the function.
6910 * @param aMinElems [out] The minimum number of elements to read.
6911 * @param aMaxElems [out] The maximum number of elements to read
6912 * @param aVariantMask [out] The variant mask to use during parsing
6913 * @return Whether the information was loaded successfully.
6915 static PRBool
GetFunctionParseInformation(nsCSSKeyword aToken
,
6916 PRUint16
&aMinElems
,
6917 PRUint16
&aMaxElems
,
6918 const PRInt32
*& aVariantMask
)
6920 /* These types represent the common variant masks that will be used to
6921 * parse out the individual functions. The order in the enumeration
6922 * must match the order in which the masks are declared.
6924 enum { eLengthPercent
,
6932 static const PRInt32 kMaxElemsPerFunction
= 6;
6933 static const PRInt32 kVariantMasks
[eNumVariantMasks
][kMaxElemsPerFunction
] = {
6934 {VARIANT_LENGTH
| VARIANT_PERCENT
},
6935 {VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
},
6937 {VARIANT_ANGLE
, VARIANT_ANGLE
},
6939 {VARIANT_NUMBER
, VARIANT_NUMBER
},
6940 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
6941 VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
}};
6944 static const PRUint8 kVariantMaskLengths
[eNumVariantMasks
] =
6945 {1, 2, 1, 2, 1, 2, 6};
6948 PRInt32 variantIndex
= eNumVariantMasks
;
6951 case eCSSKeyword_translatex
:
6952 /* Exactly one length or percent. */
6953 variantIndex
= eLengthPercent
;
6957 case eCSSKeyword_translatey
:
6958 /* Exactly one length or percent. */
6959 variantIndex
= eLengthPercent
;
6963 case eCSSKeyword_scalex
:
6964 /* Exactly one scale factor. */
6965 variantIndex
= eNumber
;
6969 case eCSSKeyword_scaley
:
6970 /* Exactly one scale factor. */
6971 variantIndex
= eNumber
;
6975 case eCSSKeyword_rotate
:
6976 /* Exactly one angle. */
6977 variantIndex
= eAngle
;
6981 case eCSSKeyword_translate
:
6982 /* One or two lengths or percents. */
6983 variantIndex
= eTwoLengthPercents
;
6987 case eCSSKeyword_skew
:
6988 /* Exactly one or two angles. */
6989 variantIndex
= eTwoAngles
;
6993 case eCSSKeyword_scale
:
6994 /* One or two scale factors. */
6995 variantIndex
= eTwoNumbers
;
6999 case eCSSKeyword_skewx
:
7000 /* Exactly one angle. */
7001 variantIndex
= eAngle
;
7005 case eCSSKeyword_skewy
:
7006 /* Exactly one angle. */
7007 variantIndex
= eAngle
;
7011 case eCSSKeyword_matrix
:
7012 /* Six values, which can be numbers, lengths, or percents. */
7013 variantIndex
= eMatrix
;
7018 /* Oh dear, we didn't match. Report an error. */
7022 NS_ASSERTION(aMinElems
> 0, "Didn't update minimum elements!");
7023 NS_ASSERTION(aMaxElems
> 0, "Didn't update maximum elements!");
7024 NS_ASSERTION(aMinElems
<= aMaxElems
, "aMinElems > aMaxElems!");
7025 NS_ASSERTION(variantIndex
>= 0, "Invalid variant mask!");
7026 NS_ASSERTION(variantIndex
< eNumVariantMasks
, "Invalid variant mask!");
7028 NS_ASSERTION(aMaxElems
<= kVariantMaskLengths
[variantIndex
],
7029 "Invalid aMaxElems for this variant mask.");
7032 // Convert the index into a mask.
7033 aVariantMask
= kVariantMasks
[variantIndex
];
7039 /* Reads a single transform function from the tokenizer stream, reporting an
7040 * error if something goes wrong.
7042 PRBool
CSSParserImpl::ReadSingleTransform(nsCSSValueList
**& aTail
)
7044 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
7046 if (!GetToken(PR_TRUE
))
7049 /* Check to make sure that we've read a function. */
7050 if (mToken
.mType
!= eCSSToken_Function
) {
7055 /* Load up the variant mask information for ParseFunction. If we can't,
7058 const PRInt32
* variantMask
;
7059 PRUint16 minElems
, maxElems
;
7060 if (!GetFunctionParseInformation(nsCSSKeywords::LookupKeyword(mToken
.mIdent
),
7061 minElems
, maxElems
, variantMask
))
7064 /* Create a cell to populate, fail if we're out of memory. */
7065 nsAutoPtr
<nsCSSValue
> newCell(new nsCSSValue
);
7067 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7071 /* Try reading things in, failing if we can't */
7072 if (!ParseFunction(mToken
.mIdent
, variantMask
, minElems
, maxElems
, *newCell
))
7075 /* Wrap up our result in an nsCSSValueList cell. */
7076 nsAutoPtr
<nsCSSValueList
> toAppend(new nsCSSValueList
);
7080 toAppend
->mValue
= *newCell
;
7082 /* Chain the element to the end of the transform list, then update the
7085 *aTail
= toAppend
.forget();
7086 aTail
= &(*aTail
)->mNext
;
7088 /* It worked! Return true. */
7092 /* Parses a -moz-transform property list by continuously reading in properties
7093 * and constructing a matrix from it.
7095 PRBool
CSSParserImpl::ParseMozTransform()
7097 mTempData
.mDisplay
.mTransform
= nsnull
;
7099 /* First, check to see if this is some sort of keyword - none, inherit,
7102 nsCSSValue keywordValue
;
7103 if (ParseVariant(keywordValue
, VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
7104 /* Looks like it is. Make a new value list and fill it in, failing if
7107 mTempData
.mDisplay
.mTransform
= new nsCSSValueList
;
7108 if (!mTempData
.mDisplay
.mTransform
) {
7109 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7113 /* Inform the parser that everything worked. */
7114 mTempData
.mDisplay
.mTransform
->mValue
= keywordValue
;
7115 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7119 /* We will read a nonempty list of transforms. Thus we'll read in a
7120 * transform, then continuously read transforms until we're no longer
7123 nsCSSValueList
*transformList
= nsnull
;
7124 nsCSSValueList
**tail
= &transformList
;
7126 /* Try reading a transform. If we fail to do so, abort. */
7127 if (!ReadSingleTransform(tail
)) {
7128 delete transformList
;
7132 while (!CheckEndProperty());
7134 /* Confirm that this is the end of the property and set error code
7135 * appropriately otherwise.
7137 if (!ExpectEndProperty()) {
7138 delete transformList
;
7142 /* Validate our data. */
7143 NS_ASSERTION(transformList
, "Didn't read any transforms!");
7145 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7146 mTempData
.mDisplay
.mTransform
= transformList
;
7151 PRBool
CSSParserImpl::ParseMozTransformOrigin()
7153 /* Read in a box position, fail if we can't. */
7154 if (!ParseBoxPosition(mTempData
.mDisplay
.mTransformOrigin
))
7157 /* Set the property bit and return. */
7158 mTempData
.SetPropertyBit(eCSSProperty__moz_transform_origin
);
7163 CSSParserImpl::ParseFamily(nsCSSValue
& aValue
)
7165 if (!GetToken(PR_TRUE
))
7168 if (eCSSToken_Ident
== mToken
.mType
) {
7169 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
7170 if (keyword
== eCSSKeyword_inherit
) {
7171 aValue
.SetInheritValue();
7174 if (keyword
== eCSSKeyword__moz_initial
) {
7175 aValue
.SetInitialValue();
7178 if (keyword
== eCSSKeyword__moz_use_system_font
&&
7179 !IsParsingCompoundProperty()) {
7180 aValue
.SetSystemFontValue();
7187 nsAutoString family
;
7189 if (!ParseOneFamily(family
))
7192 if (!ExpectSymbol(',', PR_TRUE
))
7195 family
.Append(PRUnichar(','));
7198 if (family
.IsEmpty()) {
7201 aValue
.SetStringValue(family
, eCSSUnit_String
);
7205 // src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*
7206 // uri-src: uri [ 'format(' string ( ',' string )* ')' ]
7207 // local-src: 'local(' ( string | ident ) ')'
7210 CSSParserImpl::ParseFontSrc(nsCSSValue
& aValue
)
7212 // could we maybe turn nsCSSValue::Array into nsTArray<nsCSSValue>?
7213 nsTArray
<nsCSSValue
> values
;
7216 if (!GetToken(PR_TRUE
))
7219 if (mToken
.mType
== eCSSToken_Function
&&
7220 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
7223 values
.AppendElement(cur
);
7224 if (!ParseFontSrcFormat(values
))
7227 } else if (mToken
.mType
== eCSSToken_Function
&&
7228 mToken
.mIdent
.LowerCaseEqualsLiteral("local")) {
7229 // css3-fonts does not specify a formal grammar for local().
7230 // The text permits both unquoted identifiers and quoted
7231 // strings. We resolve this ambiguity in the spec by
7232 // assuming that the appropriate production is a single
7233 // <family-name>, possibly surrounded by whitespace.
7235 nsAutoString family
;
7236 if (!ExpectSymbol('(', PR_FALSE
))
7238 if (!ParseOneFamily(family
))
7240 if (!ExpectSymbol(')', PR_TRUE
))
7243 // the style parameters to the nsFont constructor are ignored,
7244 // because it's only being used to call EnumerateFamilies
7245 nsFont
font(family
, 0, 0, 0, 0, 0);
7246 ExtractFirstFamilyData dat
;
7248 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
7252 cur
.SetStringValue(dat
.mFamilyName
, eCSSUnit_Local_Font
);
7253 values
.AppendElement(cur
);
7258 if (!ExpectSymbol(',', PR_TRUE
))
7262 nsRefPtr
<nsCSSValue::Array
> srcVals
7263 = nsCSSValue::Array::Create(values
.Length());
7268 for (i
= 0; i
< values
.Length(); i
++)
7269 srcVals
->Item(i
) = values
[i
];
7270 aValue
.SetArrayValue(srcVals
, eCSSUnit_Array
);
7275 CSSParserImpl::ParseFontSrcFormat(nsTArray
<nsCSSValue
> & values
)
7277 if (!GetToken(PR_TRUE
))
7278 return PR_TRUE
; // EOF harmless here
7279 if (mToken
.mType
!= eCSSToken_Function
||
7280 !mToken
.mIdent
.LowerCaseEqualsLiteral("format")) {
7284 if (!ExpectSymbol('(', PR_FALSE
))
7288 if (!GetToken(PR_TRUE
))
7291 if (mToken
.mType
!= eCSSToken_String
)
7294 nsCSSValue
cur(mToken
.mIdent
, eCSSUnit_Font_Format
);
7295 values
.AppendElement(cur
);
7296 } while (ExpectSymbol(',', PR_TRUE
));
7298 return ExpectSymbol(')', PR_TRUE
);
7301 // font-ranges: urange ( ',' urange )*
7303 CSSParserImpl::ParseFontRanges(nsCSSValue
& aValue
)
7305 // not currently implemented (bug 443976)
7310 CSSParserImpl::ParseListStyle()
7312 const PRInt32 numProps
= 3;
7313 static const nsCSSProperty listStyleIDs
[] = {
7314 eCSSProperty_list_style_type
,
7315 eCSSProperty_list_style_position
,
7316 eCSSProperty_list_style_image
7319 nsCSSValue values
[numProps
];
7321 PRInt32 found
= ParseChoice(values
, listStyleIDs
, numProps
);
7322 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7326 // Provide default values
7327 if ((found
& 1) == 0) {
7328 values
[0].SetIntValue(NS_STYLE_LIST_STYLE_DISC
, eCSSUnit_Enumerated
);
7330 if ((found
& 2) == 0) {
7331 values
[1].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE
, eCSSUnit_Enumerated
);
7333 if ((found
& 4) == 0) {
7334 values
[2].SetNoneValue();
7337 for (index
= 0; index
< numProps
; index
++) {
7338 AppendValue(listStyleIDs
[index
], values
[index
]);
7344 CSSParserImpl::ParseMargin()
7346 static const nsCSSProperty kMarginSideIDs
[] = {
7347 eCSSProperty_margin_top
,
7348 eCSSProperty_margin_right_value
,
7349 eCSSProperty_margin_bottom
,
7350 eCSSProperty_margin_left_value
7352 static const nsCSSProperty kMarginSources
[] = {
7353 eCSSProperty_margin_left_ltr_source
,
7354 eCSSProperty_margin_left_rtl_source
,
7355 eCSSProperty_margin_right_ltr_source
,
7356 eCSSProperty_margin_right_rtl_source
,
7357 eCSSProperty_UNKNOWN
7360 // do this now, in case 4 values weren't specified
7361 InitBoxPropsAsPhysical(kMarginSources
);
7362 return ParseBoxProperties(mTempData
.mMargin
.mMargin
,
7367 CSSParserImpl::ParseMarks(nsCSSValue
& aValue
)
7369 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kPageMarksKTable
)) {
7370 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
7371 if (PR_FALSE
== CheckEndProperty()) {
7373 if (ParseEnum(second
, nsCSSProps::kPageMarksKTable
)) {
7374 aValue
.SetIntValue(aValue
.GetIntValue() | second
.GetIntValue(), eCSSUnit_Enumerated
);
7386 CSSParserImpl::ParseOutline()
7388 const PRInt32 numProps
= 3;
7389 static const nsCSSProperty kOutlineIDs
[] = {
7390 eCSSProperty_outline_color
,
7391 eCSSProperty_outline_style
,
7392 eCSSProperty_outline_width
7395 nsCSSValue values
[numProps
];
7396 PRInt32 found
= ParseChoice(values
, kOutlineIDs
, numProps
);
7397 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7401 // Provide default values
7402 if ((found
& 1) == 0) {
7403 #ifdef GFX_HAS_INVERT
7404 values
[0].SetIntValue(NS_STYLE_COLOR_INVERT
, eCSSUnit_Enumerated
);
7406 values
[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
7409 if ((found
& 2) == 0) {
7410 values
[1].SetNoneValue();
7412 if ((found
& 4) == 0) {
7413 values
[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
7417 for (index
= 0; index
< numProps
; index
++) {
7418 AppendValue(kOutlineIDs
[index
], values
[index
]);
7424 CSSParserImpl::ParseOverflow()
7426 nsCSSValue overflow
;
7427 if (!ParseVariant(overflow
, VARIANT_AHK
,
7428 nsCSSProps::kOverflowKTable
) ||
7429 !ExpectEndProperty())
7432 nsCSSValue
overflowX(overflow
);
7433 nsCSSValue
overflowY(overflow
);
7434 if (eCSSUnit_Enumerated
== overflow
.GetUnit())
7435 switch(overflow
.GetIntValue()) {
7436 case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL
:
7437 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7438 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7440 case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL
:
7441 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7442 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7445 AppendValue(eCSSProperty_overflow_x
, overflowX
);
7446 AppendValue(eCSSProperty_overflow_y
, overflowY
);
7451 CSSParserImpl::ParsePadding()
7453 static const nsCSSProperty kPaddingSideIDs
[] = {
7454 eCSSProperty_padding_top
,
7455 eCSSProperty_padding_right_value
,
7456 eCSSProperty_padding_bottom
,
7457 eCSSProperty_padding_left_value
7459 static const nsCSSProperty kPaddingSources
[] = {
7460 eCSSProperty_padding_left_ltr_source
,
7461 eCSSProperty_padding_left_rtl_source
,
7462 eCSSProperty_padding_right_ltr_source
,
7463 eCSSProperty_padding_right_rtl_source
,
7464 eCSSProperty_UNKNOWN
7467 // do this now, in case 4 values weren't specified
7468 InitBoxPropsAsPhysical(kPaddingSources
);
7469 return ParseBoxProperties(mTempData
.mMargin
.mPadding
,
7474 CSSParserImpl::ParsePause()
7477 if (ParseSingleValueProperty(before
, eCSSProperty_pause_before
)) {
7478 if (eCSSUnit_Inherit
!= before
.GetUnit() && eCSSUnit_Initial
!= before
.GetUnit()) {
7480 if (ParseSingleValueProperty(after
, eCSSProperty_pause_after
)) {
7481 if (ExpectEndProperty()) {
7482 AppendValue(eCSSProperty_pause_before
, before
);
7483 AppendValue(eCSSProperty_pause_after
, after
);
7489 if (ExpectEndProperty()) {
7490 AppendValue(eCSSProperty_pause_before
, before
);
7491 AppendValue(eCSSProperty_pause_after
, before
);
7499 CSSParserImpl::ParseQuotes()
7502 if (ParseVariant(open
, VARIANT_HOS
, nsnull
)) {
7503 if (eCSSUnit_String
== open
.GetUnit()) {
7504 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7505 nsCSSValuePairList
* quotes
= quotesHead
;
7506 if (nsnull
== quotes
) {
7507 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7510 quotes
->mXValue
= open
;
7511 while (nsnull
!= quotes
) {
7512 // get mandatory close
7513 if (ParseVariant(quotes
->mYValue
, VARIANT_STRING
,
7515 if (CheckEndProperty()) {
7516 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7517 mTempData
.mContent
.mQuotes
= quotesHead
;
7520 // look for another open
7521 if (ParseVariant(open
, VARIANT_STRING
, nsnull
)) {
7522 quotes
->mNext
= new nsCSSValuePairList();
7523 quotes
= quotes
->mNext
;
7524 if (nsnull
!= quotes
) {
7525 quotes
->mXValue
= open
;
7528 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7536 if (ExpectEndProperty()) {
7537 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7538 quotesHead
->mXValue
= open
;
7539 mTempData
.mContent
.mQuotes
= quotesHead
;
7540 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7548 CSSParserImpl::ParseSize()
7551 if (ParseVariant(width
, VARIANT_AHKL
, nsCSSProps::kPageSizeKTable
)) {
7552 if (width
.IsLengthUnit()) {
7554 if (ParseVariant(height
, VARIANT_LENGTH
, nsnull
)) {
7555 if (ExpectEndProperty()) {
7556 mTempData
.mPage
.mSize
.mXValue
= width
;
7557 mTempData
.mPage
.mSize
.mYValue
= height
;
7558 mTempData
.SetPropertyBit(eCSSProperty_size
);
7564 if (ExpectEndProperty()) {
7565 mTempData
.mPage
.mSize
.SetBothValuesTo(width
);
7566 mTempData
.SetPropertyBit(eCSSProperty_size
);
7574 CSSParserImpl::ParseTextDecoration(nsCSSValue
& aValue
)
7576 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kTextDecorationKTable
)) {
7577 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) { // look for more keywords
7578 PRInt32 intValue
= aValue
.GetIntValue();
7581 for (index
= 0; index
< 3; index
++) {
7582 if (ParseEnum(keyword
, nsCSSProps::kTextDecorationKTable
)) {
7583 intValue
|= keyword
.GetIntValue();
7589 aValue
.SetIntValue(intValue
, eCSSUnit_Enumerated
);
7597 CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread
)
7599 nsAutoParseCompoundProperty
compound(this);
7601 // Parses x, y, radius, color (in two possible orders)
7602 // This parses the input into a list. Either it contains just a "none" or
7603 // "inherit" value, or a list of arrays.
7604 // The resulting arrays will always contain the above order, with color and
7605 // radius as null values as needed
7614 nsCSSValueList
*list
= nsnull
;
7615 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
7616 cur
= *curp
= new nsCSSValueList();
7618 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7621 if (!ParseVariant(cur
->mValue
,
7622 (cur
== list
) ? VARIANT_HC
| VARIANT_LENGTH
| VARIANT_NONE
7623 : VARIANT_COLOR
| VARIANT_LENGTH
,
7628 nsCSSUnit unit
= cur
->mValue
.GetUnit();
7629 if (unit
!= eCSSUnit_None
&& unit
!= eCSSUnit_Inherit
&&
7630 unit
!= eCSSUnit_Initial
) {
7631 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(5);
7633 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7636 PRBool haveColor
= PR_FALSE
;
7637 if (cur
->mValue
.IsLengthUnit()) {
7638 val
->Item(IndexX
) = cur
->mValue
;
7640 // Must be a color (as string or color value)
7641 NS_ASSERTION(unit
== eCSSUnit_String
|| unit
== eCSSUnit_Color
||
7642 unit
== eCSSUnit_EnumColor
,
7643 "Must be a color value (named color, numeric color, "
7644 "or system color)");
7645 haveColor
= PR_TRUE
;
7646 val
->Item(IndexColor
) = cur
->mValue
;
7648 // Parse the X coordinate
7649 if (!ParseVariant(val
->Item(IndexX
), VARIANT_LENGTH
,
7654 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
7656 // Y coordinate; this one is not optional
7657 if (!ParseVariant(val
->Item(IndexY
), VARIANT_LENGTH
, nsnull
)) {
7661 // Optional radius. Ignore errors except if they pass a negative
7662 // value which we must reject. If we use ParsePositiveVariant we can't
7663 // tell the difference between an unspecified radius and a negative
7664 // radius, so that's why we don't use it.
7665 if (ParseVariant(val
->Item(IndexRadius
), VARIANT_LENGTH
, nsnull
) &&
7666 val
->Item(IndexRadius
).GetFloatValue() < 0) {
7671 // Optional spread (ignore errors)
7672 ParseVariant(val
->Item(IndexSpread
), VARIANT_LENGTH
,
7677 // Optional color (ignore errors)
7678 ParseVariant(val
->Item(IndexColor
), VARIANT_COLOR
,
7682 // Might be at a comma now
7683 if (ExpectSymbol(',', PR_TRUE
)) {
7689 if (!ExpectEndProperty()) {
7690 // If we don't have a comma to delimit the next value, we
7691 // must be at the end of the property. Otherwise we've hit
7692 // something else, which is an error.
7696 // Only success case here, since having the failure case at the
7697 // end allows more sharing of code.
7700 // Have failure case at the end so we can |break| to get to it.
7706 CSSParserImpl::ParseTextShadow()
7708 nsCSSValueList
* list
= ParseCSSShadowList(PR_FALSE
);
7712 mTempData
.SetPropertyBit(eCSSProperty_text_shadow
);
7713 mTempData
.mText
.mTextShadow
= list
;
7718 CSSParserImpl::ParseBoxShadow()
7720 nsCSSValueList
* list
= ParseCSSShadowList(PR_TRUE
);
7724 mTempData
.SetPropertyBit(eCSSProperty_box_shadow
);
7725 mTempData
.mMargin
.mBoxShadow
= list
;
7730 CSSParserImpl::GetNamespaceIdForPrefix(const nsString
& aPrefix
,
7731 PRInt32
* aNameSpaceID
)
7733 NS_PRECONDITION(!aPrefix
.IsEmpty(), "Must have a prefix here");
7735 PRInt32 nameSpaceID
= kNameSpaceID_Unknown
;
7736 if (mNameSpaceMap
) {
7737 // user-specified identifiers are case-sensitive (bug 416106)
7738 nsCOMPtr
<nsIAtom
> prefix
= do_GetAtom(aPrefix
);
7739 nameSpaceID
= mNameSpaceMap
->FindNameSpaceID(prefix
);
7741 // else no declared namespaces
7743 if (kNameSpaceID_Unknown
== nameSpaceID
) { // unknown prefix, dump it
7744 const PRUnichar
*params
[] = {
7747 REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix
, params
);
7748 if (mUnresolvablePrefixException
)
7749 mScanner
.SetLowLevelError(NS_ERROR_DOM_NAMESPACE_ERR
);
7753 *aNameSpaceID
= nameSpaceID
;
7758 CSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
)
7760 if (mNameSpaceMap
) {
7761 aSelector
.SetNameSpace(mNameSpaceMap
->FindNameSpaceID(nsnull
));
7763 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // wildcard
7769 CSSParserImpl::ParsePaint(nsCSSValuePair
* aResult
,
7770 nsCSSProperty aPropID
)
7772 if (!ParseVariant(aResult
->mXValue
,
7773 VARIANT_HC
| VARIANT_NONE
| VARIANT_URL
,
7777 if (aResult
->mXValue
.GetUnit() == eCSSUnit_URL
) {
7778 if (!ParseVariant(aResult
->mYValue
, VARIANT_COLOR
| VARIANT_NONE
,
7780 aResult
->mYValue
.SetColorValue(NS_RGB(0, 0, 0));
7782 aResult
->mYValue
= aResult
->mXValue
;
7785 if (!ExpectEndProperty())
7788 mTempData
.SetPropertyBit(aPropID
);
7793 CSSParserImpl::ParseDasharray()
7796 if (ParseVariant(value
, VARIANT_HLPN
| VARIANT_NONE
, nsnull
)) {
7797 nsCSSValueList
*listHead
= new nsCSSValueList
;
7798 nsCSSValueList
*list
= listHead
;
7800 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7804 list
->mValue
= value
;
7807 if (CheckEndProperty()) {
7808 mTempData
.SetPropertyBit(eCSSProperty_stroke_dasharray
);
7809 mTempData
.mSVG
.mStrokeDasharray
= listHead
;
7813 if (eCSSUnit_Inherit
== value
.GetUnit() ||
7814 eCSSUnit_Initial
== value
.GetUnit() ||
7815 eCSSUnit_None
== value
.GetUnit())
7818 if (!ExpectSymbol(',', PR_TRUE
))
7821 if (!ParseVariant(value
,
7822 VARIANT_LENGTH
| VARIANT_PERCENT
| VARIANT_NUMBER
,
7826 list
->mNext
= new nsCSSValueList
;
7829 list
->mValue
= value
;
7831 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7841 CSSParserImpl::ParseMarker()
7844 if (ParseSingleValueProperty(marker
, eCSSProperty_marker_end
)) {
7845 if (ExpectEndProperty()) {
7846 AppendValue(eCSSProperty_marker_end
, marker
);
7847 AppendValue(eCSSProperty_marker_mid
, marker
);
7848 AppendValue(eCSSProperty_marker_start
, marker
);