1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * emk <VYV03354@nifty.ne.jp>
24 * Daniel Glazman <glazman@netscape.com>
25 * L. David Baron <dbaron@dbaron.org>
26 * Boris Zbarsky <bzbarsky@mit.edu>
27 * Mats Palmgren <mats.palmgren@bredband.net>
28 * Christian Biesinger <cbiesinger@web.de>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
44 /* parsing of CSS stylesheets, based on a token stream from the CSS scanner */
46 #include "nsICSSParser.h"
47 #include "nsCSSProps.h"
48 #include "nsCSSKeywords.h"
49 #include "nsCSSScanner.h"
50 #include "nsICSSLoader.h"
51 #include "nsICSSStyleRule.h"
52 #include "nsICSSImportRule.h"
53 #include "nsCSSRules.h"
54 #include "nsICSSNameSpaceRule.h"
55 #include "nsIUnicharInputStream.h"
56 #include "nsICSSStyleSheet.h"
57 #include "nsCSSDeclaration.h"
58 #include "nsStyleConsts.h"
60 #include "nsNetUtil.h"
63 #include "nsReadableUtils.h"
64 #include "nsUnicharUtils.h"
66 #include "nsVoidArray.h"
67 #include "nsCOMArray.h"
69 #include "nsStyleConsts.h"
70 #include "nsCSSPseudoClasses.h"
71 #include "nsCSSPseudoElements.h"
72 #include "nsCSSAnonBoxes.h"
73 #include "nsINameSpaceManager.h"
74 #include "nsXMLNameSpaceMap.h"
75 #include "nsThemeConstants.h"
76 #include "nsContentErrors.h"
77 #include "nsPrintfCString.h"
78 #include "nsIMediaList.h"
79 #include "nsILookAndFeel.h"
80 #include "nsStyleUtil.h"
81 #include "nsIPrincipal.h"
84 #include "nsContentUtils.h"
85 #include "nsDOMError.h"
86 #include "nsAutoPtr.h"
89 // Flags for ParseVariant method
90 #define VARIANT_KEYWORD 0x000001 // K
91 #define VARIANT_LENGTH 0x000002 // L
92 #define VARIANT_PERCENT 0x000004 // P
93 #define VARIANT_COLOR 0x000008 // C eCSSUnit_Color, eCSSUnit_String (e.g. "red")
94 #define VARIANT_URL 0x000010 // U
95 #define VARIANT_NUMBER 0x000020 // N
96 #define VARIANT_INTEGER 0x000040 // I
97 #define VARIANT_ANGLE 0x000080 // G
98 #define VARIANT_FREQUENCY 0x000100 // F
99 #define VARIANT_TIME 0x000200 // T
100 #define VARIANT_STRING 0x000400 // S
101 #define VARIANT_COUNTER 0x000800 //
102 #define VARIANT_ATTR 0x001000 //
103 #define VARIANT_IDENTIFIER 0x002000 // D
104 #define VARIANT_AUTO 0x010000 // A
105 #define VARIANT_INHERIT 0x020000 // H eCSSUnit_Initial, eCSSUnit_Inherit
106 #define VARIANT_NONE 0x040000 // O
107 #define VARIANT_NORMAL 0x080000 // M
108 #define VARIANT_SYSFONT 0x100000 // eCSSUnit_System_Font
110 // Common combinations of variants
111 #define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
112 #define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)
113 #define VARIANT_AH (VARIANT_AUTO | VARIANT_INHERIT)
114 #define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
115 #define VARIANT_AHI (VARIANT_AH | VARIANT_INTEGER)
116 #define VARIANT_AHK (VARIANT_AH | VARIANT_KEYWORD)
117 #define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)
118 #define VARIANT_AUK (VARIANT_AUTO | VARIANT_URL | VARIANT_KEYWORD)
119 #define VARIANT_AHUK (VARIANT_AH | VARIANT_URL | VARIANT_KEYWORD)
120 #define VARIANT_AHL (VARIANT_AH | VARIANT_LENGTH)
121 #define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
122 #define VARIANT_HK (VARIANT_INHERIT | VARIANT_KEYWORD)
123 #define VARIANT_HKF (VARIANT_HK | VARIANT_FREQUENCY)
124 #define VARIANT_HKL (VARIANT_HK | VARIANT_LENGTH)
125 #define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
126 #define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)
127 #define VARIANT_HL (VARIANT_INHERIT | VARIANT_LENGTH)
128 #define VARIANT_HI (VARIANT_INHERIT | VARIANT_INTEGER)
129 #define VARIANT_HLP (VARIANT_HL | VARIANT_PERCENT)
130 #define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
131 #define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
132 #define VARIANT_HTP (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
133 #define VARIANT_HMK (VARIANT_HK | VARIANT_NORMAL)
134 #define VARIANT_HMKI (VARIANT_HMK | VARIANT_INTEGER)
135 #define VARIANT_HC (VARIANT_INHERIT | VARIANT_COLOR)
136 #define VARIANT_HCK (VARIANT_HK | VARIANT_COLOR)
137 #define VARIANT_HUO (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
138 #define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
139 #define VARIANT_HPN (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
140 #define VARIANT_HOK (VARIANT_HK | VARIANT_NONE)
141 #define VARIANT_HN (VARIANT_INHERIT | VARIANT_NUMBER)
142 #define VARIANT_HON (VARIANT_HN | VARIANT_NONE)
143 #define VARIANT_HOS (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
145 //----------------------------------------------------------------------
147 // Your basic top-down recursive descent style parser
148 class CSSParserImpl
: public nsICSSParser
{
151 virtual ~CSSParserImpl();
155 NS_IMETHOD
SetStyleSheet(nsICSSStyleSheet
* aSheet
);
157 NS_IMETHOD
SetCaseSensitive(PRBool aCaseSensitive
);
159 NS_IMETHOD
SetQuirkMode(PRBool aQuirkMode
);
162 NS_IMETHOD
SetSVGMode(PRBool aSVGMode
);
165 NS_IMETHOD
SetChildLoader(nsICSSLoader
* aChildLoader
);
167 NS_IMETHOD
Parse(nsIUnicharInputStream
* aInput
,
170 nsIPrincipal
* aSheetPrincipal
,
171 PRUint32 aLineNumber
,
172 PRBool aAllowUnsafeRules
);
174 NS_IMETHOD
ParseStyleAttribute(const nsAString
& aAttributeValue
,
177 nsIPrincipal
* aNodePrincipal
,
178 nsICSSStyleRule
** aResult
);
180 NS_IMETHOD
ParseAndAppendDeclaration(const nsAString
& aBuffer
,
183 nsIPrincipal
* aSheetPrincipal
,
184 nsCSSDeclaration
* aDeclaration
,
185 PRBool aParseOnlyOneDecl
,
187 PRBool aClearOldDecl
);
189 NS_IMETHOD
ParseRule(const nsAString
& aRule
,
192 nsIPrincipal
* aSheetPrincipal
,
193 nsCOMArray
<nsICSSRule
>& aResult
);
195 NS_IMETHOD
ParseProperty(const nsCSSProperty aPropID
,
196 const nsAString
& aPropValue
,
199 nsIPrincipal
* aSheetPrincipal
,
200 nsCSSDeclaration
* aDeclaration
,
203 NS_IMETHOD
ParseMediaList(const nsSubstring
& aBuffer
,
204 nsIURI
* aURL
, // for error reporting
205 PRUint32 aLineNumber
, // for error reporting
206 nsMediaList
* aMediaList
,
209 NS_IMETHOD
ParseColorString(const nsSubstring
& aBuffer
,
210 nsIURI
* aURL
, // for error reporting
211 PRUint32 aLineNumber
, // for error reporting
214 NS_IMETHOD
ParseSelectorString(const nsSubstring
& aSelectorString
,
215 nsIURI
* aURL
, // for error reporting
216 PRUint32 aLineNumber
, // for error reporting
217 nsCSSSelectorList
**aSelectorList
);
219 void AppendRule(nsICSSRule
* aRule
);
222 class nsAutoParseCompoundProperty
;
223 friend class nsAutoParseCompoundProperty
;
226 * This helper class automatically calls SetParsingCompoundProperty in its
227 * constructor and takes care of resetting it to false in its destructor.
229 class nsAutoParseCompoundProperty
{
231 nsAutoParseCompoundProperty(CSSParserImpl
* aParser
) : mParser(aParser
)
233 NS_ASSERTION(!aParser
->IsParsingCompoundProperty(),
234 "already parsing compound property");
235 NS_ASSERTION(aParser
, "Null parser?");
236 aParser
->SetParsingCompoundProperty(PR_TRUE
);
239 ~nsAutoParseCompoundProperty()
241 mParser
->SetParsingCompoundProperty(PR_FALSE
);
244 CSSParserImpl
* mParser
;
247 void InitScanner(nsIUnicharInputStream
* aInput
, nsIURI
* aSheetURI
,
248 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
249 nsIPrincipal
* aSheetPrincipal
);
250 // the caller must hold on to aBuffer until parsing is done
251 void InitScanner(const nsSubstring
& aString
, nsIURI
* aSheetURI
,
252 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
253 nsIPrincipal
* aSheetPrincipal
);
254 void ReleaseScanner(void);
256 PRBool
IsSVGMode() const {
257 return mScanner
.IsSVGMode();
261 PRBool
GetToken(PRBool aSkipWS
);
262 PRBool
GetURLToken();
265 void AssertInitialState() {
266 NS_PRECONDITION(!mHTMLMediaMode
, "Bad initial state");
267 NS_PRECONDITION(!mUnresolvablePrefixException
, "Bad initial state");
268 NS_PRECONDITION(!mParsingCompoundProperty
, "Bad initial state");
271 PRBool
ExpectSymbol(PRUnichar aSymbol
, PRBool aSkipWS
);
272 PRBool
ExpectEndProperty();
273 PRBool
CheckEndProperty();
274 nsSubstring
* NextIdent();
275 void SkipUntil(PRUnichar aStopSymbol
);
276 void SkipUntilOneOf(const PRUnichar
* aStopSymbolChars
);
279 PRBool
SkipDeclaration(PRBool aCheckForBraces
);
280 PRBool
GetNonCloseParenToken(PRBool aSkipWS
);
282 PRBool
PushGroup(nsICSSGroupRule
* aRule
);
285 PRBool
ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aProcessData
);
286 PRBool
ParseAtRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
287 PRBool
ParseCharsetRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
288 PRBool
ParseImportRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
289 PRBool
GatherURL(nsString
& aURL
);
290 PRBool
GatherMedia(nsMediaList
* aMedia
,
291 PRUnichar aStopSymbol
);
292 PRBool
ParseMediaQuery(PRUnichar aStopSymbol
, nsMediaQuery
**aQuery
,
293 PRBool
*aParsedSomething
, PRBool
*aHitStop
);
294 PRBool
ParseMediaQueryExpression(nsMediaQuery
* aQuery
);
295 PRBool
ProcessImport(const nsString
& aURLSpec
,
297 RuleAppendFunc aAppendFunc
,
299 PRBool
ParseGroupRule(nsICSSGroupRule
* aRule
, RuleAppendFunc aAppendFunc
,
301 PRBool
ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
302 PRBool
ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
303 PRBool
ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
304 PRBool
ProcessNameSpace(const nsString
& aPrefix
,
305 const nsString
& aURLSpec
, RuleAppendFunc aAppendFunc
,
308 PRBool
ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
309 PRBool
ParseFontDescriptor(nsCSSFontFaceRule
* aRule
);
310 PRBool
ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
313 PRBool
ParsePageRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
315 enum nsSelectorParsingStatus
{
316 // we have parsed a selector and we saw a token that cannot be
317 // part of a selector:
318 eSelectorParsingStatus_Done
,
319 // we should continue parsing the selector:
320 eSelectorParsingStatus_Continue
,
321 // same as "Done" but we did not find a selector:
322 eSelectorParsingStatus_Empty
,
323 // we saw an unexpected token or token value,
324 // or we saw end-of-file with an unfinished selector:
325 eSelectorParsingStatus_Error
327 nsSelectorParsingStatus
ParseIDSelector(PRInt32
& aDataMask
,
328 nsCSSSelector
& aSelector
);
330 nsSelectorParsingStatus
ParseClassSelector(PRInt32
& aDataMask
,
331 nsCSSSelector
& aSelector
);
333 nsSelectorParsingStatus
ParsePseudoSelector(PRInt32
& aDataMask
,
334 nsCSSSelector
& aSelector
,
337 nsSelectorParsingStatus
ParseAttributeSelector(PRInt32
& aDataMask
,
338 nsCSSSelector
& aSelector
);
340 nsSelectorParsingStatus
ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
341 nsCSSSelector
& aSelector
,
344 nsSelectorParsingStatus
ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
347 nsSelectorParsingStatus
ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
350 nsSelectorParsingStatus
ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
351 nsCSSSelector
& aSelector
);
353 nsSelectorParsingStatus
ParseSelector(nsCSSSelector
& aSelectorResult
);
355 // If aTerminateAtBrace is true, the selector list is done when we
356 // hit a '{'. Otherwise, it's done when we hit EOF.
357 PRBool
ParseSelectorList(nsCSSSelectorList
*& aListHead
,
358 PRBool aTerminateAtBrace
);
359 PRBool
ParseSelectorGroup(nsCSSSelectorList
*& aListHead
);
360 nsCSSDeclaration
* ParseDeclarationBlock(PRBool aCheckForBraces
);
361 PRBool
ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
362 PRBool aCheckForBraces
,
363 PRBool aMustCallValueAppended
,
365 // After a parse error parsing |aPropID|, clear the data in
367 void ClearTempData(nsCSSProperty aPropID
);
368 // After a successful parse of |aPropID|, transfer data from
369 // |mTempData| to |mData|. Set |*aChanged| to true if something
370 // changed, but leave it unmodified otherwise. If aMustCallValueAppended
371 // is false, will not call ValueAppended on aDeclaration if the property
372 // is already set in it.
373 void TransferTempData(nsCSSDeclaration
* aDeclaration
,
374 nsCSSProperty aPropID
, PRBool aIsImportant
,
375 PRBool aMustCallValueAppended
,
377 void DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
378 nsCSSProperty aPropID
, PRBool aIsImportant
,
379 PRBool aMustCallValueAppended
,
381 PRBool
ParseProperty(nsCSSProperty aPropID
);
382 PRBool
ParseSingleValueProperty(nsCSSValue
& aValue
,
383 nsCSSProperty aPropID
);
386 PRBool
ParseTreePseudoElement(nsCSSSelector
& aSelector
);
389 void InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
);
391 // Property specific parsing routines
392 PRBool
ParseAzimuth(nsCSSValue
& aValue
);
393 PRBool
ParseBackground();
394 PRBool
ParseBackgroundPosition();
395 PRBool
ParseBackgroundPositionValues();
396 PRBool
ParseBoxPosition(nsCSSValuePair
& aOut
);
397 PRBool
ParseBoxPositionValues(nsCSSValuePair
& aOut
);
398 PRBool
ParseBorderColor();
399 PRBool
ParseBorderColors(nsCSSValueList
** aResult
,
400 nsCSSProperty aProperty
);
401 PRBool
ParseBorderImage();
402 PRBool
ParseBorderSpacing();
403 PRBool
ParseBorderSide(const nsCSSProperty aPropIDs
[],
404 PRBool aSetAllSides
);
405 PRBool
ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
406 PRInt32 aSourceType
);
407 PRBool
ParseBorderStyle();
408 PRBool
ParseBorderWidth();
409 // for 'clip' and '-moz-image-region'
410 PRBool
ParseRect(nsCSSRect
& aRect
,
411 nsCSSProperty aPropID
);
412 PRBool
DoParseRect(nsCSSRect
& aRect
);
413 PRBool
ParseContent();
414 PRBool
ParseCounterData(nsCSSValuePairList
** aResult
,
415 nsCSSProperty aPropID
);
417 PRBool
ParseCursor();
419 PRBool
ParseFontWeight(nsCSSValue
& aValue
);
420 PRBool
ParseOneFamily(nsAString
& aValue
);
421 PRBool
ParseFamily(nsCSSValue
& aValue
);
422 PRBool
ParseFontSrc(nsCSSValue
& aValue
);
423 PRBool
ParseFontSrcFormat(nsTArray
<nsCSSValue
>& values
);
424 PRBool
ParseFontRanges(nsCSSValue
& aValue
);
425 PRBool
ParseListStyle();
426 PRBool
ParseMargin();
427 PRBool
ParseMarks(nsCSSValue
& aValue
);
428 PRBool
ParseMozTransform();
429 PRBool
ParseOutline();
430 PRBool
ParseOverflow();
431 PRBool
ParsePadding();
433 PRBool
ParseQuotes();
435 PRBool
ParseTextDecoration(nsCSSValue
& aValue
);
437 nsCSSValueList
* ParseCSSShadowList(PRBool aUsesSpread
);
438 PRBool
ParseTextShadow();
439 PRBool
ParseBoxShadow();
442 PRBool
ParsePaint(nsCSSValuePair
* aResult
,
443 nsCSSProperty aPropID
);
444 PRBool
ParseDasharray();
445 PRBool
ParseMarker();
448 // Reused utility parsing routines
449 void AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
);
450 PRBool
ParseBoxProperties(nsCSSRect
& aResult
,
451 const nsCSSProperty aPropIDs
[]);
452 PRBool
ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
453 PRInt32 aSourceType
);
454 PRBool
ParseBoxCornerRadius(const nsCSSProperty aPropID
);
455 PRBool
ParseBoxCornerRadii(nsCSSCornerSizes
& aRadii
,
456 const nsCSSProperty aPropIDs
[]);
457 PRInt32
ParseChoice(nsCSSValue aValues
[],
458 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
);
459 PRBool
ParseColor(nsCSSValue
& aValue
);
460 PRBool
ParseColorComponent(PRUint8
& aComponent
,
461 PRInt32
& aType
, char aStop
);
462 // ParseHSLColor parses everything starting with the opening '('
463 // up through and including the aStop char.
464 PRBool
ParseHSLColor(nscolor
& aColor
, char aStop
);
465 // ParseColorOpacity will enforce that the color ends with a ')'
467 PRBool
ParseColorOpacity(PRUint8
& aOpacity
);
468 PRBool
ParseEnum(nsCSSValue
& aValue
, const PRInt32 aKeywordTable
[]);
469 PRBool
ParseVariant(nsCSSValue
& aValue
,
470 PRInt32 aVariantMask
,
471 const PRInt32 aKeywordTable
[]);
472 PRBool
ParsePositiveVariant(nsCSSValue
& aValue
,
473 PRInt32 aVariantMask
,
474 const PRInt32 aKeywordTable
[]);
475 PRBool
ParseCounter(nsCSSValue
& aValue
);
476 PRBool
ParseAttr(nsCSSValue
& aValue
);
477 PRBool
ParseURL(nsCSSValue
& aValue
);
478 PRBool
TranslateDimension(nsCSSValue
& aValue
, PRInt32 aVariantMask
,
479 float aNumber
, const nsString
& aUnit
);
481 void SetParsingCompoundProperty(PRBool aBool
) {
482 NS_ASSERTION(aBool
== PR_TRUE
|| aBool
== PR_FALSE
, "bad PRBool value");
483 mParsingCompoundProperty
= aBool
;
485 PRBool
IsParsingCompoundProperty(void) const {
486 return mParsingCompoundProperty
;
489 /* Functions for -moz-transform Parsing */
490 PRBool
ReadSingleTransform(nsCSSValueList
**& aTail
);
491 PRBool
ParseFunction(const nsString
&aFunction
, const PRInt32 aAllowedTypes
[],
492 PRUint16 aMinElems
, PRUint16 aMaxElems
,
494 PRBool
ParseFunctionInternals(const PRInt32 aVariantMask
[],
497 nsTArray
<nsCSSValue
>& aOutput
);
499 /* Functions for -moz-transform-origin Parsing */
500 PRBool
ParseMozTransformOrigin();
503 /* Find and return the correct namespace ID for the prefix aPrefix.
504 If the prefix cannot be resolved to a namespace, this method will
505 return false. Otherwise it will return true. When returning
506 false, it may set the low-level error code, depending on the
507 value of mUnresolvablePrefixException.
509 This method never returns kNameSpaceID_Unknown or
510 kNameSpaceID_None for aNameSpaceID while returning true.
512 PRBool
GetNamespaceIdForPrefix(const nsString
& aPrefix
,
513 PRInt32
* aNameSpaceID
);
515 /* Find the correct default namespace, and set it on aSelector. */
516 void SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
);
518 // Current token. The value is valid after calling GetToken and invalidated
523 nsCSSScanner mScanner
;
525 // The URI to be used as a base for relative URIs.
526 nsCOMPtr
<nsIURI
> mBaseURL
;
528 // The URI to be used as an HTTP "Referer" and for error reporting.
529 nsCOMPtr
<nsIURI
> mSheetURL
;
531 // The principal of the sheet involved
532 nsCOMPtr
<nsIPrincipal
> mSheetPrincipal
;
534 // The sheet we're parsing into
535 nsCOMPtr
<nsICSSStyleSheet
> mSheet
;
537 // Used for @import rules
538 nsICSSLoader
* mChildLoader
; // not ref counted, it owns us
540 // Sheet section we're in. This is used to enforce correct ordering of the
541 // various rule types (eg the fact that a @charset rule must come before
542 // anything else). Note that there are checks of similar things in various
543 // places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
547 eCSSSection_NameSpace
,
550 nsCSSSection mSection
;
552 nsXMLNameSpaceMap
*mNameSpaceMap
; // weak, mSheet owns it
554 // After an UngetToken is done this flag is true. The next call to
555 // GetToken clears the flag.
556 PRPackedBool mHavePushBack
: 1;
558 // True if we are in quirks mode; false in standards or almost standards mode
559 PRPackedBool mNavQuirkMode
: 1;
561 // True if unsafe rules should be allowed
562 PRPackedBool mUnsafeRulesEnabled
: 1;
564 // True for parsing media lists for HTML attributes, where we have to
565 // ignore CSS comments.
566 PRPackedBool mHTMLMediaMode
: 1;
568 // True if tagnames and attributes are case-sensitive
569 PRPackedBool mCaseSensitive
: 1;
571 // This flag is set when parsing a non-box shorthand; it's used to not apply
572 // some quirks during shorthand parsing
573 PRPackedBool mParsingCompoundProperty
: 1;
575 // If this flag is true, failure to resolve a namespace prefix
576 // should set the low-level error to NS_ERROR_DOM_NAMESPACE_ERR
577 PRPackedBool mUnresolvablePrefixException
: 1;
579 // Stack of rule groups; used for @media and such.
580 nsCOMArray
<nsICSSGroupRule
> mGroupStack
;
582 // During the parsing of a property (which may be a shorthand), the data
583 // are stored in |mTempData|. (It is needed to ensure that parser
584 // errors cause the data to be ignored, and to ensure that a
585 // non-'!important' declaration does not override an '!important'
587 nsCSSExpandedDataBlock mTempData
;
589 // All data from successfully parsed properties are placed into |mData|.
590 nsCSSExpandedDataBlock mData
;
593 PRPackedBool mScannerInited
;
597 static void AppendRuleToArray(nsICSSRule
* aRule
, void* aArray
)
599 static_cast<nsCOMArray
<nsICSSRule
>*>(aArray
)->AppendObject(aRule
);
602 static void AppendRuleToSheet(nsICSSRule
* aRule
, void* aParser
)
604 CSSParserImpl
* parser
= (CSSParserImpl
*) aParser
;
605 parser
->AppendRule(aRule
);
609 NS_NewCSSParser(nsICSSParser
** aInstancePtrResult
)
611 CSSParserImpl
*it
= new CSSParserImpl();
614 return NS_ERROR_OUT_OF_MEMORY
;
617 return it
->QueryInterface(NS_GET_IID(nsICSSParser
), (void **) aInstancePtrResult
);
620 #ifdef CSS_REPORT_PARSE_ERRORS
622 #define REPORT_UNEXPECTED(msg_) \
623 mScanner.ReportUnexpected(#msg_)
625 #define REPORT_UNEXPECTED_P(msg_, params_) \
626 mScanner.ReportUnexpectedParams(#msg_, params_, NS_ARRAY_LENGTH(params_))
628 #define REPORT_UNEXPECTED_EOF(lf_) \
629 mScanner.ReportUnexpectedEOF(#lf_)
631 #define REPORT_UNEXPECTED_EOF_CHAR(ch_) \
632 mScanner.ReportUnexpectedEOF(ch_)
634 #define REPORT_UNEXPECTED_TOKEN(msg_) \
635 mScanner.ReportUnexpectedToken(mToken, #msg_)
637 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_) \
638 mScanner.ReportUnexpectedTokenParams(mToken, #msg_, \
639 params_, NS_ARRAY_LENGTH(params_))
642 #define OUTPUT_ERROR() \
643 mScanner.OutputError()
645 #define CLEAR_ERROR() \
646 mScanner.ClearError()
650 #define REPORT_UNEXPECTED(msg_)
651 #define REPORT_UNEXPECTED_P(msg_, params_)
652 #define REPORT_UNEXPECTED_EOF(lf_)
653 #define REPORT_UNEXPECTED_EOF_CHAR(ch_)
654 #define REPORT_UNEXPECTED_TOKEN(msg_)
655 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_)
656 #define OUTPUT_ERROR()
657 #define CLEAR_ERROR()
661 CSSParserImpl::CSSParserImpl()
664 mChildLoader(nsnull
),
665 mSection(eCSSSection_Charset
),
666 mNameSpaceMap(nsnull
),
667 mHavePushBack(PR_FALSE
),
668 mNavQuirkMode(PR_FALSE
),
669 mUnsafeRulesEnabled(PR_FALSE
),
670 mHTMLMediaMode(PR_FALSE
),
671 mCaseSensitive(PR_FALSE
),
672 mParsingCompoundProperty(PR_FALSE
),
673 mUnresolvablePrefixException(PR_FALSE
)
675 , mScannerInited(PR_FALSE
)
680 NS_IMPL_ISUPPORTS1(CSSParserImpl
, nsICSSParser
)
682 CSSParserImpl::~CSSParserImpl()
684 mData
.AssertInitialState();
685 mTempData
.AssertInitialState();
689 CSSParserImpl::SetStyleSheet(nsICSSStyleSheet
* aSheet
)
691 if (aSheet
!= mSheet
) {
692 // Switch to using the new sheet, if any
696 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
698 mNameSpaceMap
= nsnull
;
706 CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive
)
708 NS_ASSERTION(aCaseSensitive
== PR_TRUE
|| aCaseSensitive
== PR_FALSE
, "bad PRBool value");
709 mCaseSensitive
= aCaseSensitive
;
714 CSSParserImpl::SetQuirkMode(PRBool aQuirkMode
)
716 NS_ASSERTION(aQuirkMode
== PR_TRUE
|| aQuirkMode
== PR_FALSE
, "bad PRBool value");
717 mNavQuirkMode
= aQuirkMode
;
723 CSSParserImpl::SetSVGMode(PRBool aSVGMode
)
725 NS_ASSERTION(aSVGMode
== PR_TRUE
|| aSVGMode
== PR_FALSE
,
727 mScanner
.SetSVGMode(aSVGMode
);
733 CSSParserImpl::SetChildLoader(nsICSSLoader
* aChildLoader
)
735 mChildLoader
= aChildLoader
; // not ref counted, it owns us
740 CSSParserImpl::InitScanner(nsIUnicharInputStream
* aInput
, nsIURI
* aSheetURI
,
741 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
742 nsIPrincipal
* aSheetPrincipal
)
744 NS_ASSERTION(! mScannerInited
, "already have scanner");
746 mScanner
.Init(aInput
, nsnull
, 0, aSheetURI
, aLineNumber
);
748 mScannerInited
= PR_TRUE
;
751 mSheetURL
= aSheetURI
;
752 mSheetPrincipal
= aSheetPrincipal
;
754 mHavePushBack
= PR_FALSE
;
758 CSSParserImpl::InitScanner(const nsSubstring
& aString
, nsIURI
* aSheetURI
,
759 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
760 nsIPrincipal
* aSheetPrincipal
)
762 // Having it not own the string is OK since the caller will hold on to
763 // the stream until we're done parsing.
764 NS_ASSERTION(! mScannerInited
, "already have scanner");
766 mScanner
.Init(nsnull
, aString
.BeginReading(), aString
.Length(), aSheetURI
, aLineNumber
);
769 mScannerInited
= PR_TRUE
;
772 mSheetURL
= aSheetURI
;
773 mSheetPrincipal
= aSheetPrincipal
;
775 mHavePushBack
= PR_FALSE
;
779 CSSParserImpl::ReleaseScanner(void)
783 mScannerInited
= PR_FALSE
;
787 mSheetPrincipal
= nsnull
;
792 CSSParserImpl::Parse(nsIUnicharInputStream
* aInput
,
795 nsIPrincipal
* aSheetPrincipal
,
796 PRUint32 aLineNumber
,
797 PRBool aAllowUnsafeRules
)
799 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
801 NS_ASSERTION(nsnull
!= aBaseURI
, "need base URL");
802 NS_ASSERTION(nsnull
!= aSheetURI
, "need sheet URL");
803 AssertInitialState();
805 NS_PRECONDITION(mSheet
, "Must have sheet to parse into");
806 NS_ENSURE_STATE(mSheet
);
809 nsCOMPtr
<nsIURI
> uri
;
810 mSheet
->GetSheetURI(getter_AddRefs(uri
));
812 NS_ASSERTION(NS_SUCCEEDED(aSheetURI
->Equals(uri
, &equal
)) && equal
,
813 "Sheet URI does not match passed URI");
814 NS_ASSERTION(NS_SUCCEEDED(mSheet
->Principal()->Equals(aSheetPrincipal
,
817 "Sheet principal does not match passed principal");
820 InitScanner(aInput
, aSheetURI
, aLineNumber
, aBaseURI
, aSheetPrincipal
);
822 PRInt32 ruleCount
= 0;
823 mSheet
->StyleRuleCount(ruleCount
);
825 nsICSSRule
* lastRule
= nsnull
;
826 mSheet
->GetStyleRuleAt(ruleCount
- 1, lastRule
);
829 lastRule
->GetType(type
);
831 case nsICSSRule::CHARSET_RULE
:
832 case nsICSSRule::IMPORT_RULE
:
833 mSection
= eCSSSection_Import
;
835 case nsICSSRule::NAMESPACE_RULE
:
836 mSection
= eCSSSection_NameSpace
;
839 mSection
= eCSSSection_General
;
842 NS_RELEASE(lastRule
);
846 mSection
= eCSSSection_Charset
; // sheet is empty, any rules are fair
849 mUnsafeRulesEnabled
= aAllowUnsafeRules
;
851 nsCSSToken
* tk
= &mToken
;
853 // Get next non-whitespace token
854 if (!GetToken(PR_TRUE
)) {
858 if (eCSSToken_HTMLComment
== tk
->mType
) {
859 continue; // legal here only
861 if (eCSSToken_AtKeyword
== tk
->mType
) {
862 ParseAtRule(AppendRuleToSheet
, this);
866 if (ParseRuleSet(AppendRuleToSheet
, this)) {
867 mSection
= eCSSSection_General
;
872 mUnsafeRulesEnabled
= PR_FALSE
;
874 // XXX check for low level errors
879 * Determines whether the identifier contained in the given string is a
880 * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1.
883 NonMozillaVendorIdentifier(const nsAString
& ident
)
885 return (ident
.First() == PRUnichar('-') &&
886 !StringBeginsWith(ident
, NS_LITERAL_STRING("-moz-"))) ||
887 ident
.First() == PRUnichar('_');
892 CSSParserImpl::ParseStyleAttribute(const nsAString
& aAttributeValue
,
895 nsIPrincipal
* aNodePrincipal
,
896 nsICSSStyleRule
** aResult
)
898 NS_PRECONDITION(aNodePrincipal
, "Must have principal here!");
899 AssertInitialState();
901 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
904 InitScanner(aAttributeValue
, aDocURL
, 0, aBaseURL
, aNodePrincipal
);
906 mSection
= eCSSSection_General
;
908 // In quirks mode, allow style declarations to have braces or not
911 if (mNavQuirkMode
&& GetToken(PR_TRUE
)) {
912 haveBraces
= eCSSToken_Symbol
== mToken
.mType
&&
913 '{' == mToken
.mSymbol
;
917 haveBraces
= PR_FALSE
;
920 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(haveBraces
);
922 // Create a style rule for the declaration
923 nsICSSStyleRule
* rule
= nsnull
;
924 nsresult rv
= NS_NewCSSStyleRule(&rule
, nsnull
, declaration
);
926 declaration
->RuleAbort();
938 // XXX check for low level errors
943 CSSParserImpl::ParseAndAppendDeclaration(const nsAString
& aBuffer
,
946 nsIPrincipal
* aSheetPrincipal
,
947 nsCSSDeclaration
* aDeclaration
,
948 PRBool aParseOnlyOneDecl
,
950 PRBool aClearOldDecl
)
952 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
953 AssertInitialState();
955 *aChanged
= PR_FALSE
;
957 InitScanner(aBuffer
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
959 mSection
= eCSSSection_General
;
962 mData
.AssertInitialState();
963 aDeclaration
->ClearData();
964 // We could check if it was already empty, but...
967 aDeclaration
->ExpandTo(&mData
);
972 // If we cleared the old decl, then we want to be calling
973 // ValueAppended as we parse.
974 if (!ParseDeclaration(aDeclaration
, PR_FALSE
, aClearOldDecl
, aChanged
)) {
975 rv
= mScanner
.GetLowLevelError();
979 if (!SkipDeclaration(PR_FALSE
)) {
980 rv
= mScanner
.GetLowLevelError();
984 } while (!aParseOnlyOneDecl
);
985 aDeclaration
->CompressFrom(&mData
);
992 CSSParserImpl::ParseRule(const nsAString
& aRule
,
995 nsIPrincipal
* aSheetPrincipal
,
996 nsCOMArray
<nsICSSRule
>& aResult
)
998 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
999 AssertInitialState();
1001 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1003 InitScanner(aRule
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1005 mSection
= eCSSSection_Charset
; // callers are responsible for rejecting invalid rules.
1007 nsCSSToken
* tk
= &mToken
;
1008 // Get first non-whitespace token
1009 if (!GetToken(PR_TRUE
)) {
1010 REPORT_UNEXPECTED(PEParseRuleWSOnly
);
1012 } else if (eCSSToken_AtKeyword
== tk
->mType
) {
1013 ParseAtRule(AppendRuleToArray
, &aResult
);
1017 ParseRuleSet(AppendRuleToArray
, &aResult
);
1021 // XXX check for low-level errors
1026 CSSParserImpl::ParseProperty(const nsCSSProperty aPropID
,
1027 const nsAString
& aPropValue
,
1030 nsIPrincipal
* aSheetPrincipal
,
1031 nsCSSDeclaration
* aDeclaration
,
1034 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1035 AssertInitialState();
1037 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1038 NS_ASSERTION(nsnull
!= aDeclaration
, "Need declaration to parse into!");
1039 *aChanged
= PR_FALSE
;
1041 InitScanner(aPropValue
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1043 mSection
= eCSSSection_General
;
1045 if (eCSSProperty_UNKNOWN
== aPropID
) { // unknown property
1046 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1047 const PRUnichar
*params
[] = {
1050 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
1051 REPORT_UNEXPECTED(PEDeclDropped
);
1057 mData
.AssertInitialState();
1058 mTempData
.AssertInitialState();
1059 aDeclaration
->ExpandTo(&mData
);
1060 nsresult result
= NS_OK
;
1061 PRBool parsedOK
= ParseProperty(aPropID
);
1062 if (parsedOK
&& !GetToken(PR_TRUE
)) {
1063 TransferTempData(aDeclaration
, aPropID
, PR_FALSE
, PR_FALSE
, aChanged
);
1066 // Junk at end of property value.
1067 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
1069 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1070 const PRUnichar
*params
[] = {
1073 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
1074 REPORT_UNEXPECTED(PEDeclDropped
);
1076 ClearTempData(aPropID
);
1077 result
= mScanner
.GetLowLevelError();
1081 aDeclaration
->CompressFrom(&mData
);
1088 CSSParserImpl::ParseMediaList(const nsSubstring
& aBuffer
,
1089 nsIURI
* aURL
, // for error reporting
1090 PRUint32 aLineNumber
, // for error reporting
1091 nsMediaList
* aMediaList
,
1094 // XXX Are there cases where the caller wants to keep what it already
1095 // has in case of parser error?
1096 aMediaList
->Clear();
1098 // fake base URL since media lists don't have URLs in them
1099 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1101 AssertInitialState();
1102 NS_ASSERTION(aHTMLMode
== PR_TRUE
|| aHTMLMode
== PR_FALSE
,
1104 mHTMLMediaMode
= aHTMLMode
;
1106 // XXXldb We need to make the scanner not skip CSS comments! (Or
1109 // For aHTMLMode, we used to follow the parsing rules in
1110 // http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors
1111 // which wouldn't work for media queries since they remove all but the
1112 // first word. However, they're changed in
1113 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2
1114 // (as of 2008-05-29) which says that the media attribute just points
1115 // to a media query. (The main substative difference is the relative
1116 // precedence of commas and paretheses.)
1118 if (!GatherMedia(aMediaList
, PRUnichar(0))) {
1119 aMediaList
->Clear();
1120 aMediaList
->SetNonEmpty(); // don't match anything
1121 if (!mHTMLMediaMode
) {
1125 nsresult rv
= mScanner
.GetLowLevelError();
1128 mHTMLMediaMode
= PR_FALSE
;
1134 CSSParserImpl::ParseColorString(const nsSubstring
& aBuffer
,
1135 nsIURI
* aURL
, // for error reporting
1136 PRUint32 aLineNumber
, // for error reporting
1139 AssertInitialState();
1140 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1143 PRBool colorParsed
= ParseColor(value
);
1144 nsresult rv
= mScanner
.GetLowLevelError();
1149 return NS_FAILED(rv
) ? rv
: NS_ERROR_FAILURE
;
1152 if (value
.GetUnit() == eCSSUnit_String
) {
1154 if (NS_ColorNameToRGB(nsDependentString(value
.GetStringBufferValue()), &rgba
)) {
1158 } else if (value
.GetUnit() == eCSSUnit_Color
) {
1159 (*aColor
) = value
.GetColorValue();
1161 } else if (value
.GetUnit() == eCSSUnit_EnumColor
) {
1162 PRInt32 intValue
= value
.GetIntValue();
1163 if (intValue
>= 0) {
1164 nsCOMPtr
<nsILookAndFeel
> lfSvc
= do_GetService("@mozilla.org/widget/lookandfeel;1");
1167 rv
= lfSvc
->GetColor((nsILookAndFeel::nsColorID
) value
.GetIntValue(), rgba
);
1168 if (NS_SUCCEEDED(rv
))
1172 // XXX - this is NS_COLOR_CURRENTCOLOR, NS_COLOR_MOZ_HYPERLINKTEXT, etc.
1173 // which we don't handle as per the ParseColorString definition. Should
1174 // remove this limitation at some point.
1175 rv
= NS_ERROR_FAILURE
;
1183 CSSParserImpl::ParseSelectorString(const nsSubstring
& aSelectorString
,
1184 nsIURI
* aURL
, // for error reporting
1185 PRUint32 aLineNumber
, // for error reporting
1186 nsCSSSelectorList
**aSelectorList
)
1188 InitScanner(aSelectorString
, aURL
, aLineNumber
, aURL
, nsnull
);
1190 AssertInitialState();
1192 mUnresolvablePrefixException
= PR_TRUE
;
1194 PRBool success
= ParseSelectorList(*aSelectorList
, PR_FALSE
);
1195 nsresult rv
= mScanner
.GetLowLevelError();
1199 mUnresolvablePrefixException
= PR_FALSE
;
1202 NS_ASSERTION(*aSelectorList
, "Should have list!");
1206 NS_ASSERTION(!*aSelectorList
, "Shouldn't have list!");
1207 if (NS_SUCCEEDED(rv
)) {
1208 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
1213 //----------------------------------------------------------------------
1216 CSSParserImpl::GetToken(PRBool aSkipWS
)
1219 if (!mHavePushBack
) {
1220 if (!mScanner
.Next(mToken
)) {
1224 mHavePushBack
= PR_FALSE
;
1225 if (aSkipWS
&& (eCSSToken_WhiteSpace
== mToken
.mType
)) {
1234 CSSParserImpl::GetURLToken()
1237 // XXXldb This pushback code doesn't make sense.
1238 if (! mHavePushBack
) {
1239 if (! mScanner
.NextURL(mToken
)) {
1243 mHavePushBack
= PR_FALSE
;
1244 if (eCSSToken_WhiteSpace
!= mToken
.mType
) {
1252 CSSParserImpl::UngetToken()
1254 NS_PRECONDITION(mHavePushBack
== PR_FALSE
, "double pushback");
1255 mHavePushBack
= PR_TRUE
;
1259 CSSParserImpl::ExpectSymbol(PRUnichar aSymbol
,
1262 if (!GetToken(aSkipWS
)) {
1263 // CSS2.1 specifies that all "open constructs" are to be closed at
1264 // EOF. It simplifies higher layers if we claim to have found an
1265 // ), ], }, or ; if we encounter EOF while looking for one of them.
1266 // Do still issue a diagnostic, to aid debugging.
1267 if (aSymbol
== ')' || aSymbol
== ']' ||
1268 aSymbol
== '}' || aSymbol
== ';') {
1269 REPORT_UNEXPECTED_EOF_CHAR(aSymbol
);
1275 if (mToken
.IsSymbol(aSymbol
)) {
1282 // Checks to see if we're at the end of a property. If an error occurs during
1283 // the check, does not signal a parse error.
1285 CSSParserImpl::CheckEndProperty()
1287 if (!GetToken(PR_TRUE
)) {
1288 return PR_TRUE
; // properties may end with eof
1290 if ((eCSSToken_Symbol
== mToken
.mType
) &&
1291 ((';' == mToken
.mSymbol
) ||
1292 ('!' == mToken
.mSymbol
) ||
1293 ('}' == mToken
.mSymbol
))) {
1294 // XXX need to verify that ! is only followed by "important [;|}]
1295 // XXX this requires a multi-token pushback buffer
1303 // Checks if we're at the end of a property, raising an error if we're not.
1305 CSSParserImpl::ExpectEndProperty()
1307 if (CheckEndProperty())
1310 // If we're here, we read something incorrect, so we should report it.
1311 REPORT_UNEXPECTED_TOKEN(PRExpectEndValue
);
1317 CSSParserImpl::NextIdent()
1319 // XXX Error reporting?
1320 if (!GetToken(PR_TRUE
)) {
1323 if (eCSSToken_Ident
!= mToken
.mType
) {
1327 return &mToken
.mIdent
;
1331 CSSParserImpl::SkipAtRule()
1334 if (!GetToken(PR_TRUE
)) {
1335 REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF
);
1338 if (eCSSToken_Symbol
== mToken
.mType
) {
1339 PRUnichar symbol
= mToken
.mSymbol
;
1340 if (symbol
== ';') {
1343 if (symbol
== '{') {
1346 } else if (symbol
== '(') {
1348 } else if (symbol
== '[') {
1357 CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc
,
1360 if ((mSection
<= eCSSSection_Charset
) &&
1361 (mToken
.mIdent
.LowerCaseEqualsLiteral("charset"))) {
1362 if (ParseCharsetRule(aAppendFunc
, aData
)) {
1363 mSection
= eCSSSection_Import
; // only one charset allowed
1367 if ((mSection
<= eCSSSection_Import
) &&
1368 mToken
.mIdent
.LowerCaseEqualsLiteral("import")) {
1369 if (ParseImportRule(aAppendFunc
, aData
)) {
1370 mSection
= eCSSSection_Import
;
1374 if ((mSection
<= eCSSSection_NameSpace
) &&
1375 mToken
.mIdent
.LowerCaseEqualsLiteral("namespace")) {
1376 if (ParseNameSpaceRule(aAppendFunc
, aData
)) {
1377 mSection
= eCSSSection_NameSpace
;
1381 if (mToken
.mIdent
.LowerCaseEqualsLiteral("media")) {
1382 if (ParseMediaRule(aAppendFunc
, aData
)) {
1383 mSection
= eCSSSection_General
;
1387 if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-document")) {
1388 if (ParseMozDocumentRule(aAppendFunc
, aData
)) {
1389 mSection
= eCSSSection_General
;
1393 if (mToken
.mIdent
.LowerCaseEqualsLiteral("font-face")) {
1394 if (ParseFontFaceRule(aAppendFunc
, aData
)) {
1395 mSection
= eCSSSection_General
;
1399 if (mToken
.mIdent
.LowerCaseEqualsLiteral("page")) {
1400 if (ParsePageRule(aAppendFunc
, aData
)) {
1401 mSection
= eCSSSection_General
;
1406 if (!NonMozillaVendorIdentifier(mToken
.mIdent
)) {
1407 REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule
);
1411 // Skip over unsupported at rule, don't advance section
1412 return SkipAtRule();
1416 CSSParserImpl::ParseCharsetRule(RuleAppendFunc aAppendFunc
,
1419 if (!GetToken(PR_TRUE
)) {
1420 REPORT_UNEXPECTED_EOF(PECharsetRuleEOF
);
1424 if (eCSSToken_String
!= mToken
.mType
) {
1425 REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString
);
1429 nsAutoString charset
= mToken
.mIdent
;
1431 if (!ExpectSymbol(';', PR_TRUE
)) {
1435 nsCOMPtr
<nsICSSRule
> rule
;
1436 NS_NewCSSCharsetRule(getter_AddRefs(rule
), charset
);
1439 (*aAppendFunc
)(rule
, aData
);
1446 CSSParserImpl::GatherURL(nsString
& aURL
)
1448 if (!GetToken(PR_TRUE
)) {
1451 if (eCSSToken_String
== mToken
.mType
) {
1452 aURL
= mToken
.mIdent
;
1455 else if (eCSSToken_Function
== mToken
.mType
&&
1456 mToken
.mIdent
.LowerCaseEqualsLiteral("url") &&
1457 ExpectSymbol('(', PR_FALSE
) &&
1459 (eCSSToken_String
== mToken
.mType
||
1460 eCSSToken_URL
== mToken
.mType
)) {
1461 aURL
= mToken
.mIdent
;
1462 if (ExpectSymbol(')', PR_TRUE
)) {
1470 CSSParserImpl::ParseMediaQuery(PRUnichar aStopSymbol
,
1471 nsMediaQuery
**aQuery
,
1472 PRBool
*aParsedSomething
,
1476 *aParsedSomething
= PR_FALSE
;
1477 *aHitStop
= PR_FALSE
;
1479 // "If the comma-separated list is the empty list it is assumed to
1480 // specify the media query 'all'." (css3-mediaqueries, section
1482 if (!GetToken(PR_TRUE
)) {
1483 *aHitStop
= PR_TRUE
;
1484 // expected termination by EOF
1485 if (aStopSymbol
== PRUnichar(0))
1488 // unexpected termination by EOF
1489 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1493 if (eCSSToken_Symbol
== mToken
.mType
&&
1494 mToken
.mSymbol
== aStopSymbol
) {
1495 *aHitStop
= PR_TRUE
;
1501 *aParsedSomething
= PR_TRUE
;
1503 nsAutoPtr
<nsMediaQuery
> query(new nsMediaQuery
);
1505 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1509 if (ExpectSymbol('(', PR_TRUE
)) {
1510 // we got an expression without a media type
1511 UngetToken(); // so ParseMediaQueryExpression can handle it
1512 query
->SetType(nsGkAtoms::all
);
1513 query
->SetTypeOmitted();
1514 // Just parse the first expression here.
1515 if (!ParseMediaQueryExpression(query
)) {
1517 query
->SetHadUnknownExpression();
1520 nsCOMPtr
<nsIAtom
> mediaType
;
1521 PRBool gotNotOrOnly
= PR_FALSE
;
1523 if (!GetToken(PR_TRUE
)) {
1524 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1527 if (eCSSToken_Ident
!= mToken
.mType
) {
1528 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent
);
1532 // case insensitive from CSS - must be lower cased
1533 ToLowerCase(mToken
.mIdent
);
1534 mediaType
= do_GetAtom(mToken
.mIdent
);
1536 (mediaType
!= nsGkAtoms::_not
&& mediaType
!= nsGkAtoms::only
))
1538 gotNotOrOnly
= PR_TRUE
;
1539 if (mediaType
== nsGkAtoms::_not
)
1540 query
->SetNegated();
1542 query
->SetHasOnly();
1544 query
->SetType(mediaType
);
1548 if (!GetToken(PR_TRUE
)) {
1549 *aHitStop
= PR_TRUE
;
1550 // expected termination by EOF
1551 if (aStopSymbol
== PRUnichar(0))
1554 // unexpected termination by EOF
1555 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1559 if (eCSSToken_Symbol
== mToken
.mType
&&
1560 mToken
.mSymbol
== aStopSymbol
) {
1561 *aHitStop
= PR_TRUE
;
1565 if (eCSSToken_Symbol
== mToken
.mType
&& mToken
.mSymbol
== ',') {
1566 // Done with the expressions for this query
1569 if (eCSSToken_Ident
!= mToken
.mType
||
1570 !mToken
.mIdent
.LowerCaseEqualsLiteral("and")) {
1571 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma
);
1575 if (!ParseMediaQueryExpression(query
)) {
1577 query
->SetHadUnknownExpression();
1580 *aQuery
= query
.forget();
1584 // Returns false only when there is a low-level error in the scanner
1587 CSSParserImpl::GatherMedia(nsMediaList
* aMedia
,
1588 PRUnichar aStopSymbol
)
1591 nsAutoPtr
<nsMediaQuery
> query
;
1592 PRBool parsedSomething
, hitStop
;
1593 if (!ParseMediaQuery(aStopSymbol
, getter_Transfers(query
),
1594 &parsedSomething
, &hitStop
)) {
1595 NS_ASSERTION(!hitStop
, "should return true when hit stop");
1596 if (NS_FAILED(mScanner
.GetLowLevelError())) {
1599 const PRUnichar stopChars
[] =
1600 { PRUnichar(','), aStopSymbol
/* may be null */, PRUnichar(0) };
1601 SkipUntilOneOf(stopChars
);
1602 // Rely on SkipUntilOneOf leaving mToken around as the last token read.
1603 if (mToken
.mType
== eCSSToken_Symbol
&& mToken
.mSymbol
== aStopSymbol
) {
1608 if (parsedSomething
) {
1609 aMedia
->SetNonEmpty();
1612 nsresult rv
= aMedia
->AppendQuery(query
);
1613 if (NS_FAILED(rv
)) {
1614 mScanner
.SetLowLevelError(rv
);
1626 CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery
* aQuery
)
1628 if (!ExpectSymbol('(', PR_TRUE
)) {
1629 REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart
);
1632 if (! GetToken(PR_TRUE
)) {
1633 REPORT_UNEXPECTED_EOF(PEMQExpressionEOF
);
1636 if (eCSSToken_Ident
!= mToken
.mType
) {
1637 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1642 nsMediaExpression
*expr
= aQuery
->NewExpression();
1644 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1649 // case insensitive from CSS - must be lower cased
1650 ToLowerCase(mToken
.mIdent
);
1651 const PRUnichar
*featureString
;
1652 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("min-"))) {
1653 expr
->mRange
= nsMediaExpression::eMin
;
1654 featureString
= mToken
.mIdent
.get() + 4;
1655 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("max-"))) {
1656 expr
->mRange
= nsMediaExpression::eMax
;
1657 featureString
= mToken
.mIdent
.get() + 4;
1659 expr
->mRange
= nsMediaExpression::eEqual
;
1660 featureString
= mToken
.mIdent
.get();
1663 nsCOMPtr
<nsIAtom
> mediaFeatureAtom
= do_GetAtom(featureString
);
1664 const nsMediaFeature
*feature
= nsMediaFeatures::features
;
1665 for (; feature
->mName
; ++feature
) {
1666 if (*(feature
->mName
) == mediaFeatureAtom
) {
1670 if (!feature
->mName
||
1671 (expr
->mRange
!= nsMediaExpression::eEqual
&&
1672 feature
->mRangeType
!= nsMediaFeature::eMinMaxAllowed
)) {
1673 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1677 expr
->mFeature
= feature
;
1679 if (!GetToken(PR_TRUE
) || mToken
.IsSymbol(')')) {
1680 // Query expressions for any feature can be given without a value.
1681 // However, min/max prefixes are not allowed.
1682 if (expr
->mRange
!= nsMediaExpression::eEqual
) {
1683 REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue
);
1686 expr
->mValue
.Reset();
1690 if (!mToken
.IsSymbol(':')) {
1691 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd
);
1697 switch (feature
->mValueType
) {
1698 case nsMediaFeature::eLength
:
1699 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_LENGTH
, nsnull
);
1701 case nsMediaFeature::eInteger
:
1702 case nsMediaFeature::eBoolInteger
:
1703 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_INTEGER
, nsnull
);
1704 // Enforce extra restrictions for eBoolInteger
1706 feature
->mValueType
== nsMediaFeature::eBoolInteger
&&
1707 expr
->mValue
.GetIntValue() > 1)
1710 case nsMediaFeature::eIntRatio
:
1712 // Two integers separated by '/', with optional whitespace on
1713 // either side of the '/'.
1714 nsRefPtr
<nsCSSValue::Array
> a
= nsCSSValue::Array::Create(2);
1716 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1720 expr
->mValue
.SetArrayValue(a
, eCSSUnit_Array
);
1721 // We don't bother with ParsePositiveVariant since we have to
1722 // check for != 0 as well; no need to worry about the UngetToken
1723 // since we're throwing out up to the next ')' anyway.
1724 rv
= ParseVariant(a
->Item(0), VARIANT_INTEGER
, nsnull
) &&
1725 a
->Item(0).GetIntValue() > 0 &&
1726 ExpectSymbol('/', PR_TRUE
) &&
1727 ParseVariant(a
->Item(1), VARIANT_INTEGER
, nsnull
) &&
1728 a
->Item(1).GetIntValue() > 0;
1731 case nsMediaFeature::eResolution
:
1732 rv
= GetToken(PR_TRUE
) && mToken
.IsDimension() &&
1733 mToken
.mIntegerValid
&& mToken
.mNumber
> 0.0f
;
1735 // No worries about whether unitless zero is allowed, since the
1736 // value must be positive (and we checked that above).
1737 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(), "IsDimension lied");
1738 if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpi")) {
1739 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Inch
);
1740 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpcm")) {
1741 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Centimeter
);
1747 case nsMediaFeature::eEnumerated
:
1748 rv
= ParseVariant(expr
->mValue
, VARIANT_KEYWORD
,
1749 feature
->mKeywordTable
);
1752 if (!rv
|| !ExpectSymbol(')', PR_TRUE
)) {
1753 REPORT_UNEXPECTED(PEMQExpectedFeatureValue
);
1761 // Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"
1763 CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc
, void* aData
)
1765 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1767 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1772 if (!GatherURL(url
)) {
1773 REPORT_UNEXPECTED_TOKEN(PEImportNotURI
);
1777 if (!ExpectSymbol(';', PR_TRUE
)) {
1778 if (!GatherMedia(media
, ';') ||
1779 !ExpectSymbol(';', PR_TRUE
)) {
1780 REPORT_UNEXPECTED_TOKEN(PEImportUnexpected
);
1781 // don't advance section, simply ignore invalid @import
1785 // Safe to assert this, since we ensured that there is something
1786 // other than the ';' coming after the @import's url() token.
1787 NS_ASSERTION(media
->Count() != 0, "media list must be nonempty");
1790 ProcessImport(url
, media
, aAppendFunc
, aData
);
1796 CSSParserImpl::ProcessImport(const nsString
& aURLSpec
,
1797 nsMediaList
* aMedia
,
1798 RuleAppendFunc aAppendFunc
,
1801 nsCOMPtr
<nsICSSImportRule
> rule
;
1802 nsresult rv
= NS_NewCSSImportRule(getter_AddRefs(rule
), aURLSpec
, aMedia
);
1803 if (NS_FAILED(rv
)) {
1804 mScanner
.SetLowLevelError(rv
);
1807 (*aAppendFunc
)(rule
, aData
);
1810 nsCOMPtr
<nsIURI
> url
;
1811 // XXX should pass a charset!
1812 rv
= NS_NewURI(getter_AddRefs(url
), aURLSpec
, nsnull
, mBaseURL
);
1814 if (NS_FAILED(rv
)) {
1815 // import url is bad
1816 // XXX log this somewhere for easier web page debugging
1817 mScanner
.SetLowLevelError(rv
);
1821 mChildLoader
->LoadChildSheet(mSheet
, url
, aMedia
, rule
);
1827 // Parse the {} part of an @media or @-moz-document rule.
1829 CSSParserImpl::ParseGroupRule(nsICSSGroupRule
* aRule
,
1830 RuleAppendFunc aAppendFunc
,
1833 // XXXbz this could use better error reporting throughout the method
1834 if (!ExpectSymbol('{', PR_TRUE
)) {
1838 // push rule on stack, loop over children
1839 if (!PushGroup(aRule
)) {
1840 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1843 nsCSSSection holdSection
= mSection
;
1844 mSection
= eCSSSection_General
;
1847 // Get next non-whitespace token
1848 if (! GetToken(PR_TRUE
)) {
1849 REPORT_UNEXPECTED_EOF(PEGroupRuleEOF
);
1852 if (mToken
.IsSymbol('}')) { // done!
1856 if (eCSSToken_AtKeyword
== mToken
.mType
) {
1857 SkipAtRule(); // group rules cannot contain @rules
1861 ParseRuleSet(AppendRuleToSheet
, this);
1865 if (!ExpectSymbol('}', PR_TRUE
)) {
1866 mSection
= holdSection
;
1869 (*aAppendFunc
)(aRule
, aData
);
1873 // Parse a CSS2 media rule: "@media medium [, medium] { ... }"
1875 CSSParserImpl::ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aData
)
1877 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1879 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1883 if (GatherMedia(media
, '{')) {
1884 // XXXbz this could use better error reporting throughout the method
1885 nsRefPtr
<nsCSSMediaRule
> rule(new nsCSSMediaRule());
1886 // Append first, so when we do SetMedia() the rule
1887 // knows what its stylesheet is.
1888 if (rule
&& ParseGroupRule(rule
, aAppendFunc
, aData
)) {
1889 rule
->SetMedia(media
);
1897 // Parse a @-moz-document rule. This is like an @media rule, but instead
1898 // of a medium it has a nonempty list of items where each item is either
1899 // url(), url-prefix(), or domain().
1901 CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aData
)
1903 nsCSSDocumentRule::URL
*urls
= nsnull
;
1904 nsCSSDocumentRule::URL
**next
= &urls
;
1906 if (!GetToken(PR_TRUE
) ||
1907 eCSSToken_Function
!= mToken
.mType
||
1908 !(mToken
.mIdent
.LowerCaseEqualsLiteral("url") ||
1909 mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix") ||
1910 mToken
.mIdent
.LowerCaseEqualsLiteral("domain"))) {
1911 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc
);
1915 nsCSSDocumentRule::URL
*cur
= *next
= new nsCSSDocumentRule::URL
;
1917 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1922 if (mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
1923 cur
->func
= nsCSSDocumentRule::eURL
;
1924 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix")) {
1925 cur
->func
= nsCSSDocumentRule::eURLPrefix
;
1926 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("domain")) {
1927 cur
->func
= nsCSSDocumentRule::eDomain
;
1930 if (!ExpectSymbol('(', PR_FALSE
) ||
1932 (eCSSToken_String
!= mToken
.mType
&&
1933 eCSSToken_URL
!= mToken
.mType
)) {
1934 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI
);
1938 if (!ExpectSymbol(')', PR_TRUE
)) {
1943 // We could try to make the URL (as long as it's not domain())
1944 // canonical and absolute with NS_NewURI and GetSpec, but I'm
1945 // inclined to think we shouldn't.
1946 CopyUTF16toUTF8(mToken
.mIdent
, cur
->url
);
1947 } while (ExpectSymbol(',', PR_TRUE
));
1949 nsRefPtr
<nsCSSDocumentRule
> rule(new nsCSSDocumentRule());
1951 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1955 rule
->SetURLs(urls
);
1957 return ParseGroupRule(rule
, aAppendFunc
, aData
);
1960 // Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"
1962 CSSParserImpl::ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
1964 if (!GetToken(PR_TRUE
)) {
1965 REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF
);
1969 nsAutoString prefix
;
1972 if (eCSSToken_Ident
== mToken
.mType
) {
1973 prefix
= mToken
.mIdent
;
1974 // user-specified identifiers are case-sensitive (bug 416106)
1975 if (! GetToken(PR_TRUE
)) {
1976 REPORT_UNEXPECTED_EOF(PEAtNSURIEOF
);
1981 if (eCSSToken_String
== mToken
.mType
) {
1982 url
= mToken
.mIdent
;
1983 if (ExpectSymbol(';', PR_TRUE
)) {
1984 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
1988 else if ((eCSSToken_Function
== mToken
.mType
) &&
1989 (mToken
.mIdent
.LowerCaseEqualsLiteral("url"))) {
1990 if (ExpectSymbol('(', PR_FALSE
)) {
1991 if (GetURLToken()) {
1992 if ((eCSSToken_String
== mToken
.mType
) || (eCSSToken_URL
== mToken
.mType
)) {
1993 url
= mToken
.mIdent
;
1994 if (ExpectSymbol(')', PR_TRUE
)) {
1995 if (ExpectSymbol(';', PR_TRUE
)) {
1996 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
2004 REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected
);
2010 CSSParserImpl::ProcessNameSpace(const nsString
& aPrefix
,
2011 const nsString
& aURLSpec
,
2012 RuleAppendFunc aAppendFunc
,
2015 PRBool result
= PR_FALSE
;
2017 nsCOMPtr
<nsICSSNameSpaceRule
> rule
;
2018 nsCOMPtr
<nsIAtom
> prefix
;
2020 if (!aPrefix
.IsEmpty()) {
2021 prefix
= do_GetAtom(aPrefix
);
2024 NS_NewCSSNameSpaceRule(getter_AddRefs(rule
), prefix
, aURLSpec
);
2026 (*aAppendFunc
)(rule
, aData
);
2028 // If this was the first namespace rule encountered, it will trigger
2029 // creation of a namespace map.
2030 if (!mNameSpaceMap
) {
2031 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
2038 // font-face-rule: '@font-face' '{' font-description '}'
2039 // font-description: font-descriptor+
2041 CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
2043 if (!ExpectSymbol('{', PR_TRUE
))
2046 nsRefPtr
<nsCSSFontFaceRule
> rule(new nsCSSFontFaceRule());
2048 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2053 if (!GetToken(PR_TRUE
)) {
2054 REPORT_UNEXPECTED_EOF(PEFontFaceEOF
);
2057 if (mToken
.IsSymbol('}')) { // done!
2062 // ignore extra semicolons
2063 if (mToken
.IsSymbol(';'))
2066 if (!ParseFontDescriptor(rule
)) {
2067 REPORT_UNEXPECTED(PEDeclSkipped
);
2069 if (!SkipDeclaration(PR_TRUE
))
2073 if (!ExpectSymbol('}', PR_TRUE
))
2075 (*aAppendFunc
)(rule
, aData
);
2079 // font-descriptor: font-family-desc
2080 // | font-style-desc
2081 // | font-weight-desc
2082 // | font-stretch-desc
2084 // | unicode-range-desc
2086 // All font-*-desc productions follow the pattern
2087 // IDENT ':' value ';'
2089 // On entry to this function, mToken is the IDENT.
2092 CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule
* aRule
)
2094 if (eCSSToken_Ident
!= mToken
.mType
) {
2095 REPORT_UNEXPECTED_TOKEN(PEFontDescExpected
);
2099 nsString descName
= mToken
.mIdent
;
2100 if (!ExpectSymbol(':', PR_TRUE
)) {
2101 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
2106 nsCSSFontDesc descID
= nsCSSProps::LookupFontDesc(descName
);
2109 if (descID
== eCSSFontDesc_UNKNOWN
) {
2110 if (NonMozillaVendorIdentifier(descName
)) {
2111 // silently skip other vendors' extensions
2112 SkipDeclaration(PR_TRUE
);
2115 const PRUnichar
*params
[] = {
2118 REPORT_UNEXPECTED_P(PEUnknownFontDesc
, params
);
2123 if (!ParseFontDescriptorValue(descID
, value
)) {
2124 const PRUnichar
*params
[] = {
2127 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
2131 if (!ExpectEndProperty())
2134 aRule
->SetDesc(descID
, value
);
2140 CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc
, void* aData
)
2142 // XXX not yet implemented
2147 CSSParserImpl::SkipUntil(PRUnichar aStopSymbol
)
2149 nsCSSToken
* tk
= &mToken
;
2150 nsAutoTArray
<PRUnichar
, 16> stack
;
2151 stack
.AppendElement(aStopSymbol
);
2153 if (!GetToken(PR_TRUE
)) {
2156 if (eCSSToken_Symbol
== tk
->mType
) {
2157 PRUnichar symbol
= tk
->mSymbol
;
2158 PRUint32 stackTopIndex
= stack
.Length() - 1;
2159 if (symbol
== stack
.ElementAt(stackTopIndex
)) {
2160 stack
.RemoveElementAt(stackTopIndex
);
2161 if (stackTopIndex
== 0) {
2164 } else if ('{' == symbol
) {
2165 // In this case and the two below, just handle out-of-memory by
2166 // parsing incorrectly. It's highly unlikely we're dealing with
2167 // a legitimate style sheet anyway.
2168 stack
.AppendElement('}');
2169 } else if ('[' == symbol
) {
2170 stack
.AppendElement(']');
2171 } else if ('(' == symbol
) {
2172 stack
.AppendElement(')');
2179 CSSParserImpl::SkipUntilOneOf(const PRUnichar
* aStopSymbolChars
)
2181 nsCSSToken
* tk
= &mToken
;
2182 nsDependentString
stopSymbolChars(aStopSymbolChars
);
2184 if (!GetToken(PR_TRUE
)) {
2187 if (eCSSToken_Symbol
== tk
->mType
) {
2188 PRUnichar symbol
= tk
->mSymbol
;
2189 if (stopSymbolChars
.FindChar(symbol
) != -1) {
2191 } else if ('{' == symbol
) {
2193 } else if ('[' == symbol
) {
2195 } else if ('(' == symbol
) {
2203 CSSParserImpl::GetNonCloseParenToken(PRBool aSkipWS
)
2205 if (!GetToken(aSkipWS
))
2207 if (mToken
.mType
== eCSSToken_Symbol
&& mToken
.mSymbol
== ')') {
2215 CSSParserImpl::SkipDeclaration(PRBool aCheckForBraces
)
2217 nsCSSToken
* tk
= &mToken
;
2219 if (!GetToken(PR_TRUE
)) {
2220 if (aCheckForBraces
) {
2221 REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF
);
2225 if (eCSSToken_Symbol
== tk
->mType
) {
2226 PRUnichar symbol
= tk
->mSymbol
;
2227 if (';' == symbol
) {
2230 if (aCheckForBraces
) {
2231 if ('}' == symbol
) {
2236 if ('{' == symbol
) {
2238 } else if ('(' == symbol
) {
2240 } else if ('[' == symbol
) {
2249 CSSParserImpl::SkipRuleSet()
2251 nsCSSToken
* tk
= &mToken
;
2253 if (!GetToken(PR_TRUE
)) {
2254 REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF
);
2257 if (eCSSToken_Symbol
== tk
->mType
) {
2258 PRUnichar symbol
= tk
->mSymbol
;
2259 if ('{' == symbol
) {
2263 if ('(' == symbol
) {
2265 } else if ('[' == symbol
) {
2273 CSSParserImpl::PushGroup(nsICSSGroupRule
* aRule
)
2275 if (mGroupStack
.AppendObject(aRule
))
2282 CSSParserImpl::PopGroup(void)
2284 PRInt32 count
= mGroupStack
.Count();
2286 mGroupStack
.RemoveObjectAt(count
- 1);
2291 CSSParserImpl::AppendRule(nsICSSRule
* aRule
)
2293 PRInt32 count
= mGroupStack
.Count();
2295 mGroupStack
[count
- 1]->AppendStyleRule(aRule
);
2298 mSheet
->AppendStyleRule(aRule
);
2303 CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aData
)
2305 // First get the list of selectors for the rule
2306 nsCSSSelectorList
* slist
= nsnull
;
2307 PRUint32 linenum
= mScanner
.GetLineNumber();
2308 if (! ParseSelectorList(slist
, PR_TRUE
)) {
2309 REPORT_UNEXPECTED(PEBadSelectorRSIgnored
);
2314 NS_ASSERTION(nsnull
!= slist
, "null selector list");
2317 // Next parse the declaration block
2318 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(PR_TRUE
);
2319 if (nsnull
== declaration
) {
2320 // XXX skip something here
2327 fputs("{\n", stdout
);
2328 declaration
->List();
2329 fputs("}\n", stdout
);
2332 // Translate the selector list and declaration block into style data
2334 nsCOMPtr
<nsICSSStyleRule
> rule
;
2335 NS_NewCSSStyleRule(getter_AddRefs(rule
), slist
, declaration
);
2337 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2341 rule
->SetLineNumber(linenum
);
2342 (*aAppendFunc
)(rule
, aData
);
2348 CSSParserImpl::ParseSelectorList(nsCSSSelectorList
*& aListHead
,
2349 PRBool aTerminateAtBrace
)
2351 nsCSSSelectorList
* list
= nsnull
;
2352 if (! ParseSelectorGroup(list
)) {
2353 // must have at least one selector group
2357 NS_ASSERTION(nsnull
!= list
, "no selector list");
2360 // After that there must either be a "," or a "{" (the latter if
2361 // aTerminateAtBrace is true)
2362 nsCSSToken
* tk
= &mToken
;
2364 if (! GetToken(PR_TRUE
)) {
2365 if (!aTerminateAtBrace
) {
2369 REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF
);
2373 if (eCSSToken_Symbol
== tk
->mType
) {
2374 if (',' == tk
->mSymbol
) {
2375 nsCSSSelectorList
* newList
= nsnull
;
2376 // Another selector group must follow
2377 if (! ParseSelectorGroup(newList
)) {
2380 // add new list to the end of the selector list
2381 list
->mNext
= newList
;
2384 } else if ('{' == tk
->mSymbol
&& aTerminateAtBrace
) {
2389 REPORT_UNEXPECTED_TOKEN(PESelectorListExtra
);
2399 static PRBool
IsSinglePseudoClass(const nsCSSSelector
& aSelector
)
2401 return PRBool((aSelector
.mNameSpace
== kNameSpaceID_Unknown
) &&
2402 (aSelector
.mTag
== nsnull
) &&
2403 (aSelector
.mIDList
== nsnull
) &&
2404 (aSelector
.mClassList
== nsnull
) &&
2405 (aSelector
.mAttrList
== nsnull
) &&
2406 (aSelector
.mNegations
== nsnull
) &&
2407 (aSelector
.mPseudoClassList
!= nsnull
) &&
2408 (aSelector
.mPseudoClassList
->mNext
== nsnull
));
2412 static PRBool
IsTreePseudoElement(nsIAtom
* aPseudo
)
2415 aPseudo
->GetUTF8String(&str
);
2416 static const char moz_tree
[] = ":-moz-tree-";
2417 return nsCRT::strncmp(str
, moz_tree
, PRInt32(sizeof(moz_tree
)-1)) == 0;
2422 CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList
*& aList
)
2424 nsAutoPtr
<nsCSSSelectorList
> list
;
2425 PRUnichar combinator
= PRUnichar(0);
2427 PRBool havePseudoElement
= PR_FALSE
;
2428 PRBool done
= PR_FALSE
;
2430 nsAutoPtr
<nsCSSSelector
> newSelector(new nsCSSSelector());
2432 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2435 nsSelectorParsingStatus parsingStatus
=
2436 ParseSelector(*newSelector
);
2437 if (parsingStatus
== eSelectorParsingStatus_Empty
) {
2439 REPORT_UNEXPECTED(PESelectorGroupNoSelector
);
2443 if (parsingStatus
== eSelectorParsingStatus_Error
) {
2447 if (nsnull
== list
) {
2448 list
= new nsCSSSelectorList();
2449 if (nsnull
== list
) {
2450 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2454 list
->AddSelector(newSelector
);
2455 nsCSSSelector
* listSel
= list
->mSelectors
;
2457 // pull out pseudo elements here
2458 nsPseudoClassList
* prevList
= nsnull
;
2459 nsPseudoClassList
* pseudoClassList
= listSel
->mPseudoClassList
;
2460 while (nsnull
!= pseudoClassList
) {
2461 if (! nsCSSPseudoClasses::IsPseudoClass(pseudoClassList
->mAtom
)) {
2462 havePseudoElement
= PR_TRUE
;
2463 if (IsSinglePseudoClass(*listSel
)) { // convert to pseudo element selector
2464 nsIAtom
* pseudoElement
= pseudoClassList
->mAtom
; // steal ref count
2465 pseudoClassList
->mAtom
= nsnull
;
2467 if (listSel
->mNext
) {// more to the selector
2468 listSel
->mOperator
= PRUnichar('>');
2469 nsAutoPtr
<nsCSSSelector
> empty(new nsCSSSelector());
2471 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2474 list
->AddSelector(empty
); // leave a blank (universal) selector in the middle
2475 listSel
= list
->mSelectors
; // use the new one for the pseudo
2477 listSel
->mTag
= pseudoElement
;
2479 else { // append new pseudo element selector
2480 nsAutoPtr
<nsCSSSelector
> pseudoTagSelector(new nsCSSSelector());
2481 if (!pseudoTagSelector
) {
2482 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2485 pseudoTagSelector
->mTag
= pseudoClassList
->mAtom
; // steal ref count
2487 if (IsTreePseudoElement(pseudoTagSelector
->mTag
)) {
2488 // Take the remaining "pseudoclasses" that we parsed
2489 // inside the tree pseudoelement's ()-list, and
2490 // make our new selector have these pseudoclasses
2491 // in its pseudoclass list.
2492 pseudoTagSelector
->mPseudoClassList
= pseudoClassList
->mNext
;
2493 pseudoClassList
->mNext
= nsnull
;
2496 list
->AddSelector(pseudoTagSelector
);
2497 pseudoClassList
->mAtom
= nsnull
;
2498 listSel
->mOperator
= PRUnichar('>');
2499 if (nsnull
== prevList
) { // delete list entry
2500 listSel
->mPseudoClassList
= pseudoClassList
->mNext
;
2503 prevList
->mNext
= pseudoClassList
->mNext
;
2505 pseudoClassList
->mNext
= nsnull
;
2506 delete pseudoClassList
;
2507 weight
+= listSel
->CalcWeight(); // capture weight from remainder
2509 break; // only one pseudo element per selector
2511 prevList
= pseudoClassList
;
2512 pseudoClassList
= pseudoClassList
->mNext
;
2515 combinator
= PRUnichar(0);
2516 if (!GetToken(PR_FALSE
)) {
2520 // Assume we are done unless we find a combinator here.
2522 if (eCSSToken_WhiteSpace
== mToken
.mType
) {
2523 if (!GetToken(PR_TRUE
)) {
2529 if (eCSSToken_Symbol
== mToken
.mType
&&
2530 ('+' == mToken
.mSymbol
||
2531 '>' == mToken
.mSymbol
||
2532 '~' == mToken
.mSymbol
)) {
2534 combinator
= mToken
.mSymbol
;
2535 list
->mSelectors
->SetOperator(combinator
);
2538 if (eCSSToken_Symbol
== mToken
.mType
&&
2539 ('{' == mToken
.mSymbol
||
2540 ',' == mToken
.mSymbol
)) {
2541 // End of this selector group
2544 UngetToken(); // give it back to selector if we're not done, or make sure
2545 // we see it as the end of the selector if we are.
2548 if (havePseudoElement
) {
2552 weight
+= listSel
->CalcWeight();
2556 if (PRUnichar(0) != combinator
) { // no dangling combinators
2558 // This should report the problematic combinator
2559 REPORT_UNEXPECTED(PESelectorGroupExtraCombinator
);
2561 aList
= list
.forget();
2563 aList
->mWeight
= weight
;
2565 return PRBool(nsnull
!= aList
);
2568 #define SEL_MASK_NSPACE 0x01
2569 #define SEL_MASK_ELEM 0x02
2570 #define SEL_MASK_ID 0x04
2571 #define SEL_MASK_CLASS 0x08
2572 #define SEL_MASK_ATTRIB 0x10
2573 #define SEL_MASK_PCLASS 0x20
2574 #define SEL_MASK_PELEM 0x40
2577 // Parses an ID selector #name
2579 CSSParserImpl::nsSelectorParsingStatus
2580 CSSParserImpl::ParseIDSelector(PRInt32
& aDataMask
,
2581 nsCSSSelector
& aSelector
)
2583 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(),
2584 "Empty mIdent in eCSSToken_ID token?");
2585 aDataMask
|= SEL_MASK_ID
;
2586 aSelector
.AddID(mToken
.mIdent
);
2587 return eSelectorParsingStatus_Continue
;
2591 // Parses a class selector .name
2593 CSSParserImpl::nsSelectorParsingStatus
2594 CSSParserImpl::ParseClassSelector(PRInt32
& aDataMask
,
2595 nsCSSSelector
& aSelector
)
2597 if (! GetToken(PR_FALSE
)) { // get ident
2598 REPORT_UNEXPECTED_EOF(PEClassSelEOF
);
2599 return eSelectorParsingStatus_Error
;
2601 if (eCSSToken_Ident
!= mToken
.mType
) { // malformed selector
2602 REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent
);
2604 return eSelectorParsingStatus_Error
;
2606 aDataMask
|= SEL_MASK_CLASS
;
2608 aSelector
.AddClass(mToken
.mIdent
);
2610 return eSelectorParsingStatus_Continue
;
2614 // Parse a type element selector or a universal selector
2615 // namespace|type or namespace|* or *|* or *
2617 CSSParserImpl::nsSelectorParsingStatus
2618 CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
2619 nsCSSSelector
& aSelector
,
2622 nsAutoString buffer
;
2623 if (mToken
.IsSymbol('*')) { // universal element selector, or universal namespace
2624 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2625 aDataMask
|= SEL_MASK_NSPACE
;
2626 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // namespace wildcard
2628 if (! GetToken(PR_FALSE
)) {
2629 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2630 return eSelectorParsingStatus_Error
;
2632 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2633 aDataMask
|= SEL_MASK_ELEM
;
2634 if (mCaseSensitive
) {
2635 aSelector
.SetTag(mToken
.mIdent
);
2638 ToLowerCase(mToken
.mIdent
, buffer
);
2639 aSelector
.SetTag(buffer
);
2642 else if (mToken
.IsSymbol('*')) { // universal selector
2643 aDataMask
|= SEL_MASK_ELEM
;
2647 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2649 return eSelectorParsingStatus_Error
;
2652 else { // was universal element selector
2653 SetDefaultNamespaceOnSelector(aSelector
);
2654 aDataMask
|= SEL_MASK_ELEM
;
2655 // don't set any tag in the selector
2657 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2658 return eSelectorParsingStatus_Done
;
2661 else if (eCSSToken_Ident
== mToken
.mType
) { // element name or namespace name
2662 buffer
= mToken
.mIdent
; // hang on to ident
2664 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2665 aDataMask
|= SEL_MASK_NSPACE
;
2666 PRInt32 nameSpaceID
;
2667 if (!GetNamespaceIdForPrefix(buffer
, &nameSpaceID
)) {
2668 return eSelectorParsingStatus_Error
;
2670 aSelector
.SetNameSpace(nameSpaceID
);
2672 if (! GetToken(PR_FALSE
)) {
2673 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2674 return eSelectorParsingStatus_Error
;
2676 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2677 aDataMask
|= SEL_MASK_ELEM
;
2678 if (mCaseSensitive
) {
2679 aSelector
.SetTag(mToken
.mIdent
);
2682 ToLowerCase(mToken
.mIdent
, buffer
);
2683 aSelector
.SetTag(buffer
);
2686 else if (mToken
.IsSymbol('*')) { // universal selector
2687 aDataMask
|= SEL_MASK_ELEM
;
2691 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2693 return eSelectorParsingStatus_Error
;
2696 else { // was element name
2697 SetDefaultNamespaceOnSelector(aSelector
);
2698 if (mCaseSensitive
) {
2699 aSelector
.SetTag(buffer
);
2702 ToLowerCase(buffer
);
2703 aSelector
.SetTag(buffer
);
2705 aDataMask
|= SEL_MASK_ELEM
;
2707 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2708 return eSelectorParsingStatus_Done
;
2711 else if (mToken
.IsSymbol('|')) { // No namespace
2712 aDataMask
|= SEL_MASK_NSPACE
;
2713 aSelector
.SetNameSpace(kNameSpaceID_None
); // explicit NO namespace
2715 // get mandatory tag
2716 if (! GetToken(PR_FALSE
)) {
2717 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2718 return eSelectorParsingStatus_Error
;
2720 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2721 aDataMask
|= SEL_MASK_ELEM
;
2722 if (mCaseSensitive
) {
2723 aSelector
.SetTag(mToken
.mIdent
);
2726 ToLowerCase(mToken
.mIdent
, buffer
);
2727 aSelector
.SetTag(buffer
);
2730 else if (mToken
.IsSymbol('*')) { // universal selector
2731 aDataMask
|= SEL_MASK_ELEM
;
2735 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2737 return eSelectorParsingStatus_Error
;
2739 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2740 return eSelectorParsingStatus_Done
;
2744 SetDefaultNamespaceOnSelector(aSelector
);
2748 // restore last token read in case of a negated type selector
2751 return eSelectorParsingStatus_Continue
;
2755 // Parse attribute selectors [attr], [attr=value], [attr|=value],
2756 // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
2758 CSSParserImpl::nsSelectorParsingStatus
2759 CSSParserImpl::ParseAttributeSelector(PRInt32
& aDataMask
,
2760 nsCSSSelector
& aSelector
)
2762 if (! GetToken(PR_TRUE
)) { // premature EOF
2763 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2764 return eSelectorParsingStatus_Error
;
2767 PRInt32 nameSpaceID
= kNameSpaceID_None
;
2769 if (mToken
.IsSymbol('*')) { // wildcard namespace
2770 nameSpaceID
= kNameSpaceID_Unknown
;
2771 if (ExpectSymbol('|', PR_FALSE
)) {
2772 if (! GetToken(PR_FALSE
)) { // premature EOF
2773 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2774 return eSelectorParsingStatus_Error
;
2776 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2777 attr
= mToken
.mIdent
;
2780 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2782 return eSelectorParsingStatus_Error
;
2786 REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar
);
2787 return eSelectorParsingStatus_Error
;
2790 else if (mToken
.IsSymbol('|')) { // NO namespace
2791 if (! GetToken(PR_FALSE
)) { // premature EOF
2792 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2793 return eSelectorParsingStatus_Error
;
2795 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2796 attr
= mToken
.mIdent
;
2799 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2801 return eSelectorParsingStatus_Error
;
2804 else if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
2805 attr
= mToken
.mIdent
; // hang on to it
2806 if (ExpectSymbol('|', PR_FALSE
)) { // was a namespace
2807 if (!GetNamespaceIdForPrefix(attr
, &nameSpaceID
)) {
2808 return eSelectorParsingStatus_Error
;
2810 if (! GetToken(PR_FALSE
)) { // premature EOF
2811 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2812 return eSelectorParsingStatus_Error
;
2814 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2815 attr
= mToken
.mIdent
;
2818 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2820 return eSelectorParsingStatus_Error
;
2825 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
2827 return eSelectorParsingStatus_Error
;
2830 if (! mCaseSensitive
) {
2833 if (! GetToken(PR_TRUE
)) { // premature EOF
2834 REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF
);
2835 return eSelectorParsingStatus_Error
;
2837 if ((eCSSToken_Symbol
== mToken
.mType
) ||
2838 (eCSSToken_Includes
== mToken
.mType
) ||
2839 (eCSSToken_Dashmatch
== mToken
.mType
) ||
2840 (eCSSToken_Beginsmatch
== mToken
.mType
) ||
2841 (eCSSToken_Endsmatch
== mToken
.mType
) ||
2842 (eCSSToken_Containsmatch
== mToken
.mType
)) {
2844 if (eCSSToken_Includes
== mToken
.mType
) {
2845 func
= NS_ATTR_FUNC_INCLUDES
;
2847 else if (eCSSToken_Dashmatch
== mToken
.mType
) {
2848 func
= NS_ATTR_FUNC_DASHMATCH
;
2850 else if (eCSSToken_Beginsmatch
== mToken
.mType
) {
2851 func
= NS_ATTR_FUNC_BEGINSMATCH
;
2853 else if (eCSSToken_Endsmatch
== mToken
.mType
) {
2854 func
= NS_ATTR_FUNC_ENDSMATCH
;
2856 else if (eCSSToken_Containsmatch
== mToken
.mType
) {
2857 func
= NS_ATTR_FUNC_CONTAINSMATCH
;
2859 else if (']' == mToken
.mSymbol
) {
2860 aDataMask
|= SEL_MASK_ATTRIB
;
2861 aSelector
.AddAttribute(nameSpaceID
, attr
);
2862 func
= NS_ATTR_FUNC_SET
;
2864 else if ('=' == mToken
.mSymbol
) {
2865 func
= NS_ATTR_FUNC_EQUALS
;
2868 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2869 UngetToken(); // bad function
2870 return eSelectorParsingStatus_Error
;
2872 if (NS_ATTR_FUNC_SET
!= func
) { // get value
2873 if (! GetToken(PR_TRUE
)) { // premature EOF
2874 REPORT_UNEXPECTED_EOF(PEAttSelValueEOF
);
2875 return eSelectorParsingStatus_Error
;
2877 if ((eCSSToken_Ident
== mToken
.mType
) || (eCSSToken_String
== mToken
.mType
)) {
2878 nsAutoString
value(mToken
.mIdent
);
2879 if (! GetToken(PR_TRUE
)) { // premature EOF
2880 REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF
);
2881 return eSelectorParsingStatus_Error
;
2883 if (mToken
.IsSymbol(']')) {
2884 PRBool isCaseSensitive
= PR_TRUE
;
2886 // If we're parsing a style sheet for an HTML document, and
2887 // the attribute selector is for a non-namespaced attribute,
2888 // then check to see if it's one of the known attributes whose
2889 // VALUE is case-insensitive.
2890 if (!mCaseSensitive
&& nameSpaceID
== kNameSpaceID_None
) {
2891 static const char* caseInsensitiveHTMLAttribute
[] = {
2892 // list based on http://www.w3.org/TR/html4/
2938 // additional attributes not in HTML4
2939 "direction", // marquee
2943 const char* htmlAttr
;
2944 while ((htmlAttr
= caseInsensitiveHTMLAttribute
[i
++])) {
2945 if (attr
.EqualsIgnoreCase(htmlAttr
)) {
2946 isCaseSensitive
= PR_FALSE
;
2951 aDataMask
|= SEL_MASK_ATTRIB
;
2952 aSelector
.AddAttribute(nameSpaceID
, attr
, func
, value
, isCaseSensitive
);
2955 REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose
);
2957 return eSelectorParsingStatus_Error
;
2961 REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue
);
2963 return eSelectorParsingStatus_Error
;
2968 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2969 UngetToken(); // bad dog, no biscut!
2970 return eSelectorParsingStatus_Error
;
2972 return eSelectorParsingStatus_Continue
;
2976 // Parse pseudo-classes and pseudo-elements
2978 CSSParserImpl::nsSelectorParsingStatus
2979 CSSParserImpl::ParsePseudoSelector(PRInt32
& aDataMask
,
2980 nsCSSSelector
& aSelector
,
2983 if (! GetToken(PR_FALSE
)) { // premature eof
2984 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2985 return eSelectorParsingStatus_Error
;
2988 // First, find out whether we are parsing a CSS3 pseudo-element
2989 PRBool parsingPseudoElement
= PR_FALSE
;
2990 if (mToken
.IsSymbol(':')) {
2991 parsingPseudoElement
= PR_TRUE
;
2992 if (! GetToken(PR_FALSE
)) { // premature eof
2993 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2994 return eSelectorParsingStatus_Error
;
2998 // Do some sanity-checking on the token
2999 if (eCSSToken_Ident
!= mToken
.mType
&& eCSSToken_Function
!= mToken
.mType
) {
3000 // malformed selector
3001 REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName
);
3003 return eSelectorParsingStatus_Error
;
3006 // OK, now we know we have an mIdent. Atomize it. All the atoms, for
3007 // pseudo-classes as well as pseudo-elements, start with a single ':'.
3008 nsAutoString buffer
;
3009 buffer
.Append(PRUnichar(':'));
3010 buffer
.Append(mToken
.mIdent
);
3011 ToLowerCase(buffer
);
3012 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(buffer
);
3014 // stash away some info about this pseudo so we only have to get it once.
3015 PRBool isTreePseudo
= PR_FALSE
;
3017 isTreePseudo
= IsTreePseudoElement(pseudo
);
3018 // If a tree pseudo-element is using the function syntax, it will
3019 // get isTree set here and will pass the check below that only
3020 // allows functions if they are in our list of things allowed to be
3021 // functions. If it is _not_ using the function syntax, isTree will
3022 // be false, and it will still pass that check. So the tree
3023 // pseudo-elements are allowed to be either functions or not, as
3025 PRBool isTree
= (eCSSToken_Function
== mToken
.mType
) && isTreePseudo
;
3027 PRBool isPseudoElement
= nsCSSPseudoElements::IsPseudoElement(pseudo
);
3028 // anonymous boxes are only allowed if they're the tree boxes or we have
3029 // enabled unsafe rules
3030 PRBool isAnonBox
= nsCSSAnonBoxes::IsAnonBox(pseudo
) &&
3031 (mUnsafeRulesEnabled
|| isTreePseudo
);
3032 PRBool isPseudoClass
= nsCSSPseudoClasses::IsPseudoClass(pseudo
);
3034 if (!isPseudoClass
&& !isPseudoElement
&& !isAnonBox
) {
3035 // Not a pseudo-class, not a pseudo-element.... forget it
3036 REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown
);
3038 return eSelectorParsingStatus_Error
;
3041 // If it's a function token, it better be on our "ok" list, and if the name
3042 // is that of a function pseudo it better be a function token
3043 if ((eCSSToken_Function
== mToken
.mType
) !=
3048 nsCSSPseudoClasses::notPseudo
== pseudo
||
3049 nsCSSPseudoClasses::HasStringArg(pseudo
) ||
3050 nsCSSPseudoClasses::HasNthPairArg(pseudo
))) {
3051 // There are no other function pseudos
3052 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc
);
3054 return eSelectorParsingStatus_Error
;
3057 // If it starts with "::", it better be a pseudo-element
3058 if (parsingPseudoElement
&&
3061 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE
);
3063 return eSelectorParsingStatus_Error
;
3066 if (!parsingPseudoElement
&& nsCSSPseudoClasses::notPseudo
== pseudo
) {
3067 if (aIsNegated
) { // :not() can't be itself negated
3068 REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot
);
3070 return eSelectorParsingStatus_Error
;
3072 // CSS 3 Negation pseudo-class takes one simple selector as argument
3073 nsSelectorParsingStatus parsingStatus
=
3074 ParseNegatedSimpleSelector(aDataMask
, aSelector
);
3075 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3076 return parsingStatus
;
3079 else if (!parsingPseudoElement
&& isPseudoClass
) {
3080 aDataMask
|= SEL_MASK_PCLASS
;
3081 if (nsCSSPseudoClasses::HasStringArg(pseudo
)) {
3082 nsSelectorParsingStatus parsingStatus
=
3083 ParsePseudoClassWithIdentArg(aSelector
, pseudo
);
3084 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3085 return parsingStatus
;
3088 else if (nsCSSPseudoClasses::HasNthPairArg(pseudo
)) {
3089 nsSelectorParsingStatus parsingStatus
=
3090 ParsePseudoClassWithNthPairArg(aSelector
, pseudo
);
3091 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3092 return parsingStatus
;
3096 aSelector
.AddPseudoClass(pseudo
);
3099 else if (isPseudoElement
|| isAnonBox
) {
3100 // Pseudo-element. Make some more sanity checks.
3102 if (aIsNegated
) { // pseudo-elements can't be negated
3103 REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot
);
3105 return eSelectorParsingStatus_Error
;
3107 // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
3108 // to have a single ':' on them. Others (CSS3+ pseudo-elements and
3109 // various -moz-* pseudo-elements) must have |parsingPseudoElement|
3111 if (!parsingPseudoElement
&&
3112 !nsCSSPseudoElements::IsCSS2PseudoElement(pseudo
)
3117 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly
);
3119 return eSelectorParsingStatus_Error
;
3122 if (0 == (aDataMask
& SEL_MASK_PELEM
)) {
3123 aDataMask
|= SEL_MASK_PELEM
;
3124 aSelector
.AddPseudoClass(pseudo
); // store it here, it gets pulled later
3128 // We have encountered a pseudoelement of the form
3129 // -moz-tree-xxxx(a,b,c). We parse (a,b,c) and add each
3130 // item in the list to the pseudoclass list. They will be pulled
3131 // from the list later along with the pseudo-element.
3132 if (!ParseTreePseudoElement(aSelector
)) {
3133 return eSelectorParsingStatus_Error
;
3138 // ensure selector ends here, must be followed by EOF, space, '{' or ','
3139 if (GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3140 if ((eCSSToken_WhiteSpace
== mToken
.mType
) ||
3141 (mToken
.IsSymbol('{') || mToken
.IsSymbol(','))) {
3143 return eSelectorParsingStatus_Done
;
3145 REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing
);
3147 return eSelectorParsingStatus_Error
;
3150 else { // multiple pseudo elements, not legal
3151 REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE
);
3153 return eSelectorParsingStatus_Error
;
3158 // We should never end up here. Indeed, if we ended up here, we know (from
3159 // the current if/else cascade) that !isPseudoElement and !isAnonBox. But
3160 // then due to our earlier check we know that isPseudoClass. Since we
3161 // didn't fall into the isPseudoClass case in this cascade, we must have
3162 // parsingPseudoElement. But we've already checked the
3163 // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if
3165 NS_NOTREACHED("How did this happen?");
3168 return eSelectorParsingStatus_Continue
;
3172 // Parse the argument of a negation pseudo-class :not()
3174 CSSParserImpl::nsSelectorParsingStatus
3175 CSSParserImpl::ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
3176 nsCSSSelector
& aSelector
)
3178 // Check if we have the first parenthesis
3179 if (!ExpectSymbol('(', PR_FALSE
)) {
3180 REPORT_UNEXPECTED_TOKEN(PENegationBadArg
);
3181 return eSelectorParsingStatus_Error
;
3184 if (! GetToken(PR_TRUE
)) { // premature eof
3185 REPORT_UNEXPECTED_EOF(PENegationEOF
);
3186 return eSelectorParsingStatus_Error
;
3189 // Create a new nsCSSSelector and add it to the end of
3190 // aSelector.mNegations.
3191 // Given the current parsing rules, every selector in mNegations
3192 // contains only one simple selector (css3 definition) within it.
3193 // This could easily change in future versions of CSS, and the only
3194 // thing we need to change to support that is this parsing code and the
3195 // serialization code for nsCSSSelector.
3196 nsCSSSelector
*newSel
= new nsCSSSelector();
3198 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
3199 return eSelectorParsingStatus_Error
;
3201 nsCSSSelector
* negations
= &aSelector
;
3202 while (negations
->mNegations
) {
3203 negations
= negations
->mNegations
;
3205 negations
->mNegations
= newSel
;
3207 nsSelectorParsingStatus parsingStatus
;
3208 if (eCSSToken_ID
== mToken
.mType
) { // #id
3209 parsingStatus
= ParseIDSelector(aDataMask
, *newSel
);
3211 else if (mToken
.IsSymbol('.')) { // .class
3212 parsingStatus
= ParseClassSelector(aDataMask
, *newSel
);
3214 else if (mToken
.IsSymbol(':')) { // :pseudo
3215 parsingStatus
= ParsePseudoSelector(aDataMask
, *newSel
, PR_TRUE
);
3217 else if (mToken
.IsSymbol('[')) { // [attribute
3218 parsingStatus
= ParseAttributeSelector(aDataMask
, *newSel
);
3221 // then it should be a type element or universal selector
3222 parsingStatus
= ParseTypeOrUniversalSelector(aDataMask
, *newSel
, PR_TRUE
);
3224 if (eSelectorParsingStatus_Error
== parsingStatus
) {
3225 REPORT_UNEXPECTED_TOKEN(PENegationBadInner
);
3226 return parsingStatus
;
3228 // close the parenthesis
3229 if (!ExpectSymbol(')', PR_TRUE
)) {
3230 REPORT_UNEXPECTED_TOKEN(PENegationNoClose
);
3231 return eSelectorParsingStatus_Error
;
3234 NS_ASSERTION(newSel
->mNameSpace
== kNameSpaceID_Unknown
||
3235 (!newSel
->mIDList
&& !newSel
->mClassList
&&
3236 !newSel
->mPseudoClassList
&& !newSel
->mAttrList
),
3237 "Need to fix the serialization code to deal with this");
3239 return eSelectorParsingStatus_Continue
;
3243 // Parse the argument of a pseudo-class that has an ident arg
3245 CSSParserImpl::nsSelectorParsingStatus
3246 CSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
3249 // Check if we have the first parenthesis
3250 if (!ExpectSymbol('(', PR_FALSE
)) {
3251 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3252 return eSelectorParsingStatus_Error
;
3255 if (! GetToken(PR_TRUE
)) { // premature eof
3256 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3257 return eSelectorParsingStatus_Error
;
3259 // We expect an identifier with a language abbreviation
3260 if (eCSSToken_Ident
!= mToken
.mType
) {
3261 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent
);
3263 // XXX Call SkipUntil to the next ")"?
3264 return eSelectorParsingStatus_Error
;
3267 // Add the pseudo with the language parameter
3268 aSelector
.AddPseudoClass(aPseudo
, mToken
.mIdent
.get());
3270 // close the parenthesis
3271 if (!ExpectSymbol(')', PR_TRUE
)) {
3272 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3273 // XXX Call SkipUntil to the next ")"?
3274 return eSelectorParsingStatus_Error
;
3277 return eSelectorParsingStatus_Continue
;
3280 CSSParserImpl::nsSelectorParsingStatus
3281 CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
3284 PRInt32 numbers
[2] = { 0, 0 };
3285 PRBool lookForB
= PR_TRUE
;
3287 // Check whether we have the first parenthesis
3288 if (!ExpectSymbol('(', PR_FALSE
)) {
3289 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3290 return eSelectorParsingStatus_Error
;
3293 // Follow the whitespace rules as proposed in
3294 // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
3296 if (! GetToken(PR_TRUE
)) {
3297 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3298 return eSelectorParsingStatus_Error
;
3301 if (eCSSToken_Ident
== mToken
.mType
|| eCSSToken_Dimension
== mToken
.mType
) {
3302 // The CSS tokenization doesn't handle :nth-child() containing - well:
3303 // 2n-1 is a dimension
3304 // n-1 is an identifier
3305 // The easiest way to deal with that is to push everything from the
3306 // minus on back onto the scanner's pushback buffer.
3307 PRUint32 truncAt
= 0;
3308 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("n-"))) {
3310 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("-n-"))) {
3314 for (PRUint32 i
= mToken
.mIdent
.Length() - 1; i
>= truncAt
; --i
) {
3315 mScanner
.Pushback(mToken
.mIdent
[i
]);
3317 mToken
.mIdent
.Truncate(truncAt
);
3321 if (eCSSToken_Ident
== mToken
.mType
) {
3322 if (mToken
.mIdent
.EqualsIgnoreCase("odd")) {
3325 lookForB
= PR_FALSE
;
3327 else if (mToken
.mIdent
.EqualsIgnoreCase("even")) {
3330 lookForB
= PR_FALSE
;
3332 else if (mToken
.mIdent
.EqualsIgnoreCase("n")) {
3335 else if (mToken
.mIdent
.EqualsIgnoreCase("-n")) {
3339 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3340 // XXX Call SkipUntil to the next ")"?
3341 return eSelectorParsingStatus_Error
;
3344 else if (eCSSToken_Number
== mToken
.mType
) {
3345 if (!mToken
.mIntegerValid
) {
3346 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3347 // XXX Call SkipUntil to the next ")"?
3348 return eSelectorParsingStatus_Error
;
3350 numbers
[1] = mToken
.mInteger
;
3351 lookForB
= PR_FALSE
;
3353 else if (eCSSToken_Dimension
== mToken
.mType
) {
3354 if (!mToken
.mIntegerValid
|| !mToken
.mIdent
.EqualsIgnoreCase("n")) {
3355 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3356 // XXX Call SkipUntil to the next ")"?
3357 return eSelectorParsingStatus_Error
;
3359 numbers
[0] = mToken
.mInteger
;
3361 // XXX If it's a ')', is that valid? (as 0n+0)
3363 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3364 // XXX Call SkipUntil to the next ")" (unless this is one already)?
3365 return eSelectorParsingStatus_Error
;
3368 if (! GetToken(PR_TRUE
)) {
3369 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3370 return eSelectorParsingStatus_Error
;
3372 if (lookForB
&& !mToken
.IsSymbol(')')) {
3373 // The '+' or '-' sign can optionally be separated by whitespace.
3374 // If it is separated by whitespace from what follows it, it appears
3375 // as a separate token rather than part of the number token.
3376 PRBool haveSign
= PR_FALSE
;
3378 if (mToken
.IsSymbol('+') || mToken
.IsSymbol('-')) {
3380 if (mToken
.IsSymbol('-')) {
3383 if (! GetToken(PR_TRUE
)) {
3384 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3385 return eSelectorParsingStatus_Error
;
3388 if (eCSSToken_Number
!= mToken
.mType
||
3389 !mToken
.mIntegerValid
|| mToken
.mHasSign
== haveSign
) {
3390 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3391 // XXX Call SkipUntil to the next ")"?
3392 return eSelectorParsingStatus_Error
;
3394 numbers
[1] = mToken
.mInteger
* sign
;
3395 if (! GetToken(PR_TRUE
)) {
3396 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3397 return eSelectorParsingStatus_Error
;
3400 if (!mToken
.IsSymbol(')')) {
3401 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3402 // XXX Call SkipUntil to the next ")"?
3403 return eSelectorParsingStatus_Error
;
3405 aSelector
.AddPseudoClass(aPseudo
, numbers
);
3406 return eSelectorParsingStatus_Continue
;
3411 * This is the format for selectors:
3412 * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
3414 CSSParserImpl::nsSelectorParsingStatus
3415 CSSParserImpl::ParseSelector(nsCSSSelector
& aSelector
)
3417 if (! GetToken(PR_TRUE
)) {
3418 REPORT_UNEXPECTED_EOF(PESelectorEOF
);
3419 return eSelectorParsingStatus_Error
;
3422 PRInt32 dataMask
= 0;
3423 nsSelectorParsingStatus parsingStatus
=
3424 ParseTypeOrUniversalSelector(dataMask
, aSelector
, PR_FALSE
);
3425 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3426 return parsingStatus
;
3430 if (eCSSToken_ID
== mToken
.mType
) { // #id
3431 parsingStatus
= ParseIDSelector(dataMask
, aSelector
);
3433 else if (mToken
.IsSymbol('.')) { // .class
3434 parsingStatus
= ParseClassSelector(dataMask
, aSelector
);
3436 else if (mToken
.IsSymbol(':')) { // :pseudo
3437 parsingStatus
= ParsePseudoSelector(dataMask
, aSelector
, PR_FALSE
);
3439 else if (mToken
.IsSymbol('[')) { // [attribute
3440 parsingStatus
= ParseAttributeSelector(dataMask
, aSelector
);
3442 else { // not a selector token, we're done
3443 parsingStatus
= eSelectorParsingStatus_Done
;
3447 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3448 return parsingStatus
;
3451 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3452 return eSelectorParsingStatus_Done
;
3456 return dataMask
? parsingStatus
: eSelectorParsingStatus_Empty
;
3460 CSSParserImpl::ParseDeclarationBlock(PRBool aCheckForBraces
)
3462 if (aCheckForBraces
) {
3463 if (!ExpectSymbol('{', PR_TRUE
)) {
3464 REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart
);
3469 nsCSSDeclaration
* declaration
= new nsCSSDeclaration();
3470 mData
.AssertInitialState();
3474 if (!ParseDeclaration(declaration
, aCheckForBraces
,
3475 PR_TRUE
, &changed
)) {
3476 if (!SkipDeclaration(aCheckForBraces
)) {
3479 if (aCheckForBraces
) {
3480 if (ExpectSymbol('}', PR_TRUE
)) {
3484 // Since the skipped declaration didn't end the block we parse
3485 // the next declaration.
3488 declaration
->CompressFrom(&mData
);
3493 // The types to pass to ParseColorComponent. These correspond to the
3494 // various datatypes that can go within rgb().
3495 #define COLOR_TYPE_UNKNOWN 0
3496 #define COLOR_TYPE_INTEGERS 1
3497 #define COLOR_TYPE_PERCENTAGES 2
3500 CSSParserImpl::ParseColor(nsCSSValue
& aValue
)
3502 if (!GetToken(PR_TRUE
)) {
3503 REPORT_UNEXPECTED_EOF(PEColorEOF
);
3507 nsCSSToken
* tk
= &mToken
;
3509 switch (tk
->mType
) {
3513 if (NS_HexToRGB(tk
->mIdent
, &rgba
)) {
3514 aValue
.SetColorValue(rgba
);
3519 case eCSSToken_Ident
:
3520 if (NS_ColorNameToRGB(tk
->mIdent
, &rgba
)) {
3521 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
3525 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
3526 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
3528 if (nsCSSProps::FindKeyword(keyword
, nsCSSProps::kColorKTable
, value
)) {
3529 aValue
.SetIntValue(value
, eCSSUnit_EnumColor
);
3535 case eCSSToken_Function
:
3536 if (mToken
.mIdent
.LowerCaseEqualsLiteral("rgb")) {
3537 // rgb ( component , component , component )
3539 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3540 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3541 ParseColorComponent(r
, type
, ',') &&
3542 ParseColorComponent(g
, type
, ',') &&
3543 ParseColorComponent(b
, type
, ')')) {
3544 aValue
.SetColorValue(NS_RGB(r
,g
,b
));
3547 return PR_FALSE
; // already pushed back
3549 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
3550 mToken
.mIdent
.LowerCaseEqualsLiteral("rgba")) {
3551 // rgba ( component , component , component , opacity )
3553 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3554 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3555 ParseColorComponent(r
, type
, ',') &&
3556 ParseColorComponent(g
, type
, ',') &&
3557 ParseColorComponent(b
, type
, ',') &&
3558 ParseColorOpacity(a
)) {
3559 aValue
.SetColorValue(NS_RGBA(r
, g
, b
, a
));
3562 return PR_FALSE
; // already pushed back
3564 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("hsl")) {
3565 // hsl ( hue , saturation , lightness )
3566 // "hue" is a number, "saturation" and "lightness" are percentages.
3567 if (ParseHSLColor(rgba
, ')')) {
3568 aValue
.SetColorValue(rgba
);
3573 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
3574 mToken
.mIdent
.LowerCaseEqualsLiteral("hsla")) {
3575 // hsla ( hue , saturation , lightness , opacity )
3576 // "hue" is a number, "saturation" and "lightness" are percentages,
3577 // "opacity" is a number.
3579 if (ParseHSLColor(rgba
, ',') &&
3580 ParseColorOpacity(a
)) {
3581 aValue
.SetColorValue(NS_RGBA(NS_GET_R(rgba
), NS_GET_G(rgba
),
3582 NS_GET_B(rgba
), a
));
3592 // try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)
3593 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) {
3594 // - If the string starts with 'a-f', the nsCSSScanner builds the
3595 // token as a eCSSToken_Ident and we can parse the string as a
3596 // 'xxyyzz' RGB color.
3597 // - If it only contains '0-9' digits, the token is a
3598 // eCSSToken_Number and it must be converted back to a 6
3599 // characters string to be parsed as a RGB color.
3600 // - If it starts with '0-9' and contains any 'a-f', the token is a
3601 // eCSSToken_Dimension, the mNumber part must be converted back to
3602 // a string and the mIdent part must be appended to that string so
3603 // that the resulting string has 6 characters.
3604 // Note: This is a hack for Nav compatibility. Do not attempt to
3605 // simplify it by hacking into the ncCSSScanner. This would be very
3609 switch (tk
->mType
) {
3610 case eCSSToken_Ident
:
3611 str
.Assign(tk
->mIdent
);
3614 case eCSSToken_Number
:
3615 if (tk
->mIntegerValid
) {
3616 PR_snprintf(buffer
, sizeof(buffer
), "%06d", tk
->mInteger
);
3617 str
.AssignWithConversion(buffer
);
3621 case eCSSToken_Dimension
:
3622 if (tk
->mIdent
.Length() <= 6) {
3623 PR_snprintf(buffer
, sizeof(buffer
), "%06.0f", tk
->mNumber
);
3625 temp
.AssignWithConversion(buffer
);
3626 temp
.Right(str
, 6 - tk
->mIdent
.Length());
3627 str
.Append(tk
->mIdent
);
3631 // There is a whole bunch of cases that are
3632 // not handled by this switch. Ignore them.
3635 if (NS_HexToRGB(str
, &rgba
)) {
3636 aValue
.SetColorValue(rgba
);
3642 REPORT_UNEXPECTED_TOKEN(PEColorNotColor
);
3647 // aType will be set if we have already parsed other color components
3648 // in this color spec
3650 CSSParserImpl::ParseColorComponent(PRUint8
& aComponent
,
3654 if (!GetToken(PR_TRUE
)) {
3655 REPORT_UNEXPECTED_EOF(PEColorComponentEOF
);
3659 nsCSSToken
* tk
= &mToken
;
3660 switch (tk
->mType
) {
3661 case eCSSToken_Number
:
3663 case COLOR_TYPE_UNKNOWN
:
3664 aType
= COLOR_TYPE_INTEGERS
;
3666 case COLOR_TYPE_INTEGERS
:
3668 case COLOR_TYPE_PERCENTAGES
:
3669 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3673 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3676 if (!mToken
.mIntegerValid
) {
3677 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3681 value
= tk
->mNumber
;
3683 case eCSSToken_Percentage
:
3685 case COLOR_TYPE_UNKNOWN
:
3686 aType
= COLOR_TYPE_PERCENTAGES
;
3688 case COLOR_TYPE_INTEGERS
:
3689 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3692 case COLOR_TYPE_PERCENTAGES
:
3695 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3697 value
= tk
->mNumber
* 255.0f
;
3700 REPORT_UNEXPECTED_TOKEN(PEColorBadRGBContents
);
3704 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3705 if (value
< 0.0f
) value
= 0.0f
;
3706 if (value
> 255.0f
) value
= 255.0f
;
3707 aComponent
= NSToIntRound(value
);
3710 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3711 const PRUnichar
*params
[] = {
3715 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3721 CSSParserImpl::ParseHSLColor(nscolor
& aColor
,
3725 if (!ExpectSymbol('(', PR_FALSE
)) {
3726 NS_ERROR("How did this get to be a function token?");
3731 if (!GetToken(PR_TRUE
)) {
3732 REPORT_UNEXPECTED_EOF(PEColorHueEOF
);
3735 if (mToken
.mType
!= eCSSToken_Number
) {
3736 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3742 // hue values are wraparound
3745 if (!ExpectSymbol(',', PR_TRUE
)) {
3746 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3750 // Get the saturation
3751 if (!GetToken(PR_TRUE
)) {
3752 REPORT_UNEXPECTED_EOF(PEColorSaturationEOF
);
3755 if (mToken
.mType
!= eCSSToken_Percentage
) {
3756 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3761 if (s
< 0.0f
) s
= 0.0f
;
3762 if (s
> 1.0f
) s
= 1.0f
;
3764 if (!ExpectSymbol(',', PR_TRUE
)) {
3765 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3769 // Get the lightness
3770 if (!GetToken(PR_TRUE
)) {
3771 REPORT_UNEXPECTED_EOF(PEColorLightnessEOF
);
3774 if (mToken
.mType
!= eCSSToken_Percentage
) {
3775 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3780 if (l
< 0.0f
) l
= 0.0f
;
3781 if (l
> 1.0f
) l
= 1.0f
;
3783 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3784 aColor
= NS_HSL2RGB(h
, s
, l
);
3788 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3789 const PRUnichar
*params
[] = {
3793 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3799 CSSParserImpl::ParseColorOpacity(PRUint8
& aOpacity
)
3801 if (!GetToken(PR_TRUE
)) {
3802 REPORT_UNEXPECTED_EOF(PEColorOpacityEOF
);
3806 if (mToken
.mType
!= eCSSToken_Number
) {
3807 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3812 if (mToken
.mNumber
< 0.0f
) {
3813 mToken
.mNumber
= 0.0f
;
3814 } else if (mToken
.mNumber
> 1.0f
) {
3815 mToken
.mNumber
= 1.0f
;
3818 PRUint8 value
= nsStyleUtil::FloatToColorComponent(mToken
.mNumber
);
3819 NS_ASSERTION(fabs(mToken
.mNumber
- value
/255.0f
) <= 0.5f
,
3820 "FloatToColorComponent did something weird");
3822 if (!ExpectSymbol(')', PR_TRUE
)) {
3823 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
3834 CSSParserImpl::ParseTreePseudoElement(nsCSSSelector
& aSelector
)
3836 if (ExpectSymbol('(', PR_FALSE
)) {
3837 while (!ExpectSymbol(')', PR_TRUE
)) {
3838 if (!GetToken(PR_TRUE
)) {
3841 else if (eCSSToken_Ident
== mToken
.mType
) {
3842 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(mToken
.mIdent
);
3843 aSelector
.AddPseudoClass(pseudo
);
3845 else if (eCSSToken_Symbol
== mToken
.mType
) {
3846 if (!mToken
.IsSymbol(','))
3849 else return PR_FALSE
;
3857 //----------------------------------------------------------------------
3860 CSSParserImpl::ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
3861 PRBool aCheckForBraces
,
3862 PRBool aMustCallValueAppended
,
3865 mTempData
.AssertInitialState();
3867 // Get property name
3868 nsCSSToken
* tk
= &mToken
;
3869 nsAutoString propertyName
;
3871 if (!GetToken(PR_TRUE
)) {
3872 if (aCheckForBraces
) {
3873 REPORT_UNEXPECTED_EOF(PEDeclEndEOF
);
3877 if (eCSSToken_Ident
== tk
->mType
) {
3878 propertyName
= tk
->mIdent
;
3879 // grab the ident before the ExpectSymbol trashes the token
3880 if (!ExpectSymbol(':', PR_TRUE
)) {
3881 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
3882 REPORT_UNEXPECTED(PEDeclDropped
);
3888 if (tk
->IsSymbol(';')) {
3889 // dangling semicolons are skipped
3893 if (!tk
->IsSymbol('}')) {
3894 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected
);
3895 REPORT_UNEXPECTED(PEDeclSkipped
);
3898 // Not a declaration...
3903 // Map property name to its ID and then parse the property
3904 nsCSSProperty propID
= nsCSSProps::LookupProperty(propertyName
);
3905 if (eCSSProperty_UNKNOWN
== propID
) { // unknown property
3906 if (!NonMozillaVendorIdentifier(propertyName
)) {
3907 const PRUnichar
*params
[] = {
3910 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
3911 REPORT_UNEXPECTED(PEDeclDropped
);
3917 if (! ParseProperty(propID
)) {
3918 // XXX Much better to put stuff in the value parsers instead...
3919 const PRUnichar
*params
[] = {
3922 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
3923 REPORT_UNEXPECTED(PEDeclDropped
);
3925 ClearTempData(propID
);
3930 // See if the declaration is followed by a "!important" declaration
3931 PRBool isImportant
= PR_FALSE
;
3932 if (!GetToken(PR_TRUE
)) {
3933 // EOF is a perfectly good way to end a declaration and declaration block
3934 TransferTempData(aDeclaration
, propID
, isImportant
,
3935 aMustCallValueAppended
, aChanged
);
3939 if (eCSSToken_Symbol
== tk
->mType
&& '!' == tk
->mSymbol
) {
3940 // Look for important ident
3941 if (!GetToken(PR_TRUE
)) {
3942 // Premature eof is not ok
3943 REPORT_UNEXPECTED_EOF(PEImportantEOF
);
3944 ClearTempData(propID
);
3947 if ((eCSSToken_Ident
!= tk
->mType
) ||
3948 !tk
->mIdent
.LowerCaseEqualsLiteral("important")) {
3949 REPORT_UNEXPECTED_TOKEN(PEExpectedImportant
);
3952 ClearTempData(propID
);
3955 isImportant
= PR_TRUE
;
3958 // Not a !important declaration
3962 // Make sure valid property declaration is terminated with either a
3963 // semicolon, EOF or a right-curly-brace (this last only when
3964 // aCheckForBraces is true).
3965 if (!GetToken(PR_TRUE
)) {
3966 // EOF is a perfectly good way to end a declaration and declaration block
3967 TransferTempData(aDeclaration
, propID
, isImportant
,
3968 aMustCallValueAppended
, aChanged
);
3971 if (eCSSToken_Symbol
== tk
->mType
) {
3972 if (';' == tk
->mSymbol
) {
3973 TransferTempData(aDeclaration
, propID
, isImportant
,
3974 aMustCallValueAppended
, aChanged
);
3977 if (aCheckForBraces
&& '}' == tk
->mSymbol
) {
3978 // Unget the '}' so we'll be able to tell that this is the end
3979 // of the declaration block when we unwind from here.
3981 TransferTempData(aDeclaration
, propID
, isImportant
,
3982 aMustCallValueAppended
, aChanged
);
3986 if (aCheckForBraces
)
3987 REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2
);
3989 REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd
);
3990 REPORT_UNEXPECTED(PEDeclDropped
);
3992 ClearTempData(propID
);
3997 CSSParserImpl::ClearTempData(nsCSSProperty aPropID
)
3999 if (nsCSSProps::IsShorthand(aPropID
)) {
4000 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
4001 mTempData
.ClearProperty(*p
);
4004 mTempData
.ClearProperty(aPropID
);
4006 mTempData
.AssertInitialState();
4010 CSSParserImpl::TransferTempData(nsCSSDeclaration
* aDeclaration
,
4011 nsCSSProperty aPropID
, PRBool aIsImportant
,
4012 PRBool aMustCallValueAppended
,
4015 if (nsCSSProps::IsShorthand(aPropID
)) {
4016 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
4017 DoTransferTempData(aDeclaration
, *p
, aIsImportant
,
4018 aMustCallValueAppended
, aChanged
);
4021 DoTransferTempData(aDeclaration
, aPropID
, aIsImportant
,
4022 aMustCallValueAppended
, aChanged
);
4024 mTempData
.AssertInitialState();
4027 // Perhaps the transferring code should be in nsCSSExpandedDataBlock, in
4028 // case some other caller wants to use it in the future (although I
4029 // can't think of why).
4031 CSSParserImpl::DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
4032 nsCSSProperty aPropID
, PRBool aIsImportant
,
4033 PRBool aMustCallValueAppended
,
4036 NS_ASSERTION(mTempData
.HasPropertyBit(aPropID
), "oops");
4038 if (!mData
.HasImportantBit(aPropID
))
4039 *aChanged
= PR_TRUE
;
4040 mData
.SetImportantBit(aPropID
);
4042 if (mData
.HasImportantBit(aPropID
)) {
4043 mTempData
.ClearProperty(aPropID
);
4048 if (aMustCallValueAppended
|| !mData
.HasPropertyBit(aPropID
)) {
4049 aDeclaration
->ValueAppended(aPropID
);
4052 mData
.SetPropertyBit(aPropID
);
4053 mTempData
.ClearPropertyBit(aPropID
);
4056 * Save needless copying and allocation by calling the destructor in
4057 * the destination, copying memory directly, and then using placement
4060 void *v_source
= mTempData
.PropertyAt(aPropID
);
4061 void *v_dest
= mData
.PropertyAt(aPropID
);
4062 switch (nsCSSProps::kTypeTable
[aPropID
]) {
4063 case eCSSType_Value
: {
4064 nsCSSValue
*source
= static_cast<nsCSSValue
*>(v_source
);
4065 nsCSSValue
*dest
= static_cast<nsCSSValue
*>(v_dest
);
4066 if (*source
!= *dest
)
4067 *aChanged
= PR_TRUE
;
4068 dest
->~nsCSSValue();
4069 memcpy(dest
, source
, sizeof(nsCSSValue
));
4070 new (source
) nsCSSValue();
4073 case eCSSType_Rect
: {
4074 nsCSSRect
*source
= static_cast<nsCSSRect
*>(v_source
);
4075 nsCSSRect
*dest
= static_cast<nsCSSRect
*>(v_dest
);
4076 if (*source
!= *dest
)
4077 *aChanged
= PR_TRUE
;
4079 memcpy(dest
, source
, sizeof(nsCSSRect
));
4080 new (source
) nsCSSRect();
4083 case eCSSType_ValuePair
: {
4084 nsCSSValuePair
*source
= static_cast<nsCSSValuePair
*>(v_source
);
4085 nsCSSValuePair
*dest
= static_cast<nsCSSValuePair
*>(v_dest
);
4086 if (*source
!= *dest
)
4087 *aChanged
= PR_TRUE
;
4088 dest
->~nsCSSValuePair();
4089 memcpy(dest
, source
, sizeof(nsCSSValuePair
));
4090 new (source
) nsCSSValuePair();
4093 case eCSSType_ValueList
: {
4094 nsCSSValueList
**source
= static_cast<nsCSSValueList
**>(v_source
);
4095 nsCSSValueList
**dest
= static_cast<nsCSSValueList
**>(v_dest
);
4096 if (!nsCSSValueList::Equal(*source
, *dest
))
4097 *aChanged
= PR_TRUE
;
4103 case eCSSType_ValuePairList
: {
4104 nsCSSValuePairList
**source
=
4105 static_cast<nsCSSValuePairList
**>(v_source
);
4106 nsCSSValuePairList
**dest
=
4107 static_cast<nsCSSValuePairList
**>(v_dest
);
4108 if (!nsCSSValuePairList::Equal(*source
, *dest
))
4109 *aChanged
= PR_TRUE
;
4117 static const nsCSSProperty kBorderTopIDs
[] = {
4118 eCSSProperty_border_top_width
,
4119 eCSSProperty_border_top_style
,
4120 eCSSProperty_border_top_color
4122 static const nsCSSProperty kBorderRightIDs
[] = {
4123 eCSSProperty_border_right_width_value
,
4124 eCSSProperty_border_right_style_value
,
4125 eCSSProperty_border_right_color_value
,
4126 eCSSProperty_border_right_width
,
4127 eCSSProperty_border_right_style
,
4128 eCSSProperty_border_right_color
4130 static const nsCSSProperty kBorderBottomIDs
[] = {
4131 eCSSProperty_border_bottom_width
,
4132 eCSSProperty_border_bottom_style
,
4133 eCSSProperty_border_bottom_color
4135 static const nsCSSProperty kBorderLeftIDs
[] = {
4136 eCSSProperty_border_left_width_value
,
4137 eCSSProperty_border_left_style_value
,
4138 eCSSProperty_border_left_color_value
,
4139 eCSSProperty_border_left_width
,
4140 eCSSProperty_border_left_style
,
4141 eCSSProperty_border_left_color
4143 static const nsCSSProperty kBorderStartIDs
[] = {
4144 eCSSProperty_border_start_width_value
,
4145 eCSSProperty_border_start_style_value
,
4146 eCSSProperty_border_start_color_value
,
4147 eCSSProperty_border_start_width
,
4148 eCSSProperty_border_start_style
,
4149 eCSSProperty_border_start_color
4151 static const nsCSSProperty kBorderEndIDs
[] = {
4152 eCSSProperty_border_end_width_value
,
4153 eCSSProperty_border_end_style_value
,
4154 eCSSProperty_border_end_color_value
,
4155 eCSSProperty_border_end_width
,
4156 eCSSProperty_border_end_style
,
4157 eCSSProperty_border_end_color
4159 static const nsCSSProperty kColumnRuleIDs
[] = {
4160 eCSSProperty__moz_column_rule_width
,
4161 eCSSProperty__moz_column_rule_style
,
4162 eCSSProperty__moz_column_rule_color
4166 CSSParserImpl::ParseEnum(nsCSSValue
& aValue
,
4167 const PRInt32 aKeywordTable
[])
4169 nsSubstring
* ident
= NextIdent();
4170 if (nsnull
== ident
) {
4173 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(*ident
);
4174 if (eCSSKeyword_UNKNOWN
< keyword
) {
4176 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4177 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4182 // Put the unknown identifier back and return
4189 char name
[5]; // needs to be long enough for the longest unit, with
4190 // terminating null.
4196 #define STR_WITH_LEN(_str) \
4197 _str, sizeof(_str) - 1
4199 const UnitInfo UnitData
[] = {
4200 { STR_WITH_LEN("px"), eCSSUnit_Pixel
, VARIANT_LENGTH
},
4201 { STR_WITH_LEN("em"), eCSSUnit_EM
, VARIANT_LENGTH
},
4202 { STR_WITH_LEN("ex"), eCSSUnit_XHeight
, VARIANT_LENGTH
},
4203 { STR_WITH_LEN("pt"), eCSSUnit_Point
, VARIANT_LENGTH
},
4204 { STR_WITH_LEN("in"), eCSSUnit_Inch
, VARIANT_LENGTH
},
4205 { STR_WITH_LEN("cm"), eCSSUnit_Centimeter
, VARIANT_LENGTH
},
4206 { STR_WITH_LEN("ch"), eCSSUnit_Char
, VARIANT_LENGTH
},
4207 { STR_WITH_LEN("mm"), eCSSUnit_Millimeter
, VARIANT_LENGTH
},
4208 { STR_WITH_LEN("pc"), eCSSUnit_Pica
, VARIANT_LENGTH
},
4209 { STR_WITH_LEN("deg"), eCSSUnit_Degree
, VARIANT_ANGLE
},
4210 { STR_WITH_LEN("grad"), eCSSUnit_Grad
, VARIANT_ANGLE
},
4211 { STR_WITH_LEN("rad"), eCSSUnit_Radian
, VARIANT_ANGLE
},
4212 { STR_WITH_LEN("hz"), eCSSUnit_Hertz
, VARIANT_FREQUENCY
},
4213 { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz
, VARIANT_FREQUENCY
},
4214 { STR_WITH_LEN("s"), eCSSUnit_Seconds
, VARIANT_TIME
},
4215 { STR_WITH_LEN("ms"), eCSSUnit_Milliseconds
, VARIANT_TIME
}
4221 CSSParserImpl::TranslateDimension(nsCSSValue
& aValue
,
4222 PRInt32 aVariantMask
,
4224 const nsString
& aUnit
)
4228 if (!aUnit
.IsEmpty()) {
4230 for (i
= 0; i
< NS_ARRAY_LENGTH(UnitData
); ++i
) {
4231 if (aUnit
.LowerCaseEqualsASCII(UnitData
[i
].name
,
4232 UnitData
[i
].length
)) {
4233 units
= UnitData
[i
].unit
;
4234 type
= UnitData
[i
].type
;
4239 if (i
== NS_ARRAY_LENGTH(UnitData
)) {
4244 // Must be a zero number...
4245 NS_ASSERTION(0 == aNumber
, "numbers without units must be 0");
4246 if ((VARIANT_LENGTH
& aVariantMask
) != 0) {
4247 units
= eCSSUnit_Point
;
4248 type
= VARIANT_LENGTH
;
4250 else if ((VARIANT_ANGLE
& aVariantMask
) != 0) {
4251 units
= eCSSUnit_Degree
;
4252 type
= VARIANT_ANGLE
;
4254 else if ((VARIANT_FREQUENCY
& aVariantMask
) != 0) {
4255 units
= eCSSUnit_Hertz
;
4256 type
= VARIANT_FREQUENCY
;
4258 else if ((VARIANT_TIME
& aVariantMask
) != 0) {
4259 units
= eCSSUnit_Seconds
;
4260 type
= VARIANT_TIME
;
4263 NS_ERROR("Variant mask does not include dimension; why were we called?");
4267 if ((type
& aVariantMask
) != 0) {
4268 aValue
.SetFloatValue(aNumber
, units
);
4275 CSSParserImpl::ParsePositiveVariant(nsCSSValue
& aValue
,
4276 PRInt32 aVariantMask
,
4277 const PRInt32 aKeywordTable
[])
4279 if (ParseVariant(aValue
, aVariantMask
, aKeywordTable
)) {
4280 if (eCSSUnit_Number
== aValue
.GetUnit() ||
4281 aValue
.IsLengthUnit()){
4282 if (aValue
.GetFloatValue() < 0) {
4287 else if (aValue
.GetUnit() == eCSSUnit_Percent
) {
4288 if (aValue
.GetPercentValue() < 0) {
4292 } else if (aValue
.GetUnit() == eCSSUnit_Integer
) {
4293 if (aValue
.GetIntValue() < 0) {
4303 // Assigns to aValue iff it returns PR_TRUE.
4305 CSSParserImpl::ParseVariant(nsCSSValue
& aValue
,
4306 PRInt32 aVariantMask
,
4307 const PRInt32 aKeywordTable
[])
4309 NS_ASSERTION(IsParsingCompoundProperty() ||
4310 ((~aVariantMask
) & (VARIANT_LENGTH
|VARIANT_COLOR
)),
4311 "cannot distinguish lengths and colors in quirks mode");
4313 if (!GetToken(PR_TRUE
)) {
4316 nsCSSToken
* tk
= &mToken
;
4317 if (((aVariantMask
& (VARIANT_AHK
| VARIANT_NORMAL
| VARIANT_NONE
)) != 0) &&
4318 (eCSSToken_Ident
== tk
->mType
)) {
4319 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
4320 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
4321 if ((aVariantMask
& VARIANT_AUTO
) != 0) {
4322 if (eCSSKeyword_auto
== keyword
) {
4323 aValue
.SetAutoValue();
4327 if ((aVariantMask
& VARIANT_INHERIT
) != 0) {
4328 // XXX Should we check IsParsingCompoundProperty, or do all
4329 // callers handle it? (Not all callers set it, though, since
4330 // they want the quirks that are disabled by setting it.)
4331 if (eCSSKeyword_inherit
== keyword
) {
4332 aValue
.SetInheritValue();
4335 else if (eCSSKeyword__moz_initial
== keyword
) { // anything that can inherit can also take an initial val.
4336 aValue
.SetInitialValue();
4340 if ((aVariantMask
& VARIANT_NONE
) != 0) {
4341 if (eCSSKeyword_none
== keyword
) {
4342 aValue
.SetNoneValue();
4346 if ((aVariantMask
& VARIANT_NORMAL
) != 0) {
4347 if (eCSSKeyword_normal
== keyword
) {
4348 aValue
.SetNormalValue();
4352 if ((aVariantMask
& VARIANT_SYSFONT
) != 0) {
4353 if (eCSSKeyword__moz_use_system_font
== keyword
&&
4354 !IsParsingCompoundProperty()) {
4355 aValue
.SetSystemFontValue();
4359 if ((aVariantMask
& VARIANT_KEYWORD
) != 0) {
4361 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4362 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4368 if (((aVariantMask
& (VARIANT_LENGTH
| VARIANT_ANGLE
| VARIANT_FREQUENCY
| VARIANT_TIME
)) != 0) &&
4369 tk
->IsDimension()) {
4370 if (TranslateDimension(aValue
, aVariantMask
, tk
->mNumber
, tk
->mIdent
)) {
4373 // Put the token back; we didn't parse it, so we shouldn't consume it
4377 if (((aVariantMask
& VARIANT_PERCENT
) != 0) &&
4378 (eCSSToken_Percentage
== tk
->mType
)) {
4379 aValue
.SetPercentValue(tk
->mNumber
);
4382 if (((aVariantMask
& VARIANT_NUMBER
) != 0) &&
4383 (eCSSToken_Number
== tk
->mType
)) {
4384 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Number
);
4387 if (((aVariantMask
& VARIANT_INTEGER
) != 0) &&
4388 (eCSSToken_Number
== tk
->mType
) && tk
->mIntegerValid
) {
4389 aValue
.SetIntValue(tk
->mInteger
, eCSSUnit_Integer
);
4392 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) { // NONSTANDARD: Nav interprets unitless numbers as px
4393 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4394 (eCSSToken_Number
== tk
->mType
)) {
4395 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4401 if (IsSVGMode() && !IsParsingCompoundProperty()) {
4402 // STANDARD: SVG Spec states that lengths and coordinates can be unitless
4403 // in which case they default to user-units (1 px = 1 user unit)
4404 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4405 (eCSSToken_Number
== tk
->mType
)) {
4406 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4412 if (((aVariantMask
& VARIANT_URL
) != 0) &&
4413 (eCSSToken_Function
== tk
->mType
) &&
4414 tk
->mIdent
.LowerCaseEqualsLiteral("url")) {
4415 if (ParseURL(aValue
)) {
4420 if ((aVariantMask
& VARIANT_COLOR
) != 0) {
4421 if ((mNavQuirkMode
&& !IsParsingCompoundProperty()) || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
4422 (eCSSToken_ID
== tk
->mType
) ||
4423 (eCSSToken_Ref
== tk
->mType
) ||
4424 (eCSSToken_Ident
== tk
->mType
) ||
4425 ((eCSSToken_Function
== tk
->mType
) &&
4426 (tk
->mIdent
.LowerCaseEqualsLiteral("rgb") ||
4427 tk
->mIdent
.LowerCaseEqualsLiteral("hsl") ||
4428 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
4429 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
4430 tk
->mIdent
.LowerCaseEqualsLiteral("rgba") ||
4431 tk
->mIdent
.LowerCaseEqualsLiteral("hsla"))))
4433 // Put token back so that parse color can get it
4435 if (ParseColor(aValue
)) {
4441 if (((aVariantMask
& VARIANT_STRING
) != 0) &&
4442 (eCSSToken_String
== tk
->mType
)) {
4443 nsAutoString buffer
;
4444 buffer
.Append(tk
->mSymbol
);
4445 buffer
.Append(tk
->mIdent
);
4446 buffer
.Append(tk
->mSymbol
);
4447 aValue
.SetStringValue(buffer
, eCSSUnit_String
);
4450 if (((aVariantMask
& VARIANT_IDENTIFIER
) != 0) &&
4451 (eCSSToken_Ident
== tk
->mType
)) {
4452 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
4455 if (((aVariantMask
& VARIANT_COUNTER
) != 0) &&
4456 (eCSSToken_Function
== tk
->mType
) &&
4457 (tk
->mIdent
.LowerCaseEqualsLiteral("counter") ||
4458 tk
->mIdent
.LowerCaseEqualsLiteral("counters"))) {
4459 return ParseCounter(aValue
);
4461 if (((aVariantMask
& VARIANT_ATTR
) != 0) &&
4462 (eCSSToken_Function
== tk
->mType
) &&
4463 tk
->mIdent
.LowerCaseEqualsLiteral("attr")) {
4464 return ParseAttr(aValue
);
4473 CSSParserImpl::ParseCounter(nsCSSValue
& aValue
)
4475 nsCSSUnit unit
= (mToken
.mIdent
.LowerCaseEqualsLiteral("counter") ?
4476 eCSSUnit_Counter
: eCSSUnit_Counters
);
4478 if (!ExpectSymbol('(', PR_FALSE
))
4481 if (!GetNonCloseParenToken(PR_TRUE
) ||
4482 eCSSToken_Ident
!= mToken
.mType
) {
4487 nsRefPtr
<nsCSSValue::Array
> val
=
4488 nsCSSValue::Array::Create(unit
== eCSSUnit_Counter
? 2 : 3);
4490 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4494 val
->Item(0).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4496 if (eCSSUnit_Counters
== unit
) {
4497 // get mandatory separator string
4498 if (!ExpectSymbol(',', PR_TRUE
) ||
4499 !(GetNonCloseParenToken(PR_TRUE
) &&
4500 eCSSToken_String
== mToken
.mType
)) {
4504 val
->Item(1).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4507 // get optional type
4508 PRInt32 type
= NS_STYLE_LIST_STYLE_DECIMAL
;
4509 if (ExpectSymbol(',', PR_TRUE
)) {
4510 nsCSSKeyword keyword
;
4511 PRBool success
= GetNonCloseParenToken(PR_TRUE
) &&
4512 eCSSToken_Ident
== mToken
.mType
&&
4513 (keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
)) !=
4514 eCSSKeyword_UNKNOWN
;
4516 if (keyword
== eCSSKeyword_none
) {
4517 type
= NS_STYLE_LIST_STYLE_NONE
;
4519 success
= nsCSSProps::FindKeyword(keyword
,
4520 nsCSSProps::kListStyleKTable
, type
);
4528 PRInt32 typeItem
= eCSSUnit_Counters
== unit
? 2 : 1;
4529 val
->Item(typeItem
).SetIntValue(type
, eCSSUnit_Enumerated
);
4531 if (!ExpectSymbol(')', PR_TRUE
)) {
4536 aValue
.SetArrayValue(val
, unit
);
4541 CSSParserImpl::ParseAttr(nsCSSValue
& aValue
)
4543 if (ExpectSymbol('(', PR_FALSE
)) {
4544 if (GetToken(PR_TRUE
)) {
4546 if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
4547 nsAutoString
holdIdent(mToken
.mIdent
);
4548 if (ExpectSymbol('|', PR_FALSE
)) { // namespace
4549 PRInt32 nameSpaceID
;
4550 if (!GetNamespaceIdForPrefix(holdIdent
, &nameSpaceID
)) {
4553 attr
.AppendInt(nameSpaceID
, 10);
4554 attr
.Append(PRUnichar('|'));
4555 if (! GetToken(PR_FALSE
)) {
4556 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4559 if (eCSSToken_Ident
== mToken
.mType
) {
4560 if (mCaseSensitive
) {
4561 attr
.Append(mToken
.mIdent
);
4563 nsAutoString buffer
;
4564 ToLowerCase(mToken
.mIdent
, buffer
);
4565 attr
.Append(buffer
);
4569 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4574 else { // no namespace
4575 if (mCaseSensitive
) {
4579 ToLowerCase(holdIdent
, attr
);
4583 else if (mToken
.IsSymbol('*')) { // namespace wildcard
4584 // Wildcard namespace makes no sense here and is not allowed
4585 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4589 else if (mToken
.IsSymbol('|')) { // explicit NO namespace
4590 if (! GetToken(PR_FALSE
)) {
4591 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4594 if (eCSSToken_Ident
== mToken
.mType
) {
4595 if (mCaseSensitive
) {
4596 attr
.Append(mToken
.mIdent
);
4598 nsAutoString buffer
;
4599 ToLowerCase(mToken
.mIdent
, buffer
);
4600 attr
.Append(buffer
);
4604 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4610 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
4614 if (ExpectSymbol(')', PR_TRUE
)) {
4615 aValue
.SetStringValue(attr
, eCSSUnit_Attr
);
4624 CSSParserImpl::ParseURL(nsCSSValue
& aValue
)
4626 if (!mSheetPrincipal
) {
4627 NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
4628 "origin principal");
4632 if (!ExpectSymbol('(', PR_FALSE
))
4637 nsCSSToken
* tk
= &mToken
;
4638 if (eCSSToken_String
!= tk
->mType
&& eCSSToken_URL
!= tk
->mType
)
4641 nsString url
= tk
->mIdent
;
4642 if (!ExpectSymbol(')', PR_TRUE
))
4645 // Translate url into an absolute url if the url is relative to the
4647 nsCOMPtr
<nsIURI
> uri
;
4648 NS_NewURI(getter_AddRefs(uri
), url
, nsnull
, mBaseURL
);
4650 nsStringBuffer
* buffer
= nsCSSValue::BufferFromString(url
);
4651 if (NS_UNLIKELY(!buffer
)) {
4652 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4655 nsCSSValue::URL
*urlVal
=
4656 new nsCSSValue::URL(uri
, buffer
, mSheetURL
, mSheetPrincipal
);
4659 if (NS_UNLIKELY(!urlVal
)) {
4660 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4663 aValue
.SetURLValue(urlVal
);
4668 CSSParserImpl::ParseChoice(nsCSSValue aValues
[],
4669 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
)
4672 nsAutoParseCompoundProperty
compound(this);
4675 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4676 // Try each property parser in order
4677 PRInt32 hadFound
= found
;
4679 for (index
= 0; index
< aNumIDs
; index
++) {
4680 PRInt32 bit
= 1 << index
;
4681 if ((found
& bit
) == 0) {
4682 if (ParseSingleValueProperty(aValues
[index
], aPropIDs
[index
])) {
4687 if (found
== hadFound
) { // found nothing new
4692 if (1 == found
) { // only first property
4693 if (eCSSUnit_Inherit
== aValues
[0].GetUnit()) { // one inherit, all inherit
4694 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4695 aValues
[loop
].SetInheritValue();
4697 found
= ((1 << aNumIDs
) - 1);
4699 else if (eCSSUnit_Initial
== aValues
[0].GetUnit()) { // one initial, all initial
4700 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4701 aValues
[loop
].SetInitialValue();
4703 found
= ((1 << aNumIDs
) - 1);
4706 else { // more than one value, verify no inherits or initials
4707 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4708 if (eCSSUnit_Inherit
== aValues
[loop
].GetUnit()) {
4712 else if (eCSSUnit_Initial
== aValues
[loop
].GetUnit()) {
4723 CSSParserImpl::AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
)
4725 NS_ASSERTION(0 <= aPropID
&& aPropID
< eCSSProperty_COUNT_no_shorthands
,
4726 "property out of range");
4727 NS_ASSERTION(nsCSSProps::kTypeTable
[aPropID
] == eCSSType_Value
,
4728 nsPrintfCString(64, "type error (property=\'%s\')",
4729 nsCSSProps::GetStringValue(aPropID
).get()).get());
4730 nsCSSValue
& storage
=
4731 *static_cast<nsCSSValue
*>(mTempData
.PropertyAt(aPropID
));
4733 mTempData
.SetPropertyBit(aPropID
);
4737 * Parse a "box" property. Box properties have 1 to 4 values. When less
4738 * than 4 values are provided a standard mapping is used to replicate
4742 CSSParserImpl::ParseBoxProperties(nsCSSRect
& aResult
,
4743 const nsCSSProperty aPropIDs
[])
4745 // Get up to four values for the property
4748 NS_FOR_CSS_SIDES (index
) {
4749 if (! ParseSingleValueProperty(result
.*(nsCSSRect::sides
[index
]),
4755 if ((count
== 0) || (PR_FALSE
== ExpectEndProperty())) {
4759 if (1 < count
) { // verify no more than single inherit or initial
4760 NS_FOR_CSS_SIDES (index
) {
4761 nsCSSUnit unit
= (result
.*(nsCSSRect::sides
[index
])).GetUnit();
4762 if (eCSSUnit_Inherit
== unit
|| eCSSUnit_Initial
== unit
) {
4768 // Provide missing values by replicating some of the values found
4770 case 1: // Make right == top
4771 result
.mRight
= result
.mTop
;
4772 case 2: // Make bottom == top
4773 result
.mBottom
= result
.mTop
;
4774 case 3: // Make left == right
4775 result
.mLeft
= result
.mRight
;
4778 NS_FOR_CSS_SIDES (index
) {
4779 mTempData
.SetPropertyBit(aPropIDs
[index
]);
4786 CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
4787 PRInt32 aSourceType
)
4789 const nsCSSProperty
* subprops
= nsCSSProps::SubpropertyEntryFor(aProperty
);
4790 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
4791 "not box property with physical vs. logical cascading");
4793 if (!ParseSingleValueProperty(value
, subprops
[0]) ||
4794 !ExpectEndProperty())
4797 AppendValue(subprops
[0], value
);
4798 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
4799 AppendValue(subprops
[1], typeVal
);
4800 AppendValue(subprops
[2], typeVal
);
4805 CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID
)
4807 nsCSSValue dimenX
, dimenY
;
4808 // required first value
4809 if (! ParsePositiveVariant(dimenX
, VARIANT_HLP
, nsnull
))
4811 // optional second value (forbidden if first value is inherit/initial)
4812 if (dimenX
.GetUnit() == eCSSUnit_Inherit
||
4813 dimenX
.GetUnit() == eCSSUnit_Initial
||
4814 ! ParsePositiveVariant(dimenY
, VARIANT_LP
, nsnull
))
4817 NS_ASSERTION(nsCSSProps::kTypeTable
[aPropID
] == eCSSType_ValuePair
,
4818 nsPrintfCString(64, "type error (property='%s')",
4819 nsCSSProps::GetStringValue(aPropID
).get())
4821 nsCSSValuePair
& storage
=
4822 *static_cast<nsCSSValuePair
*>(mTempData
.PropertyAt(aPropID
));
4823 storage
.mXValue
= dimenX
;
4824 storage
.mYValue
= dimenY
;
4825 mTempData
.SetPropertyBit(aPropID
);
4830 CSSParserImpl::ParseBoxCornerRadii(nsCSSCornerSizes
& aRadii
,
4831 const nsCSSProperty aPropIDs
[])
4833 // Rectangles are used as scratch storage.
4834 // top => top-left, right => top-right,
4835 // bottom => bottom-right, left => bottom-left.
4836 nsCSSRect dimenX
, dimenY
;
4837 PRInt32 countX
= 0, countY
= 0;
4839 NS_FOR_CSS_SIDES (side
) {
4840 if (! ParsePositiveVariant(dimenX
.*nsCSSRect::sides
[side
],
4841 side
> 0 ? VARIANT_LP
: VARIANT_HLP
, nsnull
))
4848 if (ExpectSymbol('/', PR_TRUE
)) {
4849 NS_FOR_CSS_SIDES (side
) {
4850 if (! ParsePositiveVariant(dimenY
.*nsCSSRect::sides
[side
],
4851 VARIANT_LP
, nsnull
))
4858 if (!ExpectEndProperty())
4861 // if 'initial' or 'inherit' was used, it must be the only value
4862 if (countX
> 1 || countY
> 0) {
4863 nsCSSUnit unit
= dimenX
.mTop
.GetUnit();
4864 if (eCSSUnit_Inherit
== unit
|| eCSSUnit_Initial
== unit
)
4868 // if we have no Y-values, use the X-values
4874 // Provide missing values by replicating some of the values found
4876 case 1: dimenX
.mRight
= dimenX
.mTop
; // top-right same as top-left, and
4877 case 2: dimenX
.mBottom
= dimenX
.mTop
; // bottom-right same as top-left, and
4878 case 3: dimenX
.mLeft
= dimenX
.mRight
; // bottom-left same as top-right
4882 case 1: dimenY
.mRight
= dimenY
.mTop
; // top-right same as top-left, and
4883 case 2: dimenY
.mBottom
= dimenY
.mTop
; // bottom-right same as top-left, and
4884 case 3: dimenY
.mLeft
= dimenY
.mRight
; // bottom-left same as top-right
4887 NS_FOR_CSS_SIDES(side
) {
4888 nsCSSValuePair
& corner
=
4889 aRadii
.GetFullCorner(NS_SIDE_TO_FULL_CORNER(side
, PR_FALSE
));
4890 corner
.mXValue
= dimenX
.*nsCSSRect::sides
[side
];
4891 corner
.mYValue
= dimenY
.*nsCSSRect::sides
[side
];
4892 mTempData
.SetPropertyBit(aPropIDs
[side
]);
4897 // These must be in CSS order (top,right,bottom,left) for indexing to work
4898 static const nsCSSProperty kBorderStyleIDs
[] = {
4899 eCSSProperty_border_top_style
,
4900 eCSSProperty_border_right_style_value
,
4901 eCSSProperty_border_bottom_style
,
4902 eCSSProperty_border_left_style_value
4904 static const nsCSSProperty kBorderWidthIDs
[] = {
4905 eCSSProperty_border_top_width
,
4906 eCSSProperty_border_right_width_value
,
4907 eCSSProperty_border_bottom_width
,
4908 eCSSProperty_border_left_width_value
4910 static const nsCSSProperty kBorderColorIDs
[] = {
4911 eCSSProperty_border_top_color
,
4912 eCSSProperty_border_right_color_value
,
4913 eCSSProperty_border_bottom_color
,
4914 eCSSProperty_border_left_color_value
4916 static const nsCSSProperty kBorderRadiusIDs
[] = {
4917 eCSSProperty__moz_border_radius_topLeft
,
4918 eCSSProperty__moz_border_radius_topRight
,
4919 eCSSProperty__moz_border_radius_bottomRight
,
4920 eCSSProperty__moz_border_radius_bottomLeft
4922 static const nsCSSProperty kOutlineRadiusIDs
[] = {
4923 eCSSProperty__moz_outline_radius_topLeft
,
4924 eCSSProperty__moz_outline_radius_topRight
,
4925 eCSSProperty__moz_outline_radius_bottomRight
,
4926 eCSSProperty__moz_outline_radius_bottomLeft
4930 CSSParserImpl::ParseProperty(nsCSSProperty aPropID
)
4932 NS_ASSERTION(aPropID
< eCSSProperty_COUNT
, "index out of range");
4934 switch (aPropID
) { // handle shorthand or multiple properties
4935 case eCSSProperty_background
:
4936 return ParseBackground();
4937 case eCSSProperty_background_position
:
4938 return ParseBackgroundPosition();
4939 case eCSSProperty_border
:
4940 return ParseBorderSide(kBorderTopIDs
, PR_TRUE
);
4941 case eCSSProperty_border_color
:
4942 return ParseBorderColor();
4943 case eCSSProperty_border_spacing
:
4944 return ParseBorderSpacing();
4945 case eCSSProperty_border_style
:
4946 return ParseBorderStyle();
4947 case eCSSProperty_border_bottom
:
4948 return ParseBorderSide(kBorderBottomIDs
, PR_FALSE
);
4949 case eCSSProperty_border_end
:
4950 return ParseDirectionalBorderSide(kBorderEndIDs
,
4951 NS_BOXPROP_SOURCE_LOGICAL
);
4952 case eCSSProperty_border_left
:
4953 return ParseDirectionalBorderSide(kBorderLeftIDs
,
4954 NS_BOXPROP_SOURCE_PHYSICAL
);
4955 case eCSSProperty_border_right
:
4956 return ParseDirectionalBorderSide(kBorderRightIDs
,
4957 NS_BOXPROP_SOURCE_PHYSICAL
);
4958 case eCSSProperty_border_start
:
4959 return ParseDirectionalBorderSide(kBorderStartIDs
,
4960 NS_BOXPROP_SOURCE_LOGICAL
);
4961 case eCSSProperty_border_top
:
4962 return ParseBorderSide(kBorderTopIDs
, PR_FALSE
);
4963 case eCSSProperty_border_bottom_colors
:
4964 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mBottom
,
4966 case eCSSProperty_border_left_colors
:
4967 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mLeft
,
4969 case eCSSProperty_border_right_colors
:
4970 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mRight
,
4972 case eCSSProperty_border_top_colors
:
4973 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mTop
,
4975 case eCSSProperty_border_image
:
4976 return ParseBorderImage();
4977 case eCSSProperty_border_width
:
4978 return ParseBorderWidth();
4979 case eCSSProperty_border_end_color
:
4980 return ParseDirectionalBoxProperty(eCSSProperty_border_end_color
,
4981 NS_BOXPROP_SOURCE_LOGICAL
);
4982 case eCSSProperty_border_left_color
:
4983 return ParseDirectionalBoxProperty(eCSSProperty_border_left_color
,
4984 NS_BOXPROP_SOURCE_PHYSICAL
);
4985 case eCSSProperty_border_right_color
:
4986 return ParseDirectionalBoxProperty(eCSSProperty_border_right_color
,
4987 NS_BOXPROP_SOURCE_PHYSICAL
);
4988 case eCSSProperty_border_start_color
:
4989 return ParseDirectionalBoxProperty(eCSSProperty_border_start_color
,
4990 NS_BOXPROP_SOURCE_LOGICAL
);
4991 case eCSSProperty_border_end_width
:
4992 return ParseDirectionalBoxProperty(eCSSProperty_border_end_width
,
4993 NS_BOXPROP_SOURCE_LOGICAL
);
4994 case eCSSProperty_border_left_width
:
4995 return ParseDirectionalBoxProperty(eCSSProperty_border_left_width
,
4996 NS_BOXPROP_SOURCE_PHYSICAL
);
4997 case eCSSProperty_border_right_width
:
4998 return ParseDirectionalBoxProperty(eCSSProperty_border_right_width
,
4999 NS_BOXPROP_SOURCE_PHYSICAL
);
5000 case eCSSProperty_border_start_width
:
5001 return ParseDirectionalBoxProperty(eCSSProperty_border_start_width
,
5002 NS_BOXPROP_SOURCE_LOGICAL
);
5003 case eCSSProperty_border_end_style
:
5004 return ParseDirectionalBoxProperty(eCSSProperty_border_end_style
,
5005 NS_BOXPROP_SOURCE_LOGICAL
);
5006 case eCSSProperty_border_left_style
:
5007 return ParseDirectionalBoxProperty(eCSSProperty_border_left_style
,
5008 NS_BOXPROP_SOURCE_PHYSICAL
);
5009 case eCSSProperty_border_right_style
:
5010 return ParseDirectionalBoxProperty(eCSSProperty_border_right_style
,
5011 NS_BOXPROP_SOURCE_PHYSICAL
);
5012 case eCSSProperty_border_start_style
:
5013 return ParseDirectionalBoxProperty(eCSSProperty_border_start_style
,
5014 NS_BOXPROP_SOURCE_LOGICAL
);
5015 case eCSSProperty__moz_border_radius
:
5016 return ParseBoxCornerRadii(mTempData
.mMargin
.mBorderRadius
,
5018 case eCSSProperty__moz_outline_radius
:
5019 return ParseBoxCornerRadii(mTempData
.mMargin
.mOutlineRadius
,
5022 case eCSSProperty__moz_border_radius_topLeft
:
5023 case eCSSProperty__moz_border_radius_topRight
:
5024 case eCSSProperty__moz_border_radius_bottomRight
:
5025 case eCSSProperty__moz_border_radius_bottomLeft
:
5026 case eCSSProperty__moz_outline_radius_topLeft
:
5027 case eCSSProperty__moz_outline_radius_topRight
:
5028 case eCSSProperty__moz_outline_radius_bottomRight
:
5029 case eCSSProperty__moz_outline_radius_bottomLeft
:
5030 return ParseBoxCornerRadius(aPropID
);
5032 case eCSSProperty_box_shadow
:
5033 return ParseBoxShadow();
5034 case eCSSProperty_clip
:
5035 return ParseRect(mTempData
.mDisplay
.mClip
, eCSSProperty_clip
);
5036 case eCSSProperty__moz_column_rule
:
5037 return ParseBorderSide(kColumnRuleIDs
, PR_FALSE
);
5038 case eCSSProperty_content
:
5039 return ParseContent();
5040 case eCSSProperty_counter_increment
:
5041 return ParseCounterData(&mTempData
.mContent
.mCounterIncrement
,
5043 case eCSSProperty_counter_reset
:
5044 return ParseCounterData(&mTempData
.mContent
.mCounterReset
,
5046 case eCSSProperty_cue
:
5048 case eCSSProperty_cursor
:
5049 return ParseCursor();
5050 case eCSSProperty_font
:
5052 case eCSSProperty_image_region
:
5053 return ParseRect(mTempData
.mList
.mImageRegion
,
5054 eCSSProperty_image_region
);
5055 case eCSSProperty_list_style
:
5056 return ParseListStyle();
5057 case eCSSProperty_margin
:
5058 return ParseMargin();
5059 case eCSSProperty_margin_end
:
5060 return ParseDirectionalBoxProperty(eCSSProperty_margin_end
,
5061 NS_BOXPROP_SOURCE_LOGICAL
);
5062 case eCSSProperty_margin_left
:
5063 return ParseDirectionalBoxProperty(eCSSProperty_margin_left
,
5064 NS_BOXPROP_SOURCE_PHYSICAL
);
5065 case eCSSProperty_margin_right
:
5066 return ParseDirectionalBoxProperty(eCSSProperty_margin_right
,
5067 NS_BOXPROP_SOURCE_PHYSICAL
);
5068 case eCSSProperty_margin_start
:
5069 return ParseDirectionalBoxProperty(eCSSProperty_margin_start
,
5070 NS_BOXPROP_SOURCE_LOGICAL
);
5071 case eCSSProperty_outline
:
5072 return ParseOutline();
5073 case eCSSProperty_overflow
:
5074 return ParseOverflow();
5075 case eCSSProperty_padding
:
5076 return ParsePadding();
5077 case eCSSProperty_padding_end
:
5078 return ParseDirectionalBoxProperty(eCSSProperty_padding_end
,
5079 NS_BOXPROP_SOURCE_LOGICAL
);
5080 case eCSSProperty_padding_left
:
5081 return ParseDirectionalBoxProperty(eCSSProperty_padding_left
,
5082 NS_BOXPROP_SOURCE_PHYSICAL
);
5083 case eCSSProperty_padding_right
:
5084 return ParseDirectionalBoxProperty(eCSSProperty_padding_right
,
5085 NS_BOXPROP_SOURCE_PHYSICAL
);
5086 case eCSSProperty_padding_start
:
5087 return ParseDirectionalBoxProperty(eCSSProperty_padding_start
,
5088 NS_BOXPROP_SOURCE_LOGICAL
);
5089 case eCSSProperty_pause
:
5090 return ParsePause();
5091 case eCSSProperty_quotes
:
5092 return ParseQuotes();
5093 case eCSSProperty_size
:
5095 case eCSSProperty_text_shadow
:
5096 return ParseTextShadow();
5097 case eCSSProperty__moz_transform
:
5098 return ParseMozTransform();
5099 case eCSSProperty__moz_transform_origin
:
5100 return ParseMozTransformOrigin();
5103 case eCSSProperty_fill
:
5104 return ParsePaint(&mTempData
.mSVG
.mFill
, eCSSProperty_fill
);
5105 case eCSSProperty_stroke
:
5106 return ParsePaint(&mTempData
.mSVG
.mStroke
, eCSSProperty_stroke
);
5107 case eCSSProperty_stroke_dasharray
:
5108 return ParseDasharray();
5109 case eCSSProperty_marker
:
5110 return ParseMarker();
5113 // Strip out properties we use internally.
5114 case eCSSProperty__x_system_font
:
5115 case eCSSProperty_margin_end_value
:
5116 case eCSSProperty_margin_left_value
:
5117 case eCSSProperty_margin_right_value
:
5118 case eCSSProperty_margin_start_value
:
5119 case eCSSProperty_margin_left_ltr_source
:
5120 case eCSSProperty_margin_left_rtl_source
:
5121 case eCSSProperty_margin_right_ltr_source
:
5122 case eCSSProperty_margin_right_rtl_source
:
5123 case eCSSProperty_padding_end_value
:
5124 case eCSSProperty_padding_left_value
:
5125 case eCSSProperty_padding_right_value
:
5126 case eCSSProperty_padding_start_value
:
5127 case eCSSProperty_padding_left_ltr_source
:
5128 case eCSSProperty_padding_left_rtl_source
:
5129 case eCSSProperty_padding_right_ltr_source
:
5130 case eCSSProperty_padding_right_rtl_source
:
5131 case eCSSProperty_border_end_color_value
:
5132 case eCSSProperty_border_left_color_value
:
5133 case eCSSProperty_border_right_color_value
:
5134 case eCSSProperty_border_start_color_value
:
5135 case eCSSProperty_border_left_color_ltr_source
:
5136 case eCSSProperty_border_left_color_rtl_source
:
5137 case eCSSProperty_border_right_color_ltr_source
:
5138 case eCSSProperty_border_right_color_rtl_source
:
5139 case eCSSProperty_border_end_style_value
:
5140 case eCSSProperty_border_left_style_value
:
5141 case eCSSProperty_border_right_style_value
:
5142 case eCSSProperty_border_start_style_value
:
5143 case eCSSProperty_border_left_style_ltr_source
:
5144 case eCSSProperty_border_left_style_rtl_source
:
5145 case eCSSProperty_border_right_style_ltr_source
:
5146 case eCSSProperty_border_right_style_rtl_source
:
5147 case eCSSProperty_border_end_width_value
:
5148 case eCSSProperty_border_left_width_value
:
5149 case eCSSProperty_border_right_width_value
:
5150 case eCSSProperty_border_start_width_value
:
5151 case eCSSProperty_border_left_width_ltr_source
:
5152 case eCSSProperty_border_left_width_rtl_source
:
5153 case eCSSProperty_border_right_width_ltr_source
:
5154 case eCSSProperty_border_right_width_rtl_source
:
5155 // The user can't use these
5156 REPORT_UNEXPECTED(PEInaccessibleProperty2
);
5158 default: // must be single property
5161 if (ParseSingleValueProperty(value
, aPropID
)) {
5162 if (ExpectEndProperty()) {
5163 AppendValue(aPropID
, value
);
5166 // XXX Report errors?
5168 // XXX Report errors?
5174 // Bits used in determining which background position info we have
5175 #define BG_CENTER NS_STYLE_BG_POSITION_CENTER
5176 #define BG_TOP NS_STYLE_BG_POSITION_TOP
5177 #define BG_BOTTOM NS_STYLE_BG_POSITION_BOTTOM
5178 #define BG_LEFT NS_STYLE_BG_POSITION_LEFT
5179 #define BG_RIGHT NS_STYLE_BG_POSITION_RIGHT
5180 #define BG_CTB (BG_CENTER | BG_TOP | BG_BOTTOM)
5181 #define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT)
5184 CSSParserImpl::ParseSingleValueProperty(nsCSSValue
& aValue
,
5185 nsCSSProperty aPropID
)
5188 case eCSSProperty_UNKNOWN
:
5189 case eCSSProperty_background
:
5190 case eCSSProperty_background_position
:
5191 case eCSSProperty_border
:
5192 case eCSSProperty_border_color
:
5193 case eCSSProperty_border_bottom_colors
:
5194 case eCSSProperty_border_image
:
5195 case eCSSProperty_border_left_colors
:
5196 case eCSSProperty_border_right_colors
:
5197 case eCSSProperty_border_end_color
:
5198 case eCSSProperty_border_left_color
:
5199 case eCSSProperty_border_right_color
:
5200 case eCSSProperty_border_start_color
:
5201 case eCSSProperty_border_end_style
:
5202 case eCSSProperty_border_left_style
:
5203 case eCSSProperty_border_right_style
:
5204 case eCSSProperty_border_start_style
:
5205 case eCSSProperty_border_end_width
:
5206 case eCSSProperty_border_left_width
:
5207 case eCSSProperty_border_right_width
:
5208 case eCSSProperty_border_start_width
:
5209 case eCSSProperty_border_top_colors
:
5210 case eCSSProperty_border_spacing
:
5211 case eCSSProperty_border_style
:
5212 case eCSSProperty_border_bottom
:
5213 case eCSSProperty_border_end
:
5214 case eCSSProperty_border_left
:
5215 case eCSSProperty_border_right
:
5216 case eCSSProperty_border_start
:
5217 case eCSSProperty_border_top
:
5218 case eCSSProperty_border_width
:
5219 case eCSSProperty__moz_border_radius
:
5220 case eCSSProperty__moz_border_radius_topLeft
:
5221 case eCSSProperty__moz_border_radius_topRight
:
5222 case eCSSProperty__moz_border_radius_bottomRight
:
5223 case eCSSProperty__moz_border_radius_bottomLeft
:
5224 case eCSSProperty_box_shadow
:
5225 case eCSSProperty_clip
:
5226 case eCSSProperty__moz_column_rule
:
5227 case eCSSProperty_content
:
5228 case eCSSProperty_counter_increment
:
5229 case eCSSProperty_counter_reset
:
5230 case eCSSProperty_cue
:
5231 case eCSSProperty_cursor
:
5232 case eCSSProperty_font
:
5233 case eCSSProperty_image_region
:
5234 case eCSSProperty_list_style
:
5235 case eCSSProperty_margin
:
5236 case eCSSProperty_margin_end
:
5237 case eCSSProperty_margin_left
:
5238 case eCSSProperty_margin_right
:
5239 case eCSSProperty_margin_start
:
5240 case eCSSProperty_outline
:
5241 case eCSSProperty__moz_outline_radius
:
5242 case eCSSProperty__moz_outline_radius_topLeft
:
5243 case eCSSProperty__moz_outline_radius_topRight
:
5244 case eCSSProperty__moz_outline_radius_bottomRight
:
5245 case eCSSProperty__moz_outline_radius_bottomLeft
:
5246 case eCSSProperty_overflow
:
5247 case eCSSProperty_padding
:
5248 case eCSSProperty_padding_end
:
5249 case eCSSProperty_padding_left
:
5250 case eCSSProperty_padding_right
:
5251 case eCSSProperty_padding_start
:
5252 case eCSSProperty_pause
:
5253 case eCSSProperty_quotes
:
5254 case eCSSProperty_size
:
5255 case eCSSProperty_text_shadow
:
5256 case eCSSProperty__moz_transform
:
5257 case eCSSProperty__moz_transform_origin
:
5258 case eCSSProperty_COUNT
:
5260 case eCSSProperty_fill
:
5261 case eCSSProperty_stroke
:
5262 case eCSSProperty_stroke_dasharray
:
5263 case eCSSProperty_marker
:
5265 NS_ERROR("not a single value property");
5268 case eCSSProperty__x_system_font
:
5269 case eCSSProperty_margin_left_ltr_source
:
5270 case eCSSProperty_margin_left_rtl_source
:
5271 case eCSSProperty_margin_right_ltr_source
:
5272 case eCSSProperty_margin_right_rtl_source
:
5273 case eCSSProperty_padding_left_ltr_source
:
5274 case eCSSProperty_padding_left_rtl_source
:
5275 case eCSSProperty_padding_right_ltr_source
:
5276 case eCSSProperty_padding_right_rtl_source
:
5277 case eCSSProperty_border_left_color_ltr_source
:
5278 case eCSSProperty_border_left_color_rtl_source
:
5279 case eCSSProperty_border_right_color_ltr_source
:
5280 case eCSSProperty_border_right_color_rtl_source
:
5281 case eCSSProperty_border_left_style_ltr_source
:
5282 case eCSSProperty_border_left_style_rtl_source
:
5283 case eCSSProperty_border_right_style_ltr_source
:
5284 case eCSSProperty_border_right_style_rtl_source
:
5285 case eCSSProperty_border_left_width_ltr_source
:
5286 case eCSSProperty_border_left_width_rtl_source
:
5287 case eCSSProperty_border_right_width_ltr_source
:
5288 case eCSSProperty_border_right_width_rtl_source
:
5290 case eCSSProperty_script_size_multiplier
:
5291 case eCSSProperty_script_min_size
:
5293 NS_ERROR("not currently parsed here");
5296 case eCSSProperty_appearance
:
5297 return ParseVariant(aValue
, VARIANT_HK
,
5298 nsCSSProps::kAppearanceKTable
);
5299 case eCSSProperty_azimuth
:
5300 return ParseAzimuth(aValue
);
5301 case eCSSProperty_background_attachment
:
5302 return ParseVariant(aValue
, VARIANT_HK
,
5303 nsCSSProps::kBackgroundAttachmentKTable
);
5304 case eCSSProperty__moz_background_clip
:
5305 return ParseVariant(aValue
, VARIANT_HK
,
5306 nsCSSProps::kBackgroundClipKTable
);
5307 case eCSSProperty_background_color
:
5308 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5309 case eCSSProperty_background_image
:
5310 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5311 case eCSSProperty__moz_background_inline_policy
:
5312 return ParseVariant(aValue
, VARIANT_HK
,
5313 nsCSSProps::kBackgroundInlinePolicyKTable
);
5314 case eCSSProperty__moz_background_origin
:
5315 return ParseVariant(aValue
, VARIANT_HK
,
5316 nsCSSProps::kBackgroundOriginKTable
);
5317 case eCSSProperty_background_repeat
:
5318 return ParseVariant(aValue
, VARIANT_HK
,
5319 nsCSSProps::kBackgroundRepeatKTable
);
5320 case eCSSProperty_binding
:
5321 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5322 case eCSSProperty_border_collapse
:
5323 return ParseVariant(aValue
, VARIANT_HK
,
5324 nsCSSProps::kBorderCollapseKTable
);
5325 case eCSSProperty_border_bottom_color
:
5326 case eCSSProperty_border_end_color_value
: // for internal use
5327 case eCSSProperty_border_left_color_value
: // for internal use
5328 case eCSSProperty_border_right_color_value
: // for internal use
5329 case eCSSProperty_border_start_color_value
: // for internal use
5330 case eCSSProperty_border_top_color
:
5331 case eCSSProperty__moz_column_rule_color
:
5332 return ParseVariant(aValue
, VARIANT_HCK
,
5333 nsCSSProps::kBorderColorKTable
);
5334 case eCSSProperty_border_bottom_style
:
5335 case eCSSProperty_border_end_style_value
: // for internal use
5336 case eCSSProperty_border_left_style_value
: // for internal use
5337 case eCSSProperty_border_right_style_value
: // for internal use
5338 case eCSSProperty_border_start_style_value
: // for internal use
5339 case eCSSProperty_border_top_style
:
5340 case eCSSProperty__moz_column_rule_style
:
5341 return ParseVariant(aValue
, VARIANT_HOK
,
5342 nsCSSProps::kBorderStyleKTable
);
5343 case eCSSProperty_border_bottom_width
:
5344 case eCSSProperty_border_end_width_value
: // for internal use
5345 case eCSSProperty_border_left_width_value
: // for internal use
5346 case eCSSProperty_border_right_width_value
: // for internal use
5347 case eCSSProperty_border_start_width_value
: // for internal use
5348 case eCSSProperty_border_top_width
:
5349 case eCSSProperty__moz_column_rule_width
:
5350 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5351 nsCSSProps::kBorderWidthKTable
);
5352 case eCSSProperty__moz_column_count
:
5353 return ParsePositiveVariant(aValue
, VARIANT_AHI
, nsnull
);
5354 case eCSSProperty__moz_column_width
:
5355 return ParsePositiveVariant(aValue
, VARIANT_AHL
, nsnull
);
5356 case eCSSProperty__moz_column_gap
:
5357 return ParsePositiveVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5358 case eCSSProperty_bottom
:
5359 case eCSSProperty_top
:
5360 case eCSSProperty_left
:
5361 case eCSSProperty_right
:
5362 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5363 case eCSSProperty_box_align
:
5364 return ParseVariant(aValue
, VARIANT_HK
,
5365 nsCSSProps::kBoxAlignKTable
);
5366 case eCSSProperty_box_direction
:
5367 return ParseVariant(aValue
, VARIANT_HK
,
5368 nsCSSProps::kBoxDirectionKTable
);
5369 case eCSSProperty_box_flex
:
5370 return ParsePositiveVariant(aValue
, VARIANT_HN
, nsnull
);
5371 case eCSSProperty_box_orient
:
5372 return ParseVariant(aValue
, VARIANT_HK
,
5373 nsCSSProps::kBoxOrientKTable
);
5374 case eCSSProperty_box_pack
:
5375 return ParseVariant(aValue
, VARIANT_HK
,
5376 nsCSSProps::kBoxPackKTable
);
5377 case eCSSProperty_box_ordinal_group
:
5378 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5380 case eCSSProperty_clip_path
:
5381 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5382 case eCSSProperty_clip_rule
:
5383 return ParseVariant(aValue
, VARIANT_HK
,
5384 nsCSSProps::kFillRuleKTable
);
5385 case eCSSProperty_color_interpolation
:
5386 case eCSSProperty_color_interpolation_filters
:
5387 return ParseVariant(aValue
, VARIANT_AHK
,
5388 nsCSSProps::kColorInterpolationKTable
);
5389 case eCSSProperty_dominant_baseline
:
5390 return ParseVariant(aValue
, VARIANT_AHK
,
5391 nsCSSProps::kDominantBaselineKTable
);
5392 case eCSSProperty_fill_opacity
:
5393 return ParseVariant(aValue
, VARIANT_HN
,
5395 case eCSSProperty_fill_rule
:
5396 return ParseVariant(aValue
, VARIANT_HK
,
5397 nsCSSProps::kFillRuleKTable
);
5398 case eCSSProperty_filter
:
5399 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5400 case eCSSProperty_flood_color
:
5401 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5402 case eCSSProperty_flood_opacity
:
5403 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5404 case eCSSProperty_lighting_color
:
5405 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5406 case eCSSProperty_marker_end
:
5407 case eCSSProperty_marker_mid
:
5408 case eCSSProperty_marker_start
:
5409 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5410 case eCSSProperty_mask
:
5411 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5412 case eCSSProperty_pointer_events
:
5413 return ParseVariant(aValue
, VARIANT_HOK
,
5414 nsCSSProps::kPointerEventsKTable
);
5415 case eCSSProperty_shape_rendering
:
5416 return ParseVariant(aValue
, VARIANT_AHK
,
5417 nsCSSProps::kShapeRenderingKTable
);
5418 case eCSSProperty_stop_color
:
5419 return ParseVariant(aValue
, VARIANT_HC
,
5421 case eCSSProperty_stop_opacity
:
5422 return ParseVariant(aValue
, VARIANT_HN
,
5424 case eCSSProperty_stroke_dashoffset
:
5425 return ParseVariant(aValue
, VARIANT_HLPN
,
5427 case eCSSProperty_stroke_linecap
:
5428 return ParseVariant(aValue
, VARIANT_HK
,
5429 nsCSSProps::kStrokeLinecapKTable
);
5430 case eCSSProperty_stroke_linejoin
:
5431 return ParseVariant(aValue
, VARIANT_HK
,
5432 nsCSSProps::kStrokeLinejoinKTable
);
5433 case eCSSProperty_stroke_miterlimit
:
5434 return ParsePositiveVariant(aValue
, VARIANT_HN
,
5436 case eCSSProperty_stroke_opacity
:
5437 return ParseVariant(aValue
, VARIANT_HN
,
5439 case eCSSProperty_stroke_width
:
5440 return ParsePositiveVariant(aValue
, VARIANT_HLPN
,
5442 case eCSSProperty_text_anchor
:
5443 return ParseVariant(aValue
, VARIANT_HK
,
5444 nsCSSProps::kTextAnchorKTable
);
5445 case eCSSProperty_text_rendering
:
5446 return ParseVariant(aValue
, VARIANT_AHK
,
5447 nsCSSProps::kTextRenderingKTable
);
5449 case eCSSProperty_box_sizing
:
5450 return ParseVariant(aValue
, VARIANT_HK
,
5451 nsCSSProps::kBoxSizingKTable
);
5452 case eCSSProperty_height
:
5453 return ParsePositiveVariant(aValue
, VARIANT_AHLP
, nsnull
);
5454 case eCSSProperty_width
:
5455 return ParsePositiveVariant(aValue
, VARIANT_AHKLP
,
5456 nsCSSProps::kWidthKTable
);
5457 case eCSSProperty_force_broken_image_icon
:
5458 return ParsePositiveVariant(aValue
, VARIANT_HI
, nsnull
);
5459 case eCSSProperty_caption_side
:
5460 return ParseVariant(aValue
, VARIANT_HK
,
5461 nsCSSProps::kCaptionSideKTable
);
5462 case eCSSProperty_clear
:
5463 return ParseVariant(aValue
, VARIANT_HOK
,
5464 nsCSSProps::kClearKTable
);
5465 case eCSSProperty_color
:
5466 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5467 case eCSSProperty_cue_after
:
5468 case eCSSProperty_cue_before
:
5469 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5470 case eCSSProperty_direction
:
5471 return ParseVariant(aValue
, VARIANT_HK
,
5472 nsCSSProps::kDirectionKTable
);
5473 case eCSSProperty_display
:
5474 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kDisplayKTable
)) {
5475 if (aValue
.GetUnit() == eCSSUnit_Enumerated
) {
5476 switch (aValue
.GetIntValue()) {
5477 case NS_STYLE_DISPLAY_MARKER
: // bug 2055
5478 case NS_STYLE_DISPLAY_RUN_IN
: // bug 2056
5479 case NS_STYLE_DISPLAY_COMPACT
: // bug 14983
5486 case eCSSProperty_elevation
:
5487 return ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5488 nsCSSProps::kElevationKTable
);
5489 case eCSSProperty_empty_cells
:
5490 return ParseVariant(aValue
, VARIANT_HK
,
5491 nsCSSProps::kEmptyCellsKTable
);
5492 case eCSSProperty_float
:
5493 return ParseVariant(aValue
, VARIANT_HOK
,
5494 nsCSSProps::kFloatKTable
);
5495 case eCSSProperty_float_edge
:
5496 return ParseVariant(aValue
, VARIANT_HK
,
5497 nsCSSProps::kFloatEdgeKTable
);
5498 case eCSSProperty_font_family
:
5499 return ParseFamily(aValue
);
5500 case eCSSProperty_font_size
:
5501 return ParsePositiveVariant(aValue
,
5502 VARIANT_HKLP
| VARIANT_SYSFONT
,
5503 nsCSSProps::kFontSizeKTable
);
5504 case eCSSProperty_font_size_adjust
:
5505 return ParseVariant(aValue
, VARIANT_HON
| VARIANT_SYSFONT
,
5507 case eCSSProperty_font_stretch
:
5508 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5509 nsCSSProps::kFontStretchKTable
);
5510 case eCSSProperty_font_style
:
5511 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5512 nsCSSProps::kFontStyleKTable
);
5513 case eCSSProperty_font_variant
:
5514 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5515 nsCSSProps::kFontVariantKTable
);
5516 case eCSSProperty_font_weight
:
5517 return ParseFontWeight(aValue
);
5518 case eCSSProperty_ime_mode
:
5519 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NORMAL
,
5520 nsCSSProps::kIMEModeKTable
);
5521 case eCSSProperty_letter_spacing
:
5522 case eCSSProperty_word_spacing
:
5523 return ParseVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5524 case eCSSProperty_line_height
:
5525 return ParsePositiveVariant(aValue
, VARIANT_HLPN
| VARIANT_NORMAL
| VARIANT_SYSFONT
, nsnull
);
5526 case eCSSProperty_list_style_image
:
5527 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5528 case eCSSProperty_list_style_position
:
5529 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kListStylePositionKTable
);
5530 case eCSSProperty_list_style_type
:
5531 return ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kListStyleKTable
);
5532 case eCSSProperty_margin_bottom
:
5533 case eCSSProperty_margin_end_value
: // for internal use
5534 case eCSSProperty_margin_left_value
: // for internal use
5535 case eCSSProperty_margin_right_value
: // for internal use
5536 case eCSSProperty_margin_start_value
: // for internal use
5537 case eCSSProperty_margin_top
:
5538 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5539 case eCSSProperty_marker_offset
:
5540 return ParseVariant(aValue
, VARIANT_AHL
, nsnull
);
5541 case eCSSProperty_marks
:
5542 return ParseMarks(aValue
);
5543 case eCSSProperty_max_height
:
5544 return ParsePositiveVariant(aValue
, VARIANT_HLPO
, nsnull
);
5545 case eCSSProperty_max_width
:
5546 return ParsePositiveVariant(aValue
, VARIANT_HKLPO
,
5547 nsCSSProps::kWidthKTable
);
5548 case eCSSProperty_min_height
:
5549 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5550 case eCSSProperty_min_width
:
5551 return ParsePositiveVariant(aValue
, VARIANT_HKLP
,
5552 nsCSSProps::kWidthKTable
);
5553 case eCSSProperty_opacity
:
5554 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5555 case eCSSProperty_orphans
:
5556 case eCSSProperty_widows
:
5557 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5558 case eCSSProperty_outline_color
:
5559 return ParseVariant(aValue
, VARIANT_HCK
,
5560 nsCSSProps::kOutlineColorKTable
);
5561 case eCSSProperty_outline_style
:
5562 return ParseVariant(aValue
, VARIANT_HOK
| VARIANT_AUTO
,
5563 nsCSSProps::kOutlineStyleKTable
);
5564 case eCSSProperty_outline_width
:
5565 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5566 nsCSSProps::kBorderWidthKTable
);
5567 case eCSSProperty_outline_offset
:
5568 return ParseVariant(aValue
, VARIANT_HL
, nsnull
);
5569 case eCSSProperty_overflow_x
:
5570 case eCSSProperty_overflow_y
:
5571 return ParseVariant(aValue
, VARIANT_AHK
,
5572 nsCSSProps::kOverflowSubKTable
);
5573 case eCSSProperty_padding_bottom
:
5574 case eCSSProperty_padding_end_value
: // for internal use
5575 case eCSSProperty_padding_left_value
: // for internal use
5576 case eCSSProperty_padding_right_value
: // for internal use
5577 case eCSSProperty_padding_start_value
: // for internal use
5578 case eCSSProperty_padding_top
:
5579 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5580 case eCSSProperty_page
:
5581 return ParseVariant(aValue
, VARIANT_AUTO
| VARIANT_IDENTIFIER
, nsnull
);
5582 case eCSSProperty_page_break_after
:
5583 case eCSSProperty_page_break_before
:
5584 return ParseVariant(aValue
, VARIANT_AHK
,
5585 nsCSSProps::kPageBreakKTable
);
5586 case eCSSProperty_page_break_inside
:
5587 return ParseVariant(aValue
, VARIANT_AHK
,
5588 nsCSSProps::kPageBreakInsideKTable
);
5589 case eCSSProperty_pause_after
:
5590 case eCSSProperty_pause_before
:
5591 return ParseVariant(aValue
, VARIANT_HTP
, nsnull
);
5592 case eCSSProperty_pitch
:
5593 return ParseVariant(aValue
, VARIANT_HKF
, nsCSSProps::kPitchKTable
);
5594 case eCSSProperty_pitch_range
:
5595 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5596 case eCSSProperty_position
:
5597 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kPositionKTable
);
5598 case eCSSProperty_richness
:
5599 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5601 // script-level can take Integer or Number values, but only Integer ("relative")
5602 // values can be specified in a style sheet. Also we only allow this property
5603 // when unsafe rules are enabled, because otherwise it could interfere
5604 // with rulenode optimizations if used in a non-MathML-enabled document.
5605 case eCSSProperty_script_level
:
5606 if (!mUnsafeRulesEnabled
)
5608 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5610 case eCSSProperty_speak
:
5611 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5612 nsCSSProps::kSpeakKTable
);
5613 case eCSSProperty_speak_header
:
5614 return ParseVariant(aValue
, VARIANT_HK
,
5615 nsCSSProps::kSpeakHeaderKTable
);
5616 case eCSSProperty_speak_numeral
:
5617 return ParseVariant(aValue
, VARIANT_HK
,
5618 nsCSSProps::kSpeakNumeralKTable
);
5619 case eCSSProperty_speak_punctuation
:
5620 return ParseVariant(aValue
, VARIANT_HOK
,
5621 nsCSSProps::kSpeakPunctuationKTable
);
5622 case eCSSProperty_speech_rate
:
5623 return ParseVariant(aValue
, VARIANT_HN
| VARIANT_KEYWORD
,
5624 nsCSSProps::kSpeechRateKTable
);
5625 case eCSSProperty_stack_sizing
:
5626 return ParseVariant(aValue
, VARIANT_HK
,
5627 nsCSSProps::kStackSizingKTable
);
5628 case eCSSProperty_stress
:
5629 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5630 case eCSSProperty_table_layout
:
5631 return ParseVariant(aValue
, VARIANT_AHK
,
5632 nsCSSProps::kTableLayoutKTable
);
5633 case eCSSProperty_text_align
:
5634 // When we support aligning on a string, we can parse text-align
5636 return ParseVariant(aValue
, VARIANT_HK
/* | VARIANT_STRING */,
5637 nsCSSProps::kTextAlignKTable
);
5638 case eCSSProperty_text_decoration
:
5639 return ParseTextDecoration(aValue
);
5640 case eCSSProperty_text_indent
:
5641 return ParseVariant(aValue
, VARIANT_HLP
, nsnull
);
5642 case eCSSProperty_text_transform
:
5643 return ParseVariant(aValue
, VARIANT_HOK
,
5644 nsCSSProps::kTextTransformKTable
);
5645 case eCSSProperty_unicode_bidi
:
5646 return ParseVariant(aValue
, VARIANT_HMK
,
5647 nsCSSProps::kUnicodeBidiKTable
);
5648 case eCSSProperty_user_focus
:
5649 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5650 nsCSSProps::kUserFocusKTable
);
5651 case eCSSProperty_user_input
:
5652 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5653 nsCSSProps::kUserInputKTable
);
5654 case eCSSProperty_user_modify
:
5655 return ParseVariant(aValue
, VARIANT_HK
,
5656 nsCSSProps::kUserModifyKTable
);
5657 case eCSSProperty_user_select
:
5658 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5659 nsCSSProps::kUserSelectKTable
);
5660 case eCSSProperty_vertical_align
:
5661 return ParseVariant(aValue
, VARIANT_HKLP
,
5662 nsCSSProps::kVerticalAlignKTable
);
5663 case eCSSProperty_visibility
:
5664 return ParseVariant(aValue
, VARIANT_HK
,
5665 nsCSSProps::kVisibilityKTable
);
5666 case eCSSProperty_voice_family
:
5667 return ParseFamily(aValue
);
5668 case eCSSProperty_volume
:
5669 return ParseVariant(aValue
, VARIANT_HPN
| VARIANT_KEYWORD
,
5670 nsCSSProps::kVolumeKTable
);
5671 case eCSSProperty_white_space
:
5672 return ParseVariant(aValue
, VARIANT_HMK
,
5673 nsCSSProps::kWhitespaceKTable
);
5674 case eCSSProperty__moz_window_shadow
:
5675 return ParseVariant(aValue
, VARIANT_HOK
,
5676 nsCSSProps::kWindowShadowKTable
);
5677 case eCSSProperty_word_wrap
:
5678 return ParseVariant(aValue
, VARIANT_HMK
,
5679 nsCSSProps::kWordwrapKTable
);
5680 case eCSSProperty_z_index
:
5681 return ParseVariant(aValue
, VARIANT_AHI
, nsnull
);
5683 // explicitly do NOT have a default case to let the compiler
5684 // help find missing properties
5688 // nsFont::EnumerateFamilies callback for ParseFontDescriptorValue
5689 struct NS_STACK_CLASS ExtractFirstFamilyData
{
5690 nsAutoString mFamilyName
;
5692 ExtractFirstFamilyData() : mFamilyName(), mGood(PR_FALSE
) {}
5696 ExtractFirstFamily(const nsString
& aFamily
,
5700 ExtractFirstFamilyData
* realData
= (ExtractFirstFamilyData
*) aData
;
5701 if (aGeneric
|| realData
->mFamilyName
.Length() > 0) {
5702 realData
->mGood
= PR_FALSE
;
5705 realData
->mFamilyName
.Assign(aFamily
);
5706 realData
->mGood
= PR_TRUE
;
5710 // font-descriptor: descriptor ':' value ';'
5711 // caller has advanced mToken to point at the descriptor
5713 CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
5717 // These four are similar to the properties of the same name,
5718 // possibly with more restrictions on the values they can take.
5719 case eCSSFontDesc_Family
: {
5720 if (!ParseFamily(aValue
) ||
5721 aValue
.GetUnit() != eCSSUnit_String
)
5724 // the style parameters to the nsFont constructor are ignored,
5725 // because it's only being used to call EnumerateFamilies
5726 nsAutoString valueStr
;
5727 aValue
.GetStringValue(valueStr
);
5728 nsFont
font(valueStr
, 0, 0, 0, 0, 0);
5729 ExtractFirstFamilyData dat
;
5731 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
5735 aValue
.SetStringValue(dat
.mFamilyName
, eCSSUnit_String
);
5739 case eCSSFontDesc_Style
:
5740 // property is VARIANT_HMK|VARIANT_SYSFONT
5741 return ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5742 nsCSSProps::kFontStyleKTable
);
5744 case eCSSFontDesc_Weight
:
5745 return (ParseFontWeight(aValue
) &&
5746 aValue
.GetUnit() != eCSSUnit_Inherit
&&
5747 aValue
.GetUnit() != eCSSUnit_Initial
&&
5748 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5749 (aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER
&&
5750 aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER
)));
5752 case eCSSFontDesc_Stretch
:
5753 // property is VARIANT_HMK|VARIANT_SYSFONT
5754 return (ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5755 nsCSSProps::kFontStretchKTable
) &&
5756 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5757 (aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_WIDER
&&
5758 aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_NARROWER
)));
5760 // These two are unique to @font-face and have their own special grammar.
5761 case eCSSFontDesc_Src
:
5762 return ParseFontSrc(aValue
);
5764 case eCSSFontDesc_UnicodeRange
:
5765 return ParseFontRanges(aValue
);
5767 case eCSSFontDesc_UNKNOWN
:
5768 case eCSSFontDesc_COUNT
:
5769 NS_NOTREACHED("bad nsCSSFontDesc code");
5771 // explicitly do NOT have a default case to let the compiler
5772 // help find missing descriptors
5777 CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
)
5779 nsCSSValue
physical(NS_BOXPROP_SOURCE_PHYSICAL
, eCSSUnit_Enumerated
);
5780 for (const nsCSSProperty
*prop
= aSourceProperties
;
5781 *prop
!= eCSSProperty_UNKNOWN
; ++prop
) {
5782 AppendValue(*prop
, physical
);
5787 CSSParserImpl::ParseAzimuth(nsCSSValue
& aValue
)
5789 if (ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5790 nsCSSProps::kAzimuthKTable
)) {
5791 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
5792 PRInt32 intValue
= aValue
.GetIntValue();
5793 if ((NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) &&
5794 (intValue
<= NS_STYLE_AZIMUTH_BEHIND
)) { // look for optional modifier
5795 nsCSSValue modifier
;
5796 if (ParseEnum(modifier
, nsCSSProps::kAzimuthKTable
)) {
5797 PRInt32 enumValue
= modifier
.GetIntValue();
5798 if (((intValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5799 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= enumValue
) && (enumValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
)) ||
5800 ((enumValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5801 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) && (intValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
))) {
5802 aValue
.SetIntValue(intValue
| enumValue
, eCSSUnit_Enumerated
);
5805 // Put the unknown identifier back and return
5817 BoxPositionMaskToCSSValue(PRInt32 aMask
, PRBool isX
)
5819 PRInt32 val
= NS_STYLE_BG_POSITION_CENTER
;
5821 if (aMask
& BG_LEFT
) {
5822 val
= NS_STYLE_BG_POSITION_LEFT
;
5824 else if (aMask
& BG_RIGHT
) {
5825 val
= NS_STYLE_BG_POSITION_RIGHT
;
5829 if (aMask
& BG_TOP
) {
5830 val
= NS_STYLE_BG_POSITION_TOP
;
5832 else if (aMask
& BG_BOTTOM
) {
5833 val
= NS_STYLE_BG_POSITION_BOTTOM
;
5837 return nsCSSValue(val
, eCSSUnit_Enumerated
);
5841 CSSParserImpl::ParseBackground()
5843 nsAutoParseCompoundProperty
compound(this);
5845 // Fill in the values that the shorthand will set if we don't find
5847 mTempData
.mColor
.mBackColor
.SetColorValue(NS_RGBA(0, 0, 0, 0));
5848 mTempData
.SetPropertyBit(eCSSProperty_background_color
);
5849 mTempData
.mColor
.mBackImage
.SetNoneValue();
5850 mTempData
.SetPropertyBit(eCSSProperty_background_image
);
5851 mTempData
.mColor
.mBackRepeat
.SetIntValue(NS_STYLE_BG_REPEAT_XY
,
5852 eCSSUnit_Enumerated
);
5853 mTempData
.SetPropertyBit(eCSSProperty_background_repeat
);
5854 mTempData
.mColor
.mBackAttachment
.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL
,
5855 eCSSUnit_Enumerated
);
5856 mTempData
.SetPropertyBit(eCSSProperty_background_attachment
);
5857 mTempData
.mColor
.mBackPosition
.mXValue
.SetPercentValue(0.0f
);
5858 mTempData
.mColor
.mBackPosition
.mYValue
.SetPercentValue(0.0f
);
5859 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
5860 // including the ones that we can't set from the shorthand.
5861 mTempData
.mColor
.mBackClip
.SetIntValue(NS_STYLE_BG_CLIP_BORDER
,
5862 eCSSUnit_Enumerated
);
5863 mTempData
.SetPropertyBit(eCSSProperty__moz_background_clip
);
5864 mTempData
.mColor
.mBackOrigin
.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING
,
5865 eCSSUnit_Enumerated
);
5866 mTempData
.SetPropertyBit(eCSSProperty__moz_background_origin
);
5867 mTempData
.mColor
.mBackInlinePolicy
.SetIntValue(
5868 NS_STYLE_BG_INLINE_POLICY_CONTINUOUS
, eCSSUnit_Enumerated
);
5869 mTempData
.SetPropertyBit(eCSSProperty__moz_background_inline_policy
);
5871 // XXX If ParseSingleValueProperty were table-driven (bug 376079) and
5872 // automatically filled in the right field of mTempData, we could move
5873 // ParseBackgroundPosition to it (as a special case) and switch back
5874 // to using ParseChoice here.
5876 PRBool haveColor
= PR_FALSE
,
5877 haveImage
= PR_FALSE
,
5878 haveRepeat
= PR_FALSE
,
5879 haveAttach
= PR_FALSE
,
5880 havePosition
= PR_FALSE
;
5881 while (GetToken(PR_TRUE
)) {
5882 nsCSSTokenType tt
= mToken
.mType
;
5883 UngetToken(); // ...but we'll still cheat and use mToken
5884 if (tt
== eCSSToken_Symbol
) {
5885 // ExpectEndProperty only looks for symbols, and nothing else will
5890 if (tt
== eCSSToken_Ident
) {
5891 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
5893 if (keyword
== eCSSKeyword_inherit
||
5894 keyword
== eCSSKeyword__moz_initial
) {
5895 if (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
)
5897 haveColor
= haveImage
= haveRepeat
= haveAttach
= havePosition
=
5899 GetToken(PR_TRUE
); // undo the UngetToken above
5901 if (keyword
== eCSSKeyword_inherit
) {
5902 val
.SetInheritValue();
5904 val
.SetInitialValue();
5906 mTempData
.mColor
.mBackColor
= val
;
5907 mTempData
.mColor
.mBackImage
= val
;
5908 mTempData
.mColor
.mBackRepeat
= val
;
5909 mTempData
.mColor
.mBackAttachment
= val
;
5910 mTempData
.mColor
.mBackPosition
.mXValue
= val
;
5911 mTempData
.mColor
.mBackPosition
.mYValue
= val
;
5912 // Reset (for 'inherit') the 3 properties that can't be
5913 // specified, although it's not entirely clear in the spec:
5914 // http://lists.w3.org/Archives/Public/www-style/2007Mar/0110
5915 mTempData
.mColor
.mBackClip
= val
;
5916 mTempData
.mColor
.mBackOrigin
= val
;
5917 mTempData
.mColor
.mBackInlinePolicy
= val
;
5919 } else if (keyword
== eCSSKeyword_none
) {
5922 haveImage
= PR_TRUE
;
5923 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5924 eCSSProperty_background_image
)) {
5925 NS_NOTREACHED("should be able to parse");
5928 } else if (nsCSSProps::FindKeyword(keyword
,
5929 nsCSSProps::kBackgroundAttachmentKTable
, dummy
)) {
5932 haveAttach
= PR_TRUE
;
5933 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackAttachment
,
5934 eCSSProperty_background_attachment
)) {
5935 NS_NOTREACHED("should be able to parse");
5938 } else if (nsCSSProps::FindKeyword(keyword
,
5939 nsCSSProps::kBackgroundRepeatKTable
, dummy
)) {
5942 haveRepeat
= PR_TRUE
;
5943 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackRepeat
,
5944 eCSSProperty_background_repeat
)) {
5945 NS_NOTREACHED("should be able to parse");
5948 } else if (nsCSSProps::FindKeyword(keyword
,
5949 nsCSSProps::kBackgroundPositionKTable
, dummy
)) {
5952 havePosition
= PR_TRUE
;
5953 if (!ParseBackgroundPositionValues()) {
5959 haveColor
= PR_TRUE
;
5960 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5961 eCSSProperty_background_color
)) {
5965 } else if (eCSSToken_Function
== tt
&&
5966 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
5969 haveImage
= PR_TRUE
;
5970 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5971 eCSSProperty_background_image
)) {
5974 } else if (mToken
.IsDimension() || tt
== eCSSToken_Percentage
) {
5977 havePosition
= PR_TRUE
;
5978 if (!ParseBackgroundPositionValues()) {
5984 haveColor
= PR_TRUE
;
5985 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5986 eCSSProperty_background_color
)) {
5992 return ExpectEndProperty() &&
5993 (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
);
5997 CSSParserImpl::ParseBackgroundPosition()
5999 if (!ParseBoxPosition(mTempData
.mColor
.mBackPosition
))
6001 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
6006 CSSParserImpl::ParseBackgroundPositionValues()
6008 return ParseBoxPositionValues(mTempData
.mColor
.mBackPosition
);
6012 * Parses two values that correspond to positions in a box. These can be
6013 * values corresponding to percentages of the box, raw offsets, or keywords
6014 * like "top," "left center," etc.
6016 * @param aOut The nsCSSValuePair where to place the result.
6017 * @return Whether or not the operation succeeded.
6019 PRBool
CSSParserImpl::ParseBoxPosition(nsCSSValuePair
&aOut
)
6021 // Need to read the box positions and the end of the property.
6022 return ParseBoxPositionValues(aOut
) && ExpectEndProperty();
6025 PRBool
CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair
&aOut
)
6027 // First try a percentage or a length value
6028 nsCSSValue
&xValue
= aOut
.mXValue
,
6029 &yValue
= aOut
.mYValue
;
6030 if (ParseVariant(xValue
, VARIANT_HLP
, nsnull
)) {
6031 if (eCSSUnit_Inherit
== xValue
.GetUnit() ||
6032 eCSSUnit_Initial
== xValue
.GetUnit()) { // both are inherited or both are set to initial
6036 // We have one percentage/length. Get the optional second
6037 // percentage/length/keyword.
6038 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
6039 // We have two numbers
6043 if (ParseEnum(yValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6044 PRInt32 yVal
= yValue
.GetIntValue();
6045 if (!(yVal
& BG_CTB
)) {
6046 // The second keyword can only be 'center', 'top', or 'bottom'
6049 yValue
= BoxPositionMaskToCSSValue(yVal
, PR_FALSE
);
6053 // If only one percentage or length value is given, it sets the
6054 // horizontal position only, and the vertical position will be 50%.
6055 yValue
.SetPercentValue(0.5f
);
6059 // Now try keywords. We do this manually to allow for the first
6060 // appearance of "center" to apply to the either the x or y
6061 // position (it's ambiguous so we have to disambiguate). Each
6062 // allowed keyword value is assigned it's own bit. We don't allow
6063 // any duplicate keywords other than center. We try to get two
6064 // keywords but it's okay if there is only one.
6066 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6067 PRInt32 bit
= xValue
.GetIntValue();
6069 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
6070 bit
= xValue
.GetIntValue();
6071 if (mask
& (bit
& ~BG_CENTER
)) {
6072 // Only the 'center' keyword can be duplicated.
6078 // Only one keyword. See if we have a length or percentage.
6079 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
6080 if (!(mask
& BG_CLR
)) {
6081 // The first keyword can only be 'center', 'left', or 'right'
6085 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
6091 // Check for bad input. Bad input consists of no matching keywords,
6092 // or pairs of x keywords or pairs of y keywords.
6093 if ((mask
== 0) || (mask
== (BG_TOP
| BG_BOTTOM
)) ||
6094 (mask
== (BG_LEFT
| BG_RIGHT
))) {
6098 // Create style values
6099 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
6100 yValue
= BoxPositionMaskToCSSValue(mask
, PR_FALSE
);
6105 CSSParserImpl::ParseBorderColor()
6107 static const nsCSSProperty kBorderColorSources
[] = {
6108 eCSSProperty_border_left_color_ltr_source
,
6109 eCSSProperty_border_left_color_rtl_source
,
6110 eCSSProperty_border_right_color_ltr_source
,
6111 eCSSProperty_border_right_color_rtl_source
,
6112 eCSSProperty_UNKNOWN
6115 // do this now, in case 4 values weren't specified
6116 InitBoxPropsAsPhysical(kBorderColorSources
);
6117 return ParseBoxProperties(mTempData
.mMargin
.mBorderColor
,
6122 CSSParserImpl::ParseBorderImage()
6124 if (ParseVariant(mTempData
.mMargin
.mBorderImage
,
6125 VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
6126 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
6130 // <uri> [<number> | <percentage>]{1,4} [ / <border-width>{1,4} ]? [stretch | repeat | round]{0,2}
6131 nsRefPtr
<nsCSSValue::Array
> arr
= nsCSSValue::Array::Create(11);
6133 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6137 nsCSSValue
& url
= arr
->Item(0);
6138 nsCSSValue
& splitTop
= arr
->Item(1);
6139 nsCSSValue
& splitRight
= arr
->Item(2);
6140 nsCSSValue
& splitBottom
= arr
->Item(3);
6141 nsCSSValue
& splitLeft
= arr
->Item(4);
6142 nsCSSValue
& borderWidthTop
= arr
->Item(5);
6143 nsCSSValue
& borderWidthRight
= arr
->Item(6);
6144 nsCSSValue
& borderWidthBottom
= arr
->Item(7);
6145 nsCSSValue
& borderWidthLeft
= arr
->Item(8);
6146 nsCSSValue
& horizontalKeyword
= arr
->Item(9);
6147 nsCSSValue
& verticalKeyword
= arr
->Item(10);
6150 if (!ParseVariant(url
, VARIANT_URL
, nsnull
)) {
6154 // [<number> | <percentage>]{1,4}
6155 if (!ParsePositiveVariant(splitTop
,
6156 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6159 if (!ParsePositiveVariant(splitRight
,
6160 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6161 splitRight
= splitTop
;
6163 if (!ParsePositiveVariant(splitBottom
,
6164 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6165 splitBottom
= splitTop
;
6167 if (!ParsePositiveVariant(splitLeft
,
6168 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
6169 splitLeft
= splitRight
;
6172 // [ / <border-width>{1,4} ]?
6173 if (ExpectSymbol('/', PR_TRUE
)) {
6174 // if have '/', at least one value is required
6175 if (!ParsePositiveVariant(borderWidthTop
, VARIANT_LENGTH
, nsnull
)) {
6178 if (!ParsePositiveVariant(borderWidthRight
, VARIANT_LENGTH
, nsnull
)) {
6179 borderWidthRight
= borderWidthTop
;
6181 if (!ParsePositiveVariant(borderWidthBottom
, VARIANT_LENGTH
, nsnull
)) {
6182 borderWidthBottom
= borderWidthTop
;
6184 if (!ParsePositiveVariant(borderWidthLeft
, VARIANT_LENGTH
, nsnull
)) {
6185 borderWidthLeft
= borderWidthRight
;
6189 // [stretch | repeat | round]{0,2}
6190 // missing keywords are handled in nsRuleNode::ComputeBorderData()
6191 if (ParseEnum(horizontalKeyword
, nsCSSProps::kBorderImageKTable
)) {
6192 ParseEnum(verticalKeyword
, nsCSSProps::kBorderImageKTable
);
6195 if (!ExpectEndProperty()) {
6199 mTempData
.mMargin
.mBorderImage
.SetArrayValue(arr
, eCSSUnit_Array
);
6200 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
6206 CSSParserImpl::ParseBorderSpacing()
6209 if (ParsePositiveVariant(xValue
, VARIANT_HL
, nsnull
)) {
6210 if (xValue
.IsLengthUnit()) {
6211 // We have one length. Get the optional second length.
6213 if (ParsePositiveVariant(yValue
, VARIANT_LENGTH
, nsnull
)) {
6214 // We have two numbers
6215 if (ExpectEndProperty()) {
6216 mTempData
.mTable
.mBorderSpacing
.mXValue
= xValue
;
6217 mTempData
.mTable
.mBorderSpacing
.mYValue
= yValue
;
6218 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6225 // We have one length which is the horizontal spacing. Create a value for
6226 // the vertical spacing which is equal
6227 if (ExpectEndProperty()) {
6228 mTempData
.mTable
.mBorderSpacing
.SetBothValuesTo(xValue
);
6229 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6237 CSSParserImpl::ParseBorderSide(const nsCSSProperty aPropIDs
[],
6238 PRBool aSetAllSides
)
6240 const PRInt32 numProps
= 3;
6241 nsCSSValue values
[numProps
];
6243 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6244 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6248 if ((found
& 1) == 0) { // Provide default border-width
6249 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6251 if ((found
& 2) == 0) { // Provide default border-style
6252 values
[1].SetNoneValue();
6254 if ((found
& 4) == 0) { // text color will be used
6255 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6259 static const nsCSSProperty kBorderSources
[] = {
6260 eCSSProperty_border_left_color_ltr_source
,
6261 eCSSProperty_border_left_color_rtl_source
,
6262 eCSSProperty_border_right_color_ltr_source
,
6263 eCSSProperty_border_right_color_rtl_source
,
6264 eCSSProperty_border_left_style_ltr_source
,
6265 eCSSProperty_border_left_style_rtl_source
,
6266 eCSSProperty_border_right_style_ltr_source
,
6267 eCSSProperty_border_right_style_rtl_source
,
6268 eCSSProperty_border_left_width_ltr_source
,
6269 eCSSProperty_border_left_width_rtl_source
,
6270 eCSSProperty_border_right_width_ltr_source
,
6271 eCSSProperty_border_right_width_rtl_source
,
6272 eCSSProperty_UNKNOWN
6275 InitBoxPropsAsPhysical(kBorderSources
);
6277 // Parsing "border" shorthand; set all four sides to the same thing
6278 for (PRInt32 index
= 0; index
< 4; index
++) {
6279 NS_ASSERTION(numProps
== 3, "This code needs updating");
6280 AppendValue(kBorderWidthIDs
[index
], values
[0]);
6281 AppendValue(kBorderStyleIDs
[index
], values
[1]);
6282 AppendValue(kBorderColorIDs
[index
], values
[2]);
6286 // Just set our one side
6287 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6288 AppendValue(aPropIDs
[index
], values
[index
]);
6295 CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
6296 PRInt32 aSourceType
)
6298 const PRInt32 numProps
= 3;
6299 nsCSSValue values
[numProps
];
6301 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6302 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6306 if ((found
& 1) == 0) { // Provide default border-width
6307 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6309 if ((found
& 2) == 0) { // Provide default border-style
6310 values
[1].SetNoneValue();
6312 if ((found
& 4) == 0) { // text color will be used
6313 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6315 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6316 const nsCSSProperty
* subprops
=
6317 nsCSSProps::SubpropertyEntryFor(aPropIDs
[index
+ numProps
]);
6318 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
6319 "not box property with physical vs. logical cascading");
6320 AppendValue(subprops
[0], values
[index
]);
6321 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
6322 AppendValue(subprops
[1], typeVal
);
6323 AppendValue(subprops
[2], typeVal
);
6329 CSSParserImpl::ParseBorderStyle()
6331 static const nsCSSProperty kBorderStyleSources
[] = {
6332 eCSSProperty_border_left_style_ltr_source
,
6333 eCSSProperty_border_left_style_rtl_source
,
6334 eCSSProperty_border_right_style_ltr_source
,
6335 eCSSProperty_border_right_style_rtl_source
,
6336 eCSSProperty_UNKNOWN
6339 // do this now, in case 4 values weren't specified
6340 InitBoxPropsAsPhysical(kBorderStyleSources
);
6341 return ParseBoxProperties(mTempData
.mMargin
.mBorderStyle
,
6346 CSSParserImpl::ParseBorderWidth()
6348 static const nsCSSProperty kBorderWidthSources
[] = {
6349 eCSSProperty_border_left_width_ltr_source
,
6350 eCSSProperty_border_left_width_rtl_source
,
6351 eCSSProperty_border_right_width_ltr_source
,
6352 eCSSProperty_border_right_width_rtl_source
,
6353 eCSSProperty_UNKNOWN
6356 // do this now, in case 4 values weren't specified
6357 InitBoxPropsAsPhysical(kBorderWidthSources
);
6358 return ParseBoxProperties(mTempData
.mMargin
.mBorderWidth
,
6363 CSSParserImpl::ParseBorderColors(nsCSSValueList
** aResult
,
6364 nsCSSProperty aProperty
)
6367 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6368 nsCSSValueList
* listHead
= new nsCSSValueList();
6369 nsCSSValueList
* list
= listHead
;
6371 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6374 list
->mValue
= value
;
6377 if (ExpectEndProperty()) {
6378 mTempData
.SetPropertyBit(aProperty
);
6379 *aResult
= listHead
;
6382 // FIXME Bug 389404: We should not accept inherit, -moz-initial,
6383 // or none as anything other than the first value.
6384 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6385 list
->mNext
= new nsCSSValueList();
6388 list
->mValue
= value
;
6390 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6401 CSSParserImpl::ParseRect(nsCSSRect
& aRect
, nsCSSProperty aPropID
)
6405 if ((result
= DoParseRect(rect
)) &&
6408 mTempData
.SetPropertyBit(aPropID
);
6414 CSSParserImpl::DoParseRect(nsCSSRect
& aRect
)
6416 if (! GetToken(PR_TRUE
)) {
6419 if (eCSSToken_Ident
== mToken
.mType
) {
6420 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
6422 case eCSSKeyword_auto
:
6423 if (ExpectEndProperty()) {
6424 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Auto
));
6428 case eCSSKeyword_inherit
:
6429 if (ExpectEndProperty()) {
6430 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Inherit
));
6434 case eCSSKeyword__moz_initial
:
6435 if (ExpectEndProperty()) {
6436 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Initial
));
6444 } else if ((eCSSToken_Function
== mToken
.mType
) &&
6445 mToken
.mIdent
.LowerCaseEqualsLiteral("rect")) {
6446 if (!ExpectSymbol('(', PR_TRUE
)) {
6449 NS_FOR_CSS_SIDES(side
) {
6450 if (! ParseVariant(aRect
.*(nsCSSRect::sides
[side
]),
6451 VARIANT_AL
, nsnull
)) {
6455 // skip optional commas between elements
6456 ExpectSymbol(',', PR_TRUE
);
6459 if (!ExpectSymbol(')', PR_TRUE
)) {
6462 if (ExpectEndProperty()) {
6471 #define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
6474 CSSParserImpl::ParseContent()
6476 // XXX Rewrite to make it look more like ParseCursor or ParseCounterData?
6478 if (ParseVariant(value
,
6479 VARIANT_CONTENT
| VARIANT_INHERIT
| VARIANT_NORMAL
|
6481 nsCSSProps::kContentKTable
)) {
6482 nsCSSValueList
* listHead
= new nsCSSValueList();
6483 nsCSSValueList
* list
= listHead
;
6484 if (nsnull
== list
) {
6485 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6488 list
->mValue
= value
;
6490 while (nsnull
!= list
) {
6491 if (ExpectEndProperty()) {
6492 mTempData
.SetPropertyBit(eCSSProperty_content
);
6493 mTempData
.mContent
.mContent
= listHead
;
6496 if (eCSSUnit_Inherit
== value
.GetUnit() ||
6497 eCSSUnit_Initial
== value
.GetUnit() ||
6498 eCSSUnit_Normal
== value
.GetUnit() ||
6499 eCSSUnit_None
== value
.GetUnit() ||
6500 (eCSSUnit_Enumerated
== value
.GetUnit() &&
6501 NS_STYLE_CONTENT_ALT_CONTENT
== value
.GetIntValue())) {
6502 // This only matters the first time through the loop.
6506 if (ParseVariant(value
, VARIANT_CONTENT
, nsCSSProps::kContentKTable
) &&
6507 // Make sure we didn't end up with NS_STYLE_CONTENT_ALT_CONTENT here
6508 (value
.GetUnit() != eCSSUnit_Enumerated
||
6509 value
.GetIntValue() != NS_STYLE_CONTENT_ALT_CONTENT
)) {
6510 list
->mNext
= new nsCSSValueList();
6512 if (nsnull
!= list
) {
6513 list
->mValue
= value
;
6516 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6528 struct SingleCounterPropValue
{
6534 CSSParserImpl::ParseCounterData(nsCSSValuePairList
** aResult
,
6535 nsCSSProperty aPropID
)
6537 nsSubstring
* ident
= NextIdent();
6538 if (nsnull
== ident
) {
6541 static const SingleCounterPropValue singleValues
[] = {
6542 { "none", eCSSUnit_None
},
6543 { "inherit", eCSSUnit_Inherit
},
6544 { "-moz-initial", eCSSUnit_Initial
}
6546 for (const SingleCounterPropValue
*sv
= singleValues
,
6547 *sv_end
= singleValues
+ NS_ARRAY_LENGTH(singleValues
);
6548 sv
!= sv_end
; ++sv
) {
6549 if (ident
->LowerCaseEqualsASCII(sv
->str
)) {
6550 if (CheckEndProperty()) {
6551 nsCSSValuePairList
* dataHead
= new nsCSSValuePairList();
6553 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6556 dataHead
->mXValue
= nsCSSValue(sv
->unit
);
6557 *aResult
= dataHead
;
6558 mTempData
.SetPropertyBit(aPropID
);
6564 UngetToken(); // undo NextIdent
6566 nsCSSValuePairList
* dataHead
= nsnull
;
6567 nsCSSValuePairList
**next
= &dataHead
;
6569 if (!GetToken(PR_TRUE
) || mToken
.mType
!= eCSSToken_Ident
) {
6572 nsCSSValuePairList
*data
= *next
= new nsCSSValuePairList();
6574 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6577 next
= &data
->mNext
;
6578 data
->mXValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
6579 if (GetToken(PR_TRUE
)) {
6580 if (eCSSToken_Number
== mToken
.mType
&& mToken
.mIntegerValid
) {
6581 data
->mYValue
.SetIntValue(mToken
.mInteger
, eCSSUnit_Integer
);
6586 if (ExpectEndProperty()) {
6587 mTempData
.SetPropertyBit(aPropID
);
6588 *aResult
= dataHead
;
6597 CSSParserImpl::ParseCue()
6600 if (ParseSingleValueProperty(before
, eCSSProperty_cue_before
)) {
6601 if (eCSSUnit_Inherit
!= before
.GetUnit() &&
6602 eCSSUnit_Initial
!= before
.GetUnit()) {
6604 if (ParseSingleValueProperty(after
, eCSSProperty_cue_after
)) {
6605 if (ExpectEndProperty()) {
6606 AppendValue(eCSSProperty_cue_before
, before
);
6607 AppendValue(eCSSProperty_cue_after
, after
);
6613 if (ExpectEndProperty()) {
6614 AppendValue(eCSSProperty_cue_before
, before
);
6615 AppendValue(eCSSProperty_cue_after
, before
);
6623 CSSParserImpl::ParseCursor()
6625 nsCSSValueList
*list
= nsnull
;
6626 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
6627 cur
= *curp
= new nsCSSValueList();
6629 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6632 if (!ParseVariant(cur
->mValue
,
6633 (cur
== list
) ? VARIANT_AHUK
: VARIANT_AUK
,
6634 nsCSSProps::kCursorKTable
)) {
6637 if (cur
->mValue
.GetUnit() != eCSSUnit_URL
) {
6638 if (!ExpectEndProperty()) {
6641 // Only success case here, since having the failure case at the
6642 // end allows more sharing of code.
6643 mTempData
.SetPropertyBit(eCSSProperty_cursor
);
6644 mTempData
.mUserInterface
.mCursor
= list
;
6647 // We have a URL, so make a value array with three values.
6648 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(3);
6650 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6653 val
->Item(0) = cur
->mValue
;
6654 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
6656 // Parse optional x and y position of cursor hotspot (css3-ui).
6657 if (ParseVariant(val
->Item(1), VARIANT_NUMBER
, nsnull
)) {
6658 // If we have one number, we must have two.
6659 if (!ParseVariant(val
->Item(2), VARIANT_NUMBER
, nsnull
)) {
6664 if (!ExpectSymbol(',', PR_TRUE
)) {
6668 // Have failure case at the end so we can |break| to get to it.
6675 CSSParserImpl::ParseFont()
6677 static const nsCSSProperty fontIDs
[] = {
6678 eCSSProperty_font_style
,
6679 eCSSProperty_font_variant
,
6680 eCSSProperty_font_weight
6684 if (ParseVariant(family
, VARIANT_HK
, nsCSSProps::kFontKTable
)) {
6685 if (ExpectEndProperty()) {
6686 if (eCSSUnit_Inherit
== family
.GetUnit() ||
6687 eCSSUnit_Initial
== family
.GetUnit()) {
6688 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6689 AppendValue(eCSSProperty_font_family
, family
);
6690 AppendValue(eCSSProperty_font_style
, family
);
6691 AppendValue(eCSSProperty_font_variant
, family
);
6692 AppendValue(eCSSProperty_font_weight
, family
);
6693 AppendValue(eCSSProperty_font_size
, family
);
6694 AppendValue(eCSSProperty_line_height
, family
);
6695 AppendValue(eCSSProperty_font_stretch
, family
);
6696 AppendValue(eCSSProperty_font_size_adjust
, family
);
6699 AppendValue(eCSSProperty__x_system_font
, family
);
6700 nsCSSValue
systemFont(eCSSUnit_System_Font
);
6701 AppendValue(eCSSProperty_font_family
, systemFont
);
6702 AppendValue(eCSSProperty_font_style
, systemFont
);
6703 AppendValue(eCSSProperty_font_variant
, systemFont
);
6704 AppendValue(eCSSProperty_font_weight
, systemFont
);
6705 AppendValue(eCSSProperty_font_size
, systemFont
);
6706 AppendValue(eCSSProperty_line_height
, systemFont
);
6707 AppendValue(eCSSProperty_font_stretch
, systemFont
);
6708 AppendValue(eCSSProperty_font_size_adjust
, systemFont
);
6715 // Get optional font-style, font-variant and font-weight (in any order)
6716 const PRInt32 numProps
= 3;
6717 nsCSSValue values
[numProps
];
6718 PRInt32 found
= ParseChoice(values
, fontIDs
, numProps
);
6719 if ((found
< 0) || (eCSSUnit_Inherit
== values
[0].GetUnit()) ||
6720 (eCSSUnit_Initial
== values
[0].GetUnit())) { // illegal data
6723 if ((found
& 1) == 0) {
6724 // Provide default font-style
6725 values
[0].SetNormalValue();
6727 if ((found
& 2) == 0) {
6728 // Provide default font-variant
6729 values
[1].SetNormalValue();
6731 if ((found
& 4) == 0) {
6732 // Provide default font-weight
6733 values
[2].SetNormalValue();
6736 // Get mandatory font-size
6738 if (! ParseVariant(size
, VARIANT_KEYWORD
| VARIANT_LP
, nsCSSProps::kFontSizeKTable
)) {
6742 // Get optional "/" line-height
6743 nsCSSValue lineHeight
;
6744 if (ExpectSymbol('/', PR_TRUE
)) {
6745 if (! ParsePositiveVariant(lineHeight
,
6746 VARIANT_NUMBER
| VARIANT_LP
| VARIANT_NORMAL
,
6752 lineHeight
.SetNormalValue();
6755 // Get final mandatory font-family
6756 nsAutoParseCompoundProperty
compound(this);
6757 if (ParseFamily(family
)) {
6758 if ((eCSSUnit_Inherit
!= family
.GetUnit()) && (eCSSUnit_Initial
!= family
.GetUnit()) &&
6759 ExpectEndProperty()) {
6760 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6761 AppendValue(eCSSProperty_font_family
, family
);
6762 AppendValue(eCSSProperty_font_style
, values
[0]);
6763 AppendValue(eCSSProperty_font_variant
, values
[1]);
6764 AppendValue(eCSSProperty_font_weight
, values
[2]);
6765 AppendValue(eCSSProperty_font_size
, size
);
6766 AppendValue(eCSSProperty_line_height
, lineHeight
);
6767 AppendValue(eCSSProperty_font_stretch
, nsCSSValue(eCSSUnit_Normal
));
6768 AppendValue(eCSSProperty_font_size_adjust
, nsCSSValue(eCSSUnit_None
));
6776 CSSParserImpl::ParseFontWeight(nsCSSValue
& aValue
)
6778 if (ParseVariant(aValue
, VARIANT_HMKI
| VARIANT_SYSFONT
, nsCSSProps::kFontWeightKTable
)) {
6779 if (eCSSUnit_Integer
== aValue
.GetUnit()) { // ensure unit value
6780 PRInt32 intValue
= aValue
.GetIntValue();
6781 if ((100 <= intValue
) &&
6782 (intValue
<= 900) &&
6783 (0 == (intValue
% 100))) {
6796 CSSParserImpl::ParseOneFamily(nsAString
& aFamily
)
6798 if (!GetToken(PR_TRUE
))
6801 nsCSSToken
* tk
= &mToken
;
6803 if (eCSSToken_Ident
== tk
->mType
) {
6804 aFamily
.Append(tk
->mIdent
);
6806 if (!GetToken(PR_FALSE
))
6809 if (eCSSToken_Ident
== tk
->mType
) {
6810 aFamily
.Append(tk
->mIdent
);
6811 } else if (eCSSToken_WhiteSpace
== tk
->mType
) {
6812 // Lookahead one token and drop whitespace if we are ending the
6814 if (!GetToken(PR_TRUE
))
6818 if (eCSSToken_Ident
== tk
->mType
)
6819 aFamily
.Append(PRUnichar(' '));
6829 } else if (eCSSToken_String
== tk
->mType
) {
6830 aFamily
.Append(tk
->mSymbol
); // replace the quotes
6831 aFamily
.Append(tk
->mIdent
); // XXX What if it had escaped quotes?
6832 aFamily
.Append(tk
->mSymbol
);
6841 ///////////////////////////////////////////////////////
6842 // -moz-transform Parsing Implementation
6844 /* Reads a function list of arguments. Do not call this function
6845 * directly; it's mean to be caled from ParseFunction.
6848 CSSParserImpl::ParseFunctionInternals(const PRInt32 aVariantMask
[],
6851 nsTArray
<nsCSSValue
> &aOutput
)
6853 for (PRUint16 index
= 0; index
< aMaxElems
; ++index
) {
6854 nsCSSValue newValue
;
6855 if (!ParseVariant(newValue
, aVariantMask
[index
], nsnull
))
6858 if (!aOutput
.AppendElement(newValue
)) {
6859 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6863 // See whether to continue or whether to look for end of function.
6864 if (!ExpectSymbol(',', PR_TRUE
)) {
6865 // We need to read the closing parenthesis, and also must take care
6866 // that we haven't read too few symbols.
6867 return ExpectSymbol(')', PR_TRUE
) && (index
+ 1) >= aMinElems
;
6871 // If we're here, we finished looping without hitting the end, so we read too
6876 /* Parses a function [ input of the form (a [, b]*) ] and stores it
6877 * as an nsCSSValue that holds a function of the form
6878 * function-name arg1 arg2 ... argN
6880 * On error, the return value is PR_FALSE.
6882 * @param aFunction The name of the function that we're reading.
6883 * @param aAllowedTypes An array of values corresponding to the legal
6884 * types for each element in the function. The zeroth element in the
6885 * array corresponds to the first function parameter, etc. The length
6886 * of this array _must_ be greater than or equal to aMaxElems or the
6887 * behavior is undefined.
6888 * @param aMinElems Minimum number of elements to read. Reading fewer than
6889 * this many elements will result in the function failing.
6890 * @param aMaxElems Maximum number of elements to read. Reading more than
6891 * this many elements will result in the function failing.
6892 * @param aValue (out) The value that was parsed.
6895 CSSParserImpl::ParseFunction(const nsString
&aFunction
,
6896 const PRInt32 aAllowedTypes
[],
6897 PRUint16 aMinElems
, PRUint16 aMaxElems
,
6900 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
6902 /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
6903 * elements stored in the the nsCSSValue::Array.
6905 static const arrlen_t MAX_ALLOWED_ELEMS
= 0xFFFE;
6907 /* Make a copy of the function name, since the reference is _probably_ to
6908 * mToken.mIdent, which is going to get overwritten during the course of this
6911 nsString
functionName(aFunction
);
6913 /* First things first... read the parenthesis. If it fails, abort. */
6914 if (!ExpectSymbol('(', PR_TRUE
))
6917 /* Read in a list of values as an nsTArray, failing if we can't or if
6918 * it's out of bounds.
6920 nsTArray
<nsCSSValue
> foundValues
;
6921 if (!ParseFunctionInternals(aAllowedTypes
, aMinElems
, aMaxElems
,
6925 /* Now, convert this nsTArray into an nsCSSValue::Array object.
6926 * We'll need N + 1 spots, one for the function name and the rest for the
6927 * arguments. In case the user has given us more than 2^16 - 2 arguments,
6928 * we'll truncate them at 2^16 - 2 arguments.
6930 PRUint16 numElements
= (foundValues
.Length() <= MAX_ALLOWED_ELEMS
?
6931 foundValues
.Length() + 1 : MAX_ALLOWED_ELEMS
);
6932 nsRefPtr
<nsCSSValue::Array
> convertedArray
=
6933 nsCSSValue::Array::Create(numElements
);
6934 if (!convertedArray
) {
6935 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6939 /* Copy things over. */
6940 convertedArray
->Item(0).SetStringValue(functionName
, eCSSUnit_String
);
6941 for (PRUint16 index
= 0; index
+ 1 < numElements
; ++index
)
6942 convertedArray
->Item(index
+ 1) = foundValues
[static_cast<arrlen_t
>(index
)];
6944 /* Fill in the outparam value with the array. */
6945 aValue
.SetArrayValue(convertedArray
, eCSSUnit_Function
);
6952 * Given a token, determines the minimum and maximum number of function
6953 * parameters to read, along with the mask that should be used to read
6954 * those function parameters. If the token isn't a transform function,
6957 * @param aToken The token identifying the function.
6958 * @param aMinElems [out] The minimum number of elements to read.
6959 * @param aMaxElems [out] The maximum number of elements to read
6960 * @param aVariantMask [out] The variant mask to use during parsing
6961 * @return Whether the information was loaded successfully.
6963 static PRBool
GetFunctionParseInformation(nsCSSKeyword aToken
,
6964 PRUint16
&aMinElems
,
6965 PRUint16
&aMaxElems
,
6966 const PRInt32
*& aVariantMask
)
6968 /* These types represent the common variant masks that will be used to
6969 * parse out the individual functions. The order in the enumeration
6970 * must match the order in which the masks are declared.
6972 enum { eLengthPercent
,
6980 static const PRInt32 kMaxElemsPerFunction
= 6;
6981 static const PRInt32 kVariantMasks
[eNumVariantMasks
][kMaxElemsPerFunction
] = {
6982 {VARIANT_LENGTH
| VARIANT_PERCENT
},
6983 {VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
},
6985 {VARIANT_ANGLE
, VARIANT_ANGLE
},
6987 {VARIANT_NUMBER
, VARIANT_NUMBER
},
6988 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
6989 VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
}};
6992 static const PRUint8 kVariantMaskLengths
[eNumVariantMasks
] =
6993 {1, 2, 1, 2, 1, 2, 6};
6996 PRInt32 variantIndex
= eNumVariantMasks
;
6999 case eCSSKeyword_translatex
:
7000 /* Exactly one length or percent. */
7001 variantIndex
= eLengthPercent
;
7005 case eCSSKeyword_translatey
:
7006 /* Exactly one length or percent. */
7007 variantIndex
= eLengthPercent
;
7011 case eCSSKeyword_scalex
:
7012 /* Exactly one scale factor. */
7013 variantIndex
= eNumber
;
7017 case eCSSKeyword_scaley
:
7018 /* Exactly one scale factor. */
7019 variantIndex
= eNumber
;
7023 case eCSSKeyword_rotate
:
7024 /* Exactly one angle. */
7025 variantIndex
= eAngle
;
7029 case eCSSKeyword_translate
:
7030 /* One or two lengths or percents. */
7031 variantIndex
= eTwoLengthPercents
;
7035 case eCSSKeyword_skew
:
7036 /* Exactly one or two angles. */
7037 variantIndex
= eTwoAngles
;
7041 case eCSSKeyword_scale
:
7042 /* One or two scale factors. */
7043 variantIndex
= eTwoNumbers
;
7047 case eCSSKeyword_skewx
:
7048 /* Exactly one angle. */
7049 variantIndex
= eAngle
;
7053 case eCSSKeyword_skewy
:
7054 /* Exactly one angle. */
7055 variantIndex
= eAngle
;
7059 case eCSSKeyword_matrix
:
7060 /* Six values, which can be numbers, lengths, or percents. */
7061 variantIndex
= eMatrix
;
7066 /* Oh dear, we didn't match. Report an error. */
7070 NS_ASSERTION(aMinElems
> 0, "Didn't update minimum elements!");
7071 NS_ASSERTION(aMaxElems
> 0, "Didn't update maximum elements!");
7072 NS_ASSERTION(aMinElems
<= aMaxElems
, "aMinElems > aMaxElems!");
7073 NS_ASSERTION(variantIndex
>= 0, "Invalid variant mask!");
7074 NS_ASSERTION(variantIndex
< eNumVariantMasks
, "Invalid variant mask!");
7076 NS_ASSERTION(aMaxElems
<= kVariantMaskLengths
[variantIndex
],
7077 "Invalid aMaxElems for this variant mask.");
7080 // Convert the index into a mask.
7081 aVariantMask
= kVariantMasks
[variantIndex
];
7087 /* Reads a single transform function from the tokenizer stream, reporting an
7088 * error if something goes wrong.
7090 PRBool
CSSParserImpl::ReadSingleTransform(nsCSSValueList
**& aTail
)
7092 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
7094 if (!GetToken(PR_TRUE
))
7097 /* Check to make sure that we've read a function. */
7098 if (mToken
.mType
!= eCSSToken_Function
) {
7103 /* Load up the variant mask information for ParseFunction. If we can't,
7106 const PRInt32
* variantMask
;
7107 PRUint16 minElems
, maxElems
;
7108 if (!GetFunctionParseInformation(nsCSSKeywords::LookupKeyword(mToken
.mIdent
),
7109 minElems
, maxElems
, variantMask
))
7112 /* Create a cell to populate, fail if we're out of memory. */
7113 nsAutoPtr
<nsCSSValue
> newCell(new nsCSSValue
);
7115 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7119 /* Try reading things in, failing if we can't */
7120 if (!ParseFunction(mToken
.mIdent
, variantMask
, minElems
, maxElems
, *newCell
))
7123 /* Wrap up our result in an nsCSSValueList cell. */
7124 nsAutoPtr
<nsCSSValueList
> toAppend(new nsCSSValueList
);
7128 toAppend
->mValue
= *newCell
;
7130 /* Chain the element to the end of the transform list, then update the
7133 *aTail
= toAppend
.forget();
7134 aTail
= &(*aTail
)->mNext
;
7136 /* It worked! Return true. */
7140 /* Parses a -moz-transform property list by continuously reading in properties
7141 * and constructing a matrix from it.
7143 PRBool
CSSParserImpl::ParseMozTransform()
7145 mTempData
.mDisplay
.mTransform
= nsnull
;
7147 /* First, check to see if this is some sort of keyword - none, inherit,
7150 nsCSSValue keywordValue
;
7151 if (ParseVariant(keywordValue
, VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
7152 /* Looks like it is. Make a new value list and fill it in, failing if
7155 mTempData
.mDisplay
.mTransform
= new nsCSSValueList
;
7156 if (!mTempData
.mDisplay
.mTransform
) {
7157 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7161 /* Inform the parser that everything worked. */
7162 mTempData
.mDisplay
.mTransform
->mValue
= keywordValue
;
7163 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7167 /* We will read a nonempty list of transforms. Thus we'll read in a
7168 * transform, then continuously read transforms until we're no longer
7171 nsCSSValueList
*transformList
= nsnull
;
7172 nsCSSValueList
**tail
= &transformList
;
7174 /* Try reading a transform. If we fail to do so, abort. */
7175 if (!ReadSingleTransform(tail
)) {
7176 delete transformList
;
7180 while (!CheckEndProperty());
7182 /* Confirm that this is the end of the property and set error code
7183 * appropriately otherwise.
7185 if (!ExpectEndProperty()) {
7186 delete transformList
;
7190 /* Validate our data. */
7191 NS_ASSERTION(transformList
, "Didn't read any transforms!");
7193 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7194 mTempData
.mDisplay
.mTransform
= transformList
;
7199 PRBool
CSSParserImpl::ParseMozTransformOrigin()
7201 /* Read in a box position, fail if we can't. */
7202 if (!ParseBoxPosition(mTempData
.mDisplay
.mTransformOrigin
))
7205 /* Set the property bit and return. */
7206 mTempData
.SetPropertyBit(eCSSProperty__moz_transform_origin
);
7211 CSSParserImpl::ParseFamily(nsCSSValue
& aValue
)
7213 if (!GetToken(PR_TRUE
))
7216 if (eCSSToken_Ident
== mToken
.mType
) {
7217 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
7218 if (keyword
== eCSSKeyword_inherit
) {
7219 aValue
.SetInheritValue();
7222 if (keyword
== eCSSKeyword__moz_initial
) {
7223 aValue
.SetInitialValue();
7226 if (keyword
== eCSSKeyword__moz_use_system_font
&&
7227 !IsParsingCompoundProperty()) {
7228 aValue
.SetSystemFontValue();
7235 nsAutoString family
;
7237 if (!ParseOneFamily(family
))
7240 if (!ExpectSymbol(',', PR_TRUE
))
7243 family
.Append(PRUnichar(','));
7246 if (family
.IsEmpty()) {
7249 aValue
.SetStringValue(family
, eCSSUnit_String
);
7253 // src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*
7254 // uri-src: uri [ 'format(' string ( ',' string )* ')' ]
7255 // local-src: 'local(' ( string | ident ) ')'
7258 CSSParserImpl::ParseFontSrc(nsCSSValue
& aValue
)
7260 // could we maybe turn nsCSSValue::Array into nsTArray<nsCSSValue>?
7261 nsTArray
<nsCSSValue
> values
;
7264 if (!GetToken(PR_TRUE
))
7267 if (mToken
.mType
== eCSSToken_Function
&&
7268 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
7271 values
.AppendElement(cur
);
7272 if (!ParseFontSrcFormat(values
))
7275 } else if (mToken
.mType
== eCSSToken_Function
&&
7276 mToken
.mIdent
.LowerCaseEqualsLiteral("local")) {
7277 // css3-fonts does not specify a formal grammar for local().
7278 // The text permits both unquoted identifiers and quoted
7279 // strings. We resolve this ambiguity in the spec by
7280 // assuming that the appropriate production is a single
7281 // <family-name>, possibly surrounded by whitespace.
7283 nsAutoString family
;
7284 if (!ExpectSymbol('(', PR_FALSE
))
7286 if (!ParseOneFamily(family
))
7288 if (!ExpectSymbol(')', PR_TRUE
))
7291 // the style parameters to the nsFont constructor are ignored,
7292 // because it's only being used to call EnumerateFamilies
7293 nsFont
font(family
, 0, 0, 0, 0, 0);
7294 ExtractFirstFamilyData dat
;
7296 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
7300 cur
.SetStringValue(dat
.mFamilyName
, eCSSUnit_Local_Font
);
7301 values
.AppendElement(cur
);
7306 if (!ExpectSymbol(',', PR_TRUE
))
7310 nsRefPtr
<nsCSSValue::Array
> srcVals
7311 = nsCSSValue::Array::Create(values
.Length());
7316 for (i
= 0; i
< values
.Length(); i
++)
7317 srcVals
->Item(i
) = values
[i
];
7318 aValue
.SetArrayValue(srcVals
, eCSSUnit_Array
);
7323 CSSParserImpl::ParseFontSrcFormat(nsTArray
<nsCSSValue
> & values
)
7325 if (!GetToken(PR_TRUE
))
7326 return PR_TRUE
; // EOF harmless here
7327 if (mToken
.mType
!= eCSSToken_Function
||
7328 !mToken
.mIdent
.LowerCaseEqualsLiteral("format")) {
7332 if (!ExpectSymbol('(', PR_FALSE
))
7336 if (!GetToken(PR_TRUE
))
7339 if (mToken
.mType
!= eCSSToken_String
)
7342 nsCSSValue
cur(mToken
.mIdent
, eCSSUnit_Font_Format
);
7343 values
.AppendElement(cur
);
7344 } while (ExpectSymbol(',', PR_TRUE
));
7346 return ExpectSymbol(')', PR_TRUE
);
7349 // font-ranges: urange ( ',' urange )*
7351 CSSParserImpl::ParseFontRanges(nsCSSValue
& aValue
)
7353 // not currently implemented (bug 443976)
7358 CSSParserImpl::ParseListStyle()
7360 const PRInt32 numProps
= 3;
7361 static const nsCSSProperty listStyleIDs
[] = {
7362 eCSSProperty_list_style_type
,
7363 eCSSProperty_list_style_position
,
7364 eCSSProperty_list_style_image
7367 nsCSSValue values
[numProps
];
7369 PRInt32 found
= ParseChoice(values
, listStyleIDs
, numProps
);
7370 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7374 // Provide default values
7375 if ((found
& 1) == 0) {
7376 values
[0].SetIntValue(NS_STYLE_LIST_STYLE_DISC
, eCSSUnit_Enumerated
);
7378 if ((found
& 2) == 0) {
7379 values
[1].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE
, eCSSUnit_Enumerated
);
7381 if ((found
& 4) == 0) {
7382 values
[2].SetNoneValue();
7385 for (index
= 0; index
< numProps
; index
++) {
7386 AppendValue(listStyleIDs
[index
], values
[index
]);
7392 CSSParserImpl::ParseMargin()
7394 static const nsCSSProperty kMarginSideIDs
[] = {
7395 eCSSProperty_margin_top
,
7396 eCSSProperty_margin_right_value
,
7397 eCSSProperty_margin_bottom
,
7398 eCSSProperty_margin_left_value
7400 static const nsCSSProperty kMarginSources
[] = {
7401 eCSSProperty_margin_left_ltr_source
,
7402 eCSSProperty_margin_left_rtl_source
,
7403 eCSSProperty_margin_right_ltr_source
,
7404 eCSSProperty_margin_right_rtl_source
,
7405 eCSSProperty_UNKNOWN
7408 // do this now, in case 4 values weren't specified
7409 InitBoxPropsAsPhysical(kMarginSources
);
7410 return ParseBoxProperties(mTempData
.mMargin
.mMargin
,
7415 CSSParserImpl::ParseMarks(nsCSSValue
& aValue
)
7417 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kPageMarksKTable
)) {
7418 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
7419 if (PR_FALSE
== CheckEndProperty()) {
7421 if (ParseEnum(second
, nsCSSProps::kPageMarksKTable
)) {
7422 aValue
.SetIntValue(aValue
.GetIntValue() | second
.GetIntValue(), eCSSUnit_Enumerated
);
7434 CSSParserImpl::ParseOutline()
7436 const PRInt32 numProps
= 3;
7437 static const nsCSSProperty kOutlineIDs
[] = {
7438 eCSSProperty_outline_color
,
7439 eCSSProperty_outline_style
,
7440 eCSSProperty_outline_width
7443 nsCSSValue values
[numProps
];
7444 PRInt32 found
= ParseChoice(values
, kOutlineIDs
, numProps
);
7445 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7449 // Provide default values
7450 if ((found
& 1) == 0) {
7451 #ifdef GFX_HAS_INVERT
7452 values
[0].SetIntValue(NS_STYLE_COLOR_INVERT
, eCSSUnit_Enumerated
);
7454 values
[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
7457 if ((found
& 2) == 0) {
7458 values
[1].SetNoneValue();
7460 if ((found
& 4) == 0) {
7461 values
[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
7465 for (index
= 0; index
< numProps
; index
++) {
7466 AppendValue(kOutlineIDs
[index
], values
[index
]);
7472 CSSParserImpl::ParseOverflow()
7474 nsCSSValue overflow
;
7475 if (!ParseVariant(overflow
, VARIANT_AHK
,
7476 nsCSSProps::kOverflowKTable
) ||
7477 !ExpectEndProperty())
7480 nsCSSValue
overflowX(overflow
);
7481 nsCSSValue
overflowY(overflow
);
7482 if (eCSSUnit_Enumerated
== overflow
.GetUnit())
7483 switch(overflow
.GetIntValue()) {
7484 case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL
:
7485 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7486 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7488 case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL
:
7489 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7490 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7493 AppendValue(eCSSProperty_overflow_x
, overflowX
);
7494 AppendValue(eCSSProperty_overflow_y
, overflowY
);
7499 CSSParserImpl::ParsePadding()
7501 static const nsCSSProperty kPaddingSideIDs
[] = {
7502 eCSSProperty_padding_top
,
7503 eCSSProperty_padding_right_value
,
7504 eCSSProperty_padding_bottom
,
7505 eCSSProperty_padding_left_value
7507 static const nsCSSProperty kPaddingSources
[] = {
7508 eCSSProperty_padding_left_ltr_source
,
7509 eCSSProperty_padding_left_rtl_source
,
7510 eCSSProperty_padding_right_ltr_source
,
7511 eCSSProperty_padding_right_rtl_source
,
7512 eCSSProperty_UNKNOWN
7515 // do this now, in case 4 values weren't specified
7516 InitBoxPropsAsPhysical(kPaddingSources
);
7517 return ParseBoxProperties(mTempData
.mMargin
.mPadding
,
7522 CSSParserImpl::ParsePause()
7525 if (ParseSingleValueProperty(before
, eCSSProperty_pause_before
)) {
7526 if (eCSSUnit_Inherit
!= before
.GetUnit() && eCSSUnit_Initial
!= before
.GetUnit()) {
7528 if (ParseSingleValueProperty(after
, eCSSProperty_pause_after
)) {
7529 if (ExpectEndProperty()) {
7530 AppendValue(eCSSProperty_pause_before
, before
);
7531 AppendValue(eCSSProperty_pause_after
, after
);
7537 if (ExpectEndProperty()) {
7538 AppendValue(eCSSProperty_pause_before
, before
);
7539 AppendValue(eCSSProperty_pause_after
, before
);
7547 CSSParserImpl::ParseQuotes()
7550 if (ParseVariant(open
, VARIANT_HOS
, nsnull
)) {
7551 if (eCSSUnit_String
== open
.GetUnit()) {
7552 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7553 nsCSSValuePairList
* quotes
= quotesHead
;
7554 if (nsnull
== quotes
) {
7555 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7558 quotes
->mXValue
= open
;
7559 while (nsnull
!= quotes
) {
7560 // get mandatory close
7561 if (ParseVariant(quotes
->mYValue
, VARIANT_STRING
,
7563 if (CheckEndProperty()) {
7564 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7565 mTempData
.mContent
.mQuotes
= quotesHead
;
7568 // look for another open
7569 if (ParseVariant(open
, VARIANT_STRING
, nsnull
)) {
7570 quotes
->mNext
= new nsCSSValuePairList();
7571 quotes
= quotes
->mNext
;
7572 if (nsnull
!= quotes
) {
7573 quotes
->mXValue
= open
;
7576 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7584 if (ExpectEndProperty()) {
7585 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7586 quotesHead
->mXValue
= open
;
7587 mTempData
.mContent
.mQuotes
= quotesHead
;
7588 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7596 CSSParserImpl::ParseSize()
7599 if (ParseVariant(width
, VARIANT_AHKL
, nsCSSProps::kPageSizeKTable
)) {
7600 if (width
.IsLengthUnit()) {
7602 if (ParseVariant(height
, VARIANT_LENGTH
, nsnull
)) {
7603 if (ExpectEndProperty()) {
7604 mTempData
.mPage
.mSize
.mXValue
= width
;
7605 mTempData
.mPage
.mSize
.mYValue
= height
;
7606 mTempData
.SetPropertyBit(eCSSProperty_size
);
7612 if (ExpectEndProperty()) {
7613 mTempData
.mPage
.mSize
.SetBothValuesTo(width
);
7614 mTempData
.SetPropertyBit(eCSSProperty_size
);
7622 CSSParserImpl::ParseTextDecoration(nsCSSValue
& aValue
)
7624 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kTextDecorationKTable
)) {
7625 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) { // look for more keywords
7626 PRInt32 intValue
= aValue
.GetIntValue();
7629 for (index
= 0; index
< 3; index
++) {
7630 if (ParseEnum(keyword
, nsCSSProps::kTextDecorationKTable
)) {
7631 intValue
|= keyword
.GetIntValue();
7637 aValue
.SetIntValue(intValue
, eCSSUnit_Enumerated
);
7645 CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread
)
7647 nsAutoParseCompoundProperty
compound(this);
7649 // Parses x, y, radius, color (in two possible orders)
7650 // This parses the input into a list. Either it contains just a "none" or
7651 // "inherit" value, or a list of arrays.
7652 // The resulting arrays will always contain the above order, with color and
7653 // radius as null values as needed
7662 nsCSSValueList
*list
= nsnull
;
7663 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
7664 cur
= *curp
= new nsCSSValueList();
7666 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7669 if (!ParseVariant(cur
->mValue
,
7670 (cur
== list
) ? VARIANT_HC
| VARIANT_LENGTH
| VARIANT_NONE
7671 : VARIANT_COLOR
| VARIANT_LENGTH
,
7676 nsCSSUnit unit
= cur
->mValue
.GetUnit();
7677 if (unit
!= eCSSUnit_None
&& unit
!= eCSSUnit_Inherit
&&
7678 unit
!= eCSSUnit_Initial
) {
7679 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(5);
7681 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7684 PRBool haveColor
= PR_FALSE
;
7685 if (cur
->mValue
.IsLengthUnit()) {
7686 val
->Item(IndexX
) = cur
->mValue
;
7688 // Must be a color (as string or color value)
7689 NS_ASSERTION(unit
== eCSSUnit_String
|| unit
== eCSSUnit_Color
||
7690 unit
== eCSSUnit_EnumColor
,
7691 "Must be a color value (named color, numeric color, "
7692 "or system color)");
7693 haveColor
= PR_TRUE
;
7694 val
->Item(IndexColor
) = cur
->mValue
;
7696 // Parse the X coordinate
7697 if (!ParseVariant(val
->Item(IndexX
), VARIANT_LENGTH
,
7702 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
7704 // Y coordinate; this one is not optional
7705 if (!ParseVariant(val
->Item(IndexY
), VARIANT_LENGTH
, nsnull
)) {
7709 // Optional radius. Ignore errors except if they pass a negative
7710 // value which we must reject. If we use ParsePositiveVariant we can't
7711 // tell the difference between an unspecified radius and a negative
7712 // radius, so that's why we don't use it.
7713 if (ParseVariant(val
->Item(IndexRadius
), VARIANT_LENGTH
, nsnull
) &&
7714 val
->Item(IndexRadius
).GetFloatValue() < 0) {
7719 // Optional spread (ignore errors)
7720 ParseVariant(val
->Item(IndexSpread
), VARIANT_LENGTH
,
7725 // Optional color (ignore errors)
7726 ParseVariant(val
->Item(IndexColor
), VARIANT_COLOR
,
7730 // Might be at a comma now
7731 if (ExpectSymbol(',', PR_TRUE
)) {
7737 if (!ExpectEndProperty()) {
7738 // If we don't have a comma to delimit the next value, we
7739 // must be at the end of the property. Otherwise we've hit
7740 // something else, which is an error.
7744 // Only success case here, since having the failure case at the
7745 // end allows more sharing of code.
7748 // Have failure case at the end so we can |break| to get to it.
7754 CSSParserImpl::ParseTextShadow()
7756 nsCSSValueList
* list
= ParseCSSShadowList(PR_FALSE
);
7760 mTempData
.SetPropertyBit(eCSSProperty_text_shadow
);
7761 mTempData
.mText
.mTextShadow
= list
;
7766 CSSParserImpl::ParseBoxShadow()
7768 nsCSSValueList
* list
= ParseCSSShadowList(PR_TRUE
);
7772 mTempData
.SetPropertyBit(eCSSProperty_box_shadow
);
7773 mTempData
.mMargin
.mBoxShadow
= list
;
7778 CSSParserImpl::GetNamespaceIdForPrefix(const nsString
& aPrefix
,
7779 PRInt32
* aNameSpaceID
)
7781 NS_PRECONDITION(!aPrefix
.IsEmpty(), "Must have a prefix here");
7783 PRInt32 nameSpaceID
= kNameSpaceID_Unknown
;
7784 if (mNameSpaceMap
) {
7785 // user-specified identifiers are case-sensitive (bug 416106)
7786 nsCOMPtr
<nsIAtom
> prefix
= do_GetAtom(aPrefix
);
7787 nameSpaceID
= mNameSpaceMap
->FindNameSpaceID(prefix
);
7789 // else no declared namespaces
7791 if (kNameSpaceID_Unknown
== nameSpaceID
) { // unknown prefix, dump it
7792 const PRUnichar
*params
[] = {
7795 REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix
, params
);
7796 if (mUnresolvablePrefixException
)
7797 mScanner
.SetLowLevelError(NS_ERROR_DOM_NAMESPACE_ERR
);
7801 *aNameSpaceID
= nameSpaceID
;
7806 CSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
)
7808 if (mNameSpaceMap
) {
7809 aSelector
.SetNameSpace(mNameSpaceMap
->FindNameSpaceID(nsnull
));
7811 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // wildcard
7817 CSSParserImpl::ParsePaint(nsCSSValuePair
* aResult
,
7818 nsCSSProperty aPropID
)
7820 if (!ParseVariant(aResult
->mXValue
,
7821 VARIANT_HC
| VARIANT_NONE
| VARIANT_URL
,
7825 if (aResult
->mXValue
.GetUnit() == eCSSUnit_URL
) {
7826 if (!ParseVariant(aResult
->mYValue
, VARIANT_COLOR
| VARIANT_NONE
,
7828 aResult
->mYValue
.SetColorValue(NS_RGB(0, 0, 0));
7830 aResult
->mYValue
= aResult
->mXValue
;
7833 if (!ExpectEndProperty())
7836 mTempData
.SetPropertyBit(aPropID
);
7841 CSSParserImpl::ParseDasharray()
7844 if (ParseVariant(value
, VARIANT_HLPN
| VARIANT_NONE
, nsnull
)) {
7845 nsCSSValueList
*listHead
= new nsCSSValueList
;
7846 nsCSSValueList
*list
= listHead
;
7848 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7852 list
->mValue
= value
;
7855 if (CheckEndProperty()) {
7856 mTempData
.SetPropertyBit(eCSSProperty_stroke_dasharray
);
7857 mTempData
.mSVG
.mStrokeDasharray
= listHead
;
7861 if (eCSSUnit_Inherit
== value
.GetUnit() ||
7862 eCSSUnit_Initial
== value
.GetUnit() ||
7863 eCSSUnit_None
== value
.GetUnit())
7866 if (!ExpectSymbol(',', PR_TRUE
))
7869 if (!ParseVariant(value
,
7870 VARIANT_LENGTH
| VARIANT_PERCENT
| VARIANT_NUMBER
,
7874 list
->mNext
= new nsCSSValueList
;
7877 list
->mValue
= value
;
7879 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7889 CSSParserImpl::ParseMarker()
7892 if (ParseSingleValueProperty(marker
, eCSSProperty_marker_end
)) {
7893 if (ExpectEndProperty()) {
7894 AppendValue(eCSSProperty_marker_end
, marker
);
7895 AppendValue(eCSSProperty_marker_mid
, marker
);
7896 AppendValue(eCSSProperty_marker_start
, marker
);