1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * emk <VYV03354@nifty.ne.jp>
24 * Daniel Glazman <glazman@netscape.com>
25 * L. David Baron <dbaron@dbaron.org>
26 * Boris Zbarsky <bzbarsky@mit.edu>
27 * Mats Palmgren <mats.palmgren@bredband.net>
28 * Christian Biesinger <cbiesinger@web.de>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
44 /* parsing of CSS stylesheets, based on a token stream from the CSS scanner */
46 #include "nsICSSParser.h"
47 #include "nsCSSProps.h"
48 #include "nsCSSKeywords.h"
49 #include "nsCSSScanner.h"
50 #include "nsICSSLoader.h"
51 #include "nsICSSStyleRule.h"
52 #include "nsICSSImportRule.h"
53 #include "nsCSSRules.h"
54 #include "nsICSSNameSpaceRule.h"
55 #include "nsIUnicharInputStream.h"
56 #include "nsICSSStyleSheet.h"
57 #include "nsCSSDeclaration.h"
58 #include "nsStyleConsts.h"
60 #include "nsNetUtil.h"
63 #include "nsReadableUtils.h"
64 #include "nsUnicharUtils.h"
66 #include "nsVoidArray.h"
67 #include "nsCOMArray.h"
69 #include "nsStyleConsts.h"
70 #include "nsCSSPseudoClasses.h"
71 #include "nsCSSPseudoElements.h"
72 #include "nsCSSAnonBoxes.h"
73 #include "nsINameSpaceManager.h"
74 #include "nsXMLNameSpaceMap.h"
75 #include "nsThemeConstants.h"
76 #include "nsContentErrors.h"
77 #include "nsPrintfCString.h"
78 #include "nsIMediaList.h"
79 #include "nsILookAndFeel.h"
80 #include "nsStyleUtil.h"
81 #include "nsIPrincipal.h"
84 #include "nsContentUtils.h"
85 #include "nsDOMError.h"
86 #include "nsAutoPtr.h"
89 // Flags for ParseVariant method
90 #define VARIANT_KEYWORD 0x000001 // K
91 #define VARIANT_LENGTH 0x000002 // L
92 #define VARIANT_PERCENT 0x000004 // P
93 #define VARIANT_COLOR 0x000008 // C eCSSUnit_Color, eCSSUnit_String (e.g. "red")
94 #define VARIANT_URL 0x000010 // U
95 #define VARIANT_NUMBER 0x000020 // N
96 #define VARIANT_INTEGER 0x000040 // I
97 #define VARIANT_ANGLE 0x000080 // G
98 #define VARIANT_FREQUENCY 0x000100 // F
99 #define VARIANT_TIME 0x000200 // T
100 #define VARIANT_STRING 0x000400 // S
101 #define VARIANT_COUNTER 0x000800 //
102 #define VARIANT_ATTR 0x001000 //
103 #define VARIANT_IDENTIFIER 0x002000 // D
104 #define VARIANT_AUTO 0x010000 // A
105 #define VARIANT_INHERIT 0x020000 // H eCSSUnit_Initial, eCSSUnit_Inherit
106 #define VARIANT_NONE 0x040000 // O
107 #define VARIANT_NORMAL 0x080000 // M
108 #define VARIANT_SYSFONT 0x100000 // eCSSUnit_System_Font
110 // Common combinations of variants
111 #define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
112 #define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)
113 #define VARIANT_AH (VARIANT_AUTO | VARIANT_INHERIT)
114 #define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
115 #define VARIANT_AHI (VARIANT_AH | VARIANT_INTEGER)
116 #define VARIANT_AHK (VARIANT_AH | VARIANT_KEYWORD)
117 #define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)
118 #define VARIANT_AUK (VARIANT_AUTO | VARIANT_URL | VARIANT_KEYWORD)
119 #define VARIANT_AHUK (VARIANT_AH | VARIANT_URL | VARIANT_KEYWORD)
120 #define VARIANT_AHL (VARIANT_AH | VARIANT_LENGTH)
121 #define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
122 #define VARIANT_HK (VARIANT_INHERIT | VARIANT_KEYWORD)
123 #define VARIANT_HKF (VARIANT_HK | VARIANT_FREQUENCY)
124 #define VARIANT_HKL (VARIANT_HK | VARIANT_LENGTH)
125 #define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
126 #define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)
127 #define VARIANT_HL (VARIANT_INHERIT | VARIANT_LENGTH)
128 #define VARIANT_HI (VARIANT_INHERIT | VARIANT_INTEGER)
129 #define VARIANT_HLP (VARIANT_HL | VARIANT_PERCENT)
130 #define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
131 #define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
132 #define VARIANT_HTP (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
133 #define VARIANT_HMK (VARIANT_HK | VARIANT_NORMAL)
134 #define VARIANT_HMKI (VARIANT_HMK | VARIANT_INTEGER)
135 #define VARIANT_HC (VARIANT_INHERIT | VARIANT_COLOR)
136 #define VARIANT_HCK (VARIANT_HK | VARIANT_COLOR)
137 #define VARIANT_HUO (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
138 #define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
139 #define VARIANT_HPN (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
140 #define VARIANT_HOK (VARIANT_HK | VARIANT_NONE)
141 #define VARIANT_HN (VARIANT_INHERIT | VARIANT_NUMBER)
142 #define VARIANT_HON (VARIANT_HN | VARIANT_NONE)
143 #define VARIANT_HOS (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
145 //----------------------------------------------------------------------
147 // Your basic top-down recursive descent style parser
148 class CSSParserImpl
: public nsICSSParser
{
151 virtual ~CSSParserImpl();
155 NS_IMETHOD
SetStyleSheet(nsICSSStyleSheet
* aSheet
);
157 NS_IMETHOD
SetCaseSensitive(PRBool aCaseSensitive
);
159 NS_IMETHOD
SetQuirkMode(PRBool aQuirkMode
);
162 NS_IMETHOD
SetSVGMode(PRBool aSVGMode
);
165 NS_IMETHOD
SetChildLoader(nsICSSLoader
* aChildLoader
);
167 NS_IMETHOD
Parse(nsIUnicharInputStream
* aInput
,
170 nsIPrincipal
* aSheetPrincipal
,
171 PRUint32 aLineNumber
,
172 PRBool aAllowUnsafeRules
);
174 NS_IMETHOD
ParseStyleAttribute(const nsAString
& aAttributeValue
,
177 nsIPrincipal
* aNodePrincipal
,
178 nsICSSStyleRule
** aResult
);
180 NS_IMETHOD
ParseAndAppendDeclaration(const nsAString
& aBuffer
,
183 nsIPrincipal
* aSheetPrincipal
,
184 nsCSSDeclaration
* aDeclaration
,
185 PRBool aParseOnlyOneDecl
,
187 PRBool aClearOldDecl
);
189 NS_IMETHOD
ParseRule(const nsAString
& aRule
,
192 nsIPrincipal
* aSheetPrincipal
,
193 nsCOMArray
<nsICSSRule
>& aResult
);
195 NS_IMETHOD
ParseProperty(const nsCSSProperty aPropID
,
196 const nsAString
& aPropValue
,
199 nsIPrincipal
* aSheetPrincipal
,
200 nsCSSDeclaration
* aDeclaration
,
203 NS_IMETHOD
ParseMediaList(const nsSubstring
& aBuffer
,
204 nsIURI
* aURL
, // for error reporting
205 PRUint32 aLineNumber
, // for error reporting
206 nsMediaList
* aMediaList
,
209 NS_IMETHOD
ParseColorString(const nsSubstring
& aBuffer
,
210 nsIURI
* aURL
, // for error reporting
211 PRUint32 aLineNumber
, // for error reporting
214 NS_IMETHOD
ParseSelectorString(const nsSubstring
& aSelectorString
,
215 nsIURI
* aURL
, // for error reporting
216 PRUint32 aLineNumber
, // for error reporting
217 nsCSSSelectorList
**aSelectorList
);
219 void AppendRule(nsICSSRule
* aRule
);
222 class nsAutoParseCompoundProperty
;
223 friend class nsAutoParseCompoundProperty
;
226 * This helper class automatically calls SetParsingCompoundProperty in its
227 * constructor and takes care of resetting it to false in its destructor.
229 class nsAutoParseCompoundProperty
{
231 nsAutoParseCompoundProperty(CSSParserImpl
* aParser
) : mParser(aParser
)
233 NS_ASSERTION(!aParser
->IsParsingCompoundProperty(),
234 "already parsing compound property");
235 NS_ASSERTION(aParser
, "Null parser?");
236 aParser
->SetParsingCompoundProperty(PR_TRUE
);
239 ~nsAutoParseCompoundProperty()
241 mParser
->SetParsingCompoundProperty(PR_FALSE
);
244 CSSParserImpl
* mParser
;
247 void InitScanner(nsIUnicharInputStream
* aInput
, nsIURI
* aSheetURI
,
248 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
249 nsIPrincipal
* aSheetPrincipal
);
250 // the caller must hold on to aBuffer until parsing is done
251 void InitScanner(const nsSubstring
& aString
, nsIURI
* aSheetURI
,
252 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
253 nsIPrincipal
* aSheetPrincipal
);
254 void ReleaseScanner(void);
256 PRBool
IsSVGMode() const {
257 return mScanner
.IsSVGMode();
261 PRBool
GetToken(PRBool aSkipWS
);
262 PRBool
GetURLToken();
265 void AssertInitialState() {
266 NS_PRECONDITION(!mHTMLMediaMode
, "Bad initial state");
267 NS_PRECONDITION(!mUnresolvablePrefixException
, "Bad initial state");
268 NS_PRECONDITION(!mParsingCompoundProperty
, "Bad initial state");
271 PRBool
ExpectSymbol(PRUnichar aSymbol
, PRBool aSkipWS
);
272 PRBool
ExpectEndProperty();
273 PRBool
CheckEndProperty();
274 nsSubstring
* NextIdent();
275 void SkipUntil(PRUnichar aStopSymbol
);
278 PRBool
SkipDeclaration(PRBool aCheckForBraces
);
279 PRBool
GetNonCloseParenToken(PRBool aSkipWS
);
281 PRBool
PushGroup(nsICSSGroupRule
* aRule
);
284 PRBool
ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aProcessData
);
285 PRBool
ParseAtRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
286 PRBool
ParseCharsetRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
287 PRBool
ParseImportRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
288 PRBool
GatherURL(nsString
& aURL
);
289 // Callers must clear or throw out aMedia if GatherMedia returns false.
290 PRBool
GatherMedia(nsMediaList
* aMedia
,
291 PRUnichar aStopSymbol
);
292 PRBool
ParseMediaQueryExpression(nsMediaQuery
* aQuery
);
293 PRBool
ProcessImport(const nsString
& aURLSpec
,
295 RuleAppendFunc aAppendFunc
,
297 PRBool
ParseGroupRule(nsICSSGroupRule
* aRule
, RuleAppendFunc aAppendFunc
,
299 PRBool
ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
300 PRBool
ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
301 PRBool
ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
302 PRBool
ProcessNameSpace(const nsString
& aPrefix
,
303 const nsString
& aURLSpec
, RuleAppendFunc aAppendFunc
,
306 PRBool
ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
307 PRBool
ParseFontDescriptor(nsCSSFontFaceRule
* aRule
);
308 PRBool
ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
311 PRBool
ParsePageRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
313 enum nsSelectorParsingStatus
{
314 // we have parsed a selector and we saw a token that cannot be
315 // part of a selector:
316 eSelectorParsingStatus_Done
,
317 // we should continue parsing the selector:
318 eSelectorParsingStatus_Continue
,
319 // same as "Done" but we did not find a selector:
320 eSelectorParsingStatus_Empty
,
321 // we saw an unexpected token or token value,
322 // or we saw end-of-file with an unfinished selector:
323 eSelectorParsingStatus_Error
325 nsSelectorParsingStatus
ParseIDSelector(PRInt32
& aDataMask
,
326 nsCSSSelector
& aSelector
);
328 nsSelectorParsingStatus
ParseClassSelector(PRInt32
& aDataMask
,
329 nsCSSSelector
& aSelector
);
331 nsSelectorParsingStatus
ParsePseudoSelector(PRInt32
& aDataMask
,
332 nsCSSSelector
& aSelector
,
335 nsSelectorParsingStatus
ParseAttributeSelector(PRInt32
& aDataMask
,
336 nsCSSSelector
& aSelector
);
338 nsSelectorParsingStatus
ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
339 nsCSSSelector
& aSelector
,
342 nsSelectorParsingStatus
ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
345 nsSelectorParsingStatus
ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
348 nsSelectorParsingStatus
ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
349 nsCSSSelector
& aSelector
);
351 nsSelectorParsingStatus
ParseSelector(nsCSSSelector
& aSelectorResult
);
353 // If aTerminateAtBrace is true, the selector list is done when we
354 // hit a '{'. Otherwise, it's done when we hit EOF.
355 PRBool
ParseSelectorList(nsCSSSelectorList
*& aListHead
,
356 PRBool aTerminateAtBrace
);
357 PRBool
ParseSelectorGroup(nsCSSSelectorList
*& aListHead
);
358 nsCSSDeclaration
* ParseDeclarationBlock(PRBool aCheckForBraces
);
359 PRBool
ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
360 PRBool aCheckForBraces
,
361 PRBool aMustCallValueAppended
,
363 // After a parse error parsing |aPropID|, clear the data in
365 void ClearTempData(nsCSSProperty aPropID
);
366 // After a successful parse of |aPropID|, transfer data from
367 // |mTempData| to |mData|. Set |*aChanged| to true if something
368 // changed, but leave it unmodified otherwise. If aMustCallValueAppended
369 // is false, will not call ValueAppended on aDeclaration if the property
370 // is already set in it.
371 void TransferTempData(nsCSSDeclaration
* aDeclaration
,
372 nsCSSProperty aPropID
, PRBool aIsImportant
,
373 PRBool aMustCallValueAppended
,
375 void DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
376 nsCSSProperty aPropID
, PRBool aIsImportant
,
377 PRBool aMustCallValueAppended
,
379 PRBool
ParseProperty(nsCSSProperty aPropID
);
380 PRBool
ParseSingleValueProperty(nsCSSValue
& aValue
,
381 nsCSSProperty aPropID
);
384 PRBool
ParseTreePseudoElement(nsCSSSelector
& aSelector
);
387 void InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
);
389 // Property specific parsing routines
390 PRBool
ParseAzimuth(nsCSSValue
& aValue
);
391 PRBool
ParseBackground();
392 PRBool
ParseBackgroundPosition();
393 PRBool
ParseBackgroundPositionValues();
394 PRBool
ParseBoxPosition(nsCSSValuePair
& aOut
);
395 PRBool
ParseBoxPositionValues(nsCSSValuePair
& aOut
);
396 PRBool
ParseBorderColor();
397 PRBool
ParseBorderColors(nsCSSValueList
** aResult
,
398 nsCSSProperty aProperty
);
399 PRBool
ParseBorderImage();
400 PRBool
ParseBorderSpacing();
401 PRBool
ParseBorderSide(const nsCSSProperty aPropIDs
[],
402 PRBool aSetAllSides
);
403 PRBool
ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
404 PRInt32 aSourceType
);
405 PRBool
ParseBorderStyle();
406 PRBool
ParseBorderWidth();
407 PRBool
ParseBorderRadius();
408 PRBool
ParseOutlineRadius();
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 PRInt32
ParseChoice(nsCSSValue aValues
[],
455 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
);
456 PRBool
ParseColor(nsCSSValue
& aValue
);
457 PRBool
ParseColorComponent(PRUint8
& aComponent
,
458 PRInt32
& aType
, char aStop
);
459 // ParseHSLColor parses everything starting with the opening '('
460 // up through and including the aStop char.
461 PRBool
ParseHSLColor(nscolor
& aColor
, char aStop
);
462 // ParseColorOpacity will enforce that the color ends with a ')'
464 PRBool
ParseColorOpacity(PRUint8
& aOpacity
);
465 PRBool
ParseEnum(nsCSSValue
& aValue
, const PRInt32 aKeywordTable
[]);
466 PRBool
ParseVariant(nsCSSValue
& aValue
,
467 PRInt32 aVariantMask
,
468 const PRInt32 aKeywordTable
[]);
469 PRBool
ParsePositiveVariant(nsCSSValue
& aValue
,
470 PRInt32 aVariantMask
,
471 const PRInt32 aKeywordTable
[]);
472 PRBool
ParseCounter(nsCSSValue
& aValue
);
473 PRBool
ParseAttr(nsCSSValue
& aValue
);
474 PRBool
ParseURL(nsCSSValue
& aValue
);
475 PRBool
TranslateDimension(nsCSSValue
& aValue
, PRInt32 aVariantMask
,
476 float aNumber
, const nsString
& aUnit
);
478 void SetParsingCompoundProperty(PRBool aBool
) {
479 NS_ASSERTION(aBool
== PR_TRUE
|| aBool
== PR_FALSE
, "bad PRBool value");
480 mParsingCompoundProperty
= aBool
;
482 PRBool
IsParsingCompoundProperty(void) const {
483 return mParsingCompoundProperty
;
486 /* Functions for -moz-transform Parsing */
487 PRBool
ReadSingleTransform(nsCSSValueList
**& aTail
);
488 PRBool
ParseFunction(const nsString
&aFunction
, const PRInt32 aAllowedTypes
[],
489 PRUint16 aMinElems
, PRUint16 aMaxElems
,
491 PRBool
ParseFunctionInternals(const PRInt32 aVariantMask
[],
494 nsTArray
<nsCSSValue
>& aOutput
);
496 /* Functions for -moz-transform-origin Parsing */
497 PRBool
ParseMozTransformOrigin();
500 /* Find and return the correct namespace ID for the prefix aPrefix.
501 If the prefix cannot be resolved to a namespace, this method will
502 return false. Otherwise it will return true. When returning
503 false, it may set the low-level error code, depending on the
504 value of mUnresolvablePrefixException.
506 This method never returns kNameSpaceID_Unknown or
507 kNameSpaceID_None for aNameSpaceID while returning true.
509 PRBool
GetNamespaceIdForPrefix(const nsString
& aPrefix
,
510 PRInt32
* aNameSpaceID
);
512 /* Find the correct default namespace, and set it on aSelector. */
513 void SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
);
515 // Current token. The value is valid after calling GetToken and invalidated
520 nsCSSScanner mScanner
;
522 // The URI to be used as a base for relative URIs.
523 nsCOMPtr
<nsIURI
> mBaseURL
;
525 // The URI to be used as an HTTP "Referer" and for error reporting.
526 nsCOMPtr
<nsIURI
> mSheetURL
;
528 // The principal of the sheet involved
529 nsCOMPtr
<nsIPrincipal
> mSheetPrincipal
;
531 // The sheet we're parsing into
532 nsCOMPtr
<nsICSSStyleSheet
> mSheet
;
534 // Used for @import rules
535 nsICSSLoader
* mChildLoader
; // not ref counted, it owns us
537 // Sheet section we're in. This is used to enforce correct ordering of the
538 // various rule types (eg the fact that a @charset rule must come before
539 // anything else). Note that there are checks of similar things in various
540 // places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
544 eCSSSection_NameSpace
,
547 nsCSSSection mSection
;
549 nsXMLNameSpaceMap
*mNameSpaceMap
; // weak, mSheet owns it
551 // After an UngetToken is done this flag is true. The next call to
552 // GetToken clears the flag.
553 PRPackedBool mHavePushBack
: 1;
555 // True if we are in quirks mode; false in standards or almost standards mode
556 PRPackedBool mNavQuirkMode
: 1;
558 // True if unsafe rules should be allowed
559 PRPackedBool mUnsafeRulesEnabled
: 1;
561 // True for parsing media lists for HTML attributes, where we have to
562 // ignore CSS comments.
563 PRPackedBool mHTMLMediaMode
: 1;
565 // True if tagnames and attributes are case-sensitive
566 PRPackedBool mCaseSensitive
: 1;
568 // This flag is set when parsing a non-box shorthand; it's used to not apply
569 // some quirks during shorthand parsing
570 PRPackedBool mParsingCompoundProperty
: 1;
572 // If this flag is true, failure to resolve a namespace prefix
573 // should set the low-level error to NS_ERROR_DOM_NAMESPACE_ERR
574 PRPackedBool mUnresolvablePrefixException
: 1;
576 // Stack of rule groups; used for @media and such.
577 nsCOMArray
<nsICSSGroupRule
> mGroupStack
;
579 // During the parsing of a property (which may be a shorthand), the data
580 // are stored in |mTempData|. (It is needed to ensure that parser
581 // errors cause the data to be ignored, and to ensure that a
582 // non-'!important' declaration does not override an '!important'
584 nsCSSExpandedDataBlock mTempData
;
586 // All data from successfully parsed properties are placed into |mData|.
587 nsCSSExpandedDataBlock mData
;
590 PRPackedBool mScannerInited
;
594 PR_STATIC_CALLBACK(void) AppendRuleToArray(nsICSSRule
* aRule
, void* aArray
)
596 static_cast<nsCOMArray
<nsICSSRule
>*>(aArray
)->AppendObject(aRule
);
599 PR_STATIC_CALLBACK(void) AppendRuleToSheet(nsICSSRule
* aRule
, void* aParser
)
601 CSSParserImpl
* parser
= (CSSParserImpl
*) aParser
;
602 parser
->AppendRule(aRule
);
606 NS_NewCSSParser(nsICSSParser
** aInstancePtrResult
)
608 CSSParserImpl
*it
= new CSSParserImpl();
611 return NS_ERROR_OUT_OF_MEMORY
;
614 return it
->QueryInterface(NS_GET_IID(nsICSSParser
), (void **) aInstancePtrResult
);
617 #ifdef CSS_REPORT_PARSE_ERRORS
619 #define REPORT_UNEXPECTED(msg_) \
620 mScanner.ReportUnexpected(#msg_)
622 #define REPORT_UNEXPECTED_P(msg_, params_) \
623 mScanner.ReportUnexpectedParams(#msg_, params_, NS_ARRAY_LENGTH(params_))
625 #define REPORT_UNEXPECTED_EOF(lf_) \
626 mScanner.ReportUnexpectedEOF(#lf_)
628 #define REPORT_UNEXPECTED_EOF_CHAR(ch_) \
629 mScanner.ReportUnexpectedEOF(ch_)
631 #define REPORT_UNEXPECTED_TOKEN(msg_) \
632 mScanner.ReportUnexpectedToken(mToken, #msg_)
634 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_) \
635 mScanner.ReportUnexpectedTokenParams(mToken, #msg_, \
636 params_, NS_ARRAY_LENGTH(params_))
639 #define OUTPUT_ERROR() \
640 mScanner.OutputError()
642 #define CLEAR_ERROR() \
643 mScanner.ClearError()
647 #define REPORT_UNEXPECTED(msg_)
648 #define REPORT_UNEXPECTED_P(msg_, params_)
649 #define REPORT_UNEXPECTED_EOF(lf_)
650 #define REPORT_UNEXPECTED_EOF_CHAR(ch_)
651 #define REPORT_UNEXPECTED_TOKEN(msg_)
652 #define REPORT_UNEXPECTED_TOKEN_P(msg_, params_)
653 #define OUTPUT_ERROR()
654 #define CLEAR_ERROR()
658 CSSParserImpl::CSSParserImpl()
661 mChildLoader(nsnull
),
662 mSection(eCSSSection_Charset
),
663 mNameSpaceMap(nsnull
),
664 mHavePushBack(PR_FALSE
),
665 mNavQuirkMode(PR_FALSE
),
666 mUnsafeRulesEnabled(PR_FALSE
),
667 mHTMLMediaMode(PR_FALSE
),
668 mCaseSensitive(PR_FALSE
),
669 mParsingCompoundProperty(PR_FALSE
),
670 mUnresolvablePrefixException(PR_FALSE
)
672 , mScannerInited(PR_FALSE
)
677 NS_IMPL_ISUPPORTS1(CSSParserImpl
, nsICSSParser
)
679 CSSParserImpl::~CSSParserImpl()
681 mData
.AssertInitialState();
682 mTempData
.AssertInitialState();
686 CSSParserImpl::SetStyleSheet(nsICSSStyleSheet
* aSheet
)
688 if (aSheet
!= mSheet
) {
689 // Switch to using the new sheet, if any
693 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
695 mNameSpaceMap
= nsnull
;
703 CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive
)
705 NS_ASSERTION(aCaseSensitive
== PR_TRUE
|| aCaseSensitive
== PR_FALSE
, "bad PRBool value");
706 mCaseSensitive
= aCaseSensitive
;
711 CSSParserImpl::SetQuirkMode(PRBool aQuirkMode
)
713 NS_ASSERTION(aQuirkMode
== PR_TRUE
|| aQuirkMode
== PR_FALSE
, "bad PRBool value");
714 mNavQuirkMode
= aQuirkMode
;
720 CSSParserImpl::SetSVGMode(PRBool aSVGMode
)
722 NS_ASSERTION(aSVGMode
== PR_TRUE
|| aSVGMode
== PR_FALSE
,
724 mScanner
.SetSVGMode(aSVGMode
);
730 CSSParserImpl::SetChildLoader(nsICSSLoader
* aChildLoader
)
732 mChildLoader
= aChildLoader
; // not ref counted, it owns us
737 CSSParserImpl::InitScanner(nsIUnicharInputStream
* aInput
, nsIURI
* aSheetURI
,
738 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
739 nsIPrincipal
* aSheetPrincipal
)
741 NS_ASSERTION(! mScannerInited
, "already have scanner");
743 mScanner
.Init(aInput
, nsnull
, 0, aSheetURI
, aLineNumber
);
745 mScannerInited
= PR_TRUE
;
748 mSheetURL
= aSheetURI
;
749 mSheetPrincipal
= aSheetPrincipal
;
751 mHavePushBack
= PR_FALSE
;
755 CSSParserImpl::InitScanner(const nsSubstring
& aString
, nsIURI
* aSheetURI
,
756 PRUint32 aLineNumber
, nsIURI
* aBaseURI
,
757 nsIPrincipal
* aSheetPrincipal
)
759 // Having it not own the string is OK since the caller will hold on to
760 // the stream until we're done parsing.
761 NS_ASSERTION(! mScannerInited
, "already have scanner");
763 mScanner
.Init(nsnull
, aString
.BeginReading(), aString
.Length(), aSheetURI
, aLineNumber
);
766 mScannerInited
= PR_TRUE
;
769 mSheetURL
= aSheetURI
;
770 mSheetPrincipal
= aSheetPrincipal
;
772 mHavePushBack
= PR_FALSE
;
776 CSSParserImpl::ReleaseScanner(void)
780 mScannerInited
= PR_FALSE
;
784 mSheetPrincipal
= nsnull
;
789 CSSParserImpl::Parse(nsIUnicharInputStream
* aInput
,
792 nsIPrincipal
* aSheetPrincipal
,
793 PRUint32 aLineNumber
,
794 PRBool aAllowUnsafeRules
)
796 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
798 NS_ASSERTION(nsnull
!= aBaseURI
, "need base URL");
799 NS_ASSERTION(nsnull
!= aSheetURI
, "need sheet URL");
800 AssertInitialState();
802 NS_PRECONDITION(mSheet
, "Must have sheet to parse into");
803 NS_ENSURE_STATE(mSheet
);
806 nsCOMPtr
<nsIURI
> uri
;
807 mSheet
->GetSheetURI(getter_AddRefs(uri
));
809 NS_ASSERTION(NS_SUCCEEDED(aSheetURI
->Equals(uri
, &equal
)) && equal
,
810 "Sheet URI does not match passed URI");
811 NS_ASSERTION(NS_SUCCEEDED(mSheet
->Principal()->Equals(aSheetPrincipal
,
814 "Sheet principal does not match passed principal");
817 InitScanner(aInput
, aSheetURI
, aLineNumber
, aBaseURI
, aSheetPrincipal
);
819 PRInt32 ruleCount
= 0;
820 mSheet
->StyleRuleCount(ruleCount
);
822 nsICSSRule
* lastRule
= nsnull
;
823 mSheet
->GetStyleRuleAt(ruleCount
- 1, lastRule
);
826 lastRule
->GetType(type
);
828 case nsICSSRule::CHARSET_RULE
:
829 case nsICSSRule::IMPORT_RULE
:
830 mSection
= eCSSSection_Import
;
832 case nsICSSRule::NAMESPACE_RULE
:
833 mSection
= eCSSSection_NameSpace
;
836 mSection
= eCSSSection_General
;
839 NS_RELEASE(lastRule
);
843 mSection
= eCSSSection_Charset
; // sheet is empty, any rules are fair
846 mUnsafeRulesEnabled
= aAllowUnsafeRules
;
848 nsCSSToken
* tk
= &mToken
;
850 // Get next non-whitespace token
851 if (!GetToken(PR_TRUE
)) {
855 if (eCSSToken_HTMLComment
== tk
->mType
) {
856 continue; // legal here only
858 if (eCSSToken_AtKeyword
== tk
->mType
) {
859 ParseAtRule(AppendRuleToSheet
, this);
863 if (ParseRuleSet(AppendRuleToSheet
, this)) {
864 mSection
= eCSSSection_General
;
869 mUnsafeRulesEnabled
= PR_FALSE
;
871 // XXX check for low level errors
876 * Determines whether the identifier contained in the given string is a
877 * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1.
880 NonMozillaVendorIdentifier(const nsAString
& ident
)
882 return (ident
.First() == PRUnichar('-') &&
883 !StringBeginsWith(ident
, NS_LITERAL_STRING("-moz-"))) ||
884 ident
.First() == PRUnichar('_');
889 CSSParserImpl::ParseStyleAttribute(const nsAString
& aAttributeValue
,
892 nsIPrincipal
* aNodePrincipal
,
893 nsICSSStyleRule
** aResult
)
895 NS_PRECONDITION(aNodePrincipal
, "Must have principal here!");
896 AssertInitialState();
898 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
901 InitScanner(aAttributeValue
, aDocURL
, 0, aBaseURL
, aNodePrincipal
);
903 mSection
= eCSSSection_General
;
905 // In quirks mode, allow style declarations to have braces or not
908 if (mNavQuirkMode
&& GetToken(PR_TRUE
)) {
909 haveBraces
= eCSSToken_Symbol
== mToken
.mType
&&
910 '{' == mToken
.mSymbol
;
914 haveBraces
= PR_FALSE
;
917 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(haveBraces
);
919 // Create a style rule for the declaration
920 nsICSSStyleRule
* rule
= nsnull
;
921 nsresult rv
= NS_NewCSSStyleRule(&rule
, nsnull
, declaration
);
923 declaration
->RuleAbort();
935 // XXX check for low level errors
940 CSSParserImpl::ParseAndAppendDeclaration(const nsAString
& aBuffer
,
943 nsIPrincipal
* aSheetPrincipal
,
944 nsCSSDeclaration
* aDeclaration
,
945 PRBool aParseOnlyOneDecl
,
947 PRBool aClearOldDecl
)
949 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
950 AssertInitialState();
952 *aChanged
= PR_FALSE
;
954 InitScanner(aBuffer
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
956 mSection
= eCSSSection_General
;
959 mData
.AssertInitialState();
960 aDeclaration
->ClearData();
961 // We could check if it was already empty, but...
964 aDeclaration
->ExpandTo(&mData
);
969 // If we cleared the old decl, then we want to be calling
970 // ValueAppended as we parse.
971 if (!ParseDeclaration(aDeclaration
, PR_FALSE
, aClearOldDecl
, aChanged
)) {
972 rv
= mScanner
.GetLowLevelError();
976 if (!SkipDeclaration(PR_FALSE
)) {
977 rv
= mScanner
.GetLowLevelError();
981 } while (!aParseOnlyOneDecl
);
982 aDeclaration
->CompressFrom(&mData
);
989 CSSParserImpl::ParseRule(const nsAString
& aRule
,
992 nsIPrincipal
* aSheetPrincipal
,
993 nsCOMArray
<nsICSSRule
>& aResult
)
995 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
996 AssertInitialState();
998 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1000 InitScanner(aRule
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1002 mSection
= eCSSSection_Charset
; // callers are responsible for rejecting invalid rules.
1004 nsCSSToken
* tk
= &mToken
;
1005 // Get first non-whitespace token
1006 if (!GetToken(PR_TRUE
)) {
1007 REPORT_UNEXPECTED(PEParseRuleWSOnly
);
1009 } else if (eCSSToken_AtKeyword
== tk
->mType
) {
1010 ParseAtRule(AppendRuleToArray
, &aResult
);
1014 ParseRuleSet(AppendRuleToArray
, &aResult
);
1018 // XXX check for low-level errors
1023 CSSParserImpl::ParseProperty(const nsCSSProperty aPropID
,
1024 const nsAString
& aPropValue
,
1027 nsIPrincipal
* aSheetPrincipal
,
1028 nsCSSDeclaration
* aDeclaration
,
1031 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1032 AssertInitialState();
1034 NS_ASSERTION(nsnull
!= aBaseURL
, "need base URL");
1035 NS_ASSERTION(nsnull
!= aDeclaration
, "Need declaration to parse into!");
1036 *aChanged
= PR_FALSE
;
1038 InitScanner(aPropValue
, aSheetURL
, 0, aBaseURL
, aSheetPrincipal
);
1040 mSection
= eCSSSection_General
;
1042 if (eCSSProperty_UNKNOWN
== aPropID
) { // unknown property
1043 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1044 const PRUnichar
*params
[] = {
1047 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
1048 REPORT_UNEXPECTED(PEDeclDropped
);
1054 mData
.AssertInitialState();
1055 mTempData
.AssertInitialState();
1056 aDeclaration
->ExpandTo(&mData
);
1057 nsresult result
= NS_OK
;
1058 PRBool parsedOK
= ParseProperty(aPropID
);
1059 if (parsedOK
&& !GetToken(PR_TRUE
)) {
1060 TransferTempData(aDeclaration
, aPropID
, PR_FALSE
, PR_FALSE
, aChanged
);
1063 // Junk at end of property value.
1064 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
1066 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1067 const PRUnichar
*params
[] = {
1070 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
1071 REPORT_UNEXPECTED(PEDeclDropped
);
1073 ClearTempData(aPropID
);
1074 result
= mScanner
.GetLowLevelError();
1078 aDeclaration
->CompressFrom(&mData
);
1085 CSSParserImpl::ParseMediaList(const nsSubstring
& aBuffer
,
1086 nsIURI
* aURL
, // for error reporting
1087 PRUint32 aLineNumber
, // for error reporting
1088 nsMediaList
* aMediaList
,
1091 // XXX Are there cases where the caller wants to keep what it already
1092 // has in case of parser error?
1093 aMediaList
->Clear();
1095 // fake base URL since media lists don't have URLs in them
1096 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1098 AssertInitialState();
1099 NS_ASSERTION(aHTMLMode
== PR_TRUE
|| aHTMLMode
== PR_FALSE
,
1101 mHTMLMediaMode
= aHTMLMode
;
1103 // XXXldb We need to make the scanner not skip CSS comments! (Or
1106 // For aHTMLMode, we used to follow the parsing rules in
1107 // http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors
1108 // which wouldn't work for media queries since they remove all but the
1109 // first word. However, they're changed in
1110 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2
1111 // (as of 2008-05-29) which says that the media attribute just points
1112 // to a media query. (The main substative difference is the relative
1113 // precedence of commas and paretheses.)
1115 if (!GatherMedia(aMediaList
, PRUnichar(0))) {
1116 aMediaList
->Clear();
1117 aMediaList
->SetNonEmpty(); // don't match anything
1118 if (!mHTMLMediaMode
) {
1122 nsresult rv
= mScanner
.GetLowLevelError();
1125 mHTMLMediaMode
= PR_FALSE
;
1131 CSSParserImpl::ParseColorString(const nsSubstring
& aBuffer
,
1132 nsIURI
* aURL
, // for error reporting
1133 PRUint32 aLineNumber
, // for error reporting
1136 AssertInitialState();
1137 InitScanner(aBuffer
, aURL
, aLineNumber
, aURL
, nsnull
);
1140 PRBool colorParsed
= ParseColor(value
);
1141 nsresult rv
= mScanner
.GetLowLevelError();
1146 return NS_FAILED(rv
) ? rv
: NS_ERROR_FAILURE
;
1149 if (value
.GetUnit() == eCSSUnit_String
) {
1151 if (NS_ColorNameToRGB(nsDependentString(value
.GetStringBufferValue()), &rgba
)) {
1155 } else if (value
.GetUnit() == eCSSUnit_Color
) {
1156 (*aColor
) = value
.GetColorValue();
1158 } else if (value
.GetUnit() == eCSSUnit_EnumColor
) {
1159 PRInt32 intValue
= value
.GetIntValue();
1160 if (intValue
>= 0) {
1161 nsCOMPtr
<nsILookAndFeel
> lfSvc
= do_GetService("@mozilla.org/widget/lookandfeel;1");
1164 rv
= lfSvc
->GetColor((nsILookAndFeel::nsColorID
) value
.GetIntValue(), rgba
);
1165 if (NS_SUCCEEDED(rv
))
1169 // XXX - this is NS_COLOR_CURRENTCOLOR, NS_COLOR_MOZ_HYPERLINKTEXT, etc.
1170 // which we don't handle as per the ParseColorString definition. Should
1171 // remove this limitation at some point.
1172 rv
= NS_ERROR_FAILURE
;
1180 CSSParserImpl::ParseSelectorString(const nsSubstring
& aSelectorString
,
1181 nsIURI
* aURL
, // for error reporting
1182 PRUint32 aLineNumber
, // for error reporting
1183 nsCSSSelectorList
**aSelectorList
)
1185 InitScanner(aSelectorString
, aURL
, aLineNumber
, aURL
, nsnull
);
1187 AssertInitialState();
1189 mUnresolvablePrefixException
= PR_TRUE
;
1191 PRBool success
= ParseSelectorList(*aSelectorList
, PR_FALSE
);
1192 nsresult rv
= mScanner
.GetLowLevelError();
1196 mUnresolvablePrefixException
= PR_FALSE
;
1199 NS_ASSERTION(*aSelectorList
, "Should have list!");
1203 NS_ASSERTION(!*aSelectorList
, "Shouldn't have list!");
1204 if (NS_SUCCEEDED(rv
)) {
1205 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
1210 //----------------------------------------------------------------------
1213 CSSParserImpl::GetToken(PRBool aSkipWS
)
1216 if (!mHavePushBack
) {
1217 if (!mScanner
.Next(mToken
)) {
1221 mHavePushBack
= PR_FALSE
;
1222 if (aSkipWS
&& (eCSSToken_WhiteSpace
== mToken
.mType
)) {
1231 CSSParserImpl::GetURLToken()
1234 // XXXldb This pushback code doesn't make sense.
1235 if (! mHavePushBack
) {
1236 if (! mScanner
.NextURL(mToken
)) {
1240 mHavePushBack
= PR_FALSE
;
1241 if (eCSSToken_WhiteSpace
!= mToken
.mType
) {
1249 CSSParserImpl::UngetToken()
1251 NS_PRECONDITION(mHavePushBack
== PR_FALSE
, "double pushback");
1252 mHavePushBack
= PR_TRUE
;
1256 CSSParserImpl::ExpectSymbol(PRUnichar aSymbol
,
1259 if (!GetToken(aSkipWS
)) {
1260 // CSS2.1 specifies that all "open constructs" are to be closed at
1261 // EOF. It simplifies higher layers if we claim to have found an
1262 // ), ], }, or ; if we encounter EOF while looking for one of them.
1263 // Do still issue a diagnostic, to aid debugging.
1264 if (aSymbol
== ')' || aSymbol
== ']' ||
1265 aSymbol
== '}' || aSymbol
== ';') {
1266 REPORT_UNEXPECTED_EOF_CHAR(aSymbol
);
1272 if (mToken
.IsSymbol(aSymbol
)) {
1279 // Checks to see if we're at the end of a property. If an error occurs during
1280 // the check, does not signal a parse error.
1282 CSSParserImpl::CheckEndProperty()
1284 if (!GetToken(PR_TRUE
)) {
1285 return PR_TRUE
; // properties may end with eof
1287 if ((eCSSToken_Symbol
== mToken
.mType
) &&
1288 ((';' == mToken
.mSymbol
) ||
1289 ('!' == mToken
.mSymbol
) ||
1290 ('}' == mToken
.mSymbol
))) {
1291 // XXX need to verify that ! is only followed by "important [;|}]
1292 // XXX this requires a multi-token pushback buffer
1300 // Checks if we're at the end of a property, raising an error if we're not.
1302 CSSParserImpl::ExpectEndProperty()
1304 if (CheckEndProperty())
1307 // If we're here, we read something incorrect, so we should report it.
1308 REPORT_UNEXPECTED_TOKEN(PRExpectEndValue
);
1314 CSSParserImpl::NextIdent()
1316 // XXX Error reporting?
1317 if (!GetToken(PR_TRUE
)) {
1320 if (eCSSToken_Ident
!= mToken
.mType
) {
1324 return &mToken
.mIdent
;
1328 CSSParserImpl::SkipAtRule()
1331 if (!GetToken(PR_TRUE
)) {
1332 REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF
);
1335 if (eCSSToken_Symbol
== mToken
.mType
) {
1336 PRUnichar symbol
= mToken
.mSymbol
;
1337 if (symbol
== ';') {
1340 if (symbol
== '{') {
1343 } else if (symbol
== '(') {
1345 } else if (symbol
== '[') {
1354 CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc
,
1357 if ((mSection
<= eCSSSection_Charset
) &&
1358 (mToken
.mIdent
.LowerCaseEqualsLiteral("charset"))) {
1359 if (ParseCharsetRule(aAppendFunc
, aData
)) {
1360 mSection
= eCSSSection_Import
; // only one charset allowed
1364 if ((mSection
<= eCSSSection_Import
) &&
1365 mToken
.mIdent
.LowerCaseEqualsLiteral("import")) {
1366 if (ParseImportRule(aAppendFunc
, aData
)) {
1367 mSection
= eCSSSection_Import
;
1371 if ((mSection
<= eCSSSection_NameSpace
) &&
1372 mToken
.mIdent
.LowerCaseEqualsLiteral("namespace")) {
1373 if (ParseNameSpaceRule(aAppendFunc
, aData
)) {
1374 mSection
= eCSSSection_NameSpace
;
1378 if (mToken
.mIdent
.LowerCaseEqualsLiteral("media")) {
1379 if (ParseMediaRule(aAppendFunc
, aData
)) {
1380 mSection
= eCSSSection_General
;
1384 if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-document")) {
1385 if (ParseMozDocumentRule(aAppendFunc
, aData
)) {
1386 mSection
= eCSSSection_General
;
1390 if (mToken
.mIdent
.LowerCaseEqualsLiteral("font-face")) {
1391 if (ParseFontFaceRule(aAppendFunc
, aData
)) {
1392 mSection
= eCSSSection_General
;
1396 if (mToken
.mIdent
.LowerCaseEqualsLiteral("page")) {
1397 if (ParsePageRule(aAppendFunc
, aData
)) {
1398 mSection
= eCSSSection_General
;
1403 if (!NonMozillaVendorIdentifier(mToken
.mIdent
)) {
1404 REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule
);
1408 // Skip over unsupported at rule, don't advance section
1409 return SkipAtRule();
1413 CSSParserImpl::ParseCharsetRule(RuleAppendFunc aAppendFunc
,
1416 if (!GetToken(PR_TRUE
)) {
1417 REPORT_UNEXPECTED_EOF(PECharsetRuleEOF
);
1421 if (eCSSToken_String
!= mToken
.mType
) {
1422 REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString
);
1426 nsAutoString charset
= mToken
.mIdent
;
1428 if (!ExpectSymbol(';', PR_TRUE
)) {
1432 nsCOMPtr
<nsICSSRule
> rule
;
1433 NS_NewCSSCharsetRule(getter_AddRefs(rule
), charset
);
1436 (*aAppendFunc
)(rule
, aData
);
1443 CSSParserImpl::GatherURL(nsString
& aURL
)
1445 if (!GetToken(PR_TRUE
)) {
1448 if (eCSSToken_String
== mToken
.mType
) {
1449 aURL
= mToken
.mIdent
;
1452 else if (eCSSToken_Function
== mToken
.mType
&&
1453 mToken
.mIdent
.LowerCaseEqualsLiteral("url") &&
1454 ExpectSymbol('(', PR_FALSE
) &&
1456 (eCSSToken_String
== mToken
.mType
||
1457 eCSSToken_URL
== mToken
.mType
)) {
1458 aURL
= mToken
.mIdent
;
1459 if (ExpectSymbol(')', PR_TRUE
)) {
1466 // Callers must clear or throw out aMedia if GatherMedia returns false.
1468 CSSParserImpl::GatherMedia(nsMediaList
* aMedia
,
1469 PRUnichar aStopSymbol
)
1471 // "If the comma-separated list is the empty list it is assumed to
1472 // specify the media query 'all'." (css3-mediaqueries, section
1474 if (!GetToken(PR_TRUE
)) {
1475 // expected termination by EOF
1476 if (aStopSymbol
== PRUnichar(0))
1479 // unexpected termination by EOF; if we were looking for a
1480 // semicolon, return true anyway, for the same reason this is
1481 // done by ExpectSymbol().
1482 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1483 return aStopSymbol
== PRUnichar(';');
1486 if (eCSSToken_Symbol
== mToken
.mType
&&
1487 mToken
.mSymbol
== aStopSymbol
) {
1492 aMedia
->SetNonEmpty();
1495 // We want to still have |query| after we transfer ownership from
1496 // |queryHolder| to |aMedia|.
1497 nsMediaQuery
*query
;
1499 nsAutoPtr
<nsMediaQuery
> queryHolder(new nsMediaQuery
);
1501 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1504 query
= queryHolder
;
1506 // In terms of error handling, it doesn't really matter when we
1507 // append this, since aMedia's contents get dropped entirely
1508 // whenever there is an error.
1509 nsresult rv
= aMedia
->AppendQuery(queryHolder
);
1510 if (NS_FAILED(rv
)) {
1511 mScanner
.SetLowLevelError(rv
);
1514 NS_ASSERTION(!queryHolder
, "ownership should have been transferred");
1517 if (ExpectSymbol('(', PR_TRUE
)) {
1518 // we got an expression without a media type
1519 UngetToken(); // so ParseMediaQueryExpression can handle it
1520 query
->SetType(nsGkAtoms::all
);
1521 query
->SetTypeOmitted();
1522 // Just parse the first expression here.
1523 if (!ParseMediaQueryExpression(query
)) {
1525 query
->SetHadUnknownExpression();
1528 nsCOMPtr
<nsIAtom
> mediaType
;
1529 PRBool gotNotOrOnly
= PR_FALSE
;
1531 if (!GetToken(PR_TRUE
)) {
1532 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1535 if (eCSSToken_Ident
!= mToken
.mType
) {
1536 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent
);
1540 // case insensitive from CSS - must be lower cased
1541 ToLowerCase(mToken
.mIdent
);
1542 mediaType
= do_GetAtom(mToken
.mIdent
);
1544 (mediaType
!= nsGkAtoms::_not
&& mediaType
!= nsGkAtoms::only
))
1546 gotNotOrOnly
= PR_TRUE
;
1547 if (mediaType
== nsGkAtoms::_not
)
1548 query
->SetNegated();
1550 query
->SetHasOnly();
1552 query
->SetType(mediaType
);
1556 if (!GetToken(PR_TRUE
)) {
1557 // expected termination by EOF
1558 if (aStopSymbol
== PRUnichar(0))
1561 // unexpected termination by EOF; if we were looking for a
1562 // semicolon, return true anyway, for the same reason this is
1563 // done by ExpectSymbol().
1564 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
1565 return aStopSymbol
== PRUnichar(';');
1568 if (eCSSToken_Symbol
== mToken
.mType
&&
1569 mToken
.mSymbol
== aStopSymbol
) {
1573 if (eCSSToken_Symbol
== mToken
.mType
&& mToken
.mSymbol
== ',') {
1574 // Done with the expressions for this query
1577 if (eCSSToken_Ident
!= mToken
.mType
||
1578 !mToken
.mIdent
.LowerCaseEqualsLiteral("and")) {
1579 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma
);
1583 if (!ParseMediaQueryExpression(query
)) {
1585 query
->SetHadUnknownExpression();
1589 NS_NOTREACHED("unreachable code");
1590 return PR_FALSE
; // keep the compiler happy
1594 CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery
* aQuery
)
1596 if (!ExpectSymbol('(', PR_TRUE
)) {
1597 REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart
);
1600 if (! GetToken(PR_TRUE
)) {
1601 REPORT_UNEXPECTED_EOF(PEMQExpressionEOF
);
1604 if (eCSSToken_Ident
!= mToken
.mType
) {
1605 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1610 nsMediaExpression
*expr
= aQuery
->NewExpression();
1612 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1617 // case insensitive from CSS - must be lower cased
1618 ToLowerCase(mToken
.mIdent
);
1619 const PRUnichar
*featureString
;
1620 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("min-"))) {
1621 expr
->mRange
= nsMediaExpression::eMin
;
1622 featureString
= mToken
.mIdent
.get() + 4;
1623 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("max-"))) {
1624 expr
->mRange
= nsMediaExpression::eMax
;
1625 featureString
= mToken
.mIdent
.get() + 4;
1627 expr
->mRange
= nsMediaExpression::eEqual
;
1628 featureString
= mToken
.mIdent
.get();
1631 nsCOMPtr
<nsIAtom
> mediaFeatureAtom
= do_GetAtom(featureString
);
1632 const nsMediaFeature
*feature
= nsMediaFeatures::features
;
1633 for (; feature
->mName
; ++feature
) {
1634 if (*(feature
->mName
) == mediaFeatureAtom
) {
1638 if (!feature
->mName
||
1639 (expr
->mRange
!= nsMediaExpression::eEqual
&&
1640 feature
->mRangeType
!= nsMediaFeature::eMinMaxAllowed
)) {
1641 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
1645 expr
->mFeature
= feature
;
1647 if (!GetToken(PR_TRUE
) || mToken
.IsSymbol(')')) {
1648 // Query expressions for any feature can be given without a value.
1649 // However, min/max prefixes are not allowed.
1650 if (expr
->mRange
!= nsMediaExpression::eEqual
) {
1651 REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue
);
1654 expr
->mValue
.Reset();
1658 if (!mToken
.IsSymbol(':')) {
1659 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd
);
1665 switch (feature
->mValueType
) {
1666 case nsMediaFeature::eLength
:
1667 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_LENGTH
, nsnull
);
1669 case nsMediaFeature::eInteger
:
1670 case nsMediaFeature::eBoolInteger
:
1671 rv
= ParsePositiveVariant(expr
->mValue
, VARIANT_INTEGER
, nsnull
);
1672 // Enforce extra restrictions for eBoolInteger
1674 feature
->mValueType
== nsMediaFeature::eBoolInteger
&&
1675 expr
->mValue
.GetIntValue() > 1)
1678 case nsMediaFeature::eIntRatio
:
1680 // Two integers separated by '/', with optional whitespace on
1681 // either side of the '/'.
1682 nsRefPtr
<nsCSSValue::Array
> a
= nsCSSValue::Array::Create(2);
1684 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1688 expr
->mValue
.SetArrayValue(a
, eCSSUnit_Array
);
1689 // We don't bother with ParsePositiveVariant since we have to
1690 // check for != 0 as well; no need to worry about the UngetToken
1691 // since we're throwing out up to the next ')' anyway.
1692 rv
= ParseVariant(a
->Item(0), VARIANT_INTEGER
, nsnull
) &&
1693 a
->Item(0).GetIntValue() > 0 &&
1694 ExpectSymbol('/', PR_TRUE
) &&
1695 ParseVariant(a
->Item(1), VARIANT_INTEGER
, nsnull
) &&
1696 a
->Item(1).GetIntValue() > 0;
1699 case nsMediaFeature::eResolution
:
1700 rv
= GetToken(PR_TRUE
) && mToken
.IsDimension() &&
1701 mToken
.mIntegerValid
&& mToken
.mNumber
> 0.0f
;
1703 // No worries about whether unitless zero is allowed, since the
1704 // value must be positive (and we checked that above).
1705 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(), "IsDimension lied");
1706 if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpi")) {
1707 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Inch
);
1708 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpcm")) {
1709 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Centimeter
);
1715 case nsMediaFeature::eEnumerated
:
1716 rv
= ParseVariant(expr
->mValue
, VARIANT_KEYWORD
,
1717 feature
->mKeywordTable
);
1720 if (!rv
|| !ExpectSymbol(')', PR_TRUE
)) {
1721 REPORT_UNEXPECTED(PEMQExpectedFeatureValue
);
1729 // Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"
1731 CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc
, void* aData
)
1733 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1735 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1740 if (!GatherURL(url
)) {
1741 REPORT_UNEXPECTED_TOKEN(PEImportNotURI
);
1745 if (!ExpectSymbol(';', PR_TRUE
)) {
1746 if (!GatherMedia(media
, ';') ||
1747 !ExpectSymbol(';', PR_TRUE
)) {
1748 REPORT_UNEXPECTED_TOKEN(PEImportUnexpected
);
1749 // don't advance section, simply ignore invalid @import
1753 // Safe to assert this, since we ensured that there is something
1754 // other than the ';' coming after the @import's url() token.
1755 NS_ASSERTION(media
->Count() != 0, "media list must be nonempty");
1758 ProcessImport(url
, media
, aAppendFunc
, aData
);
1764 CSSParserImpl::ProcessImport(const nsString
& aURLSpec
,
1765 nsMediaList
* aMedia
,
1766 RuleAppendFunc aAppendFunc
,
1769 nsCOMPtr
<nsICSSImportRule
> rule
;
1770 nsresult rv
= NS_NewCSSImportRule(getter_AddRefs(rule
), aURLSpec
, aMedia
);
1771 if (NS_FAILED(rv
)) {
1772 mScanner
.SetLowLevelError(rv
);
1775 (*aAppendFunc
)(rule
, aData
);
1778 nsCOMPtr
<nsIURI
> url
;
1779 // XXX should pass a charset!
1780 rv
= NS_NewURI(getter_AddRefs(url
), aURLSpec
, nsnull
, mBaseURL
);
1782 if (NS_FAILED(rv
)) {
1783 // import url is bad
1784 // XXX log this somewhere for easier web page debugging
1785 mScanner
.SetLowLevelError(rv
);
1789 mChildLoader
->LoadChildSheet(mSheet
, url
, aMedia
, rule
);
1795 // Parse the {} part of an @media or @-moz-document rule.
1797 CSSParserImpl::ParseGroupRule(nsICSSGroupRule
* aRule
,
1798 RuleAppendFunc aAppendFunc
,
1801 // XXXbz this could use better error reporting throughout the method
1802 if (!ExpectSymbol('{', PR_TRUE
)) {
1806 // push rule on stack, loop over children
1807 if (!PushGroup(aRule
)) {
1808 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1811 nsCSSSection holdSection
= mSection
;
1812 mSection
= eCSSSection_General
;
1815 // Get next non-whitespace token
1816 if (! GetToken(PR_TRUE
)) {
1817 REPORT_UNEXPECTED_EOF(PEGroupRuleEOF
);
1820 if (mToken
.IsSymbol('}')) { // done!
1824 if (eCSSToken_AtKeyword
== mToken
.mType
) {
1825 SkipAtRule(); // group rules cannot contain @rules
1829 ParseRuleSet(AppendRuleToSheet
, this);
1833 if (!ExpectSymbol('}', PR_TRUE
)) {
1834 mSection
= holdSection
;
1837 (*aAppendFunc
)(aRule
, aData
);
1841 // Parse a CSS2 media rule: "@media medium [, medium] { ... }"
1843 CSSParserImpl::ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aData
)
1845 nsCOMPtr
<nsMediaList
> media
= new nsMediaList();
1847 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1851 if (GatherMedia(media
, '{')) {
1852 // XXXbz this could use better error reporting throughout the method
1853 nsRefPtr
<nsCSSMediaRule
> rule(new nsCSSMediaRule());
1854 // Append first, so when we do SetMedia() the rule
1855 // knows what its stylesheet is.
1856 if (rule
&& ParseGroupRule(rule
, aAppendFunc
, aData
)) {
1857 rule
->SetMedia(media
);
1865 // Parse a @-moz-document rule. This is like an @media rule, but instead
1866 // of a medium it has a nonempty list of items where each item is either
1867 // url(), url-prefix(), or domain().
1869 CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aData
)
1871 nsCSSDocumentRule::URL
*urls
= nsnull
;
1872 nsCSSDocumentRule::URL
**next
= &urls
;
1874 if (!GetToken(PR_TRUE
) ||
1875 eCSSToken_Function
!= mToken
.mType
||
1876 !(mToken
.mIdent
.LowerCaseEqualsLiteral("url") ||
1877 mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix") ||
1878 mToken
.mIdent
.LowerCaseEqualsLiteral("domain"))) {
1879 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc
);
1883 nsCSSDocumentRule::URL
*cur
= *next
= new nsCSSDocumentRule::URL
;
1885 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1890 if (mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
1891 cur
->func
= nsCSSDocumentRule::eURL
;
1892 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix")) {
1893 cur
->func
= nsCSSDocumentRule::eURLPrefix
;
1894 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("domain")) {
1895 cur
->func
= nsCSSDocumentRule::eDomain
;
1898 if (!ExpectSymbol('(', PR_FALSE
) ||
1900 (eCSSToken_String
!= mToken
.mType
&&
1901 eCSSToken_URL
!= mToken
.mType
)) {
1902 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI
);
1906 if (!ExpectSymbol(')', PR_TRUE
)) {
1911 // We could try to make the URL (as long as it's not domain())
1912 // canonical and absolute with NS_NewURI and GetSpec, but I'm
1913 // inclined to think we shouldn't.
1914 CopyUTF16toUTF8(mToken
.mIdent
, cur
->url
);
1915 } while (ExpectSymbol(',', PR_TRUE
));
1917 nsRefPtr
<nsCSSDocumentRule
> rule(new nsCSSDocumentRule());
1919 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
1923 rule
->SetURLs(urls
);
1925 return ParseGroupRule(rule
, aAppendFunc
, aData
);
1928 // Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"
1930 CSSParserImpl::ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
1932 if (!GetToken(PR_TRUE
)) {
1933 REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF
);
1937 nsAutoString prefix
;
1940 if (eCSSToken_Ident
== mToken
.mType
) {
1941 prefix
= mToken
.mIdent
;
1942 // user-specified identifiers are case-sensitive (bug 416106)
1943 if (! GetToken(PR_TRUE
)) {
1944 REPORT_UNEXPECTED_EOF(PEAtNSURIEOF
);
1949 if (eCSSToken_String
== mToken
.mType
) {
1950 url
= mToken
.mIdent
;
1951 if (ExpectSymbol(';', PR_TRUE
)) {
1952 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
1956 else if ((eCSSToken_Function
== mToken
.mType
) &&
1957 (mToken
.mIdent
.LowerCaseEqualsLiteral("url"))) {
1958 if (ExpectSymbol('(', PR_FALSE
)) {
1959 if (GetURLToken()) {
1960 if ((eCSSToken_String
== mToken
.mType
) || (eCSSToken_URL
== mToken
.mType
)) {
1961 url
= mToken
.mIdent
;
1962 if (ExpectSymbol(')', PR_TRUE
)) {
1963 if (ExpectSymbol(';', PR_TRUE
)) {
1964 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
);
1972 REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected
);
1978 CSSParserImpl::ProcessNameSpace(const nsString
& aPrefix
,
1979 const nsString
& aURLSpec
,
1980 RuleAppendFunc aAppendFunc
,
1983 PRBool result
= PR_FALSE
;
1985 nsCOMPtr
<nsICSSNameSpaceRule
> rule
;
1986 nsCOMPtr
<nsIAtom
> prefix
;
1988 if (!aPrefix
.IsEmpty()) {
1989 prefix
= do_GetAtom(aPrefix
);
1992 NS_NewCSSNameSpaceRule(getter_AddRefs(rule
), prefix
, aURLSpec
);
1994 (*aAppendFunc
)(rule
, aData
);
1996 // If this was the first namespace rule encountered, it will trigger
1997 // creation of a namespace map.
1998 if (!mNameSpaceMap
) {
1999 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
2006 // font-face-rule: '@font-face' '{' font-description '}'
2007 // font-description: font-descriptor+
2009 CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
2011 if (!ExpectSymbol('{', PR_TRUE
))
2014 nsRefPtr
<nsCSSFontFaceRule
> rule(new nsCSSFontFaceRule());
2016 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2021 if (!GetToken(PR_TRUE
)) {
2022 REPORT_UNEXPECTED_EOF(PEFontFaceEOF
);
2025 if (mToken
.IsSymbol('}')) { // done!
2030 // ignore extra semicolons
2031 if (mToken
.IsSymbol(';'))
2034 if (!ParseFontDescriptor(rule
)) {
2035 REPORT_UNEXPECTED(PEDeclSkipped
);
2037 if (!SkipDeclaration(PR_TRUE
))
2041 if (!ExpectSymbol('}', PR_TRUE
))
2043 (*aAppendFunc
)(rule
, aData
);
2047 // font-descriptor: font-family-desc
2048 // | font-style-desc
2049 // | font-weight-desc
2050 // | font-stretch-desc
2052 // | unicode-range-desc
2054 // All font-*-desc productions follow the pattern
2055 // IDENT ':' value ';'
2057 // On entry to this function, mToken is the IDENT.
2060 CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule
* aRule
)
2062 if (eCSSToken_Ident
!= mToken
.mType
) {
2063 REPORT_UNEXPECTED_TOKEN(PEFontDescExpected
);
2067 nsString descName
= mToken
.mIdent
;
2068 if (!ExpectSymbol(':', PR_TRUE
)) {
2069 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
2074 nsCSSFontDesc descID
= nsCSSProps::LookupFontDesc(descName
);
2077 if (descID
== eCSSFontDesc_UNKNOWN
) {
2078 if (NonMozillaVendorIdentifier(descName
)) {
2079 // silently skip other vendors' extensions
2080 SkipDeclaration(PR_TRUE
);
2083 const PRUnichar
*params
[] = {
2086 REPORT_UNEXPECTED_P(PEUnknownFontDesc
, params
);
2091 if (!ParseFontDescriptorValue(descID
, value
)) {
2092 const PRUnichar
*params
[] = {
2095 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
2099 if (!ExpectEndProperty())
2102 aRule
->SetDesc(descID
, value
);
2108 CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc
, void* aData
)
2110 // XXX not yet implemented
2115 CSSParserImpl::SkipUntil(PRUnichar aStopSymbol
)
2117 nsCSSToken
* tk
= &mToken
;
2119 if (!GetToken(PR_TRUE
)) {
2122 if (eCSSToken_Symbol
== tk
->mType
) {
2123 PRUnichar symbol
= tk
->mSymbol
;
2124 if (symbol
== aStopSymbol
) {
2126 } else if ('{' == symbol
) {
2128 } else if ('[' == symbol
) {
2130 } else if ('(' == symbol
) {
2138 CSSParserImpl::GetNonCloseParenToken(PRBool aSkipWS
)
2140 if (!GetToken(aSkipWS
))
2142 if (mToken
.mType
== eCSSToken_Symbol
&& mToken
.mSymbol
== ')') {
2150 CSSParserImpl::SkipDeclaration(PRBool aCheckForBraces
)
2152 nsCSSToken
* tk
= &mToken
;
2154 if (!GetToken(PR_TRUE
)) {
2155 if (aCheckForBraces
) {
2156 REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF
);
2160 if (eCSSToken_Symbol
== tk
->mType
) {
2161 PRUnichar symbol
= tk
->mSymbol
;
2162 if (';' == symbol
) {
2165 if (aCheckForBraces
) {
2166 if ('}' == symbol
) {
2171 if ('{' == symbol
) {
2173 } else if ('(' == symbol
) {
2175 } else if ('[' == symbol
) {
2184 CSSParserImpl::SkipRuleSet()
2186 nsCSSToken
* tk
= &mToken
;
2188 if (!GetToken(PR_TRUE
)) {
2189 REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF
);
2192 if (eCSSToken_Symbol
== tk
->mType
) {
2193 PRUnichar symbol
= tk
->mSymbol
;
2194 if ('{' == symbol
) {
2198 if ('(' == symbol
) {
2200 } else if ('[' == symbol
) {
2208 CSSParserImpl::PushGroup(nsICSSGroupRule
* aRule
)
2210 if (mGroupStack
.AppendObject(aRule
))
2217 CSSParserImpl::PopGroup(void)
2219 PRInt32 count
= mGroupStack
.Count();
2221 mGroupStack
.RemoveObjectAt(count
- 1);
2226 CSSParserImpl::AppendRule(nsICSSRule
* aRule
)
2228 PRInt32 count
= mGroupStack
.Count();
2230 mGroupStack
[count
- 1]->AppendStyleRule(aRule
);
2233 mSheet
->AppendStyleRule(aRule
);
2238 CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aData
)
2240 // First get the list of selectors for the rule
2241 nsCSSSelectorList
* slist
= nsnull
;
2242 PRUint32 linenum
= mScanner
.GetLineNumber();
2243 if (! ParseSelectorList(slist
, PR_TRUE
)) {
2244 REPORT_UNEXPECTED(PEBadSelectorRSIgnored
);
2249 NS_ASSERTION(nsnull
!= slist
, "null selector list");
2252 // Next parse the declaration block
2253 nsCSSDeclaration
* declaration
= ParseDeclarationBlock(PR_TRUE
);
2254 if (nsnull
== declaration
) {
2255 // XXX skip something here
2262 fputs("{\n", stdout
);
2263 declaration
->List();
2264 fputs("}\n", stdout
);
2267 // Translate the selector list and declaration block into style data
2269 nsCOMPtr
<nsICSSStyleRule
> rule
;
2270 NS_NewCSSStyleRule(getter_AddRefs(rule
), slist
, declaration
);
2272 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2276 rule
->SetLineNumber(linenum
);
2277 (*aAppendFunc
)(rule
, aData
);
2283 CSSParserImpl::ParseSelectorList(nsCSSSelectorList
*& aListHead
,
2284 PRBool aTerminateAtBrace
)
2286 nsCSSSelectorList
* list
= nsnull
;
2287 if (! ParseSelectorGroup(list
)) {
2288 // must have at least one selector group
2292 NS_ASSERTION(nsnull
!= list
, "no selector list");
2295 // After that there must either be a "," or a "{" (the latter if
2296 // aTerminateAtBrace is true)
2297 nsCSSToken
* tk
= &mToken
;
2299 if (! GetToken(PR_TRUE
)) {
2300 if (!aTerminateAtBrace
) {
2304 REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF
);
2308 if (eCSSToken_Symbol
== tk
->mType
) {
2309 if (',' == tk
->mSymbol
) {
2310 nsCSSSelectorList
* newList
= nsnull
;
2311 // Another selector group must follow
2312 if (! ParseSelectorGroup(newList
)) {
2315 // add new list to the end of the selector list
2316 list
->mNext
= newList
;
2319 } else if ('{' == tk
->mSymbol
&& aTerminateAtBrace
) {
2324 REPORT_UNEXPECTED_TOKEN(PESelectorListExtra
);
2334 static PRBool
IsSinglePseudoClass(const nsCSSSelector
& aSelector
)
2336 return PRBool((aSelector
.mNameSpace
== kNameSpaceID_Unknown
) &&
2337 (aSelector
.mTag
== nsnull
) &&
2338 (aSelector
.mIDList
== nsnull
) &&
2339 (aSelector
.mClassList
== nsnull
) &&
2340 (aSelector
.mAttrList
== nsnull
) &&
2341 (aSelector
.mNegations
== nsnull
) &&
2342 (aSelector
.mPseudoClassList
!= nsnull
) &&
2343 (aSelector
.mPseudoClassList
->mNext
== nsnull
));
2347 static PRBool
IsTreePseudoElement(nsIAtom
* aPseudo
)
2350 aPseudo
->GetUTF8String(&str
);
2351 static const char moz_tree
[] = ":-moz-tree-";
2352 return nsCRT::strncmp(str
, moz_tree
, PRInt32(sizeof(moz_tree
)-1)) == 0;
2357 CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList
*& aList
)
2359 nsAutoPtr
<nsCSSSelectorList
> list
;
2360 PRUnichar combinator
= PRUnichar(0);
2362 PRBool havePseudoElement
= PR_FALSE
;
2363 PRBool done
= PR_FALSE
;
2365 nsAutoPtr
<nsCSSSelector
> newSelector(new nsCSSSelector());
2367 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2370 nsSelectorParsingStatus parsingStatus
=
2371 ParseSelector(*newSelector
);
2372 if (parsingStatus
== eSelectorParsingStatus_Empty
) {
2374 REPORT_UNEXPECTED(PESelectorGroupNoSelector
);
2378 if (parsingStatus
== eSelectorParsingStatus_Error
) {
2382 if (nsnull
== list
) {
2383 list
= new nsCSSSelectorList();
2384 if (nsnull
== list
) {
2385 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2389 list
->AddSelector(newSelector
);
2390 nsCSSSelector
* listSel
= list
->mSelectors
;
2392 // pull out pseudo elements here
2393 nsPseudoClassList
* prevList
= nsnull
;
2394 nsPseudoClassList
* pseudoClassList
= listSel
->mPseudoClassList
;
2395 while (nsnull
!= pseudoClassList
) {
2396 if (! nsCSSPseudoClasses::IsPseudoClass(pseudoClassList
->mAtom
)) {
2397 havePseudoElement
= PR_TRUE
;
2398 if (IsSinglePseudoClass(*listSel
)) { // convert to pseudo element selector
2399 nsIAtom
* pseudoElement
= pseudoClassList
->mAtom
; // steal ref count
2400 pseudoClassList
->mAtom
= nsnull
;
2402 if (listSel
->mNext
) {// more to the selector
2403 listSel
->mOperator
= PRUnichar('>');
2404 nsAutoPtr
<nsCSSSelector
> empty(new nsCSSSelector());
2406 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2409 list
->AddSelector(empty
); // leave a blank (universal) selector in the middle
2410 listSel
= list
->mSelectors
; // use the new one for the pseudo
2412 listSel
->mTag
= pseudoElement
;
2414 else { // append new pseudo element selector
2415 nsAutoPtr
<nsCSSSelector
> pseudoTagSelector(new nsCSSSelector());
2416 if (!pseudoTagSelector
) {
2417 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
2420 pseudoTagSelector
->mTag
= pseudoClassList
->mAtom
; // steal ref count
2422 if (IsTreePseudoElement(pseudoTagSelector
->mTag
)) {
2423 // Take the remaining "pseudoclasses" that we parsed
2424 // inside the tree pseudoelement's ()-list, and
2425 // make our new selector have these pseudoclasses
2426 // in its pseudoclass list.
2427 pseudoTagSelector
->mPseudoClassList
= pseudoClassList
->mNext
;
2428 pseudoClassList
->mNext
= nsnull
;
2431 list
->AddSelector(pseudoTagSelector
);
2432 pseudoClassList
->mAtom
= nsnull
;
2433 listSel
->mOperator
= PRUnichar('>');
2434 if (nsnull
== prevList
) { // delete list entry
2435 listSel
->mPseudoClassList
= pseudoClassList
->mNext
;
2438 prevList
->mNext
= pseudoClassList
->mNext
;
2440 pseudoClassList
->mNext
= nsnull
;
2441 delete pseudoClassList
;
2442 weight
+= listSel
->CalcWeight(); // capture weight from remainder
2444 break; // only one pseudo element per selector
2446 prevList
= pseudoClassList
;
2447 pseudoClassList
= pseudoClassList
->mNext
;
2450 combinator
= PRUnichar(0);
2451 if (!GetToken(PR_FALSE
)) {
2455 // Assume we are done unless we find a combinator here.
2457 if (eCSSToken_WhiteSpace
== mToken
.mType
) {
2458 if (!GetToken(PR_TRUE
)) {
2464 if (eCSSToken_Symbol
== mToken
.mType
&&
2465 ('+' == mToken
.mSymbol
||
2466 '>' == mToken
.mSymbol
||
2467 '~' == mToken
.mSymbol
)) {
2469 combinator
= mToken
.mSymbol
;
2470 list
->mSelectors
->SetOperator(combinator
);
2473 if (eCSSToken_Symbol
== mToken
.mType
&&
2474 ('{' == mToken
.mSymbol
||
2475 ',' == mToken
.mSymbol
)) {
2476 // End of this selector group
2479 UngetToken(); // give it back to selector if we're not done, or make sure
2480 // we see it as the end of the selector if we are.
2483 if (havePseudoElement
) {
2487 weight
+= listSel
->CalcWeight();
2491 if (PRUnichar(0) != combinator
) { // no dangling combinators
2493 // This should report the problematic combinator
2494 REPORT_UNEXPECTED(PESelectorGroupExtraCombinator
);
2496 aList
= list
.forget();
2498 aList
->mWeight
= weight
;
2500 return PRBool(nsnull
!= aList
);
2503 #define SEL_MASK_NSPACE 0x01
2504 #define SEL_MASK_ELEM 0x02
2505 #define SEL_MASK_ID 0x04
2506 #define SEL_MASK_CLASS 0x08
2507 #define SEL_MASK_ATTRIB 0x10
2508 #define SEL_MASK_PCLASS 0x20
2509 #define SEL_MASK_PELEM 0x40
2512 // Parses an ID selector #name
2514 CSSParserImpl::nsSelectorParsingStatus
2515 CSSParserImpl::ParseIDSelector(PRInt32
& aDataMask
,
2516 nsCSSSelector
& aSelector
)
2518 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(),
2519 "Empty mIdent in eCSSToken_ID token?");
2520 aDataMask
|= SEL_MASK_ID
;
2521 aSelector
.AddID(mToken
.mIdent
);
2522 return eSelectorParsingStatus_Continue
;
2526 // Parses a class selector .name
2528 CSSParserImpl::nsSelectorParsingStatus
2529 CSSParserImpl::ParseClassSelector(PRInt32
& aDataMask
,
2530 nsCSSSelector
& aSelector
)
2532 if (! GetToken(PR_FALSE
)) { // get ident
2533 REPORT_UNEXPECTED_EOF(PEClassSelEOF
);
2534 return eSelectorParsingStatus_Error
;
2536 if (eCSSToken_Ident
!= mToken
.mType
) { // malformed selector
2537 REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent
);
2539 return eSelectorParsingStatus_Error
;
2541 aDataMask
|= SEL_MASK_CLASS
;
2543 aSelector
.AddClass(mToken
.mIdent
);
2545 return eSelectorParsingStatus_Continue
;
2549 // Parse a type element selector or a universal selector
2550 // namespace|type or namespace|* or *|* or *
2552 CSSParserImpl::nsSelectorParsingStatus
2553 CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32
& aDataMask
,
2554 nsCSSSelector
& aSelector
,
2557 nsAutoString buffer
;
2558 if (mToken
.IsSymbol('*')) { // universal element selector, or universal namespace
2559 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2560 aDataMask
|= SEL_MASK_NSPACE
;
2561 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // namespace wildcard
2563 if (! GetToken(PR_FALSE
)) {
2564 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2565 return eSelectorParsingStatus_Error
;
2567 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2568 aDataMask
|= SEL_MASK_ELEM
;
2569 if (mCaseSensitive
) {
2570 aSelector
.SetTag(mToken
.mIdent
);
2573 ToLowerCase(mToken
.mIdent
, buffer
);
2574 aSelector
.SetTag(buffer
);
2577 else if (mToken
.IsSymbol('*')) { // universal selector
2578 aDataMask
|= SEL_MASK_ELEM
;
2582 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2584 return eSelectorParsingStatus_Error
;
2587 else { // was universal element selector
2588 SetDefaultNamespaceOnSelector(aSelector
);
2589 aDataMask
|= SEL_MASK_ELEM
;
2590 // don't set any tag in the selector
2592 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2593 return eSelectorParsingStatus_Done
;
2596 else if (eCSSToken_Ident
== mToken
.mType
) { // element name or namespace name
2597 buffer
= mToken
.mIdent
; // hang on to ident
2599 if (ExpectSymbol('|', PR_FALSE
)) { // was namespace
2600 aDataMask
|= SEL_MASK_NSPACE
;
2601 PRInt32 nameSpaceID
;
2602 if (!GetNamespaceIdForPrefix(buffer
, &nameSpaceID
)) {
2603 return eSelectorParsingStatus_Error
;
2605 aSelector
.SetNameSpace(nameSpaceID
);
2607 if (! GetToken(PR_FALSE
)) {
2608 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2609 return eSelectorParsingStatus_Error
;
2611 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2612 aDataMask
|= SEL_MASK_ELEM
;
2613 if (mCaseSensitive
) {
2614 aSelector
.SetTag(mToken
.mIdent
);
2617 ToLowerCase(mToken
.mIdent
, buffer
);
2618 aSelector
.SetTag(buffer
);
2621 else if (mToken
.IsSymbol('*')) { // universal selector
2622 aDataMask
|= SEL_MASK_ELEM
;
2626 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2628 return eSelectorParsingStatus_Error
;
2631 else { // was element name
2632 SetDefaultNamespaceOnSelector(aSelector
);
2633 if (mCaseSensitive
) {
2634 aSelector
.SetTag(buffer
);
2637 ToLowerCase(buffer
);
2638 aSelector
.SetTag(buffer
);
2640 aDataMask
|= SEL_MASK_ELEM
;
2642 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2643 return eSelectorParsingStatus_Done
;
2646 else if (mToken
.IsSymbol('|')) { // No namespace
2647 aDataMask
|= SEL_MASK_NSPACE
;
2648 aSelector
.SetNameSpace(kNameSpaceID_None
); // explicit NO namespace
2650 // get mandatory tag
2651 if (! GetToken(PR_FALSE
)) {
2652 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
2653 return eSelectorParsingStatus_Error
;
2655 if (eCSSToken_Ident
== mToken
.mType
) { // element name
2656 aDataMask
|= SEL_MASK_ELEM
;
2657 if (mCaseSensitive
) {
2658 aSelector
.SetTag(mToken
.mIdent
);
2661 ToLowerCase(mToken
.mIdent
, buffer
);
2662 aSelector
.SetTag(buffer
);
2665 else if (mToken
.IsSymbol('*')) { // universal selector
2666 aDataMask
|= SEL_MASK_ELEM
;
2670 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
2672 return eSelectorParsingStatus_Error
;
2674 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
2675 return eSelectorParsingStatus_Done
;
2679 SetDefaultNamespaceOnSelector(aSelector
);
2683 // restore last token read in case of a negated type selector
2686 return eSelectorParsingStatus_Continue
;
2690 // Parse attribute selectors [attr], [attr=value], [attr|=value],
2691 // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
2693 CSSParserImpl::nsSelectorParsingStatus
2694 CSSParserImpl::ParseAttributeSelector(PRInt32
& aDataMask
,
2695 nsCSSSelector
& aSelector
)
2697 if (! GetToken(PR_TRUE
)) { // premature EOF
2698 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2699 return eSelectorParsingStatus_Error
;
2702 PRInt32 nameSpaceID
= kNameSpaceID_None
;
2704 if (mToken
.IsSymbol('*')) { // wildcard namespace
2705 nameSpaceID
= kNameSpaceID_Unknown
;
2706 if (ExpectSymbol('|', PR_FALSE
)) {
2707 if (! GetToken(PR_FALSE
)) { // premature EOF
2708 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2709 return eSelectorParsingStatus_Error
;
2711 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2712 attr
= mToken
.mIdent
;
2715 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2717 return eSelectorParsingStatus_Error
;
2721 REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar
);
2722 return eSelectorParsingStatus_Error
;
2725 else if (mToken
.IsSymbol('|')) { // NO namespace
2726 if (! GetToken(PR_FALSE
)) { // premature EOF
2727 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2728 return eSelectorParsingStatus_Error
;
2730 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2731 attr
= mToken
.mIdent
;
2734 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2736 return eSelectorParsingStatus_Error
;
2739 else if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
2740 attr
= mToken
.mIdent
; // hang on to it
2741 if (ExpectSymbol('|', PR_FALSE
)) { // was a namespace
2742 if (!GetNamespaceIdForPrefix(attr
, &nameSpaceID
)) {
2743 return eSelectorParsingStatus_Error
;
2745 if (! GetToken(PR_FALSE
)) { // premature EOF
2746 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
2747 return eSelectorParsingStatus_Error
;
2749 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
2750 attr
= mToken
.mIdent
;
2753 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
2755 return eSelectorParsingStatus_Error
;
2760 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
2762 return eSelectorParsingStatus_Error
;
2765 if (! mCaseSensitive
) {
2768 if (! GetToken(PR_TRUE
)) { // premature EOF
2769 REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF
);
2770 return eSelectorParsingStatus_Error
;
2772 if ((eCSSToken_Symbol
== mToken
.mType
) ||
2773 (eCSSToken_Includes
== mToken
.mType
) ||
2774 (eCSSToken_Dashmatch
== mToken
.mType
) ||
2775 (eCSSToken_Beginsmatch
== mToken
.mType
) ||
2776 (eCSSToken_Endsmatch
== mToken
.mType
) ||
2777 (eCSSToken_Containsmatch
== mToken
.mType
)) {
2779 if (eCSSToken_Includes
== mToken
.mType
) {
2780 func
= NS_ATTR_FUNC_INCLUDES
;
2782 else if (eCSSToken_Dashmatch
== mToken
.mType
) {
2783 func
= NS_ATTR_FUNC_DASHMATCH
;
2785 else if (eCSSToken_Beginsmatch
== mToken
.mType
) {
2786 func
= NS_ATTR_FUNC_BEGINSMATCH
;
2788 else if (eCSSToken_Endsmatch
== mToken
.mType
) {
2789 func
= NS_ATTR_FUNC_ENDSMATCH
;
2791 else if (eCSSToken_Containsmatch
== mToken
.mType
) {
2792 func
= NS_ATTR_FUNC_CONTAINSMATCH
;
2794 else if (']' == mToken
.mSymbol
) {
2795 aDataMask
|= SEL_MASK_ATTRIB
;
2796 aSelector
.AddAttribute(nameSpaceID
, attr
);
2797 func
= NS_ATTR_FUNC_SET
;
2799 else if ('=' == mToken
.mSymbol
) {
2800 func
= NS_ATTR_FUNC_EQUALS
;
2803 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2804 UngetToken(); // bad function
2805 return eSelectorParsingStatus_Error
;
2807 if (NS_ATTR_FUNC_SET
!= func
) { // get value
2808 if (! GetToken(PR_TRUE
)) { // premature EOF
2809 REPORT_UNEXPECTED_EOF(PEAttSelValueEOF
);
2810 return eSelectorParsingStatus_Error
;
2812 if ((eCSSToken_Ident
== mToken
.mType
) || (eCSSToken_String
== mToken
.mType
)) {
2813 nsAutoString
value(mToken
.mIdent
);
2814 if (! GetToken(PR_TRUE
)) { // premature EOF
2815 REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF
);
2816 return eSelectorParsingStatus_Error
;
2818 if (mToken
.IsSymbol(']')) {
2819 PRBool isCaseSensitive
= PR_TRUE
;
2821 // If we're parsing a style sheet for an HTML document, and
2822 // the attribute selector is for a non-namespaced attribute,
2823 // then check to see if it's one of the known attributes whose
2824 // VALUE is case-insensitive.
2825 if (!mCaseSensitive
&& nameSpaceID
== kNameSpaceID_None
) {
2826 static const char* caseInsensitiveHTMLAttribute
[] = {
2827 // list based on http://www.w3.org/TR/html4/
2873 // additional attributes not in HTML4
2874 "direction", // marquee
2878 const char* htmlAttr
;
2879 while ((htmlAttr
= caseInsensitiveHTMLAttribute
[i
++])) {
2880 if (attr
.EqualsIgnoreCase(htmlAttr
)) {
2881 isCaseSensitive
= PR_FALSE
;
2886 aDataMask
|= SEL_MASK_ATTRIB
;
2887 aSelector
.AddAttribute(nameSpaceID
, attr
, func
, value
, isCaseSensitive
);
2890 REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose
);
2892 return eSelectorParsingStatus_Error
;
2896 REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue
);
2898 return eSelectorParsingStatus_Error
;
2903 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
2904 UngetToken(); // bad dog, no biscut!
2905 return eSelectorParsingStatus_Error
;
2907 return eSelectorParsingStatus_Continue
;
2911 // Parse pseudo-classes and pseudo-elements
2913 CSSParserImpl::nsSelectorParsingStatus
2914 CSSParserImpl::ParsePseudoSelector(PRInt32
& aDataMask
,
2915 nsCSSSelector
& aSelector
,
2918 if (! GetToken(PR_FALSE
)) { // premature eof
2919 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2920 return eSelectorParsingStatus_Error
;
2923 // First, find out whether we are parsing a CSS3 pseudo-element
2924 PRBool parsingPseudoElement
= PR_FALSE
;
2925 if (mToken
.IsSymbol(':')) {
2926 parsingPseudoElement
= PR_TRUE
;
2927 if (! GetToken(PR_FALSE
)) { // premature eof
2928 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
2929 return eSelectorParsingStatus_Error
;
2933 // Do some sanity-checking on the token
2934 if (eCSSToken_Ident
!= mToken
.mType
&& eCSSToken_Function
!= mToken
.mType
) {
2935 // malformed selector
2936 REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName
);
2938 return eSelectorParsingStatus_Error
;
2941 // OK, now we know we have an mIdent. Atomize it. All the atoms, for
2942 // pseudo-classes as well as pseudo-elements, start with a single ':'.
2943 nsAutoString buffer
;
2944 buffer
.Append(PRUnichar(':'));
2945 buffer
.Append(mToken
.mIdent
);
2946 ToLowerCase(buffer
);
2947 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(buffer
);
2949 // stash away some info about this pseudo so we only have to get it once.
2950 PRBool isTreePseudo
= PR_FALSE
;
2952 isTreePseudo
= IsTreePseudoElement(pseudo
);
2953 // If a tree pseudo-element is using the function syntax, it will
2954 // get isTree set here and will pass the check below that only
2955 // allows functions if they are in our list of things allowed to be
2956 // functions. If it is _not_ using the function syntax, isTree will
2957 // be false, and it will still pass that check. So the tree
2958 // pseudo-elements are allowed to be either functions or not, as
2960 PRBool isTree
= (eCSSToken_Function
== mToken
.mType
) && isTreePseudo
;
2962 PRBool isPseudoElement
= nsCSSPseudoElements::IsPseudoElement(pseudo
);
2963 // anonymous boxes are only allowed if they're the tree boxes or we have
2964 // enabled unsafe rules
2965 PRBool isAnonBox
= nsCSSAnonBoxes::IsAnonBox(pseudo
) &&
2966 (mUnsafeRulesEnabled
|| isTreePseudo
);
2967 PRBool isPseudoClass
= nsCSSPseudoClasses::IsPseudoClass(pseudo
);
2969 if (!isPseudoClass
&& !isPseudoElement
&& !isAnonBox
) {
2970 // Not a pseudo-class, not a pseudo-element.... forget it
2971 REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown
);
2973 return eSelectorParsingStatus_Error
;
2976 // If it's a function token, it better be on our "ok" list, and if the name
2977 // is that of a function pseudo it better be a function token
2978 if ((eCSSToken_Function
== mToken
.mType
) !=
2983 nsCSSPseudoClasses::notPseudo
== pseudo
||
2984 nsCSSPseudoClasses::HasStringArg(pseudo
) ||
2985 nsCSSPseudoClasses::HasNthPairArg(pseudo
))) {
2986 // There are no other function pseudos
2987 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc
);
2989 return eSelectorParsingStatus_Error
;
2992 // If it starts with "::", it better be a pseudo-element
2993 if (parsingPseudoElement
&&
2996 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE
);
2998 return eSelectorParsingStatus_Error
;
3001 if (!parsingPseudoElement
&& nsCSSPseudoClasses::notPseudo
== pseudo
) {
3002 if (aIsNegated
) { // :not() can't be itself negated
3003 REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot
);
3005 return eSelectorParsingStatus_Error
;
3007 // CSS 3 Negation pseudo-class takes one simple selector as argument
3008 nsSelectorParsingStatus parsingStatus
=
3009 ParseNegatedSimpleSelector(aDataMask
, aSelector
);
3010 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3011 return parsingStatus
;
3014 else if (!parsingPseudoElement
&& isPseudoClass
) {
3015 aDataMask
|= SEL_MASK_PCLASS
;
3016 if (nsCSSPseudoClasses::HasStringArg(pseudo
)) {
3017 nsSelectorParsingStatus parsingStatus
=
3018 ParsePseudoClassWithIdentArg(aSelector
, pseudo
);
3019 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3020 return parsingStatus
;
3023 else if (nsCSSPseudoClasses::HasNthPairArg(pseudo
)) {
3024 nsSelectorParsingStatus parsingStatus
=
3025 ParsePseudoClassWithNthPairArg(aSelector
, pseudo
);
3026 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
3027 return parsingStatus
;
3031 aSelector
.AddPseudoClass(pseudo
);
3034 else if (isPseudoElement
|| isAnonBox
) {
3035 // Pseudo-element. Make some more sanity checks.
3037 if (aIsNegated
) { // pseudo-elements can't be negated
3038 REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot
);
3040 return eSelectorParsingStatus_Error
;
3042 // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
3043 // to have a single ':' on them. Others (CSS3+ pseudo-elements and
3044 // various -moz-* pseudo-elements) must have |parsingPseudoElement|
3046 if (!parsingPseudoElement
&&
3047 !nsCSSPseudoElements::IsCSS2PseudoElement(pseudo
)
3052 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly
);
3054 return eSelectorParsingStatus_Error
;
3057 if (0 == (aDataMask
& SEL_MASK_PELEM
)) {
3058 aDataMask
|= SEL_MASK_PELEM
;
3059 aSelector
.AddPseudoClass(pseudo
); // store it here, it gets pulled later
3063 // We have encountered a pseudoelement of the form
3064 // -moz-tree-xxxx(a,b,c). We parse (a,b,c) and add each
3065 // item in the list to the pseudoclass list. They will be pulled
3066 // from the list later along with the pseudo-element.
3067 if (!ParseTreePseudoElement(aSelector
)) {
3068 return eSelectorParsingStatus_Error
;
3073 // ensure selector ends here, must be followed by EOF, space, '{' or ','
3074 if (GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3075 if ((eCSSToken_WhiteSpace
== mToken
.mType
) ||
3076 (mToken
.IsSymbol('{') || mToken
.IsSymbol(','))) {
3078 return eSelectorParsingStatus_Done
;
3080 REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing
);
3082 return eSelectorParsingStatus_Error
;
3085 else { // multiple pseudo elements, not legal
3086 REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE
);
3088 return eSelectorParsingStatus_Error
;
3093 // We should never end up here. Indeed, if we ended up here, we know (from
3094 // the current if/else cascade) that !isPseudoElement and !isAnonBox. But
3095 // then due to our earlier check we know that isPseudoClass. Since we
3096 // didn't fall into the isPseudoClass case in this cascade, we must have
3097 // parsingPseudoElement. But we've already checked the
3098 // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if
3100 NS_NOTREACHED("How did this happen?");
3103 return eSelectorParsingStatus_Continue
;
3107 // Parse the argument of a negation pseudo-class :not()
3109 CSSParserImpl::nsSelectorParsingStatus
3110 CSSParserImpl::ParseNegatedSimpleSelector(PRInt32
& aDataMask
,
3111 nsCSSSelector
& aSelector
)
3113 // Check if we have the first parenthesis
3114 if (!ExpectSymbol('(', PR_FALSE
)) {
3115 REPORT_UNEXPECTED_TOKEN(PENegationBadArg
);
3116 return eSelectorParsingStatus_Error
;
3119 if (! GetToken(PR_TRUE
)) { // premature eof
3120 REPORT_UNEXPECTED_EOF(PENegationEOF
);
3121 return eSelectorParsingStatus_Error
;
3124 // Create a new nsCSSSelector and add it to the end of
3125 // aSelector.mNegations.
3126 // Given the current parsing rules, every selector in mNegations
3127 // contains only one simple selector (css3 definition) within it.
3128 // This could easily change in future versions of CSS, and the only
3129 // thing we need to change to support that is this parsing code.
3130 nsCSSSelector
*newSel
= new nsCSSSelector();
3132 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
3133 return eSelectorParsingStatus_Error
;
3135 nsCSSSelector
* negations
= &aSelector
;
3136 while (negations
->mNegations
) {
3137 negations
= negations
->mNegations
;
3139 negations
->mNegations
= newSel
;
3141 nsSelectorParsingStatus parsingStatus
;
3142 if (eCSSToken_ID
== mToken
.mType
) { // #id
3143 parsingStatus
= ParseIDSelector(aDataMask
, *newSel
);
3145 else if (mToken
.IsSymbol('.')) { // .class
3146 parsingStatus
= ParseClassSelector(aDataMask
, *newSel
);
3148 else if (mToken
.IsSymbol(':')) { // :pseudo
3149 parsingStatus
= ParsePseudoSelector(aDataMask
, *newSel
, PR_TRUE
);
3151 else if (mToken
.IsSymbol('[')) { // [attribute
3152 parsingStatus
= ParseAttributeSelector(aDataMask
, *newSel
);
3155 // then it should be a type element or universal selector
3156 parsingStatus
= ParseTypeOrUniversalSelector(aDataMask
, *newSel
, PR_TRUE
);
3158 if (eSelectorParsingStatus_Error
== parsingStatus
) {
3159 REPORT_UNEXPECTED_TOKEN(PENegationBadInner
);
3160 return parsingStatus
;
3162 // close the parenthesis
3163 if (!ExpectSymbol(')', PR_TRUE
)) {
3164 REPORT_UNEXPECTED_TOKEN(PENegationNoClose
);
3165 return eSelectorParsingStatus_Error
;
3168 return eSelectorParsingStatus_Continue
;
3172 // Parse the argument of a pseudo-class that has an ident arg
3174 CSSParserImpl::nsSelectorParsingStatus
3175 CSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
3178 // Check if we have the first parenthesis
3179 if (!ExpectSymbol('(', PR_FALSE
)) {
3180 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3181 return eSelectorParsingStatus_Error
;
3184 if (! GetToken(PR_TRUE
)) { // premature eof
3185 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3186 return eSelectorParsingStatus_Error
;
3188 // We expect an identifier with a language abbreviation
3189 if (eCSSToken_Ident
!= mToken
.mType
) {
3190 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent
);
3192 // XXX Call SkipUntil to the next ")"?
3193 return eSelectorParsingStatus_Error
;
3196 // Add the pseudo with the language parameter
3197 aSelector
.AddPseudoClass(aPseudo
, mToken
.mIdent
.get());
3199 // close the parenthesis
3200 if (!ExpectSymbol(')', PR_TRUE
)) {
3201 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3202 // XXX Call SkipUntil to the next ")"?
3203 return eSelectorParsingStatus_Error
;
3206 return eSelectorParsingStatus_Continue
;
3209 CSSParserImpl::nsSelectorParsingStatus
3210 CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
3213 PRInt32 numbers
[2] = { 0, 0 };
3214 PRBool lookForB
= PR_TRUE
;
3216 // Check whether we have the first parenthesis
3217 if (!ExpectSymbol('(', PR_FALSE
)) {
3218 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoArg
);
3219 return eSelectorParsingStatus_Error
;
3222 // Follow the whitespace rules as proposed in
3223 // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
3225 if (! GetToken(PR_TRUE
)) {
3226 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3227 return eSelectorParsingStatus_Error
;
3230 if (eCSSToken_Ident
== mToken
.mType
|| eCSSToken_Dimension
== mToken
.mType
) {
3231 // The CSS tokenization doesn't handle :nth-child() containing - well:
3232 // 2n-1 is a dimension
3233 // n-1 is an identifier
3234 // The easiest way to deal with that is to push everything from the
3235 // minus on back onto the scanner's pushback buffer.
3236 PRUint32 truncAt
= 0;
3237 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("n-"))) {
3239 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("-n-"))) {
3243 for (PRUint32 i
= mToken
.mIdent
.Length() - 1; i
>= truncAt
; --i
) {
3244 mScanner
.Pushback(mToken
.mIdent
[i
]);
3246 mToken
.mIdent
.Truncate(truncAt
);
3250 if (eCSSToken_Ident
== mToken
.mType
) {
3251 if (mToken
.mIdent
.EqualsIgnoreCase("odd")) {
3254 lookForB
= PR_FALSE
;
3256 else if (mToken
.mIdent
.EqualsIgnoreCase("even")) {
3259 lookForB
= PR_FALSE
;
3261 else if (mToken
.mIdent
.EqualsIgnoreCase("n")) {
3264 else if (mToken
.mIdent
.EqualsIgnoreCase("-n")) {
3268 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3269 // XXX Call SkipUntil to the next ")"?
3270 return eSelectorParsingStatus_Error
;
3273 else if (eCSSToken_Number
== mToken
.mType
) {
3274 if (!mToken
.mIntegerValid
) {
3275 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3276 // XXX Call SkipUntil to the next ")"?
3277 return eSelectorParsingStatus_Error
;
3279 numbers
[1] = mToken
.mInteger
;
3280 lookForB
= PR_FALSE
;
3282 else if (eCSSToken_Dimension
== mToken
.mType
) {
3283 if (!mToken
.mIntegerValid
|| !mToken
.mIdent
.EqualsIgnoreCase("n")) {
3284 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3285 // XXX Call SkipUntil to the next ")"?
3286 return eSelectorParsingStatus_Error
;
3288 numbers
[0] = mToken
.mInteger
;
3290 // XXX If it's a ')', is that valid? (as 0n+0)
3292 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3293 // XXX Call SkipUntil to the next ")" (unless this is one already)?
3294 return eSelectorParsingStatus_Error
;
3297 if (! GetToken(PR_TRUE
)) {
3298 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3299 return eSelectorParsingStatus_Error
;
3301 if (lookForB
&& !mToken
.IsSymbol(')')) {
3302 // The '+' or '-' sign can optionally be separated by whitespace.
3303 // If it is separated by whitespace from what follows it, it appears
3304 // as a separate token rather than part of the number token.
3305 PRBool haveSign
= PR_FALSE
;
3307 if (mToken
.IsSymbol('+') || mToken
.IsSymbol('-')) {
3309 if (mToken
.IsSymbol('-')) {
3312 if (! GetToken(PR_TRUE
)) {
3313 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3314 return eSelectorParsingStatus_Error
;
3317 if (eCSSToken_Number
!= mToken
.mType
||
3318 !mToken
.mIntegerValid
|| mToken
.mHasSign
== haveSign
) {
3319 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
3320 // XXX Call SkipUntil to the next ")"?
3321 return eSelectorParsingStatus_Error
;
3323 numbers
[1] = mToken
.mInteger
* sign
;
3324 if (! GetToken(PR_TRUE
)) {
3325 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
3326 return eSelectorParsingStatus_Error
;
3329 if (!mToken
.IsSymbol(')')) {
3330 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
3331 // XXX Call SkipUntil to the next ")"?
3332 return eSelectorParsingStatus_Error
;
3334 aSelector
.AddPseudoClass(aPseudo
, numbers
);
3335 return eSelectorParsingStatus_Continue
;
3340 * This is the format for selectors:
3341 * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
3343 CSSParserImpl::nsSelectorParsingStatus
3344 CSSParserImpl::ParseSelector(nsCSSSelector
& aSelector
)
3346 if (! GetToken(PR_TRUE
)) {
3347 REPORT_UNEXPECTED_EOF(PESelectorEOF
);
3348 return eSelectorParsingStatus_Error
;
3351 PRInt32 dataMask
= 0;
3352 nsSelectorParsingStatus parsingStatus
=
3353 ParseTypeOrUniversalSelector(dataMask
, aSelector
, PR_FALSE
);
3354 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3355 return parsingStatus
;
3359 if (eCSSToken_ID
== mToken
.mType
) { // #id
3360 parsingStatus
= ParseIDSelector(dataMask
, aSelector
);
3362 else if (mToken
.IsSymbol('.')) { // .class
3363 parsingStatus
= ParseClassSelector(dataMask
, aSelector
);
3365 else if (mToken
.IsSymbol(':')) { // :pseudo
3366 parsingStatus
= ParsePseudoSelector(dataMask
, aSelector
, PR_FALSE
);
3368 else if (mToken
.IsSymbol('[')) { // [attribute
3369 parsingStatus
= ParseAttributeSelector(dataMask
, aSelector
);
3371 else { // not a selector token, we're done
3372 parsingStatus
= eSelectorParsingStatus_Done
;
3376 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
3377 return parsingStatus
;
3380 if (! GetToken(PR_FALSE
)) { // premature eof is ok (here!)
3381 return eSelectorParsingStatus_Done
;
3385 return dataMask
? parsingStatus
: eSelectorParsingStatus_Empty
;
3389 CSSParserImpl::ParseDeclarationBlock(PRBool aCheckForBraces
)
3391 if (aCheckForBraces
) {
3392 if (!ExpectSymbol('{', PR_TRUE
)) {
3393 REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart
);
3398 nsCSSDeclaration
* declaration
= new nsCSSDeclaration();
3399 mData
.AssertInitialState();
3403 if (!ParseDeclaration(declaration
, aCheckForBraces
,
3404 PR_TRUE
, &changed
)) {
3405 if (!SkipDeclaration(aCheckForBraces
)) {
3408 if (aCheckForBraces
) {
3409 if (ExpectSymbol('}', PR_TRUE
)) {
3413 // Since the skipped declaration didn't end the block we parse
3414 // the next declaration.
3417 declaration
->CompressFrom(&mData
);
3422 // The types to pass to ParseColorComponent. These correspond to the
3423 // various datatypes that can go within rgb().
3424 #define COLOR_TYPE_UNKNOWN 0
3425 #define COLOR_TYPE_INTEGERS 1
3426 #define COLOR_TYPE_PERCENTAGES 2
3429 CSSParserImpl::ParseColor(nsCSSValue
& aValue
)
3431 if (!GetToken(PR_TRUE
)) {
3432 REPORT_UNEXPECTED_EOF(PEColorEOF
);
3436 nsCSSToken
* tk
= &mToken
;
3438 switch (tk
->mType
) {
3442 if (NS_HexToRGB(tk
->mIdent
, &rgba
)) {
3443 aValue
.SetColorValue(rgba
);
3448 case eCSSToken_Ident
:
3449 if (NS_ColorNameToRGB(tk
->mIdent
, &rgba
)) {
3450 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
3454 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
3455 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
3457 if (nsCSSProps::FindKeyword(keyword
, nsCSSProps::kColorKTable
, value
)) {
3458 aValue
.SetIntValue(value
, eCSSUnit_EnumColor
);
3464 case eCSSToken_Function
:
3465 if (mToken
.mIdent
.LowerCaseEqualsLiteral("rgb")) {
3466 // rgb ( component , component , component )
3468 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3469 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3470 ParseColorComponent(r
, type
, ',') &&
3471 ParseColorComponent(g
, type
, ',') &&
3472 ParseColorComponent(b
, type
, ')')) {
3473 aValue
.SetColorValue(NS_RGB(r
,g
,b
));
3476 return PR_FALSE
; // already pushed back
3478 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
3479 mToken
.mIdent
.LowerCaseEqualsLiteral("rgba")) {
3480 // rgba ( component , component , component , opacity )
3482 PRInt32 type
= COLOR_TYPE_UNKNOWN
;
3483 if (ExpectSymbol('(', PR_FALSE
) && // this won't fail
3484 ParseColorComponent(r
, type
, ',') &&
3485 ParseColorComponent(g
, type
, ',') &&
3486 ParseColorComponent(b
, type
, ',') &&
3487 ParseColorOpacity(a
)) {
3488 aValue
.SetColorValue(NS_RGBA(r
, g
, b
, a
));
3491 return PR_FALSE
; // already pushed back
3493 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("hsl")) {
3494 // hsl ( hue , saturation , lightness )
3495 // "hue" is a number, "saturation" and "lightness" are percentages.
3496 if (ParseHSLColor(rgba
, ')')) {
3497 aValue
.SetColorValue(rgba
);
3502 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
3503 mToken
.mIdent
.LowerCaseEqualsLiteral("hsla")) {
3504 // hsla ( hue , saturation , lightness , opacity )
3505 // "hue" is a number, "saturation" and "lightness" are percentages,
3506 // "opacity" is a number.
3508 if (ParseHSLColor(rgba
, ',') &&
3509 ParseColorOpacity(a
)) {
3510 aValue
.SetColorValue(NS_RGBA(NS_GET_R(rgba
), NS_GET_G(rgba
),
3511 NS_GET_B(rgba
), a
));
3521 // try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)
3522 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) {
3523 // - If the string starts with 'a-f', the nsCSSScanner builds the
3524 // token as a eCSSToken_Ident and we can parse the string as a
3525 // 'xxyyzz' RGB color.
3526 // - If it only contains '0-9' digits, the token is a
3527 // eCSSToken_Number and it must be converted back to a 6
3528 // characters string to be parsed as a RGB color.
3529 // - If it starts with '0-9' and contains any 'a-f', the token is a
3530 // eCSSToken_Dimension, the mNumber part must be converted back to
3531 // a string and the mIdent part must be appended to that string so
3532 // that the resulting string has 6 characters.
3533 // Note: This is a hack for Nav compatibility. Do not attempt to
3534 // simplify it by hacking into the ncCSSScanner. This would be very
3538 switch (tk
->mType
) {
3539 case eCSSToken_Ident
:
3540 str
.Assign(tk
->mIdent
);
3543 case eCSSToken_Number
:
3544 if (tk
->mIntegerValid
) {
3545 PR_snprintf(buffer
, sizeof(buffer
), "%06d", tk
->mInteger
);
3546 str
.AssignWithConversion(buffer
);
3550 case eCSSToken_Dimension
:
3551 if (tk
->mIdent
.Length() <= 6) {
3552 PR_snprintf(buffer
, sizeof(buffer
), "%06.0f", tk
->mNumber
);
3554 temp
.AssignWithConversion(buffer
);
3555 temp
.Right(str
, 6 - tk
->mIdent
.Length());
3556 str
.Append(tk
->mIdent
);
3560 // There is a whole bunch of cases that are
3561 // not handled by this switch. Ignore them.
3564 if (NS_HexToRGB(str
, &rgba
)) {
3565 aValue
.SetColorValue(rgba
);
3571 REPORT_UNEXPECTED_TOKEN(PEColorNotColor
);
3576 // aType will be set if we have already parsed other color components
3577 // in this color spec
3579 CSSParserImpl::ParseColorComponent(PRUint8
& aComponent
,
3583 if (!GetToken(PR_TRUE
)) {
3584 REPORT_UNEXPECTED_EOF(PEColorComponentEOF
);
3588 nsCSSToken
* tk
= &mToken
;
3589 switch (tk
->mType
) {
3590 case eCSSToken_Number
:
3592 case COLOR_TYPE_UNKNOWN
:
3593 aType
= COLOR_TYPE_INTEGERS
;
3595 case COLOR_TYPE_INTEGERS
:
3597 case COLOR_TYPE_PERCENTAGES
:
3598 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3602 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3605 if (!mToken
.mIntegerValid
) {
3606 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3610 value
= tk
->mNumber
;
3612 case eCSSToken_Percentage
:
3614 case COLOR_TYPE_UNKNOWN
:
3615 aType
= COLOR_TYPE_PERCENTAGES
;
3617 case COLOR_TYPE_INTEGERS
:
3618 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
3621 case COLOR_TYPE_PERCENTAGES
:
3624 NS_NOTREACHED("Someone forgot to add the new color component type in here");
3626 value
= tk
->mNumber
* 255.0f
;
3629 REPORT_UNEXPECTED_TOKEN(PEColorBadRGBContents
);
3633 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3634 if (value
< 0.0f
) value
= 0.0f
;
3635 if (value
> 255.0f
) value
= 255.0f
;
3636 aComponent
= NSToIntRound(value
);
3639 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3640 const PRUnichar
*params
[] = {
3644 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3650 CSSParserImpl::ParseHSLColor(nscolor
& aColor
,
3654 if (!ExpectSymbol('(', PR_FALSE
)) {
3655 NS_ERROR("How did this get to be a function token?");
3660 if (!GetToken(PR_TRUE
)) {
3661 REPORT_UNEXPECTED_EOF(PEColorHueEOF
);
3664 if (mToken
.mType
!= eCSSToken_Number
) {
3665 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3671 // hue values are wraparound
3674 if (!ExpectSymbol(',', PR_TRUE
)) {
3675 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3679 // Get the saturation
3680 if (!GetToken(PR_TRUE
)) {
3681 REPORT_UNEXPECTED_EOF(PEColorSaturationEOF
);
3684 if (mToken
.mType
!= eCSSToken_Percentage
) {
3685 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3690 if (s
< 0.0f
) s
= 0.0f
;
3691 if (s
> 1.0f
) s
= 1.0f
;
3693 if (!ExpectSymbol(',', PR_TRUE
)) {
3694 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
3698 // Get the lightness
3699 if (!GetToken(PR_TRUE
)) {
3700 REPORT_UNEXPECTED_EOF(PEColorLightnessEOF
);
3703 if (mToken
.mType
!= eCSSToken_Percentage
) {
3704 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
3709 if (l
< 0.0f
) l
= 0.0f
;
3710 if (l
> 1.0f
) l
= 1.0f
;
3712 if (ExpectSymbol(aStop
, PR_TRUE
)) {
3713 aColor
= NS_HSL2RGB(h
, s
, l
);
3717 const PRUnichar stopString
[] = { PRUnichar(aStop
), PRUnichar(0) };
3718 const PRUnichar
*params
[] = {
3722 REPORT_UNEXPECTED_TOKEN_P(PEColorComponentBadTerm
, params
);
3728 CSSParserImpl::ParseColorOpacity(PRUint8
& aOpacity
)
3730 if (!GetToken(PR_TRUE
)) {
3731 REPORT_UNEXPECTED_EOF(PEColorOpacityEOF
);
3735 if (mToken
.mType
!= eCSSToken_Number
) {
3736 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
3741 if (mToken
.mNumber
< 0.0f
) {
3742 mToken
.mNumber
= 0.0f
;
3743 } else if (mToken
.mNumber
> 1.0f
) {
3744 mToken
.mNumber
= 1.0f
;
3747 PRUint8 value
= nsStyleUtil::FloatToColorComponent(mToken
.mNumber
);
3748 NS_ASSERTION(fabs(mToken
.mNumber
- value
/255.0f
) <= 0.5f
,
3749 "FloatToColorComponent did something weird");
3751 if (!ExpectSymbol(')', PR_TRUE
)) {
3752 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
3763 CSSParserImpl::ParseTreePseudoElement(nsCSSSelector
& aSelector
)
3765 if (ExpectSymbol('(', PR_FALSE
)) {
3766 while (!ExpectSymbol(')', PR_TRUE
)) {
3767 if (!GetToken(PR_TRUE
)) {
3770 else if (eCSSToken_Ident
== mToken
.mType
) {
3771 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(mToken
.mIdent
);
3772 aSelector
.AddPseudoClass(pseudo
);
3774 else if (eCSSToken_Symbol
== mToken
.mType
) {
3775 if (!mToken
.IsSymbol(','))
3778 else return PR_FALSE
;
3786 //----------------------------------------------------------------------
3789 CSSParserImpl::ParseDeclaration(nsCSSDeclaration
* aDeclaration
,
3790 PRBool aCheckForBraces
,
3791 PRBool aMustCallValueAppended
,
3794 mTempData
.AssertInitialState();
3796 // Get property name
3797 nsCSSToken
* tk
= &mToken
;
3798 nsAutoString propertyName
;
3800 if (!GetToken(PR_TRUE
)) {
3801 if (aCheckForBraces
) {
3802 REPORT_UNEXPECTED_EOF(PEDeclEndEOF
);
3806 if (eCSSToken_Ident
== tk
->mType
) {
3807 propertyName
= tk
->mIdent
;
3808 // grab the ident before the ExpectSymbol trashes the token
3809 if (!ExpectSymbol(':', PR_TRUE
)) {
3810 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
3811 REPORT_UNEXPECTED(PEDeclDropped
);
3817 if (tk
->IsSymbol(';')) {
3818 // dangling semicolons are skipped
3822 if (!tk
->IsSymbol('}')) {
3823 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected
);
3824 REPORT_UNEXPECTED(PEDeclSkipped
);
3827 // Not a declaration...
3832 // Map property name to its ID and then parse the property
3833 nsCSSProperty propID
= nsCSSProps::LookupProperty(propertyName
);
3834 if (eCSSProperty_UNKNOWN
== propID
) { // unknown property
3835 if (!NonMozillaVendorIdentifier(propertyName
)) {
3836 const PRUnichar
*params
[] = {
3839 REPORT_UNEXPECTED_P(PEUnknownProperty
, params
);
3840 REPORT_UNEXPECTED(PEDeclDropped
);
3846 if (! ParseProperty(propID
)) {
3847 // XXX Much better to put stuff in the value parsers instead...
3848 const PRUnichar
*params
[] = {
3851 REPORT_UNEXPECTED_P(PEValueParsingError
, params
);
3852 REPORT_UNEXPECTED(PEDeclDropped
);
3854 ClearTempData(propID
);
3859 // See if the declaration is followed by a "!important" declaration
3860 PRBool isImportant
= PR_FALSE
;
3861 if (!GetToken(PR_TRUE
)) {
3862 // EOF is a perfectly good way to end a declaration and declaration block
3863 TransferTempData(aDeclaration
, propID
, isImportant
,
3864 aMustCallValueAppended
, aChanged
);
3868 if (eCSSToken_Symbol
== tk
->mType
&& '!' == tk
->mSymbol
) {
3869 // Look for important ident
3870 if (!GetToken(PR_TRUE
)) {
3871 // Premature eof is not ok
3872 REPORT_UNEXPECTED_EOF(PEImportantEOF
);
3873 ClearTempData(propID
);
3876 if ((eCSSToken_Ident
!= tk
->mType
) ||
3877 !tk
->mIdent
.LowerCaseEqualsLiteral("important")) {
3878 REPORT_UNEXPECTED_TOKEN(PEExpectedImportant
);
3881 ClearTempData(propID
);
3884 isImportant
= PR_TRUE
;
3887 // Not a !important declaration
3891 // Make sure valid property declaration is terminated with either a
3892 // semicolon, EOF or a right-curly-brace (this last only when
3893 // aCheckForBraces is true).
3894 if (!GetToken(PR_TRUE
)) {
3895 // EOF is a perfectly good way to end a declaration and declaration block
3896 TransferTempData(aDeclaration
, propID
, isImportant
,
3897 aMustCallValueAppended
, aChanged
);
3900 if (eCSSToken_Symbol
== tk
->mType
) {
3901 if (';' == tk
->mSymbol
) {
3902 TransferTempData(aDeclaration
, propID
, isImportant
,
3903 aMustCallValueAppended
, aChanged
);
3906 if (aCheckForBraces
&& '}' == tk
->mSymbol
) {
3907 // Unget the '}' so we'll be able to tell that this is the end
3908 // of the declaration block when we unwind from here.
3910 TransferTempData(aDeclaration
, propID
, isImportant
,
3911 aMustCallValueAppended
, aChanged
);
3915 if (aCheckForBraces
)
3916 REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2
);
3918 REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd
);
3919 REPORT_UNEXPECTED(PEDeclDropped
);
3921 ClearTempData(propID
);
3926 CSSParserImpl::ClearTempData(nsCSSProperty aPropID
)
3928 if (nsCSSProps::IsShorthand(aPropID
)) {
3929 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
3930 mTempData
.ClearProperty(*p
);
3933 mTempData
.ClearProperty(aPropID
);
3935 mTempData
.AssertInitialState();
3939 CSSParserImpl::TransferTempData(nsCSSDeclaration
* aDeclaration
,
3940 nsCSSProperty aPropID
, PRBool aIsImportant
,
3941 PRBool aMustCallValueAppended
,
3944 if (nsCSSProps::IsShorthand(aPropID
)) {
3945 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
3946 DoTransferTempData(aDeclaration
, *p
, aIsImportant
,
3947 aMustCallValueAppended
, aChanged
);
3950 DoTransferTempData(aDeclaration
, aPropID
, aIsImportant
,
3951 aMustCallValueAppended
, aChanged
);
3953 mTempData
.AssertInitialState();
3956 // Perhaps the transferring code should be in nsCSSExpandedDataBlock, in
3957 // case some other caller wants to use it in the future (although I
3958 // can't think of why).
3960 CSSParserImpl::DoTransferTempData(nsCSSDeclaration
* aDeclaration
,
3961 nsCSSProperty aPropID
, PRBool aIsImportant
,
3962 PRBool aMustCallValueAppended
,
3965 NS_ASSERTION(mTempData
.HasPropertyBit(aPropID
), "oops");
3967 if (!mData
.HasImportantBit(aPropID
))
3968 *aChanged
= PR_TRUE
;
3969 mData
.SetImportantBit(aPropID
);
3971 if (mData
.HasImportantBit(aPropID
)) {
3972 mTempData
.ClearProperty(aPropID
);
3977 if (aMustCallValueAppended
|| !mData
.HasPropertyBit(aPropID
)) {
3978 aDeclaration
->ValueAppended(aPropID
);
3981 mData
.SetPropertyBit(aPropID
);
3982 mTempData
.ClearPropertyBit(aPropID
);
3985 * Save needless copying and allocation by calling the destructor in
3986 * the destination, copying memory directly, and then using placement
3989 void *v_source
= mTempData
.PropertyAt(aPropID
);
3990 void *v_dest
= mData
.PropertyAt(aPropID
);
3991 switch (nsCSSProps::kTypeTable
[aPropID
]) {
3992 case eCSSType_Value
: {
3993 nsCSSValue
*source
= static_cast<nsCSSValue
*>(v_source
);
3994 nsCSSValue
*dest
= static_cast<nsCSSValue
*>(v_dest
);
3995 if (*source
!= *dest
)
3996 *aChanged
= PR_TRUE
;
3997 dest
->~nsCSSValue();
3998 memcpy(dest
, source
, sizeof(nsCSSValue
));
3999 new (source
) nsCSSValue();
4002 case eCSSType_Rect
: {
4003 nsCSSRect
*source
= static_cast<nsCSSRect
*>(v_source
);
4004 nsCSSRect
*dest
= static_cast<nsCSSRect
*>(v_dest
);
4005 if (*source
!= *dest
)
4006 *aChanged
= PR_TRUE
;
4008 memcpy(dest
, source
, sizeof(nsCSSRect
));
4009 new (source
) nsCSSRect();
4012 case eCSSType_ValuePair
: {
4013 nsCSSValuePair
*source
= static_cast<nsCSSValuePair
*>(v_source
);
4014 nsCSSValuePair
*dest
= static_cast<nsCSSValuePair
*>(v_dest
);
4015 if (*source
!= *dest
)
4016 *aChanged
= PR_TRUE
;
4017 dest
->~nsCSSValuePair();
4018 memcpy(dest
, source
, sizeof(nsCSSValuePair
));
4019 new (source
) nsCSSValuePair();
4022 case eCSSType_ValueList
: {
4023 nsCSSValueList
**source
= static_cast<nsCSSValueList
**>(v_source
);
4024 nsCSSValueList
**dest
= static_cast<nsCSSValueList
**>(v_dest
);
4025 if (!nsCSSValueList::Equal(*source
, *dest
))
4026 *aChanged
= PR_TRUE
;
4032 case eCSSType_ValuePairList
: {
4033 nsCSSValuePairList
**source
=
4034 static_cast<nsCSSValuePairList
**>(v_source
);
4035 nsCSSValuePairList
**dest
=
4036 static_cast<nsCSSValuePairList
**>(v_dest
);
4037 if (!nsCSSValuePairList::Equal(*source
, *dest
))
4038 *aChanged
= PR_TRUE
;
4046 static const nsCSSProperty kBorderTopIDs
[] = {
4047 eCSSProperty_border_top_width
,
4048 eCSSProperty_border_top_style
,
4049 eCSSProperty_border_top_color
4051 static const nsCSSProperty kBorderRightIDs
[] = {
4052 eCSSProperty_border_right_width_value
,
4053 eCSSProperty_border_right_style_value
,
4054 eCSSProperty_border_right_color_value
,
4055 eCSSProperty_border_right_width
,
4056 eCSSProperty_border_right_style
,
4057 eCSSProperty_border_right_color
4059 static const nsCSSProperty kBorderBottomIDs
[] = {
4060 eCSSProperty_border_bottom_width
,
4061 eCSSProperty_border_bottom_style
,
4062 eCSSProperty_border_bottom_color
4064 static const nsCSSProperty kBorderLeftIDs
[] = {
4065 eCSSProperty_border_left_width_value
,
4066 eCSSProperty_border_left_style_value
,
4067 eCSSProperty_border_left_color_value
,
4068 eCSSProperty_border_left_width
,
4069 eCSSProperty_border_left_style
,
4070 eCSSProperty_border_left_color
4072 static const nsCSSProperty kBorderStartIDs
[] = {
4073 eCSSProperty_border_start_width_value
,
4074 eCSSProperty_border_start_style_value
,
4075 eCSSProperty_border_start_color_value
,
4076 eCSSProperty_border_start_width
,
4077 eCSSProperty_border_start_style
,
4078 eCSSProperty_border_start_color
4080 static const nsCSSProperty kBorderEndIDs
[] = {
4081 eCSSProperty_border_end_width_value
,
4082 eCSSProperty_border_end_style_value
,
4083 eCSSProperty_border_end_color_value
,
4084 eCSSProperty_border_end_width
,
4085 eCSSProperty_border_end_style
,
4086 eCSSProperty_border_end_color
4088 static const nsCSSProperty kColumnRuleIDs
[] = {
4089 eCSSProperty__moz_column_rule_width
,
4090 eCSSProperty__moz_column_rule_style
,
4091 eCSSProperty__moz_column_rule_color
4095 CSSParserImpl::ParseEnum(nsCSSValue
& aValue
,
4096 const PRInt32 aKeywordTable
[])
4098 nsSubstring
* ident
= NextIdent();
4099 if (nsnull
== ident
) {
4102 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(*ident
);
4103 if (eCSSKeyword_UNKNOWN
< keyword
) {
4105 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4106 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4111 // Put the unknown identifier back and return
4118 char name
[5]; // needs to be long enough for the longest unit, with
4119 // terminating null.
4125 #define STR_WITH_LEN(_str) \
4126 _str, sizeof(_str) - 1
4128 const UnitInfo UnitData
[] = {
4129 { STR_WITH_LEN("px"), eCSSUnit_Pixel
, VARIANT_LENGTH
},
4130 { STR_WITH_LEN("em"), eCSSUnit_EM
, VARIANT_LENGTH
},
4131 { STR_WITH_LEN("ex"), eCSSUnit_XHeight
, VARIANT_LENGTH
},
4132 { STR_WITH_LEN("pt"), eCSSUnit_Point
, VARIANT_LENGTH
},
4133 { STR_WITH_LEN("in"), eCSSUnit_Inch
, VARIANT_LENGTH
},
4134 { STR_WITH_LEN("cm"), eCSSUnit_Centimeter
, VARIANT_LENGTH
},
4135 { STR_WITH_LEN("ch"), eCSSUnit_Char
, VARIANT_LENGTH
},
4136 { STR_WITH_LEN("mm"), eCSSUnit_Millimeter
, VARIANT_LENGTH
},
4137 { STR_WITH_LEN("pc"), eCSSUnit_Pica
, VARIANT_LENGTH
},
4138 { STR_WITH_LEN("deg"), eCSSUnit_Degree
, VARIANT_ANGLE
},
4139 { STR_WITH_LEN("grad"), eCSSUnit_Grad
, VARIANT_ANGLE
},
4140 { STR_WITH_LEN("rad"), eCSSUnit_Radian
, VARIANT_ANGLE
},
4141 { STR_WITH_LEN("hz"), eCSSUnit_Hertz
, VARIANT_FREQUENCY
},
4142 { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz
, VARIANT_FREQUENCY
},
4143 { STR_WITH_LEN("s"), eCSSUnit_Seconds
, VARIANT_TIME
},
4144 { STR_WITH_LEN("ms"), eCSSUnit_Milliseconds
, VARIANT_TIME
}
4150 CSSParserImpl::TranslateDimension(nsCSSValue
& aValue
,
4151 PRInt32 aVariantMask
,
4153 const nsString
& aUnit
)
4157 if (!aUnit
.IsEmpty()) {
4159 for (i
= 0; i
< NS_ARRAY_LENGTH(UnitData
); ++i
) {
4160 if (aUnit
.LowerCaseEqualsASCII(UnitData
[i
].name
,
4161 UnitData
[i
].length
)) {
4162 units
= UnitData
[i
].unit
;
4163 type
= UnitData
[i
].type
;
4168 if (i
== NS_ARRAY_LENGTH(UnitData
)) {
4173 // Must be a zero number...
4174 NS_ASSERTION(0 == aNumber
, "numbers without units must be 0");
4175 if ((VARIANT_LENGTH
& aVariantMask
) != 0) {
4176 units
= eCSSUnit_Point
;
4177 type
= VARIANT_LENGTH
;
4179 else if ((VARIANT_ANGLE
& aVariantMask
) != 0) {
4180 units
= eCSSUnit_Degree
;
4181 type
= VARIANT_ANGLE
;
4183 else if ((VARIANT_FREQUENCY
& aVariantMask
) != 0) {
4184 units
= eCSSUnit_Hertz
;
4185 type
= VARIANT_FREQUENCY
;
4187 else if ((VARIANT_TIME
& aVariantMask
) != 0) {
4188 units
= eCSSUnit_Seconds
;
4189 type
= VARIANT_TIME
;
4192 NS_ERROR("Variant mask does not include dimension; why were we called?");
4196 if ((type
& aVariantMask
) != 0) {
4197 aValue
.SetFloatValue(aNumber
, units
);
4204 CSSParserImpl::ParsePositiveVariant(nsCSSValue
& aValue
,
4205 PRInt32 aVariantMask
,
4206 const PRInt32 aKeywordTable
[])
4208 if (ParseVariant(aValue
, aVariantMask
, aKeywordTable
)) {
4209 if (eCSSUnit_Number
== aValue
.GetUnit() ||
4210 aValue
.IsLengthUnit()){
4211 if (aValue
.GetFloatValue() < 0) {
4216 else if (aValue
.GetUnit() == eCSSUnit_Percent
) {
4217 if (aValue
.GetPercentValue() < 0) {
4221 } else if (aValue
.GetUnit() == eCSSUnit_Integer
) {
4222 if (aValue
.GetIntValue() < 0) {
4232 // Assigns to aValue iff it returns PR_TRUE.
4234 CSSParserImpl::ParseVariant(nsCSSValue
& aValue
,
4235 PRInt32 aVariantMask
,
4236 const PRInt32 aKeywordTable
[])
4238 NS_ASSERTION(IsParsingCompoundProperty() ||
4239 ((~aVariantMask
) & (VARIANT_LENGTH
|VARIANT_COLOR
)),
4240 "cannot distinguish lengths and colors in quirks mode");
4242 if (!GetToken(PR_TRUE
)) {
4245 nsCSSToken
* tk
= &mToken
;
4246 if (((aVariantMask
& (VARIANT_AHK
| VARIANT_NORMAL
| VARIANT_NONE
)) != 0) &&
4247 (eCSSToken_Ident
== tk
->mType
)) {
4248 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
4249 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
4250 if ((aVariantMask
& VARIANT_AUTO
) != 0) {
4251 if (eCSSKeyword_auto
== keyword
) {
4252 aValue
.SetAutoValue();
4256 if ((aVariantMask
& VARIANT_INHERIT
) != 0) {
4257 // XXX Should we check IsParsingCompoundProperty, or do all
4258 // callers handle it? (Not all callers set it, though, since
4259 // they want the quirks that are disabled by setting it.)
4260 if (eCSSKeyword_inherit
== keyword
) {
4261 aValue
.SetInheritValue();
4264 else if (eCSSKeyword__moz_initial
== keyword
) { // anything that can inherit can also take an initial val.
4265 aValue
.SetInitialValue();
4269 if ((aVariantMask
& VARIANT_NONE
) != 0) {
4270 if (eCSSKeyword_none
== keyword
) {
4271 aValue
.SetNoneValue();
4275 if ((aVariantMask
& VARIANT_NORMAL
) != 0) {
4276 if (eCSSKeyword_normal
== keyword
) {
4277 aValue
.SetNormalValue();
4281 if ((aVariantMask
& VARIANT_SYSFONT
) != 0) {
4282 if (eCSSKeyword__moz_use_system_font
== keyword
&&
4283 !IsParsingCompoundProperty()) {
4284 aValue
.SetSystemFontValue();
4288 if ((aVariantMask
& VARIANT_KEYWORD
) != 0) {
4290 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
4291 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
4297 if (((aVariantMask
& (VARIANT_LENGTH
| VARIANT_ANGLE
| VARIANT_FREQUENCY
| VARIANT_TIME
)) != 0) &&
4298 tk
->IsDimension()) {
4299 if (TranslateDimension(aValue
, aVariantMask
, tk
->mNumber
, tk
->mIdent
)) {
4302 // Put the token back; we didn't parse it, so we shouldn't consume it
4306 if (((aVariantMask
& VARIANT_PERCENT
) != 0) &&
4307 (eCSSToken_Percentage
== tk
->mType
)) {
4308 aValue
.SetPercentValue(tk
->mNumber
);
4311 if (((aVariantMask
& VARIANT_NUMBER
) != 0) &&
4312 (eCSSToken_Number
== tk
->mType
)) {
4313 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Number
);
4316 if (((aVariantMask
& VARIANT_INTEGER
) != 0) &&
4317 (eCSSToken_Number
== tk
->mType
) && tk
->mIntegerValid
) {
4318 aValue
.SetIntValue(tk
->mInteger
, eCSSUnit_Integer
);
4321 if (mNavQuirkMode
&& !IsParsingCompoundProperty()) { // NONSTANDARD: Nav interprets unitless numbers as px
4322 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4323 (eCSSToken_Number
== tk
->mType
)) {
4324 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4330 if (IsSVGMode() && !IsParsingCompoundProperty()) {
4331 // STANDARD: SVG Spec states that lengths and coordinates can be unitless
4332 // in which case they default to user-units (1 px = 1 user unit)
4333 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
4334 (eCSSToken_Number
== tk
->mType
)) {
4335 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
4341 if (((aVariantMask
& VARIANT_URL
) != 0) &&
4342 (eCSSToken_Function
== tk
->mType
) &&
4343 tk
->mIdent
.LowerCaseEqualsLiteral("url")) {
4344 if (ParseURL(aValue
)) {
4349 if ((aVariantMask
& VARIANT_COLOR
) != 0) {
4350 if ((mNavQuirkMode
&& !IsParsingCompoundProperty()) || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
4351 (eCSSToken_ID
== tk
->mType
) ||
4352 (eCSSToken_Ref
== tk
->mType
) ||
4353 (eCSSToken_Ident
== tk
->mType
) ||
4354 ((eCSSToken_Function
== tk
->mType
) &&
4355 (tk
->mIdent
.LowerCaseEqualsLiteral("rgb") ||
4356 tk
->mIdent
.LowerCaseEqualsLiteral("hsl") ||
4357 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-rgba") ||
4358 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-hsla") ||
4359 tk
->mIdent
.LowerCaseEqualsLiteral("rgba") ||
4360 tk
->mIdent
.LowerCaseEqualsLiteral("hsla"))))
4362 // Put token back so that parse color can get it
4364 if (ParseColor(aValue
)) {
4370 if (((aVariantMask
& VARIANT_STRING
) != 0) &&
4371 (eCSSToken_String
== tk
->mType
)) {
4372 nsAutoString buffer
;
4373 buffer
.Append(tk
->mSymbol
);
4374 buffer
.Append(tk
->mIdent
);
4375 buffer
.Append(tk
->mSymbol
);
4376 aValue
.SetStringValue(buffer
, eCSSUnit_String
);
4379 if (((aVariantMask
& VARIANT_IDENTIFIER
) != 0) &&
4380 (eCSSToken_Ident
== tk
->mType
)) {
4381 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_String
);
4384 if (((aVariantMask
& VARIANT_COUNTER
) != 0) &&
4385 (eCSSToken_Function
== tk
->mType
) &&
4386 (tk
->mIdent
.LowerCaseEqualsLiteral("counter") ||
4387 tk
->mIdent
.LowerCaseEqualsLiteral("counters"))) {
4388 return ParseCounter(aValue
);
4390 if (((aVariantMask
& VARIANT_ATTR
) != 0) &&
4391 (eCSSToken_Function
== tk
->mType
) &&
4392 tk
->mIdent
.LowerCaseEqualsLiteral("attr")) {
4393 return ParseAttr(aValue
);
4402 CSSParserImpl::ParseCounter(nsCSSValue
& aValue
)
4404 nsCSSUnit unit
= (mToken
.mIdent
.LowerCaseEqualsLiteral("counter") ?
4405 eCSSUnit_Counter
: eCSSUnit_Counters
);
4407 if (!ExpectSymbol('(', PR_FALSE
))
4410 if (!GetNonCloseParenToken(PR_TRUE
) ||
4411 eCSSToken_Ident
!= mToken
.mType
) {
4416 nsRefPtr
<nsCSSValue::Array
> val
=
4417 nsCSSValue::Array::Create(unit
== eCSSUnit_Counter
? 2 : 3);
4419 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4423 val
->Item(0).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4425 if (eCSSUnit_Counters
== unit
) {
4426 // get mandatory separator string
4427 if (!ExpectSymbol(',', PR_TRUE
) ||
4428 !(GetNonCloseParenToken(PR_TRUE
) &&
4429 eCSSToken_String
== mToken
.mType
)) {
4433 val
->Item(1).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
4436 // get optional type
4437 PRInt32 type
= NS_STYLE_LIST_STYLE_DECIMAL
;
4438 if (ExpectSymbol(',', PR_TRUE
)) {
4439 nsCSSKeyword keyword
;
4440 PRBool success
= GetNonCloseParenToken(PR_TRUE
) &&
4441 eCSSToken_Ident
== mToken
.mType
&&
4442 (keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
)) !=
4443 eCSSKeyword_UNKNOWN
;
4445 if (keyword
== eCSSKeyword_none
) {
4446 type
= NS_STYLE_LIST_STYLE_NONE
;
4448 success
= nsCSSProps::FindKeyword(keyword
,
4449 nsCSSProps::kListStyleKTable
, type
);
4457 PRInt32 typeItem
= eCSSUnit_Counters
== unit
? 2 : 1;
4458 val
->Item(typeItem
).SetIntValue(type
, eCSSUnit_Enumerated
);
4460 if (!ExpectSymbol(')', PR_TRUE
)) {
4465 aValue
.SetArrayValue(val
, unit
);
4470 CSSParserImpl::ParseAttr(nsCSSValue
& aValue
)
4472 if (ExpectSymbol('(', PR_FALSE
)) {
4473 if (GetToken(PR_TRUE
)) {
4475 if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
4476 nsAutoString
holdIdent(mToken
.mIdent
);
4477 if (ExpectSymbol('|', PR_FALSE
)) { // namespace
4478 PRInt32 nameSpaceID
;
4479 if (!GetNamespaceIdForPrefix(holdIdent
, &nameSpaceID
)) {
4482 attr
.AppendInt(nameSpaceID
, 10);
4483 attr
.Append(PRUnichar('|'));
4484 if (! GetToken(PR_FALSE
)) {
4485 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4488 if (eCSSToken_Ident
== mToken
.mType
) {
4489 if (mCaseSensitive
) {
4490 attr
.Append(mToken
.mIdent
);
4492 nsAutoString buffer
;
4493 ToLowerCase(mToken
.mIdent
, buffer
);
4494 attr
.Append(buffer
);
4498 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4503 else { // no namespace
4504 if (mCaseSensitive
) {
4508 ToLowerCase(holdIdent
, attr
);
4512 else if (mToken
.IsSymbol('*')) { // namespace wildcard
4513 // Wildcard namespace makes no sense here and is not allowed
4514 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4518 else if (mToken
.IsSymbol('|')) { // explicit NO namespace
4519 if (! GetToken(PR_FALSE
)) {
4520 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
4523 if (eCSSToken_Ident
== mToken
.mType
) {
4524 if (mCaseSensitive
) {
4525 attr
.Append(mToken
.mIdent
);
4527 nsAutoString buffer
;
4528 ToLowerCase(mToken
.mIdent
, buffer
);
4529 attr
.Append(buffer
);
4533 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
4539 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
4543 if (ExpectSymbol(')', PR_TRUE
)) {
4544 aValue
.SetStringValue(attr
, eCSSUnit_Attr
);
4553 CSSParserImpl::ParseURL(nsCSSValue
& aValue
)
4555 if (!mSheetPrincipal
) {
4556 NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
4557 "origin principal");
4561 if (!ExpectSymbol('(', PR_FALSE
))
4566 nsCSSToken
* tk
= &mToken
;
4567 if (eCSSToken_String
!= tk
->mType
&& eCSSToken_URL
!= tk
->mType
)
4570 nsString url
= tk
->mIdent
;
4571 if (!ExpectSymbol(')', PR_TRUE
))
4574 // Translate url into an absolute url if the url is relative to the
4576 nsCOMPtr
<nsIURI
> uri
;
4577 NS_NewURI(getter_AddRefs(uri
), url
, nsnull
, mBaseURL
);
4579 nsStringBuffer
* buffer
= nsCSSValue::BufferFromString(url
);
4580 if (NS_UNLIKELY(!buffer
)) {
4581 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4584 nsCSSValue::URL
*urlVal
=
4585 new nsCSSValue::URL(uri
, buffer
, mSheetURL
, mSheetPrincipal
);
4588 if (NS_UNLIKELY(!urlVal
)) {
4589 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
4592 aValue
.SetURLValue(urlVal
);
4597 CSSParserImpl::ParseChoice(nsCSSValue aValues
[],
4598 const nsCSSProperty aPropIDs
[], PRInt32 aNumIDs
)
4601 nsAutoParseCompoundProperty
compound(this);
4604 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4605 // Try each property parser in order
4606 PRInt32 hadFound
= found
;
4608 for (index
= 0; index
< aNumIDs
; index
++) {
4609 PRInt32 bit
= 1 << index
;
4610 if ((found
& bit
) == 0) {
4611 if (ParseSingleValueProperty(aValues
[index
], aPropIDs
[index
])) {
4616 if (found
== hadFound
) { // found nothing new
4621 if (1 == found
) { // only first property
4622 if (eCSSUnit_Inherit
== aValues
[0].GetUnit()) { // one inherit, all inherit
4623 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4624 aValues
[loop
].SetInheritValue();
4626 found
= ((1 << aNumIDs
) - 1);
4628 else if (eCSSUnit_Initial
== aValues
[0].GetUnit()) { // one initial, all initial
4629 for (loop
= 1; loop
< aNumIDs
; loop
++) {
4630 aValues
[loop
].SetInitialValue();
4632 found
= ((1 << aNumIDs
) - 1);
4635 else { // more than one value, verify no inherits or initials
4636 for (loop
= 0; loop
< aNumIDs
; loop
++) {
4637 if (eCSSUnit_Inherit
== aValues
[loop
].GetUnit()) {
4641 else if (eCSSUnit_Initial
== aValues
[loop
].GetUnit()) {
4652 CSSParserImpl::AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
)
4654 NS_ASSERTION(0 <= aPropID
&& aPropID
< eCSSProperty_COUNT_no_shorthands
,
4655 "property out of range");
4656 NS_ASSERTION(nsCSSProps::kTypeTable
[aPropID
] == eCSSType_Value
,
4657 nsPrintfCString(64, "type error (property=\'%s\')",
4658 nsCSSProps::GetStringValue(aPropID
).get()).get());
4659 nsCSSValue
& storage
=
4660 *static_cast<nsCSSValue
*>(mTempData
.PropertyAt(aPropID
));
4662 mTempData
.SetPropertyBit(aPropID
);
4666 * Parse a "box" property. Box properties have 1 to 4 values. When less
4667 * than 4 values are provided a standard mapping is used to replicate
4671 CSSParserImpl::ParseBoxProperties(nsCSSRect
& aResult
,
4672 const nsCSSProperty aPropIDs
[])
4674 // Get up to four values for the property
4678 for (index
= 0; index
< 4; index
++) {
4679 if (! ParseSingleValueProperty(result
.*(nsCSSRect::sides
[index
]),
4685 if ((count
== 0) || (PR_FALSE
== ExpectEndProperty())) {
4689 if (1 < count
) { // verify no more than single inherit or initial
4690 for (index
= 0; index
< 4; index
++) {
4691 nsCSSUnit unit
= (result
.*(nsCSSRect::sides
[index
])).GetUnit();
4692 if (eCSSUnit_Inherit
== unit
|| eCSSUnit_Initial
== unit
) {
4698 // Provide missing values by replicating some of the values found
4700 case 1: // Make right == top
4701 result
.mRight
= result
.mTop
;
4702 case 2: // Make bottom == top
4703 result
.mBottom
= result
.mTop
;
4704 case 3: // Make left == right
4705 result
.mLeft
= result
.mRight
;
4708 for (index
= 0; index
< 4; index
++) {
4709 mTempData
.SetPropertyBit(aPropIDs
[index
]);
4716 CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
4717 PRInt32 aSourceType
)
4719 const nsCSSProperty
* subprops
= nsCSSProps::SubpropertyEntryFor(aProperty
);
4720 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
4721 "not box property with physical vs. logical cascading");
4723 if (!ParseSingleValueProperty(value
, subprops
[0]) ||
4724 !ExpectEndProperty())
4727 AppendValue(subprops
[0], value
);
4728 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
4729 AppendValue(subprops
[1], typeVal
);
4730 AppendValue(subprops
[2], typeVal
);
4735 CSSParserImpl::ParseProperty(nsCSSProperty aPropID
)
4737 NS_ASSERTION(aPropID
< eCSSProperty_COUNT
, "index out of range");
4739 switch (aPropID
) { // handle shorthand or multiple properties
4740 case eCSSProperty_background
:
4741 return ParseBackground();
4742 case eCSSProperty_background_position
:
4743 return ParseBackgroundPosition();
4744 case eCSSProperty_border
:
4745 return ParseBorderSide(kBorderTopIDs
, PR_TRUE
);
4746 case eCSSProperty_border_color
:
4747 return ParseBorderColor();
4748 case eCSSProperty_border_spacing
:
4749 return ParseBorderSpacing();
4750 case eCSSProperty_border_style
:
4751 return ParseBorderStyle();
4752 case eCSSProperty_border_bottom
:
4753 return ParseBorderSide(kBorderBottomIDs
, PR_FALSE
);
4754 case eCSSProperty_border_end
:
4755 return ParseDirectionalBorderSide(kBorderEndIDs
,
4756 NS_BOXPROP_SOURCE_LOGICAL
);
4757 case eCSSProperty_border_left
:
4758 return ParseDirectionalBorderSide(kBorderLeftIDs
,
4759 NS_BOXPROP_SOURCE_PHYSICAL
);
4760 case eCSSProperty_border_right
:
4761 return ParseDirectionalBorderSide(kBorderRightIDs
,
4762 NS_BOXPROP_SOURCE_PHYSICAL
);
4763 case eCSSProperty_border_start
:
4764 return ParseDirectionalBorderSide(kBorderStartIDs
,
4765 NS_BOXPROP_SOURCE_LOGICAL
);
4766 case eCSSProperty_border_top
:
4767 return ParseBorderSide(kBorderTopIDs
, PR_FALSE
);
4768 case eCSSProperty_border_bottom_colors
:
4769 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mBottom
,
4771 case eCSSProperty_border_left_colors
:
4772 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mLeft
,
4774 case eCSSProperty_border_right_colors
:
4775 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mRight
,
4777 case eCSSProperty_border_top_colors
:
4778 return ParseBorderColors(&mTempData
.mMargin
.mBorderColors
.mTop
,
4780 case eCSSProperty_border_image
:
4781 return ParseBorderImage();
4782 case eCSSProperty_border_width
:
4783 return ParseBorderWidth();
4784 case eCSSProperty_border_end_color
:
4785 return ParseDirectionalBoxProperty(eCSSProperty_border_end_color
,
4786 NS_BOXPROP_SOURCE_LOGICAL
);
4787 case eCSSProperty_border_left_color
:
4788 return ParseDirectionalBoxProperty(eCSSProperty_border_left_color
,
4789 NS_BOXPROP_SOURCE_PHYSICAL
);
4790 case eCSSProperty_border_right_color
:
4791 return ParseDirectionalBoxProperty(eCSSProperty_border_right_color
,
4792 NS_BOXPROP_SOURCE_PHYSICAL
);
4793 case eCSSProperty_border_start_color
:
4794 return ParseDirectionalBoxProperty(eCSSProperty_border_start_color
,
4795 NS_BOXPROP_SOURCE_LOGICAL
);
4796 case eCSSProperty_border_end_width
:
4797 return ParseDirectionalBoxProperty(eCSSProperty_border_end_width
,
4798 NS_BOXPROP_SOURCE_LOGICAL
);
4799 case eCSSProperty_border_left_width
:
4800 return ParseDirectionalBoxProperty(eCSSProperty_border_left_width
,
4801 NS_BOXPROP_SOURCE_PHYSICAL
);
4802 case eCSSProperty_border_right_width
:
4803 return ParseDirectionalBoxProperty(eCSSProperty_border_right_width
,
4804 NS_BOXPROP_SOURCE_PHYSICAL
);
4805 case eCSSProperty_border_start_width
:
4806 return ParseDirectionalBoxProperty(eCSSProperty_border_start_width
,
4807 NS_BOXPROP_SOURCE_LOGICAL
);
4808 case eCSSProperty_border_end_style
:
4809 return ParseDirectionalBoxProperty(eCSSProperty_border_end_style
,
4810 NS_BOXPROP_SOURCE_LOGICAL
);
4811 case eCSSProperty_border_left_style
:
4812 return ParseDirectionalBoxProperty(eCSSProperty_border_left_style
,
4813 NS_BOXPROP_SOURCE_PHYSICAL
);
4814 case eCSSProperty_border_right_style
:
4815 return ParseDirectionalBoxProperty(eCSSProperty_border_right_style
,
4816 NS_BOXPROP_SOURCE_PHYSICAL
);
4817 case eCSSProperty_border_start_style
:
4818 return ParseDirectionalBoxProperty(eCSSProperty_border_start_style
,
4819 NS_BOXPROP_SOURCE_LOGICAL
);
4820 case eCSSProperty__moz_border_radius
:
4821 return ParseBorderRadius();
4822 case eCSSProperty__moz_outline_radius
:
4823 return ParseOutlineRadius();
4824 case eCSSProperty_box_shadow
:
4825 return ParseBoxShadow();
4826 case eCSSProperty_clip
:
4827 return ParseRect(mTempData
.mDisplay
.mClip
, eCSSProperty_clip
);
4828 case eCSSProperty__moz_column_rule
:
4829 return ParseBorderSide(kColumnRuleIDs
, PR_FALSE
);
4830 case eCSSProperty_content
:
4831 return ParseContent();
4832 case eCSSProperty_counter_increment
:
4833 return ParseCounterData(&mTempData
.mContent
.mCounterIncrement
,
4835 case eCSSProperty_counter_reset
:
4836 return ParseCounterData(&mTempData
.mContent
.mCounterReset
,
4838 case eCSSProperty_cue
:
4840 case eCSSProperty_cursor
:
4841 return ParseCursor();
4842 case eCSSProperty_font
:
4844 case eCSSProperty_image_region
:
4845 return ParseRect(mTempData
.mList
.mImageRegion
,
4846 eCSSProperty_image_region
);
4847 case eCSSProperty_list_style
:
4848 return ParseListStyle();
4849 case eCSSProperty_margin
:
4850 return ParseMargin();
4851 case eCSSProperty_margin_end
:
4852 return ParseDirectionalBoxProperty(eCSSProperty_margin_end
,
4853 NS_BOXPROP_SOURCE_LOGICAL
);
4854 case eCSSProperty_margin_left
:
4855 return ParseDirectionalBoxProperty(eCSSProperty_margin_left
,
4856 NS_BOXPROP_SOURCE_PHYSICAL
);
4857 case eCSSProperty_margin_right
:
4858 return ParseDirectionalBoxProperty(eCSSProperty_margin_right
,
4859 NS_BOXPROP_SOURCE_PHYSICAL
);
4860 case eCSSProperty_margin_start
:
4861 return ParseDirectionalBoxProperty(eCSSProperty_margin_start
,
4862 NS_BOXPROP_SOURCE_LOGICAL
);
4863 case eCSSProperty_outline
:
4864 return ParseOutline();
4865 case eCSSProperty_overflow
:
4866 return ParseOverflow();
4867 case eCSSProperty_padding
:
4868 return ParsePadding();
4869 case eCSSProperty_padding_end
:
4870 return ParseDirectionalBoxProperty(eCSSProperty_padding_end
,
4871 NS_BOXPROP_SOURCE_LOGICAL
);
4872 case eCSSProperty_padding_left
:
4873 return ParseDirectionalBoxProperty(eCSSProperty_padding_left
,
4874 NS_BOXPROP_SOURCE_PHYSICAL
);
4875 case eCSSProperty_padding_right
:
4876 return ParseDirectionalBoxProperty(eCSSProperty_padding_right
,
4877 NS_BOXPROP_SOURCE_PHYSICAL
);
4878 case eCSSProperty_padding_start
:
4879 return ParseDirectionalBoxProperty(eCSSProperty_padding_start
,
4880 NS_BOXPROP_SOURCE_LOGICAL
);
4881 case eCSSProperty_pause
:
4882 return ParsePause();
4883 case eCSSProperty_quotes
:
4884 return ParseQuotes();
4885 case eCSSProperty_size
:
4887 case eCSSProperty_text_shadow
:
4888 return ParseTextShadow();
4889 case eCSSProperty__moz_transform
:
4890 return ParseMozTransform();
4891 case eCSSProperty__moz_transform_origin
:
4892 return ParseMozTransformOrigin();
4895 case eCSSProperty_fill
:
4896 return ParsePaint(&mTempData
.mSVG
.mFill
, eCSSProperty_fill
);
4897 case eCSSProperty_stroke
:
4898 return ParsePaint(&mTempData
.mSVG
.mStroke
, eCSSProperty_stroke
);
4899 case eCSSProperty_stroke_dasharray
:
4900 return ParseDasharray();
4901 case eCSSProperty_marker
:
4902 return ParseMarker();
4905 // Strip out properties we use internally.
4906 case eCSSProperty__x_system_font
:
4907 case eCSSProperty_margin_end_value
:
4908 case eCSSProperty_margin_left_value
:
4909 case eCSSProperty_margin_right_value
:
4910 case eCSSProperty_margin_start_value
:
4911 case eCSSProperty_margin_left_ltr_source
:
4912 case eCSSProperty_margin_left_rtl_source
:
4913 case eCSSProperty_margin_right_ltr_source
:
4914 case eCSSProperty_margin_right_rtl_source
:
4915 case eCSSProperty_padding_end_value
:
4916 case eCSSProperty_padding_left_value
:
4917 case eCSSProperty_padding_right_value
:
4918 case eCSSProperty_padding_start_value
:
4919 case eCSSProperty_padding_left_ltr_source
:
4920 case eCSSProperty_padding_left_rtl_source
:
4921 case eCSSProperty_padding_right_ltr_source
:
4922 case eCSSProperty_padding_right_rtl_source
:
4923 case eCSSProperty_border_end_color_value
:
4924 case eCSSProperty_border_left_color_value
:
4925 case eCSSProperty_border_right_color_value
:
4926 case eCSSProperty_border_start_color_value
:
4927 case eCSSProperty_border_left_color_ltr_source
:
4928 case eCSSProperty_border_left_color_rtl_source
:
4929 case eCSSProperty_border_right_color_ltr_source
:
4930 case eCSSProperty_border_right_color_rtl_source
:
4931 case eCSSProperty_border_end_style_value
:
4932 case eCSSProperty_border_left_style_value
:
4933 case eCSSProperty_border_right_style_value
:
4934 case eCSSProperty_border_start_style_value
:
4935 case eCSSProperty_border_left_style_ltr_source
:
4936 case eCSSProperty_border_left_style_rtl_source
:
4937 case eCSSProperty_border_right_style_ltr_source
:
4938 case eCSSProperty_border_right_style_rtl_source
:
4939 case eCSSProperty_border_end_width_value
:
4940 case eCSSProperty_border_left_width_value
:
4941 case eCSSProperty_border_right_width_value
:
4942 case eCSSProperty_border_start_width_value
:
4943 case eCSSProperty_border_left_width_ltr_source
:
4944 case eCSSProperty_border_left_width_rtl_source
:
4945 case eCSSProperty_border_right_width_ltr_source
:
4946 case eCSSProperty_border_right_width_rtl_source
:
4947 // The user can't use these
4948 REPORT_UNEXPECTED(PEInaccessibleProperty2
);
4950 default: // must be single property
4953 if (ParseSingleValueProperty(value
, aPropID
)) {
4954 if (ExpectEndProperty()) {
4955 AppendValue(aPropID
, value
);
4958 // XXX Report errors?
4960 // XXX Report errors?
4966 // Bits used in determining which background position info we have
4967 #define BG_CENTER NS_STYLE_BG_POSITION_CENTER
4968 #define BG_TOP NS_STYLE_BG_POSITION_TOP
4969 #define BG_BOTTOM NS_STYLE_BG_POSITION_BOTTOM
4970 #define BG_LEFT NS_STYLE_BG_POSITION_LEFT
4971 #define BG_RIGHT NS_STYLE_BG_POSITION_RIGHT
4972 #define BG_CTB (BG_CENTER | BG_TOP | BG_BOTTOM)
4973 #define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT)
4976 CSSParserImpl::ParseSingleValueProperty(nsCSSValue
& aValue
,
4977 nsCSSProperty aPropID
)
4980 case eCSSProperty_UNKNOWN
:
4981 case eCSSProperty_background
:
4982 case eCSSProperty_background_position
:
4983 case eCSSProperty_border
:
4984 case eCSSProperty_border_color
:
4985 case eCSSProperty_border_bottom_colors
:
4986 case eCSSProperty_border_image
:
4987 case eCSSProperty_border_left_colors
:
4988 case eCSSProperty_border_right_colors
:
4989 case eCSSProperty_border_end_color
:
4990 case eCSSProperty_border_left_color
:
4991 case eCSSProperty_border_right_color
:
4992 case eCSSProperty_border_start_color
:
4993 case eCSSProperty_border_end_style
:
4994 case eCSSProperty_border_left_style
:
4995 case eCSSProperty_border_right_style
:
4996 case eCSSProperty_border_start_style
:
4997 case eCSSProperty_border_end_width
:
4998 case eCSSProperty_border_left_width
:
4999 case eCSSProperty_border_right_width
:
5000 case eCSSProperty_border_start_width
:
5001 case eCSSProperty_border_top_colors
:
5002 case eCSSProperty_border_spacing
:
5003 case eCSSProperty_border_style
:
5004 case eCSSProperty_border_bottom
:
5005 case eCSSProperty_border_end
:
5006 case eCSSProperty_border_left
:
5007 case eCSSProperty_border_right
:
5008 case eCSSProperty_border_start
:
5009 case eCSSProperty_border_top
:
5010 case eCSSProperty_border_width
:
5011 case eCSSProperty__moz_border_radius
:
5012 case eCSSProperty_box_shadow
:
5013 case eCSSProperty_clip
:
5014 case eCSSProperty__moz_column_rule
:
5015 case eCSSProperty_content
:
5016 case eCSSProperty_counter_increment
:
5017 case eCSSProperty_counter_reset
:
5018 case eCSSProperty_cue
:
5019 case eCSSProperty_cursor
:
5020 case eCSSProperty_font
:
5021 case eCSSProperty_image_region
:
5022 case eCSSProperty_list_style
:
5023 case eCSSProperty_margin
:
5024 case eCSSProperty_margin_end
:
5025 case eCSSProperty_margin_left
:
5026 case eCSSProperty_margin_right
:
5027 case eCSSProperty_margin_start
:
5028 case eCSSProperty_outline
:
5029 case eCSSProperty__moz_outline_radius
:
5030 case eCSSProperty_overflow
:
5031 case eCSSProperty_padding
:
5032 case eCSSProperty_padding_end
:
5033 case eCSSProperty_padding_left
:
5034 case eCSSProperty_padding_right
:
5035 case eCSSProperty_padding_start
:
5036 case eCSSProperty_pause
:
5037 case eCSSProperty_quotes
:
5038 case eCSSProperty_size
:
5039 case eCSSProperty_text_shadow
:
5040 case eCSSProperty__moz_transform
:
5041 case eCSSProperty__moz_transform_origin
:
5042 case eCSSProperty_COUNT
:
5044 case eCSSProperty_fill
:
5045 case eCSSProperty_stroke
:
5046 case eCSSProperty_stroke_dasharray
:
5047 case eCSSProperty_marker
:
5049 NS_ERROR("not a single value property");
5052 case eCSSProperty__x_system_font
:
5053 case eCSSProperty_margin_left_ltr_source
:
5054 case eCSSProperty_margin_left_rtl_source
:
5055 case eCSSProperty_margin_right_ltr_source
:
5056 case eCSSProperty_margin_right_rtl_source
:
5057 case eCSSProperty_padding_left_ltr_source
:
5058 case eCSSProperty_padding_left_rtl_source
:
5059 case eCSSProperty_padding_right_ltr_source
:
5060 case eCSSProperty_padding_right_rtl_source
:
5061 case eCSSProperty_border_left_color_ltr_source
:
5062 case eCSSProperty_border_left_color_rtl_source
:
5063 case eCSSProperty_border_right_color_ltr_source
:
5064 case eCSSProperty_border_right_color_rtl_source
:
5065 case eCSSProperty_border_left_style_ltr_source
:
5066 case eCSSProperty_border_left_style_rtl_source
:
5067 case eCSSProperty_border_right_style_ltr_source
:
5068 case eCSSProperty_border_right_style_rtl_source
:
5069 case eCSSProperty_border_left_width_ltr_source
:
5070 case eCSSProperty_border_left_width_rtl_source
:
5071 case eCSSProperty_border_right_width_ltr_source
:
5072 case eCSSProperty_border_right_width_rtl_source
:
5074 case eCSSProperty_script_size_multiplier
:
5075 case eCSSProperty_script_min_size
:
5077 NS_ERROR("not currently parsed here");
5080 case eCSSProperty_appearance
:
5081 return ParseVariant(aValue
, VARIANT_HK
,
5082 nsCSSProps::kAppearanceKTable
);
5083 case eCSSProperty_azimuth
:
5084 return ParseAzimuth(aValue
);
5085 case eCSSProperty_background_attachment
:
5086 return ParseVariant(aValue
, VARIANT_HK
,
5087 nsCSSProps::kBackgroundAttachmentKTable
);
5088 case eCSSProperty__moz_background_clip
:
5089 return ParseVariant(aValue
, VARIANT_HK
,
5090 nsCSSProps::kBackgroundClipKTable
);
5091 case eCSSProperty_background_color
:
5092 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5093 case eCSSProperty_background_image
:
5094 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5095 case eCSSProperty__moz_background_inline_policy
:
5096 return ParseVariant(aValue
, VARIANT_HK
,
5097 nsCSSProps::kBackgroundInlinePolicyKTable
);
5098 case eCSSProperty__moz_background_origin
:
5099 return ParseVariant(aValue
, VARIANT_HK
,
5100 nsCSSProps::kBackgroundOriginKTable
);
5101 case eCSSProperty_background_repeat
:
5102 return ParseVariant(aValue
, VARIANT_HK
,
5103 nsCSSProps::kBackgroundRepeatKTable
);
5104 case eCSSProperty_binding
:
5105 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5106 case eCSSProperty_border_collapse
:
5107 return ParseVariant(aValue
, VARIANT_HK
,
5108 nsCSSProps::kBorderCollapseKTable
);
5109 case eCSSProperty_border_bottom_color
:
5110 case eCSSProperty_border_end_color_value
: // for internal use
5111 case eCSSProperty_border_left_color_value
: // for internal use
5112 case eCSSProperty_border_right_color_value
: // for internal use
5113 case eCSSProperty_border_start_color_value
: // for internal use
5114 case eCSSProperty_border_top_color
:
5115 case eCSSProperty__moz_column_rule_color
:
5116 return ParseVariant(aValue
, VARIANT_HCK
,
5117 nsCSSProps::kBorderColorKTable
);
5118 case eCSSProperty_border_bottom_style
:
5119 case eCSSProperty_border_end_style_value
: // for internal use
5120 case eCSSProperty_border_left_style_value
: // for internal use
5121 case eCSSProperty_border_right_style_value
: // for internal use
5122 case eCSSProperty_border_start_style_value
: // for internal use
5123 case eCSSProperty_border_top_style
:
5124 case eCSSProperty__moz_column_rule_style
:
5125 return ParseVariant(aValue
, VARIANT_HOK
,
5126 nsCSSProps::kBorderStyleKTable
);
5127 case eCSSProperty_border_bottom_width
:
5128 case eCSSProperty_border_end_width_value
: // for internal use
5129 case eCSSProperty_border_left_width_value
: // for internal use
5130 case eCSSProperty_border_right_width_value
: // for internal use
5131 case eCSSProperty_border_start_width_value
: // for internal use
5132 case eCSSProperty_border_top_width
:
5133 case eCSSProperty__moz_column_rule_width
:
5134 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5135 nsCSSProps::kBorderWidthKTable
);
5136 case eCSSProperty__moz_border_radius_topLeft
:
5137 case eCSSProperty__moz_border_radius_topRight
:
5138 case eCSSProperty__moz_border_radius_bottomRight
:
5139 case eCSSProperty__moz_border_radius_bottomLeft
:
5140 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5141 case eCSSProperty__moz_column_count
:
5142 return ParsePositiveVariant(aValue
, VARIANT_AHI
, nsnull
);
5143 case eCSSProperty__moz_column_width
:
5144 return ParsePositiveVariant(aValue
, VARIANT_AHL
, nsnull
);
5145 case eCSSProperty__moz_column_gap
:
5146 return ParsePositiveVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5147 case eCSSProperty__moz_outline_radius_topLeft
:
5148 case eCSSProperty__moz_outline_radius_topRight
:
5149 case eCSSProperty__moz_outline_radius_bottomRight
:
5150 case eCSSProperty__moz_outline_radius_bottomLeft
:
5151 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5152 case eCSSProperty_bottom
:
5153 case eCSSProperty_top
:
5154 case eCSSProperty_left
:
5155 case eCSSProperty_right
:
5156 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5157 case eCSSProperty_box_align
:
5158 return ParseVariant(aValue
, VARIANT_HK
,
5159 nsCSSProps::kBoxAlignKTable
);
5160 case eCSSProperty_box_direction
:
5161 return ParseVariant(aValue
, VARIANT_HK
,
5162 nsCSSProps::kBoxDirectionKTable
);
5163 case eCSSProperty_box_flex
:
5164 return ParsePositiveVariant(aValue
, VARIANT_HN
, nsnull
);
5165 case eCSSProperty_box_orient
:
5166 return ParseVariant(aValue
, VARIANT_HK
,
5167 nsCSSProps::kBoxOrientKTable
);
5168 case eCSSProperty_box_pack
:
5169 return ParseVariant(aValue
, VARIANT_HK
,
5170 nsCSSProps::kBoxPackKTable
);
5171 case eCSSProperty_box_ordinal_group
:
5172 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5174 case eCSSProperty_clip_path
:
5175 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5176 case eCSSProperty_clip_rule
:
5177 return ParseVariant(aValue
, VARIANT_HK
,
5178 nsCSSProps::kFillRuleKTable
);
5179 case eCSSProperty_color_interpolation
:
5180 case eCSSProperty_color_interpolation_filters
:
5181 return ParseVariant(aValue
, VARIANT_AHK
,
5182 nsCSSProps::kColorInterpolationKTable
);
5183 case eCSSProperty_dominant_baseline
:
5184 return ParseVariant(aValue
, VARIANT_AHK
,
5185 nsCSSProps::kDominantBaselineKTable
);
5186 case eCSSProperty_fill_opacity
:
5187 return ParseVariant(aValue
, VARIANT_HN
,
5189 case eCSSProperty_fill_rule
:
5190 return ParseVariant(aValue
, VARIANT_HK
,
5191 nsCSSProps::kFillRuleKTable
);
5192 case eCSSProperty_filter
:
5193 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5194 case eCSSProperty_flood_color
:
5195 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5196 case eCSSProperty_flood_opacity
:
5197 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5198 case eCSSProperty_lighting_color
:
5199 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5200 case eCSSProperty_marker_end
:
5201 case eCSSProperty_marker_mid
:
5202 case eCSSProperty_marker_start
:
5203 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5204 case eCSSProperty_mask
:
5205 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5206 case eCSSProperty_pointer_events
:
5207 return ParseVariant(aValue
, VARIANT_HOK
,
5208 nsCSSProps::kPointerEventsKTable
);
5209 case eCSSProperty_shape_rendering
:
5210 return ParseVariant(aValue
, VARIANT_AHK
,
5211 nsCSSProps::kShapeRenderingKTable
);
5212 case eCSSProperty_stop_color
:
5213 return ParseVariant(aValue
, VARIANT_HC
,
5215 case eCSSProperty_stop_opacity
:
5216 return ParseVariant(aValue
, VARIANT_HN
,
5218 case eCSSProperty_stroke_dashoffset
:
5219 return ParseVariant(aValue
, VARIANT_HLPN
,
5221 case eCSSProperty_stroke_linecap
:
5222 return ParseVariant(aValue
, VARIANT_HK
,
5223 nsCSSProps::kStrokeLinecapKTable
);
5224 case eCSSProperty_stroke_linejoin
:
5225 return ParseVariant(aValue
, VARIANT_HK
,
5226 nsCSSProps::kStrokeLinejoinKTable
);
5227 case eCSSProperty_stroke_miterlimit
:
5228 return ParsePositiveVariant(aValue
, VARIANT_HN
,
5230 case eCSSProperty_stroke_opacity
:
5231 return ParseVariant(aValue
, VARIANT_HN
,
5233 case eCSSProperty_stroke_width
:
5234 return ParsePositiveVariant(aValue
, VARIANT_HLPN
,
5236 case eCSSProperty_text_anchor
:
5237 return ParseVariant(aValue
, VARIANT_HK
,
5238 nsCSSProps::kTextAnchorKTable
);
5239 case eCSSProperty_text_rendering
:
5240 return ParseVariant(aValue
, VARIANT_AHK
,
5241 nsCSSProps::kTextRenderingKTable
);
5243 case eCSSProperty_box_sizing
:
5244 return ParseVariant(aValue
, VARIANT_HK
,
5245 nsCSSProps::kBoxSizingKTable
);
5246 case eCSSProperty_height
:
5247 return ParsePositiveVariant(aValue
, VARIANT_AHLP
, nsnull
);
5248 case eCSSProperty_width
:
5249 return ParsePositiveVariant(aValue
, VARIANT_AHKLP
,
5250 nsCSSProps::kWidthKTable
);
5251 case eCSSProperty_force_broken_image_icon
:
5252 return ParsePositiveVariant(aValue
, VARIANT_HI
, nsnull
);
5253 case eCSSProperty_caption_side
:
5254 return ParseVariant(aValue
, VARIANT_HK
,
5255 nsCSSProps::kCaptionSideKTable
);
5256 case eCSSProperty_clear
:
5257 return ParseVariant(aValue
, VARIANT_HOK
,
5258 nsCSSProps::kClearKTable
);
5259 case eCSSProperty_color
:
5260 return ParseVariant(aValue
, VARIANT_HC
, nsnull
);
5261 case eCSSProperty_cue_after
:
5262 case eCSSProperty_cue_before
:
5263 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5264 case eCSSProperty_direction
:
5265 return ParseVariant(aValue
, VARIANT_HK
,
5266 nsCSSProps::kDirectionKTable
);
5267 case eCSSProperty_display
:
5268 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kDisplayKTable
)) {
5269 if (aValue
.GetUnit() == eCSSUnit_Enumerated
) {
5270 switch (aValue
.GetIntValue()) {
5271 case NS_STYLE_DISPLAY_MARKER
: // bug 2055
5272 case NS_STYLE_DISPLAY_RUN_IN
: // bug 2056
5273 case NS_STYLE_DISPLAY_COMPACT
: // bug 14983
5280 case eCSSProperty_elevation
:
5281 return ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5282 nsCSSProps::kElevationKTable
);
5283 case eCSSProperty_empty_cells
:
5284 return ParseVariant(aValue
, VARIANT_HK
,
5285 nsCSSProps::kEmptyCellsKTable
);
5286 case eCSSProperty_float
:
5287 return ParseVariant(aValue
, VARIANT_HOK
,
5288 nsCSSProps::kFloatKTable
);
5289 case eCSSProperty_float_edge
:
5290 return ParseVariant(aValue
, VARIANT_HK
,
5291 nsCSSProps::kFloatEdgeKTable
);
5292 case eCSSProperty_font_family
:
5293 return ParseFamily(aValue
);
5294 case eCSSProperty_font_size
:
5295 return ParsePositiveVariant(aValue
,
5296 VARIANT_HKLP
| VARIANT_SYSFONT
,
5297 nsCSSProps::kFontSizeKTable
);
5298 case eCSSProperty_font_size_adjust
:
5299 return ParseVariant(aValue
, VARIANT_HON
| VARIANT_SYSFONT
,
5301 case eCSSProperty_font_stretch
:
5302 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5303 nsCSSProps::kFontStretchKTable
);
5304 case eCSSProperty_font_style
:
5305 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5306 nsCSSProps::kFontStyleKTable
);
5307 case eCSSProperty_font_variant
:
5308 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_SYSFONT
,
5309 nsCSSProps::kFontVariantKTable
);
5310 case eCSSProperty_font_weight
:
5311 return ParseFontWeight(aValue
);
5312 case eCSSProperty_ime_mode
:
5313 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NORMAL
,
5314 nsCSSProps::kIMEModeKTable
);
5315 case eCSSProperty_letter_spacing
:
5316 case eCSSProperty_word_spacing
:
5317 return ParseVariant(aValue
, VARIANT_HL
| VARIANT_NORMAL
, nsnull
);
5318 case eCSSProperty_line_height
:
5319 return ParsePositiveVariant(aValue
, VARIANT_HLPN
| VARIANT_NORMAL
| VARIANT_SYSFONT
, nsnull
);
5320 case eCSSProperty_list_style_image
:
5321 return ParseVariant(aValue
, VARIANT_HUO
, nsnull
);
5322 case eCSSProperty_list_style_position
:
5323 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kListStylePositionKTable
);
5324 case eCSSProperty_list_style_type
:
5325 return ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kListStyleKTable
);
5326 case eCSSProperty_margin_bottom
:
5327 case eCSSProperty_margin_end_value
: // for internal use
5328 case eCSSProperty_margin_left_value
: // for internal use
5329 case eCSSProperty_margin_right_value
: // for internal use
5330 case eCSSProperty_margin_start_value
: // for internal use
5331 case eCSSProperty_margin_top
:
5332 return ParseVariant(aValue
, VARIANT_AHLP
, nsnull
);
5333 case eCSSProperty_marker_offset
:
5334 return ParseVariant(aValue
, VARIANT_AHL
, nsnull
);
5335 case eCSSProperty_marks
:
5336 return ParseMarks(aValue
);
5337 case eCSSProperty_max_height
:
5338 return ParsePositiveVariant(aValue
, VARIANT_HLPO
, nsnull
);
5339 case eCSSProperty_max_width
:
5340 return ParsePositiveVariant(aValue
, VARIANT_HKLPO
,
5341 nsCSSProps::kWidthKTable
);
5342 case eCSSProperty_min_height
:
5343 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5344 case eCSSProperty_min_width
:
5345 return ParsePositiveVariant(aValue
, VARIANT_HKLP
,
5346 nsCSSProps::kWidthKTable
);
5347 case eCSSProperty_opacity
:
5348 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5349 case eCSSProperty_orphans
:
5350 case eCSSProperty_widows
:
5351 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5352 case eCSSProperty_outline_color
:
5353 return ParseVariant(aValue
, VARIANT_HCK
,
5354 nsCSSProps::kOutlineColorKTable
);
5355 case eCSSProperty_outline_style
:
5356 return ParseVariant(aValue
, VARIANT_HOK
| VARIANT_AUTO
,
5357 nsCSSProps::kOutlineStyleKTable
);
5358 case eCSSProperty_outline_width
:
5359 return ParsePositiveVariant(aValue
, VARIANT_HKL
,
5360 nsCSSProps::kBorderWidthKTable
);
5361 case eCSSProperty_outline_offset
:
5362 return ParseVariant(aValue
, VARIANT_HL
, nsnull
);
5363 case eCSSProperty_overflow_x
:
5364 case eCSSProperty_overflow_y
:
5365 return ParseVariant(aValue
, VARIANT_AHK
,
5366 nsCSSProps::kOverflowSubKTable
);
5367 case eCSSProperty_padding_bottom
:
5368 case eCSSProperty_padding_end_value
: // for internal use
5369 case eCSSProperty_padding_left_value
: // for internal use
5370 case eCSSProperty_padding_right_value
: // for internal use
5371 case eCSSProperty_padding_start_value
: // for internal use
5372 case eCSSProperty_padding_top
:
5373 return ParsePositiveVariant(aValue
, VARIANT_HLP
, nsnull
);
5374 case eCSSProperty_page
:
5375 return ParseVariant(aValue
, VARIANT_AUTO
| VARIANT_IDENTIFIER
, nsnull
);
5376 case eCSSProperty_page_break_after
:
5377 case eCSSProperty_page_break_before
:
5378 return ParseVariant(aValue
, VARIANT_AHK
,
5379 nsCSSProps::kPageBreakKTable
);
5380 case eCSSProperty_page_break_inside
:
5381 return ParseVariant(aValue
, VARIANT_AHK
,
5382 nsCSSProps::kPageBreakInsideKTable
);
5383 case eCSSProperty_pause_after
:
5384 case eCSSProperty_pause_before
:
5385 return ParseVariant(aValue
, VARIANT_HTP
, nsnull
);
5386 case eCSSProperty_pitch
:
5387 return ParseVariant(aValue
, VARIANT_HKF
, nsCSSProps::kPitchKTable
);
5388 case eCSSProperty_pitch_range
:
5389 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5390 case eCSSProperty_position
:
5391 return ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kPositionKTable
);
5392 case eCSSProperty_richness
:
5393 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5395 // script-level can take Integer or Number values, but only Integer ("relative")
5396 // values can be specified in a style sheet. Also we only allow this property
5397 // when unsafe rules are enabled, because otherwise it could interfere
5398 // with rulenode optimizations if used in a non-MathML-enabled document.
5399 case eCSSProperty_script_level
:
5400 if (!mUnsafeRulesEnabled
)
5402 return ParseVariant(aValue
, VARIANT_HI
, nsnull
);
5404 case eCSSProperty_speak
:
5405 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5406 nsCSSProps::kSpeakKTable
);
5407 case eCSSProperty_speak_header
:
5408 return ParseVariant(aValue
, VARIANT_HK
,
5409 nsCSSProps::kSpeakHeaderKTable
);
5410 case eCSSProperty_speak_numeral
:
5411 return ParseVariant(aValue
, VARIANT_HK
,
5412 nsCSSProps::kSpeakNumeralKTable
);
5413 case eCSSProperty_speak_punctuation
:
5414 return ParseVariant(aValue
, VARIANT_HOK
,
5415 nsCSSProps::kSpeakPunctuationKTable
);
5416 case eCSSProperty_speech_rate
:
5417 return ParseVariant(aValue
, VARIANT_HN
| VARIANT_KEYWORD
,
5418 nsCSSProps::kSpeechRateKTable
);
5419 case eCSSProperty_stack_sizing
:
5420 return ParseVariant(aValue
, VARIANT_HK
,
5421 nsCSSProps::kStackSizingKTable
);
5422 case eCSSProperty_stress
:
5423 return ParseVariant(aValue
, VARIANT_HN
, nsnull
);
5424 case eCSSProperty_table_layout
:
5425 return ParseVariant(aValue
, VARIANT_AHK
,
5426 nsCSSProps::kTableLayoutKTable
);
5427 case eCSSProperty_text_align
:
5428 // When we support aligning on a string, we can parse text-align
5430 return ParseVariant(aValue
, VARIANT_HK
/* | VARIANT_STRING */,
5431 nsCSSProps::kTextAlignKTable
);
5432 case eCSSProperty_text_decoration
:
5433 return ParseTextDecoration(aValue
);
5434 case eCSSProperty_text_indent
:
5435 return ParseVariant(aValue
, VARIANT_HLP
, nsnull
);
5436 case eCSSProperty_text_transform
:
5437 return ParseVariant(aValue
, VARIANT_HOK
,
5438 nsCSSProps::kTextTransformKTable
);
5439 case eCSSProperty_unicode_bidi
:
5440 return ParseVariant(aValue
, VARIANT_HMK
,
5441 nsCSSProps::kUnicodeBidiKTable
);
5442 case eCSSProperty_user_focus
:
5443 return ParseVariant(aValue
, VARIANT_HMK
| VARIANT_NONE
,
5444 nsCSSProps::kUserFocusKTable
);
5445 case eCSSProperty_user_input
:
5446 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5447 nsCSSProps::kUserInputKTable
);
5448 case eCSSProperty_user_modify
:
5449 return ParseVariant(aValue
, VARIANT_HK
,
5450 nsCSSProps::kUserModifyKTable
);
5451 case eCSSProperty_user_select
:
5452 return ParseVariant(aValue
, VARIANT_AHK
| VARIANT_NONE
,
5453 nsCSSProps::kUserSelectKTable
);
5454 case eCSSProperty_vertical_align
:
5455 return ParseVariant(aValue
, VARIANT_HKLP
,
5456 nsCSSProps::kVerticalAlignKTable
);
5457 case eCSSProperty_visibility
:
5458 return ParseVariant(aValue
, VARIANT_HK
,
5459 nsCSSProps::kVisibilityKTable
);
5460 case eCSSProperty_voice_family
:
5461 return ParseFamily(aValue
);
5462 case eCSSProperty_volume
:
5463 return ParseVariant(aValue
, VARIANT_HPN
| VARIANT_KEYWORD
,
5464 nsCSSProps::kVolumeKTable
);
5465 case eCSSProperty_white_space
:
5466 return ParseVariant(aValue
, VARIANT_HMK
,
5467 nsCSSProps::kWhitespaceKTable
);
5468 case eCSSProperty_word_wrap
:
5469 return ParseVariant(aValue
, VARIANT_HMK
,
5470 nsCSSProps::kWordwrapKTable
);
5471 case eCSSProperty_z_index
:
5472 return ParseVariant(aValue
, VARIANT_AHI
, nsnull
);
5474 // explicitly do NOT have a default case to let the compiler
5475 // help find missing properties
5479 // nsFont::EnumerateFamilies callback for ParseFontDescriptorValue
5480 struct NS_STACK_CLASS ExtractFirstFamilyData
{
5481 nsAutoString mFamilyName
;
5483 ExtractFirstFamilyData() : mFamilyName(), mGood(PR_FALSE
) {}
5487 ExtractFirstFamily(const nsString
& aFamily
,
5491 ExtractFirstFamilyData
* realData
= (ExtractFirstFamilyData
*) aData
;
5492 if (aGeneric
|| realData
->mFamilyName
.Length() > 0) {
5493 realData
->mGood
= PR_FALSE
;
5496 realData
->mFamilyName
.Assign(aFamily
);
5497 realData
->mGood
= PR_TRUE
;
5501 // font-descriptor: descriptor ':' value ';'
5502 // caller has advanced mToken to point at the descriptor
5504 CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
5508 // These four are similar to the properties of the same name,
5509 // possibly with more restrictions on the values they can take.
5510 case eCSSFontDesc_Family
: {
5511 if (!ParseFamily(aValue
) ||
5512 aValue
.GetUnit() != eCSSUnit_String
)
5515 // the style parameters to the nsFont constructor are ignored,
5516 // because it's only being used to call EnumerateFamilies
5517 nsAutoString valueStr
;
5518 aValue
.GetStringValue(valueStr
);
5519 nsFont
font(valueStr
, 0, 0, 0, 0, 0);
5520 ExtractFirstFamilyData dat
;
5522 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
5526 aValue
.SetStringValue(dat
.mFamilyName
, eCSSUnit_String
);
5530 case eCSSFontDesc_Style
:
5531 // property is VARIANT_HMK|VARIANT_SYSFONT
5532 return ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5533 nsCSSProps::kFontStyleKTable
);
5535 case eCSSFontDesc_Weight
:
5536 return (ParseFontWeight(aValue
) &&
5537 aValue
.GetUnit() != eCSSUnit_Inherit
&&
5538 aValue
.GetUnit() != eCSSUnit_Initial
&&
5539 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5540 (aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER
&&
5541 aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER
)));
5543 case eCSSFontDesc_Stretch
:
5544 // property is VARIANT_HMK|VARIANT_SYSFONT
5545 return (ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
5546 nsCSSProps::kFontStretchKTable
) &&
5547 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
5548 (aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_WIDER
&&
5549 aValue
.GetIntValue() != NS_STYLE_FONT_STRETCH_NARROWER
)));
5551 // These two are unique to @font-face and have their own special grammar.
5552 case eCSSFontDesc_Src
:
5553 return ParseFontSrc(aValue
);
5555 case eCSSFontDesc_UnicodeRange
:
5556 return ParseFontRanges(aValue
);
5558 case eCSSFontDesc_UNKNOWN
:
5559 case eCSSFontDesc_COUNT
:
5560 NS_NOTREACHED("bad nsCSSFontDesc code");
5562 // explicitly do NOT have a default case to let the compiler
5563 // help find missing descriptors
5568 CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
)
5570 nsCSSValue
physical(NS_BOXPROP_SOURCE_PHYSICAL
, eCSSUnit_Enumerated
);
5571 for (const nsCSSProperty
*prop
= aSourceProperties
;
5572 *prop
!= eCSSProperty_UNKNOWN
; ++prop
) {
5573 AppendValue(*prop
, physical
);
5578 CSSParserImpl::ParseAzimuth(nsCSSValue
& aValue
)
5580 if (ParseVariant(aValue
, VARIANT_HK
| VARIANT_ANGLE
,
5581 nsCSSProps::kAzimuthKTable
)) {
5582 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
5583 PRInt32 intValue
= aValue
.GetIntValue();
5584 if ((NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) &&
5585 (intValue
<= NS_STYLE_AZIMUTH_BEHIND
)) { // look for optional modifier
5586 nsCSSValue modifier
;
5587 if (ParseEnum(modifier
, nsCSSProps::kAzimuthKTable
)) {
5588 PRInt32 enumValue
= modifier
.GetIntValue();
5589 if (((intValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5590 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= enumValue
) && (enumValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
)) ||
5591 ((enumValue
== NS_STYLE_AZIMUTH_BEHIND
) &&
5592 (NS_STYLE_AZIMUTH_LEFT_SIDE
<= intValue
) && (intValue
<= NS_STYLE_AZIMUTH_RIGHT_SIDE
))) {
5593 aValue
.SetIntValue(intValue
| enumValue
, eCSSUnit_Enumerated
);
5596 // Put the unknown identifier back and return
5608 BoxPositionMaskToCSSValue(PRInt32 aMask
, PRBool isX
)
5610 PRInt32 val
= NS_STYLE_BG_POSITION_CENTER
;
5612 if (aMask
& BG_LEFT
) {
5613 val
= NS_STYLE_BG_POSITION_LEFT
;
5615 else if (aMask
& BG_RIGHT
) {
5616 val
= NS_STYLE_BG_POSITION_RIGHT
;
5620 if (aMask
& BG_TOP
) {
5621 val
= NS_STYLE_BG_POSITION_TOP
;
5623 else if (aMask
& BG_BOTTOM
) {
5624 val
= NS_STYLE_BG_POSITION_BOTTOM
;
5628 return nsCSSValue(val
, eCSSUnit_Enumerated
);
5632 CSSParserImpl::ParseBackground()
5634 nsAutoParseCompoundProperty
compound(this);
5636 // Fill in the values that the shorthand will set if we don't find
5638 mTempData
.mColor
.mBackColor
.SetColorValue(NS_RGBA(0, 0, 0, 0));
5639 mTempData
.SetPropertyBit(eCSSProperty_background_color
);
5640 mTempData
.mColor
.mBackImage
.SetNoneValue();
5641 mTempData
.SetPropertyBit(eCSSProperty_background_image
);
5642 mTempData
.mColor
.mBackRepeat
.SetIntValue(NS_STYLE_BG_REPEAT_XY
,
5643 eCSSUnit_Enumerated
);
5644 mTempData
.SetPropertyBit(eCSSProperty_background_repeat
);
5645 mTempData
.mColor
.mBackAttachment
.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL
,
5646 eCSSUnit_Enumerated
);
5647 mTempData
.SetPropertyBit(eCSSProperty_background_attachment
);
5648 mTempData
.mColor
.mBackPosition
.mXValue
.SetPercentValue(0.0f
);
5649 mTempData
.mColor
.mBackPosition
.mYValue
.SetPercentValue(0.0f
);
5650 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
5651 // including the ones that we can't set from the shorthand.
5652 mTempData
.mColor
.mBackClip
.SetInitialValue();
5653 mTempData
.SetPropertyBit(eCSSProperty__moz_background_clip
);
5654 mTempData
.mColor
.mBackOrigin
.SetInitialValue();
5655 mTempData
.SetPropertyBit(eCSSProperty__moz_background_origin
);
5656 mTempData
.mColor
.mBackInlinePolicy
.SetInitialValue();
5657 mTempData
.SetPropertyBit(eCSSProperty__moz_background_inline_policy
);
5659 // XXX If ParseSingleValueProperty were table-driven (bug 376079) and
5660 // automatically filled in the right field of mTempData, we could move
5661 // ParseBackgroundPosition to it (as a special case) and switch back
5662 // to using ParseChoice here.
5664 PRBool haveColor
= PR_FALSE
,
5665 haveImage
= PR_FALSE
,
5666 haveRepeat
= PR_FALSE
,
5667 haveAttach
= PR_FALSE
,
5668 havePosition
= PR_FALSE
;
5669 while (GetToken(PR_TRUE
)) {
5670 nsCSSTokenType tt
= mToken
.mType
;
5671 UngetToken(); // ...but we'll still cheat and use mToken
5672 if (tt
== eCSSToken_Symbol
) {
5673 // ExpectEndProperty only looks for symbols, and nothing else will
5678 if (tt
== eCSSToken_Ident
) {
5679 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
5681 if (keyword
== eCSSKeyword_inherit
||
5682 keyword
== eCSSKeyword__moz_initial
) {
5683 if (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
)
5685 haveColor
= haveImage
= haveRepeat
= haveAttach
= havePosition
=
5687 GetToken(PR_TRUE
); // undo the UngetToken above
5689 if (keyword
== eCSSKeyword_inherit
) {
5690 val
.SetInheritValue();
5692 val
.SetInitialValue();
5694 mTempData
.mColor
.mBackColor
= val
;
5695 mTempData
.mColor
.mBackImage
= val
;
5696 mTempData
.mColor
.mBackRepeat
= val
;
5697 mTempData
.mColor
.mBackAttachment
= val
;
5698 mTempData
.mColor
.mBackPosition
.mXValue
= val
;
5699 mTempData
.mColor
.mBackPosition
.mYValue
= val
;
5700 // Reset (for 'inherit') the 3 properties that can't be
5701 // specified, although it's not entirely clear in the spec:
5702 // http://lists.w3.org/Archives/Public/www-style/2007Mar/0110
5703 mTempData
.mColor
.mBackClip
= val
;
5704 mTempData
.mColor
.mBackOrigin
= val
;
5705 mTempData
.mColor
.mBackInlinePolicy
= val
;
5707 } else if (keyword
== eCSSKeyword_none
) {
5710 haveImage
= PR_TRUE
;
5711 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5712 eCSSProperty_background_image
)) {
5713 NS_NOTREACHED("should be able to parse");
5716 } else if (nsCSSProps::FindKeyword(keyword
,
5717 nsCSSProps::kBackgroundAttachmentKTable
, dummy
)) {
5720 haveAttach
= PR_TRUE
;
5721 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackAttachment
,
5722 eCSSProperty_background_attachment
)) {
5723 NS_NOTREACHED("should be able to parse");
5726 } else if (nsCSSProps::FindKeyword(keyword
,
5727 nsCSSProps::kBackgroundRepeatKTable
, dummy
)) {
5730 haveRepeat
= PR_TRUE
;
5731 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackRepeat
,
5732 eCSSProperty_background_repeat
)) {
5733 NS_NOTREACHED("should be able to parse");
5736 } else if (nsCSSProps::FindKeyword(keyword
,
5737 nsCSSProps::kBackgroundPositionKTable
, dummy
)) {
5740 havePosition
= PR_TRUE
;
5741 if (!ParseBackgroundPositionValues()) {
5747 haveColor
= PR_TRUE
;
5748 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5749 eCSSProperty_background_color
)) {
5753 } else if (eCSSToken_Function
== tt
&&
5754 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
5757 haveImage
= PR_TRUE
;
5758 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackImage
,
5759 eCSSProperty_background_image
)) {
5762 } else if (mToken
.IsDimension() || tt
== eCSSToken_Percentage
) {
5765 havePosition
= PR_TRUE
;
5766 if (!ParseBackgroundPositionValues()) {
5772 haveColor
= PR_TRUE
;
5773 if (!ParseSingleValueProperty(mTempData
.mColor
.mBackColor
,
5774 eCSSProperty_background_color
)) {
5780 return ExpectEndProperty() &&
5781 (haveColor
|| haveImage
|| haveRepeat
|| haveAttach
|| havePosition
);
5785 CSSParserImpl::ParseBackgroundPosition()
5787 if (!ParseBoxPosition(mTempData
.mColor
.mBackPosition
))
5789 mTempData
.SetPropertyBit(eCSSProperty_background_position
);
5794 CSSParserImpl::ParseBackgroundPositionValues()
5796 return ParseBoxPositionValues(mTempData
.mColor
.mBackPosition
);
5800 * Parses two values that correspond to positions in a box. These can be
5801 * values corresponding to percentages of the box, raw offsets, or keywords
5802 * like "top," "left center," etc.
5804 * @param aOut The nsCSSValuePair where to place the result.
5805 * @return Whether or not the operation succeeded.
5807 PRBool
CSSParserImpl::ParseBoxPosition(nsCSSValuePair
&aOut
)
5809 // Need to read the box positions and the end of the property.
5810 return ParseBoxPositionValues(aOut
) && ExpectEndProperty();
5813 PRBool
CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair
&aOut
)
5815 // First try a percentage or a length value
5816 nsCSSValue
&xValue
= aOut
.mXValue
,
5817 &yValue
= aOut
.mYValue
;
5818 if (ParseVariant(xValue
, VARIANT_HLP
, nsnull
)) {
5819 if (eCSSUnit_Inherit
== xValue
.GetUnit() ||
5820 eCSSUnit_Initial
== xValue
.GetUnit()) { // both are inherited or both are set to initial
5824 // We have one percentage/length. Get the optional second
5825 // percentage/length/keyword.
5826 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
5827 // We have two numbers
5831 if (ParseEnum(yValue
, nsCSSProps::kBackgroundPositionKTable
)) {
5832 PRInt32 yVal
= yValue
.GetIntValue();
5833 if (!(yVal
& BG_CTB
)) {
5834 // The second keyword can only be 'center', 'top', or 'bottom'
5837 yValue
= BoxPositionMaskToCSSValue(yVal
, PR_FALSE
);
5841 // If only one percentage or length value is given, it sets the
5842 // horizontal position only, and the vertical position will be 50%.
5843 yValue
.SetPercentValue(0.5f
);
5847 // Now try keywords. We do this manually to allow for the first
5848 // appearance of "center" to apply to the either the x or y
5849 // position (it's ambiguous so we have to disambiguate). Each
5850 // allowed keyword value is assigned it's own bit. We don't allow
5851 // any duplicate keywords other than center. We try to get two
5852 // keywords but it's okay if there is only one.
5854 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
5855 PRInt32 bit
= xValue
.GetIntValue();
5857 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
5858 bit
= xValue
.GetIntValue();
5859 if (mask
& (bit
& ~BG_CENTER
)) {
5860 // Only the 'center' keyword can be duplicated.
5866 // Only one keyword. See if we have a length or percentage.
5867 if (ParseVariant(yValue
, VARIANT_LP
, nsnull
)) {
5868 if (!(mask
& BG_CLR
)) {
5869 // The first keyword can only be 'center', 'left', or 'right'
5873 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
5879 // Check for bad input. Bad input consists of no matching keywords,
5880 // or pairs of x keywords or pairs of y keywords.
5881 if ((mask
== 0) || (mask
== (BG_TOP
| BG_BOTTOM
)) ||
5882 (mask
== (BG_LEFT
| BG_RIGHT
))) {
5886 // Create style values
5887 xValue
= BoxPositionMaskToCSSValue(mask
, PR_TRUE
);
5888 yValue
= BoxPositionMaskToCSSValue(mask
, PR_FALSE
);
5892 // These must be in CSS order (top,right,bottom,left) for indexing to work
5893 static const nsCSSProperty kBorderStyleIDs
[] = {
5894 eCSSProperty_border_top_style
,
5895 eCSSProperty_border_right_style_value
,
5896 eCSSProperty_border_bottom_style
,
5897 eCSSProperty_border_left_style_value
5899 static const nsCSSProperty kBorderWidthIDs
[] = {
5900 eCSSProperty_border_top_width
,
5901 eCSSProperty_border_right_width_value
,
5902 eCSSProperty_border_bottom_width
,
5903 eCSSProperty_border_left_width_value
5905 static const nsCSSProperty kBorderColorIDs
[] = {
5906 eCSSProperty_border_top_color
,
5907 eCSSProperty_border_right_color_value
,
5908 eCSSProperty_border_bottom_color
,
5909 eCSSProperty_border_left_color_value
5911 static const nsCSSProperty kBorderRadiusIDs
[] = {
5912 eCSSProperty__moz_border_radius_topLeft
,
5913 eCSSProperty__moz_border_radius_topRight
,
5914 eCSSProperty__moz_border_radius_bottomRight
,
5915 eCSSProperty__moz_border_radius_bottomLeft
5917 static const nsCSSProperty kOutlineRadiusIDs
[] = {
5918 eCSSProperty__moz_outline_radius_topLeft
,
5919 eCSSProperty__moz_outline_radius_topRight
,
5920 eCSSProperty__moz_outline_radius_bottomRight
,
5921 eCSSProperty__moz_outline_radius_bottomLeft
5925 CSSParserImpl::ParseBorderColor()
5927 static const nsCSSProperty kBorderColorSources
[] = {
5928 eCSSProperty_border_left_color_ltr_source
,
5929 eCSSProperty_border_left_color_rtl_source
,
5930 eCSSProperty_border_right_color_ltr_source
,
5931 eCSSProperty_border_right_color_rtl_source
,
5932 eCSSProperty_UNKNOWN
5935 // do this now, in case 4 values weren't specified
5936 InitBoxPropsAsPhysical(kBorderColorSources
);
5937 return ParseBoxProperties(mTempData
.mMargin
.mBorderColor
,
5942 CSSParserImpl::ParseBorderImage()
5944 if (ParseVariant(mTempData
.mMargin
.mBorderImage
,
5945 VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
5946 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
5950 // <uri> [<number> | <percentage>]{1,4} [ / <border-width>{1,4} ]? [stretch | repeat | round]{0,2}
5951 nsRefPtr
<nsCSSValue::Array
> arr
= nsCSSValue::Array::Create(11);
5953 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
5957 nsCSSValue
& url
= arr
->Item(0);
5958 nsCSSValue
& splitTop
= arr
->Item(1);
5959 nsCSSValue
& splitRight
= arr
->Item(2);
5960 nsCSSValue
& splitBottom
= arr
->Item(3);
5961 nsCSSValue
& splitLeft
= arr
->Item(4);
5962 nsCSSValue
& borderWidthTop
= arr
->Item(5);
5963 nsCSSValue
& borderWidthRight
= arr
->Item(6);
5964 nsCSSValue
& borderWidthBottom
= arr
->Item(7);
5965 nsCSSValue
& borderWidthLeft
= arr
->Item(8);
5966 nsCSSValue
& horizontalKeyword
= arr
->Item(9);
5967 nsCSSValue
& verticalKeyword
= arr
->Item(10);
5970 if (!ParseVariant(url
, VARIANT_URL
, nsnull
)) {
5974 // [<number> | <percentage>]{1,4}
5975 if (!ParsePositiveVariant(splitTop
,
5976 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
5979 if (!ParsePositiveVariant(splitRight
,
5980 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
5981 splitRight
= splitTop
;
5983 if (!ParsePositiveVariant(splitBottom
,
5984 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
5985 splitBottom
= splitTop
;
5987 if (!ParsePositiveVariant(splitLeft
,
5988 VARIANT_NUMBER
| VARIANT_PERCENT
, nsnull
)) {
5989 splitLeft
= splitRight
;
5992 // [ / <border-width>{1,4} ]?
5993 if (ExpectSymbol('/', PR_TRUE
)) {
5994 // if have '/', at least one value is required
5995 if (!ParsePositiveVariant(borderWidthTop
, VARIANT_LENGTH
, nsnull
)) {
5998 if (!ParsePositiveVariant(borderWidthRight
, VARIANT_LENGTH
, nsnull
)) {
5999 borderWidthRight
= borderWidthTop
;
6001 if (!ParsePositiveVariant(borderWidthBottom
, VARIANT_LENGTH
, nsnull
)) {
6002 borderWidthBottom
= borderWidthTop
;
6004 if (!ParsePositiveVariant(borderWidthLeft
, VARIANT_LENGTH
, nsnull
)) {
6005 borderWidthLeft
= borderWidthRight
;
6009 // [stretch | repeat | round]{0,2}
6010 // missing keywords are handled in nsRuleNode::ComputeBorderData()
6011 if (ParseEnum(horizontalKeyword
, nsCSSProps::kBorderImageKTable
)) {
6012 ParseEnum(verticalKeyword
, nsCSSProps::kBorderImageKTable
);
6015 if (!ExpectEndProperty()) {
6019 mTempData
.mMargin
.mBorderImage
.SetArrayValue(arr
, eCSSUnit_Array
);
6020 mTempData
.SetPropertyBit(eCSSProperty_border_image
);
6026 CSSParserImpl::ParseBorderSpacing()
6029 if (ParsePositiveVariant(xValue
, VARIANT_HL
, nsnull
)) {
6030 if (xValue
.IsLengthUnit()) {
6031 // We have one length. Get the optional second length.
6033 if (ParsePositiveVariant(yValue
, VARIANT_LENGTH
, nsnull
)) {
6034 // We have two numbers
6035 if (ExpectEndProperty()) {
6036 mTempData
.mTable
.mBorderSpacing
.mXValue
= xValue
;
6037 mTempData
.mTable
.mBorderSpacing
.mYValue
= yValue
;
6038 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6045 // We have one length which is the horizontal spacing. Create a value for
6046 // the vertical spacing which is equal
6047 if (ExpectEndProperty()) {
6048 mTempData
.mTable
.mBorderSpacing
.SetBothValuesTo(xValue
);
6049 mTempData
.SetPropertyBit(eCSSProperty_border_spacing
);
6057 CSSParserImpl::ParseBorderSide(const nsCSSProperty aPropIDs
[],
6058 PRBool aSetAllSides
)
6060 const PRInt32 numProps
= 3;
6061 nsCSSValue values
[numProps
];
6063 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6064 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6068 if ((found
& 1) == 0) { // Provide default border-width
6069 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6071 if ((found
& 2) == 0) { // Provide default border-style
6072 values
[1].SetNoneValue();
6074 if ((found
& 4) == 0) { // text color will be used
6075 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6079 static const nsCSSProperty kBorderSources
[] = {
6080 eCSSProperty_border_left_color_ltr_source
,
6081 eCSSProperty_border_left_color_rtl_source
,
6082 eCSSProperty_border_right_color_ltr_source
,
6083 eCSSProperty_border_right_color_rtl_source
,
6084 eCSSProperty_border_left_style_ltr_source
,
6085 eCSSProperty_border_left_style_rtl_source
,
6086 eCSSProperty_border_right_style_ltr_source
,
6087 eCSSProperty_border_right_style_rtl_source
,
6088 eCSSProperty_border_left_width_ltr_source
,
6089 eCSSProperty_border_left_width_rtl_source
,
6090 eCSSProperty_border_right_width_ltr_source
,
6091 eCSSProperty_border_right_width_rtl_source
,
6092 eCSSProperty_UNKNOWN
6095 InitBoxPropsAsPhysical(kBorderSources
);
6097 // Parsing "border" shorthand; set all four sides to the same thing
6098 for (PRInt32 index
= 0; index
< 4; index
++) {
6099 NS_ASSERTION(numProps
== 3, "This code needs updating");
6100 AppendValue(kBorderWidthIDs
[index
], values
[0]);
6101 AppendValue(kBorderStyleIDs
[index
], values
[1]);
6102 AppendValue(kBorderColorIDs
[index
], values
[2]);
6106 // Just set our one side
6107 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6108 AppendValue(aPropIDs
[index
], values
[index
]);
6115 CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
6116 PRInt32 aSourceType
)
6118 const PRInt32 numProps
= 3;
6119 nsCSSValue values
[numProps
];
6121 PRInt32 found
= ParseChoice(values
, aPropIDs
, numProps
);
6122 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
6126 if ((found
& 1) == 0) { // Provide default border-width
6127 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
6129 if ((found
& 2) == 0) { // Provide default border-style
6130 values
[1].SetNoneValue();
6132 if ((found
& 4) == 0) { // text color will be used
6133 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
6135 for (PRInt32 index
= 0; index
< numProps
; index
++) {
6136 const nsCSSProperty
* subprops
=
6137 nsCSSProps::SubpropertyEntryFor(aPropIDs
[index
+ numProps
]);
6138 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
6139 "not box property with physical vs. logical cascading");
6140 AppendValue(subprops
[0], values
[index
]);
6141 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
6142 AppendValue(subprops
[1], typeVal
);
6143 AppendValue(subprops
[2], typeVal
);
6149 CSSParserImpl::ParseBorderStyle()
6151 static const nsCSSProperty kBorderStyleSources
[] = {
6152 eCSSProperty_border_left_style_ltr_source
,
6153 eCSSProperty_border_left_style_rtl_source
,
6154 eCSSProperty_border_right_style_ltr_source
,
6155 eCSSProperty_border_right_style_rtl_source
,
6156 eCSSProperty_UNKNOWN
6159 // do this now, in case 4 values weren't specified
6160 InitBoxPropsAsPhysical(kBorderStyleSources
);
6161 return ParseBoxProperties(mTempData
.mMargin
.mBorderStyle
,
6166 CSSParserImpl::ParseBorderWidth()
6168 static const nsCSSProperty kBorderWidthSources
[] = {
6169 eCSSProperty_border_left_width_ltr_source
,
6170 eCSSProperty_border_left_width_rtl_source
,
6171 eCSSProperty_border_right_width_ltr_source
,
6172 eCSSProperty_border_right_width_rtl_source
,
6173 eCSSProperty_UNKNOWN
6176 // do this now, in case 4 values weren't specified
6177 InitBoxPropsAsPhysical(kBorderWidthSources
);
6178 return ParseBoxProperties(mTempData
.mMargin
.mBorderWidth
,
6183 CSSParserImpl::ParseBorderRadius()
6185 return ParseBoxProperties(mTempData
.mMargin
.mBorderRadius
,
6190 CSSParserImpl::ParseOutlineRadius()
6192 return ParseBoxProperties(mTempData
.mMargin
.mOutlineRadius
,
6197 CSSParserImpl::ParseBorderColors(nsCSSValueList
** aResult
,
6198 nsCSSProperty aProperty
)
6201 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6202 nsCSSValueList
* listHead
= new nsCSSValueList();
6203 nsCSSValueList
* list
= listHead
;
6205 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6208 list
->mValue
= value
;
6211 if (ExpectEndProperty()) {
6212 mTempData
.SetPropertyBit(aProperty
);
6213 *aResult
= listHead
;
6216 // FIXME Bug 389404: We should not accept inherit, -moz-initial,
6217 // or none as anything other than the first value.
6218 if (ParseVariant(value
, VARIANT_HCK
|VARIANT_NONE
, nsCSSProps::kBorderColorKTable
)) {
6219 list
->mNext
= new nsCSSValueList();
6222 list
->mValue
= value
;
6224 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6235 CSSParserImpl::ParseRect(nsCSSRect
& aRect
, nsCSSProperty aPropID
)
6239 if ((result
= DoParseRect(rect
)) &&
6242 mTempData
.SetPropertyBit(aPropID
);
6248 CSSParserImpl::DoParseRect(nsCSSRect
& aRect
)
6250 if (! GetToken(PR_TRUE
)) {
6253 if (eCSSToken_Ident
== mToken
.mType
) {
6254 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
6256 case eCSSKeyword_auto
:
6257 if (ExpectEndProperty()) {
6258 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Auto
));
6262 case eCSSKeyword_inherit
:
6263 if (ExpectEndProperty()) {
6264 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Inherit
));
6268 case eCSSKeyword__moz_initial
:
6269 if (ExpectEndProperty()) {
6270 aRect
.SetAllSidesTo(nsCSSValue(eCSSUnit_Initial
));
6278 } else if ((eCSSToken_Function
== mToken
.mType
) &&
6279 mToken
.mIdent
.LowerCaseEqualsLiteral("rect")) {
6280 if (!ExpectSymbol('(', PR_TRUE
)) {
6283 NS_FOR_CSS_SIDES(side
) {
6284 if (! ParseVariant(aRect
.*(nsCSSRect::sides
[side
]),
6285 VARIANT_AL
, nsnull
)) {
6289 // skip optional commas between elements
6290 ExpectSymbol(',', PR_TRUE
);
6293 if (!ExpectSymbol(')', PR_TRUE
)) {
6296 if (ExpectEndProperty()) {
6305 #define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
6308 CSSParserImpl::ParseContent()
6310 // XXX Rewrite to make it look more like ParseCursor or ParseCounterData?
6312 if (ParseVariant(value
,
6313 VARIANT_CONTENT
| VARIANT_INHERIT
| VARIANT_NORMAL
|
6315 nsCSSProps::kContentKTable
)) {
6316 nsCSSValueList
* listHead
= new nsCSSValueList();
6317 nsCSSValueList
* list
= listHead
;
6318 if (nsnull
== list
) {
6319 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6322 list
->mValue
= value
;
6324 while (nsnull
!= list
) {
6325 if (ExpectEndProperty()) {
6326 mTempData
.SetPropertyBit(eCSSProperty_content
);
6327 mTempData
.mContent
.mContent
= listHead
;
6330 if (eCSSUnit_Inherit
== value
.GetUnit() ||
6331 eCSSUnit_Initial
== value
.GetUnit() ||
6332 eCSSUnit_Normal
== value
.GetUnit() ||
6333 eCSSUnit_None
== value
.GetUnit() ||
6334 (eCSSUnit_Enumerated
== value
.GetUnit() &&
6335 NS_STYLE_CONTENT_ALT_CONTENT
== value
.GetIntValue())) {
6336 // This only matters the first time through the loop.
6340 if (ParseVariant(value
, VARIANT_CONTENT
, nsCSSProps::kContentKTable
) &&
6341 // Make sure we didn't end up with NS_STYLE_CONTENT_ALT_CONTENT here
6342 (value
.GetUnit() != eCSSUnit_Enumerated
||
6343 value
.GetIntValue() != NS_STYLE_CONTENT_ALT_CONTENT
)) {
6344 list
->mNext
= new nsCSSValueList();
6346 if (nsnull
!= list
) {
6347 list
->mValue
= value
;
6350 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6362 struct SingleCounterPropValue
{
6368 CSSParserImpl::ParseCounterData(nsCSSValuePairList
** aResult
,
6369 nsCSSProperty aPropID
)
6371 nsSubstring
* ident
= NextIdent();
6372 if (nsnull
== ident
) {
6375 static const SingleCounterPropValue singleValues
[] = {
6376 { "none", eCSSUnit_None
},
6377 { "inherit", eCSSUnit_Inherit
},
6378 { "-moz-initial", eCSSUnit_Initial
}
6380 for (const SingleCounterPropValue
*sv
= singleValues
,
6381 *sv_end
= singleValues
+ NS_ARRAY_LENGTH(singleValues
);
6382 sv
!= sv_end
; ++sv
) {
6383 if (ident
->LowerCaseEqualsASCII(sv
->str
)) {
6384 if (CheckEndProperty()) {
6385 nsCSSValuePairList
* dataHead
= new nsCSSValuePairList();
6387 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6390 dataHead
->mXValue
= nsCSSValue(sv
->unit
);
6391 *aResult
= dataHead
;
6392 mTempData
.SetPropertyBit(aPropID
);
6398 UngetToken(); // undo NextIdent
6400 nsCSSValuePairList
* dataHead
= nsnull
;
6401 nsCSSValuePairList
**next
= &dataHead
;
6403 if (!GetToken(PR_TRUE
) || mToken
.mType
!= eCSSToken_Ident
) {
6406 nsCSSValuePairList
*data
= *next
= new nsCSSValuePairList();
6408 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6411 next
= &data
->mNext
;
6412 data
->mXValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
6413 if (GetToken(PR_TRUE
)) {
6414 if (eCSSToken_Number
== mToken
.mType
&& mToken
.mIntegerValid
) {
6415 data
->mYValue
.SetIntValue(mToken
.mInteger
, eCSSUnit_Integer
);
6420 if (ExpectEndProperty()) {
6421 mTempData
.SetPropertyBit(aPropID
);
6422 *aResult
= dataHead
;
6431 CSSParserImpl::ParseCue()
6434 if (ParseSingleValueProperty(before
, eCSSProperty_cue_before
)) {
6435 if (eCSSUnit_Inherit
!= before
.GetUnit() &&
6436 eCSSUnit_Initial
!= before
.GetUnit()) {
6438 if (ParseSingleValueProperty(after
, eCSSProperty_cue_after
)) {
6439 if (ExpectEndProperty()) {
6440 AppendValue(eCSSProperty_cue_before
, before
);
6441 AppendValue(eCSSProperty_cue_after
, after
);
6447 if (ExpectEndProperty()) {
6448 AppendValue(eCSSProperty_cue_before
, before
);
6449 AppendValue(eCSSProperty_cue_after
, before
);
6457 CSSParserImpl::ParseCursor()
6459 nsCSSValueList
*list
= nsnull
;
6460 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
6461 cur
= *curp
= new nsCSSValueList();
6463 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6466 if (!ParseVariant(cur
->mValue
,
6467 (cur
== list
) ? VARIANT_AHUK
: VARIANT_AUK
,
6468 nsCSSProps::kCursorKTable
)) {
6471 if (cur
->mValue
.GetUnit() != eCSSUnit_URL
) {
6472 if (!ExpectEndProperty()) {
6475 // Only success case here, since having the failure case at the
6476 // end allows more sharing of code.
6477 mTempData
.SetPropertyBit(eCSSProperty_cursor
);
6478 mTempData
.mUserInterface
.mCursor
= list
;
6481 // We have a URL, so make a value array with three values.
6482 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(3);
6484 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6487 val
->Item(0) = cur
->mValue
;
6488 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
6490 // Parse optional x and y position of cursor hotspot (css3-ui).
6491 if (ParseVariant(val
->Item(1), VARIANT_NUMBER
, nsnull
)) {
6492 // If we have one number, we must have two.
6493 if (!ParseVariant(val
->Item(2), VARIANT_NUMBER
, nsnull
)) {
6498 if (!ExpectSymbol(',', PR_TRUE
)) {
6502 // Have failure case at the end so we can |break| to get to it.
6509 CSSParserImpl::ParseFont()
6511 static const nsCSSProperty fontIDs
[] = {
6512 eCSSProperty_font_style
,
6513 eCSSProperty_font_variant
,
6514 eCSSProperty_font_weight
6518 if (ParseVariant(family
, VARIANT_HK
, nsCSSProps::kFontKTable
)) {
6519 if (ExpectEndProperty()) {
6520 if (eCSSUnit_Inherit
== family
.GetUnit() ||
6521 eCSSUnit_Initial
== family
.GetUnit()) {
6522 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6523 AppendValue(eCSSProperty_font_family
, family
);
6524 AppendValue(eCSSProperty_font_style
, family
);
6525 AppendValue(eCSSProperty_font_variant
, family
);
6526 AppendValue(eCSSProperty_font_weight
, family
);
6527 AppendValue(eCSSProperty_font_size
, family
);
6528 AppendValue(eCSSProperty_line_height
, family
);
6529 AppendValue(eCSSProperty_font_stretch
, family
);
6530 AppendValue(eCSSProperty_font_size_adjust
, family
);
6533 AppendValue(eCSSProperty__x_system_font
, family
);
6534 nsCSSValue
systemFont(eCSSUnit_System_Font
);
6535 AppendValue(eCSSProperty_font_family
, systemFont
);
6536 AppendValue(eCSSProperty_font_style
, systemFont
);
6537 AppendValue(eCSSProperty_font_variant
, systemFont
);
6538 AppendValue(eCSSProperty_font_weight
, systemFont
);
6539 AppendValue(eCSSProperty_font_size
, systemFont
);
6540 AppendValue(eCSSProperty_line_height
, systemFont
);
6541 AppendValue(eCSSProperty_font_stretch
, systemFont
);
6542 AppendValue(eCSSProperty_font_size_adjust
, systemFont
);
6549 // Get optional font-style, font-variant and font-weight (in any order)
6550 const PRInt32 numProps
= 3;
6551 nsCSSValue values
[numProps
];
6552 PRInt32 found
= ParseChoice(values
, fontIDs
, numProps
);
6553 if ((found
< 0) || (eCSSUnit_Inherit
== values
[0].GetUnit()) ||
6554 (eCSSUnit_Initial
== values
[0].GetUnit())) { // illegal data
6557 if ((found
& 1) == 0) {
6558 // Provide default font-style
6559 values
[0].SetNormalValue();
6561 if ((found
& 2) == 0) {
6562 // Provide default font-variant
6563 values
[1].SetNormalValue();
6565 if ((found
& 4) == 0) {
6566 // Provide default font-weight
6567 values
[2].SetNormalValue();
6570 // Get mandatory font-size
6572 if (! ParseVariant(size
, VARIANT_KEYWORD
| VARIANT_LP
, nsCSSProps::kFontSizeKTable
)) {
6576 // Get optional "/" line-height
6577 nsCSSValue lineHeight
;
6578 if (ExpectSymbol('/', PR_TRUE
)) {
6579 if (! ParsePositiveVariant(lineHeight
,
6580 VARIANT_NUMBER
| VARIANT_LP
| VARIANT_NORMAL
,
6586 lineHeight
.SetNormalValue();
6589 // Get final mandatory font-family
6590 nsAutoParseCompoundProperty
compound(this);
6591 if (ParseFamily(family
)) {
6592 if ((eCSSUnit_Inherit
!= family
.GetUnit()) && (eCSSUnit_Initial
!= family
.GetUnit()) &&
6593 ExpectEndProperty()) {
6594 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
6595 AppendValue(eCSSProperty_font_family
, family
);
6596 AppendValue(eCSSProperty_font_style
, values
[0]);
6597 AppendValue(eCSSProperty_font_variant
, values
[1]);
6598 AppendValue(eCSSProperty_font_weight
, values
[2]);
6599 AppendValue(eCSSProperty_font_size
, size
);
6600 AppendValue(eCSSProperty_line_height
, lineHeight
);
6601 AppendValue(eCSSProperty_font_stretch
, nsCSSValue(eCSSUnit_Normal
));
6602 AppendValue(eCSSProperty_font_size_adjust
, nsCSSValue(eCSSUnit_None
));
6610 CSSParserImpl::ParseFontWeight(nsCSSValue
& aValue
)
6612 if (ParseVariant(aValue
, VARIANT_HMKI
| VARIANT_SYSFONT
, nsCSSProps::kFontWeightKTable
)) {
6613 if (eCSSUnit_Integer
== aValue
.GetUnit()) { // ensure unit value
6614 PRInt32 intValue
= aValue
.GetIntValue();
6615 if ((100 <= intValue
) &&
6616 (intValue
<= 900) &&
6617 (0 == (intValue
% 100))) {
6630 CSSParserImpl::ParseOneFamily(nsAString
& aFamily
)
6632 if (!GetToken(PR_TRUE
))
6635 nsCSSToken
* tk
= &mToken
;
6637 if (eCSSToken_Ident
== tk
->mType
) {
6638 aFamily
.Append(tk
->mIdent
);
6640 if (!GetToken(PR_FALSE
))
6643 if (eCSSToken_Ident
== tk
->mType
) {
6644 aFamily
.Append(tk
->mIdent
);
6645 } else if (eCSSToken_WhiteSpace
== tk
->mType
) {
6646 // Lookahead one token and drop whitespace if we are ending the
6648 if (!GetToken(PR_TRUE
))
6652 if (eCSSToken_Ident
== tk
->mType
)
6653 aFamily
.Append(PRUnichar(' '));
6663 } else if (eCSSToken_String
== tk
->mType
) {
6664 aFamily
.Append(tk
->mSymbol
); // replace the quotes
6665 aFamily
.Append(tk
->mIdent
); // XXX What if it had escaped quotes?
6666 aFamily
.Append(tk
->mSymbol
);
6675 ///////////////////////////////////////////////////////
6676 // -moz-transform Parsing Implementation
6678 /* Reads a function list of arguments. Do not call this function
6679 * directly; it's mean to be caled from ParseFunction.
6682 CSSParserImpl::ParseFunctionInternals(const PRInt32 aVariantMask
[],
6685 nsTArray
<nsCSSValue
> &aOutput
)
6687 for (PRUint16 index
= 0; index
< aMaxElems
; ++index
) {
6688 nsCSSValue newValue
;
6689 if (!ParseVariant(newValue
, aVariantMask
[index
], nsnull
))
6692 if (!aOutput
.AppendElement(newValue
)) {
6693 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6697 // See whether to continue or whether to look for end of function.
6698 if (!ExpectSymbol(',', PR_TRUE
)) {
6699 // We need to read the closing parenthesis, and also must take care
6700 // that we haven't read too few symbols.
6701 return ExpectSymbol(')', PR_TRUE
) && (index
+ 1) >= aMinElems
;
6705 // If we're here, we finished looping without hitting the end, so we read too
6710 /* Parses a function [ input of the form (a [, b]*) ] and stores it
6711 * as an nsCSSValue that holds a function of the form
6712 * function-name arg1 arg2 ... argN
6714 * On error, the return value is PR_FALSE.
6716 * @param aFunction The name of the function that we're reading.
6717 * @param aAllowedTypes An array of values corresponding to the legal
6718 * types for each element in the function. The zeroth element in the
6719 * array corresponds to the first function parameter, etc. The length
6720 * of this array _must_ be greater than or equal to aMaxElems or the
6721 * behavior is undefined.
6722 * @param aMinElems Minimum number of elements to read. Reading fewer than
6723 * this many elements will result in the function failing.
6724 * @param aMaxElems Maximum number of elements to read. Reading more than
6725 * this many elements will result in the function failing.
6726 * @param aValue (out) The value that was parsed.
6729 CSSParserImpl::ParseFunction(const nsString
&aFunction
,
6730 const PRInt32 aAllowedTypes
[],
6731 PRUint16 aMinElems
, PRUint16 aMaxElems
,
6734 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
6736 /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
6737 * elements stored in the the nsCSSValue::Array.
6739 static const arrlen_t MAX_ALLOWED_ELEMS
= 0xFFFE;
6741 /* Make a copy of the function name, since the reference is _probably_ to
6742 * mToken.mIdent, which is going to get overwritten during the course of this
6745 nsString
functionName(aFunction
);
6747 /* First things first... read the parenthesis. If it fails, abort. */
6748 if (!ExpectSymbol('(', PR_TRUE
))
6751 /* Read in a list of values as an nsTArray, failing if we can't or if
6752 * it's out of bounds.
6754 nsTArray
<nsCSSValue
> foundValues
;
6755 if (!ParseFunctionInternals(aAllowedTypes
, aMinElems
, aMaxElems
,
6759 /* Now, convert this nsTArray into an nsCSSValue::Array object.
6760 * We'll need N + 1 spots, one for the function name and the rest for the
6761 * arguments. In case the user has given us more than 2^16 - 2 arguments,
6762 * we'll truncate them at 2^16 - 2 arguments.
6764 PRUint16 numElements
= (foundValues
.Length() <= MAX_ALLOWED_ELEMS
?
6765 foundValues
.Length() + 1 : MAX_ALLOWED_ELEMS
);
6766 nsRefPtr
<nsCSSValue::Array
> convertedArray
=
6767 nsCSSValue::Array::Create(numElements
);
6768 if (!convertedArray
) {
6769 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6773 /* Copy things over. */
6774 convertedArray
->Item(0).SetStringValue(functionName
, eCSSUnit_String
);
6775 for (PRUint16 index
= 0; index
+ 1 < numElements
; ++index
)
6776 convertedArray
->Item(index
+ 1) = foundValues
[static_cast<arrlen_t
>(index
)];
6778 /* Fill in the outparam value with the array. */
6779 aValue
.SetArrayValue(convertedArray
, eCSSUnit_Function
);
6786 * Given a token, determines the minimum and maximum number of function
6787 * parameters to read, along with the mask that should be used to read
6788 * those function parameters. If the token isn't a transform function,
6791 * @param aToken The token identifying the function.
6792 * @param aMinElems [out] The minimum number of elements to read.
6793 * @param aMaxElems [out] The maximum number of elements to read
6794 * @param aVariantMask [out] The variant mask to use during parsing
6795 * @return Whether the information was loaded successfully.
6797 static PRBool
GetFunctionParseInformation(nsCSSKeyword aToken
,
6798 PRUint16
&aMinElems
,
6799 PRUint16
&aMaxElems
,
6800 const PRInt32
*& aVariantMask
)
6802 /* These types represent the common variant masks that will be used to
6803 * parse out the individual functions. The order in the enumeration
6804 * must match the order in which the masks are declared.
6806 enum { eLengthPercent
,
6814 static const PRInt32 kMaxElemsPerFunction
= 6;
6815 static const PRInt32 kVariantMasks
[eNumVariantMasks
][kMaxElemsPerFunction
] = {
6816 {VARIANT_LENGTH
| VARIANT_PERCENT
},
6817 {VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
},
6819 {VARIANT_ANGLE
, VARIANT_ANGLE
},
6821 {VARIANT_NUMBER
, VARIANT_NUMBER
},
6822 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
6823 VARIANT_LENGTH
| VARIANT_PERCENT
, VARIANT_LENGTH
| VARIANT_PERCENT
}};
6826 static const PRUint8 kVariantMaskLengths
[eNumVariantMasks
] =
6827 {1, 2, 1, 2, 1, 2, 6};
6830 PRInt32 variantIndex
= eNumVariantMasks
;
6833 case eCSSKeyword_translatex
:
6834 /* Exactly one length or percent. */
6835 variantIndex
= eLengthPercent
;
6839 case eCSSKeyword_translatey
:
6840 /* Exactly one length or percent. */
6841 variantIndex
= eLengthPercent
;
6845 case eCSSKeyword_scalex
:
6846 /* Exactly one scale factor. */
6847 variantIndex
= eNumber
;
6851 case eCSSKeyword_scaley
:
6852 /* Exactly one scale factor. */
6853 variantIndex
= eNumber
;
6857 case eCSSKeyword_rotate
:
6858 /* Exactly one angle. */
6859 variantIndex
= eAngle
;
6863 case eCSSKeyword_translate
:
6864 /* One or two lengths or percents. */
6865 variantIndex
= eTwoLengthPercents
;
6869 case eCSSKeyword_skew
:
6870 /* Exactly one or two angles. */
6871 variantIndex
= eTwoAngles
;
6875 case eCSSKeyword_scale
:
6876 /* One or two scale factors. */
6877 variantIndex
= eTwoNumbers
;
6881 case eCSSKeyword_skewx
:
6882 /* Exactly one angle. */
6883 variantIndex
= eAngle
;
6887 case eCSSKeyword_skewy
:
6888 /* Exactly one angle. */
6889 variantIndex
= eAngle
;
6893 case eCSSKeyword_matrix
:
6894 /* Six values, which can be numbers, lengths, or percents. */
6895 variantIndex
= eMatrix
;
6900 /* Oh dear, we didn't match. Report an error. */
6904 NS_ASSERTION(aMinElems
> 0, "Didn't update minimum elements!");
6905 NS_ASSERTION(aMaxElems
> 0, "Didn't update maximum elements!");
6906 NS_ASSERTION(aMinElems
<= aMaxElems
, "aMinElems > aMaxElems!");
6907 NS_ASSERTION(variantIndex
>= 0, "Invalid variant mask!");
6908 NS_ASSERTION(variantIndex
< eNumVariantMasks
, "Invalid variant mask!");
6910 NS_ASSERTION(aMaxElems
<= kVariantMaskLengths
[variantIndex
],
6911 "Invalid aMaxElems for this variant mask.");
6914 // Convert the index into a mask.
6915 aVariantMask
= kVariantMasks
[variantIndex
];
6921 /* Reads a single transform function from the tokenizer stream, reporting an
6922 * error if something goes wrong.
6924 PRBool
CSSParserImpl::ReadSingleTransform(nsCSSValueList
**& aTail
)
6926 typedef nsTArray
<nsCSSValue
>::size_type arrlen_t
;
6928 if (!GetToken(PR_TRUE
))
6931 /* Check to make sure that we've read a function. */
6932 if (mToken
.mType
!= eCSSToken_Function
) {
6937 /* Load up the variant mask information for ParseFunction. If we can't,
6940 const PRInt32
* variantMask
;
6941 PRUint16 minElems
, maxElems
;
6942 if (!GetFunctionParseInformation(nsCSSKeywords::LookupKeyword(mToken
.mIdent
),
6943 minElems
, maxElems
, variantMask
))
6946 /* Create a cell to populate, fail if we're out of memory. */
6947 nsAutoPtr
<nsCSSValue
> newCell(new nsCSSValue
);
6949 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6953 /* Try reading things in, failing if we can't */
6954 if (!ParseFunction(mToken
.mIdent
, variantMask
, minElems
, maxElems
, *newCell
))
6957 /* Wrap up our result in an nsCSSValueList cell. */
6958 nsAutoPtr
<nsCSSValueList
> toAppend(new nsCSSValueList
);
6962 toAppend
->mValue
= *newCell
;
6964 /* Chain the element to the end of the transform list, then update the
6967 *aTail
= toAppend
.forget();
6968 aTail
= &(*aTail
)->mNext
;
6970 /* It worked! Return true. */
6974 /* Parses a -moz-transform property list by continuously reading in properties
6975 * and constructing a matrix from it.
6977 PRBool
CSSParserImpl::ParseMozTransform()
6979 mTempData
.mDisplay
.mTransform
= nsnull
;
6981 /* First, check to see if this is some sort of keyword - none, inherit,
6984 nsCSSValue keywordValue
;
6985 if (ParseVariant(keywordValue
, VARIANT_INHERIT
| VARIANT_NONE
, nsnull
)) {
6986 /* Looks like it is. Make a new value list and fill it in, failing if
6989 mTempData
.mDisplay
.mTransform
= new nsCSSValueList
;
6990 if (!mTempData
.mDisplay
.mTransform
) {
6991 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
6995 /* Inform the parser that everything worked. */
6996 mTempData
.mDisplay
.mTransform
->mValue
= keywordValue
;
6997 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7001 /* We will read a nonempty list of transforms. Thus we'll read in a
7002 * transform, then continuously read transforms until we're no longer
7005 nsCSSValueList
*transformList
= nsnull
;
7006 nsCSSValueList
**tail
= &transformList
;
7008 /* Try reading a transform. If we fail to do so, abort. */
7009 if (!ReadSingleTransform(tail
)) {
7010 delete transformList
;
7014 while (!CheckEndProperty());
7016 /* Confirm that this is the end of the property and set error code
7017 * appropriately otherwise.
7019 if (!ExpectEndProperty()) {
7020 delete transformList
;
7024 /* Validate our data. */
7025 NS_ASSERTION(transformList
, "Didn't read any transforms!");
7027 mTempData
.SetPropertyBit(eCSSProperty__moz_transform
);
7028 mTempData
.mDisplay
.mTransform
= transformList
;
7033 PRBool
CSSParserImpl::ParseMozTransformOrigin()
7035 /* Read in a box position, fail if we can't. */
7036 if (!ParseBoxPosition(mTempData
.mDisplay
.mTransformOrigin
))
7039 /* Set the property bit and return. */
7040 mTempData
.SetPropertyBit(eCSSProperty__moz_transform_origin
);
7045 CSSParserImpl::ParseFamily(nsCSSValue
& aValue
)
7047 if (!GetToken(PR_TRUE
))
7050 if (eCSSToken_Ident
== mToken
.mType
) {
7051 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
7052 if (keyword
== eCSSKeyword_inherit
) {
7053 aValue
.SetInheritValue();
7056 if (keyword
== eCSSKeyword__moz_initial
) {
7057 aValue
.SetInitialValue();
7060 if (keyword
== eCSSKeyword__moz_use_system_font
&&
7061 !IsParsingCompoundProperty()) {
7062 aValue
.SetSystemFontValue();
7069 nsAutoString family
;
7071 if (!ParseOneFamily(family
))
7074 if (!ExpectSymbol(',', PR_TRUE
))
7077 family
.Append(PRUnichar(','));
7080 if (family
.IsEmpty()) {
7083 aValue
.SetStringValue(family
, eCSSUnit_String
);
7087 // src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*
7088 // uri-src: uri [ 'format(' string ( ',' string )* ')' ]
7089 // local-src: 'local(' ( string | ident ) ')'
7092 CSSParserImpl::ParseFontSrc(nsCSSValue
& aValue
)
7094 // could we maybe turn nsCSSValue::Array into nsTArray<nsCSSValue>?
7095 nsTArray
<nsCSSValue
> values
;
7098 if (!GetToken(PR_TRUE
))
7101 if (mToken
.mType
== eCSSToken_Function
&&
7102 mToken
.mIdent
.LowerCaseEqualsLiteral("url")) {
7105 values
.AppendElement(cur
);
7106 if (!ParseFontSrcFormat(values
))
7109 } else if (mToken
.mType
== eCSSToken_Function
&&
7110 mToken
.mIdent
.LowerCaseEqualsLiteral("local")) {
7111 // css3-fonts does not specify a formal grammar for local().
7112 // The text permits both unquoted identifiers and quoted
7113 // strings. We resolve this ambiguity in the spec by
7114 // assuming that the appropriate production is a single
7115 // <family-name>, possibly surrounded by whitespace.
7117 nsAutoString family
;
7118 if (!ExpectSymbol('(', PR_FALSE
))
7120 if (!ParseOneFamily(family
))
7122 if (!ExpectSymbol(')', PR_TRUE
))
7125 // the style parameters to the nsFont constructor are ignored,
7126 // because it's only being used to call EnumerateFamilies
7127 nsFont
font(family
, 0, 0, 0, 0, 0);
7128 ExtractFirstFamilyData dat
;
7130 font
.EnumerateFamilies(ExtractFirstFamily
, (void*) &dat
);
7134 cur
.SetStringValue(dat
.mFamilyName
, eCSSUnit_Local_Font
);
7135 values
.AppendElement(cur
);
7140 if (!ExpectSymbol(',', PR_TRUE
))
7144 nsRefPtr
<nsCSSValue::Array
> srcVals
7145 = nsCSSValue::Array::Create(values
.Length());
7150 for (i
= 0; i
< values
.Length(); i
++)
7151 srcVals
->Item(i
) = values
[i
];
7152 aValue
.SetArrayValue(srcVals
, eCSSUnit_Array
);
7157 CSSParserImpl::ParseFontSrcFormat(nsTArray
<nsCSSValue
> & values
)
7159 if (!GetToken(PR_TRUE
))
7160 return PR_TRUE
; // EOF harmless here
7161 if (mToken
.mType
!= eCSSToken_Function
||
7162 !mToken
.mIdent
.LowerCaseEqualsLiteral("format")) {
7166 if (!ExpectSymbol('(', PR_FALSE
))
7170 if (!GetToken(PR_TRUE
))
7173 if (mToken
.mType
!= eCSSToken_String
)
7176 nsCSSValue
cur(mToken
.mIdent
, eCSSUnit_Font_Format
);
7177 values
.AppendElement(cur
);
7178 } while (ExpectSymbol(',', PR_TRUE
));
7180 return ExpectSymbol(')', PR_TRUE
);
7183 // font-ranges: urange ( ',' urange )*
7185 CSSParserImpl::ParseFontRanges(nsCSSValue
& aValue
)
7187 // not currently implemented (bug 443976)
7192 CSSParserImpl::ParseListStyle()
7194 const PRInt32 numProps
= 3;
7195 static const nsCSSProperty listStyleIDs
[] = {
7196 eCSSProperty_list_style_type
,
7197 eCSSProperty_list_style_position
,
7198 eCSSProperty_list_style_image
7201 nsCSSValue values
[numProps
];
7203 PRInt32 found
= ParseChoice(values
, listStyleIDs
, numProps
);
7204 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7208 // Provide default values
7209 if ((found
& 1) == 0) {
7210 values
[0].SetIntValue(NS_STYLE_LIST_STYLE_DISC
, eCSSUnit_Enumerated
);
7212 if ((found
& 2) == 0) {
7213 values
[1].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE
, eCSSUnit_Enumerated
);
7215 if ((found
& 4) == 0) {
7216 values
[2].SetNoneValue();
7219 for (index
= 0; index
< numProps
; index
++) {
7220 AppendValue(listStyleIDs
[index
], values
[index
]);
7226 CSSParserImpl::ParseMargin()
7228 static const nsCSSProperty kMarginSideIDs
[] = {
7229 eCSSProperty_margin_top
,
7230 eCSSProperty_margin_right_value
,
7231 eCSSProperty_margin_bottom
,
7232 eCSSProperty_margin_left_value
7234 static const nsCSSProperty kMarginSources
[] = {
7235 eCSSProperty_margin_left_ltr_source
,
7236 eCSSProperty_margin_left_rtl_source
,
7237 eCSSProperty_margin_right_ltr_source
,
7238 eCSSProperty_margin_right_rtl_source
,
7239 eCSSProperty_UNKNOWN
7242 // do this now, in case 4 values weren't specified
7243 InitBoxPropsAsPhysical(kMarginSources
);
7244 return ParseBoxProperties(mTempData
.mMargin
.mMargin
,
7249 CSSParserImpl::ParseMarks(nsCSSValue
& aValue
)
7251 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kPageMarksKTable
)) {
7252 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
7253 if (PR_FALSE
== CheckEndProperty()) {
7255 if (ParseEnum(second
, nsCSSProps::kPageMarksKTable
)) {
7256 aValue
.SetIntValue(aValue
.GetIntValue() | second
.GetIntValue(), eCSSUnit_Enumerated
);
7268 CSSParserImpl::ParseOutline()
7270 const PRInt32 numProps
= 3;
7271 static const nsCSSProperty kOutlineIDs
[] = {
7272 eCSSProperty_outline_color
,
7273 eCSSProperty_outline_style
,
7274 eCSSProperty_outline_width
7277 nsCSSValue values
[numProps
];
7278 PRInt32 found
= ParseChoice(values
, kOutlineIDs
, numProps
);
7279 if ((found
< 1) || (PR_FALSE
== ExpectEndProperty())) {
7283 // Provide default values
7284 if ((found
& 1) == 0) {
7285 #ifdef GFX_HAS_INVERT
7286 values
[0].SetIntValue(NS_STYLE_COLOR_INVERT
, eCSSUnit_Enumerated
);
7288 values
[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
7291 if ((found
& 2) == 0) {
7292 values
[1].SetNoneValue();
7294 if ((found
& 4) == 0) {
7295 values
[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
7299 for (index
= 0; index
< numProps
; index
++) {
7300 AppendValue(kOutlineIDs
[index
], values
[index
]);
7306 CSSParserImpl::ParseOverflow()
7308 nsCSSValue overflow
;
7309 if (!ParseVariant(overflow
, VARIANT_AHK
,
7310 nsCSSProps::kOverflowKTable
) ||
7311 !ExpectEndProperty())
7314 nsCSSValue
overflowX(overflow
);
7315 nsCSSValue
overflowY(overflow
);
7316 if (eCSSUnit_Enumerated
== overflow
.GetUnit())
7317 switch(overflow
.GetIntValue()) {
7318 case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL
:
7319 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7320 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7322 case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL
:
7323 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
7324 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
7327 AppendValue(eCSSProperty_overflow_x
, overflowX
);
7328 AppendValue(eCSSProperty_overflow_y
, overflowY
);
7333 CSSParserImpl::ParsePadding()
7335 static const nsCSSProperty kPaddingSideIDs
[] = {
7336 eCSSProperty_padding_top
,
7337 eCSSProperty_padding_right_value
,
7338 eCSSProperty_padding_bottom
,
7339 eCSSProperty_padding_left_value
7341 static const nsCSSProperty kPaddingSources
[] = {
7342 eCSSProperty_padding_left_ltr_source
,
7343 eCSSProperty_padding_left_rtl_source
,
7344 eCSSProperty_padding_right_ltr_source
,
7345 eCSSProperty_padding_right_rtl_source
,
7346 eCSSProperty_UNKNOWN
7349 // do this now, in case 4 values weren't specified
7350 InitBoxPropsAsPhysical(kPaddingSources
);
7351 return ParseBoxProperties(mTempData
.mMargin
.mPadding
,
7356 CSSParserImpl::ParsePause()
7359 if (ParseSingleValueProperty(before
, eCSSProperty_pause_before
)) {
7360 if (eCSSUnit_Inherit
!= before
.GetUnit() && eCSSUnit_Initial
!= before
.GetUnit()) {
7362 if (ParseSingleValueProperty(after
, eCSSProperty_pause_after
)) {
7363 if (ExpectEndProperty()) {
7364 AppendValue(eCSSProperty_pause_before
, before
);
7365 AppendValue(eCSSProperty_pause_after
, after
);
7371 if (ExpectEndProperty()) {
7372 AppendValue(eCSSProperty_pause_before
, before
);
7373 AppendValue(eCSSProperty_pause_after
, before
);
7381 CSSParserImpl::ParseQuotes()
7384 if (ParseVariant(open
, VARIANT_HOS
, nsnull
)) {
7385 if (eCSSUnit_String
== open
.GetUnit()) {
7386 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7387 nsCSSValuePairList
* quotes
= quotesHead
;
7388 if (nsnull
== quotes
) {
7389 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7392 quotes
->mXValue
= open
;
7393 while (nsnull
!= quotes
) {
7394 // get mandatory close
7395 if (ParseVariant(quotes
->mYValue
, VARIANT_STRING
,
7397 if (CheckEndProperty()) {
7398 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7399 mTempData
.mContent
.mQuotes
= quotesHead
;
7402 // look for another open
7403 if (ParseVariant(open
, VARIANT_STRING
, nsnull
)) {
7404 quotes
->mNext
= new nsCSSValuePairList();
7405 quotes
= quotes
->mNext
;
7406 if (nsnull
!= quotes
) {
7407 quotes
->mXValue
= open
;
7410 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7418 if (ExpectEndProperty()) {
7419 nsCSSValuePairList
* quotesHead
= new nsCSSValuePairList();
7420 quotesHead
->mXValue
= open
;
7421 mTempData
.mContent
.mQuotes
= quotesHead
;
7422 mTempData
.SetPropertyBit(eCSSProperty_quotes
);
7430 CSSParserImpl::ParseSize()
7433 if (ParseVariant(width
, VARIANT_AHKL
, nsCSSProps::kPageSizeKTable
)) {
7434 if (width
.IsLengthUnit()) {
7436 if (ParseVariant(height
, VARIANT_LENGTH
, nsnull
)) {
7437 if (ExpectEndProperty()) {
7438 mTempData
.mPage
.mSize
.mXValue
= width
;
7439 mTempData
.mPage
.mSize
.mYValue
= height
;
7440 mTempData
.SetPropertyBit(eCSSProperty_size
);
7446 if (ExpectEndProperty()) {
7447 mTempData
.mPage
.mSize
.SetBothValuesTo(width
);
7448 mTempData
.SetPropertyBit(eCSSProperty_size
);
7456 CSSParserImpl::ParseTextDecoration(nsCSSValue
& aValue
)
7458 if (ParseVariant(aValue
, VARIANT_HOK
, nsCSSProps::kTextDecorationKTable
)) {
7459 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) { // look for more keywords
7460 PRInt32 intValue
= aValue
.GetIntValue();
7463 for (index
= 0; index
< 3; index
++) {
7464 if (ParseEnum(keyword
, nsCSSProps::kTextDecorationKTable
)) {
7465 intValue
|= keyword
.GetIntValue();
7471 aValue
.SetIntValue(intValue
, eCSSUnit_Enumerated
);
7479 CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread
)
7481 nsAutoParseCompoundProperty
compound(this);
7483 // Parses x, y, radius, color (in two possible orders)
7484 // This parses the input into a list. Either it contains just a "none" or
7485 // "inherit" value, or a list of arrays.
7486 // The resulting arrays will always contain the above order, with color and
7487 // radius as null values as needed
7496 nsCSSValueList
*list
= nsnull
;
7497 for (nsCSSValueList
**curp
= &list
, *cur
; ; curp
= &cur
->mNext
) {
7498 cur
= *curp
= new nsCSSValueList();
7500 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7503 if (!ParseVariant(cur
->mValue
,
7504 (cur
== list
) ? VARIANT_HC
| VARIANT_LENGTH
| VARIANT_NONE
7505 : VARIANT_COLOR
| VARIANT_LENGTH
,
7510 nsCSSUnit unit
= cur
->mValue
.GetUnit();
7511 if (unit
!= eCSSUnit_None
&& unit
!= eCSSUnit_Inherit
&&
7512 unit
!= eCSSUnit_Initial
) {
7513 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(5);
7515 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7518 PRBool haveColor
= PR_FALSE
;
7519 if (cur
->mValue
.IsLengthUnit()) {
7520 val
->Item(IndexX
) = cur
->mValue
;
7522 // Must be a color (as string or color value)
7523 NS_ASSERTION(unit
== eCSSUnit_String
|| unit
== eCSSUnit_Color
||
7524 unit
== eCSSUnit_EnumColor
,
7525 "Must be a color value (named color, numeric color, "
7526 "or system color)");
7527 haveColor
= PR_TRUE
;
7528 val
->Item(IndexColor
) = cur
->mValue
;
7530 // Parse the X coordinate
7531 if (!ParseVariant(val
->Item(IndexX
), VARIANT_LENGTH
,
7536 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
7538 // Y coordinate; this one is not optional
7539 if (!ParseVariant(val
->Item(IndexY
), VARIANT_LENGTH
, nsnull
)) {
7543 // Optional radius. Ignore errors except if they pass a negative
7544 // value which we must reject. If we use ParsePositiveVariant we can't
7545 // tell the difference between an unspecified radius and a negative
7546 // radius, so that's why we don't use it.
7547 if (ParseVariant(val
->Item(IndexRadius
), VARIANT_LENGTH
, nsnull
) &&
7548 val
->Item(IndexRadius
).GetFloatValue() < 0) {
7553 // Optional spread (ignore errors)
7554 ParseVariant(val
->Item(IndexSpread
), VARIANT_LENGTH
,
7559 // Optional color (ignore errors)
7560 ParseVariant(val
->Item(IndexColor
), VARIANT_COLOR
,
7564 // Might be at a comma now
7565 if (ExpectSymbol(',', PR_TRUE
)) {
7571 if (!ExpectEndProperty()) {
7572 // If we don't have a comma to delimit the next value, we
7573 // must be at the end of the property. Otherwise we've hit
7574 // something else, which is an error.
7578 // Only success case here, since having the failure case at the
7579 // end allows more sharing of code.
7582 // Have failure case at the end so we can |break| to get to it.
7588 CSSParserImpl::ParseTextShadow()
7590 nsCSSValueList
* list
= ParseCSSShadowList(PR_FALSE
);
7594 mTempData
.SetPropertyBit(eCSSProperty_text_shadow
);
7595 mTempData
.mText
.mTextShadow
= list
;
7600 CSSParserImpl::ParseBoxShadow()
7602 nsCSSValueList
* list
= ParseCSSShadowList(PR_TRUE
);
7606 mTempData
.SetPropertyBit(eCSSProperty_box_shadow
);
7607 mTempData
.mMargin
.mBoxShadow
= list
;
7612 CSSParserImpl::GetNamespaceIdForPrefix(const nsString
& aPrefix
,
7613 PRInt32
* aNameSpaceID
)
7615 NS_PRECONDITION(!aPrefix
.IsEmpty(), "Must have a prefix here");
7617 PRInt32 nameSpaceID
= kNameSpaceID_Unknown
;
7618 if (mNameSpaceMap
) {
7619 // user-specified identifiers are case-sensitive (bug 416106)
7620 nsCOMPtr
<nsIAtom
> prefix
= do_GetAtom(aPrefix
);
7621 nameSpaceID
= mNameSpaceMap
->FindNameSpaceID(prefix
);
7623 // else no declared namespaces
7625 NS_ASSERTION(nameSpaceID
!= kNameSpaceID_None
, "Shouldn't happen!");
7627 if (kNameSpaceID_Unknown
== nameSpaceID
) { // unknown prefix, dump it
7628 const PRUnichar
*params
[] = {
7631 REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix
, params
);
7632 if (mUnresolvablePrefixException
)
7633 mScanner
.SetLowLevelError(NS_ERROR_DOM_NAMESPACE_ERR
);
7637 *aNameSpaceID
= nameSpaceID
;
7642 CSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
)
7644 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // wildcard
7645 if (mNameSpaceMap
) { // look for default namespace
7646 PRInt32 defaultID
= mNameSpaceMap
->FindNameSpaceID(nsnull
);
7647 if (defaultID
!= kNameSpaceID_None
) {
7648 aSelector
.SetNameSpace(defaultID
);
7655 CSSParserImpl::ParsePaint(nsCSSValuePair
* aResult
,
7656 nsCSSProperty aPropID
)
7658 if (!ParseVariant(aResult
->mXValue
,
7659 VARIANT_HC
| VARIANT_NONE
| VARIANT_URL
,
7663 if (aResult
->mXValue
.GetUnit() == eCSSUnit_URL
) {
7664 if (!ParseVariant(aResult
->mYValue
, VARIANT_COLOR
| VARIANT_NONE
,
7666 aResult
->mYValue
.SetColorValue(NS_RGB(0, 0, 0));
7668 aResult
->mYValue
= aResult
->mXValue
;
7671 if (!ExpectEndProperty())
7674 mTempData
.SetPropertyBit(aPropID
);
7679 CSSParserImpl::ParseDasharray()
7682 if (ParseVariant(value
, VARIANT_HLPN
| VARIANT_NONE
, nsnull
)) {
7683 nsCSSValueList
*listHead
= new nsCSSValueList
;
7684 nsCSSValueList
*list
= listHead
;
7686 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7690 list
->mValue
= value
;
7693 if (CheckEndProperty()) {
7694 mTempData
.SetPropertyBit(eCSSProperty_stroke_dasharray
);
7695 mTempData
.mSVG
.mStrokeDasharray
= listHead
;
7699 if (eCSSUnit_Inherit
== value
.GetUnit() ||
7700 eCSSUnit_Initial
== value
.GetUnit() ||
7701 eCSSUnit_None
== value
.GetUnit())
7704 if (!ExpectSymbol(',', PR_TRUE
))
7707 if (!ParseVariant(value
,
7708 VARIANT_LENGTH
| VARIANT_PERCENT
| VARIANT_NUMBER
,
7712 list
->mNext
= new nsCSSValueList
;
7715 list
->mValue
= value
;
7717 mScanner
.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY
);
7727 CSSParserImpl::ParseMarker()
7730 if (ParseSingleValueProperty(marker
, eCSSProperty_marker_end
)) {
7731 if (ExpectEndProperty()) {
7732 AppendValue(eCSSProperty_marker_end
, marker
);
7733 AppendValue(eCSSProperty_marker_mid
, marker
);
7734 AppendValue(eCSSProperty_marker_start
, marker
);