1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* parsing of CSS stylesheets, based on a token stream from the CSS scanner */
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/DebugOnly.h"
11 #include "mozilla/Move.h"
12 #include "mozilla/MathAlgorithms.h"
14 #include "nsCSSParser.h"
15 #include "nsCSSProps.h"
16 #include "nsCSSKeywords.h"
17 #include "nsCSSScanner.h"
18 #include "mozilla/css/ErrorReporter.h"
19 #include "mozilla/css/Loader.h"
20 #include "mozilla/css/StyleRule.h"
21 #include "mozilla/css/ImportRule.h"
22 #include "nsCSSRules.h"
23 #include "mozilla/css/NameSpaceRule.h"
25 #include "mozilla/CSSStyleSheet.h"
26 #include "mozilla/css/Declaration.h"
27 #include "nsStyleConsts.h"
28 #include "nsNetUtil.h"
33 #include "nsCSSPseudoClasses.h"
34 #include "nsCSSPseudoElements.h"
35 #include "nsNameSpaceManager.h"
36 #include "nsXMLNameSpaceMap.h"
38 #include "nsIMediaList.h"
39 #include "nsStyleUtil.h"
40 #include "nsIPrincipal.h"
42 #include "nsContentUtils.h"
43 #include "nsAutoPtr.h"
45 #include "nsMediaFeatures.h"
46 #include "nsLayoutUtils.h"
47 #include "mozilla/Preferences.h"
48 #include "nsRuleData.h"
49 #include "mozilla/CSSVariableValues.h"
50 #include "mozilla/dom/URL.h"
51 #include "gfxFontFamilyList.h"
53 using namespace mozilla
;
55 typedef nsCSSProps::KTableValue KTableValue
;
58 nsCSSProps::kParserVariantTable
[eCSSProperty_COUNT_no_shorthands
] = {
59 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
60 stylestruct_, stylestructoffset_, animtype_) \
62 #include "nsCSSPropList.h"
66 // Maximum number of repetitions for the repeat() function
67 // in the grid-template-columns and grid-template-rows properties,
68 // to limit high memory usage from small stylesheets.
69 // Must be a positive integer. Should be large-ish.
70 #define GRID_TEMPLATE_MAX_REPETITIONS 10000
72 // End-of-array marker for mask arguments to ParseBitmaskValues
73 #define MASK_END_VALUE (-1)
75 MOZ_BEGIN_ENUM_CLASS(CSSParseResult
, int32_t)
76 // Parsed something successfully:
78 // Did not find what we were looking for, but did not consume any token:
80 // Unexpected token or token value, too late for UngetToken() to be enough:
82 MOZ_END_ENUM_CLASS(CSSParseResult
)
86 // Rule processing function
87 typedef void (* RuleAppendFunc
) (css::Rule
* aRule
, void* aData
);
88 static void AssignRuleToPointer(css::Rule
* aRule
, void* aPointer
);
89 static void AppendRuleToSheet(css::Rule
* aRule
, void* aParser
);
91 struct CSSParserInputState
{
92 nsCSSScannerPosition mPosition
;
97 // Your basic top-down recursive descent style parser
98 // The exposed methods and members of this class are precisely those
99 // needed by nsCSSParser, far below.
100 class CSSParserImpl
{
105 nsresult
SetStyleSheet(CSSStyleSheet
* aSheet
);
107 nsresult
SetQuirkMode(bool aQuirkMode
);
109 nsresult
SetChildLoader(mozilla::css::Loader
* aChildLoader
);
111 // Clears everything set by the above Set*() functions.
114 nsresult
ParseSheet(const nsAString
& aInput
,
117 nsIPrincipal
* aSheetPrincipal
,
118 uint32_t aLineNumber
,
119 bool aAllowUnsafeRules
);
121 nsresult
ParseStyleAttribute(const nsAString
& aAttributeValue
,
124 nsIPrincipal
* aNodePrincipal
,
125 css::StyleRule
** aResult
);
127 nsresult
ParseDeclarations(const nsAString
& aBuffer
,
130 nsIPrincipal
* aSheetPrincipal
,
131 css::Declaration
* aDeclaration
,
134 nsresult
ParseRule(const nsAString
& aRule
,
137 nsIPrincipal
* aSheetPrincipal
,
138 css::Rule
** aResult
);
140 nsresult
ParseProperty(const nsCSSProperty aPropID
,
141 const nsAString
& aPropValue
,
144 nsIPrincipal
* aSheetPrincipal
,
145 css::Declaration
* aDeclaration
,
150 void ParseMediaList(const nsSubstring
& aBuffer
,
151 nsIURI
* aURL
, // for error reporting
152 uint32_t aLineNumber
, // for error reporting
153 nsMediaList
* aMediaList
,
156 bool ParseSourceSizeList(const nsAString
& aBuffer
,
157 nsIURI
* aURI
, // for error reporting
158 uint32_t aLineNumber
, // for error reporting
159 InfallibleTArray
< nsAutoPtr
<nsMediaQuery
> >& aQueries
,
160 InfallibleTArray
<nsCSSValue
>& aValues
,
163 nsresult
ParseVariable(const nsAString
& aVariableName
,
164 const nsAString
& aPropValue
,
167 nsIPrincipal
* aSheetPrincipal
,
168 css::Declaration
* aDeclaration
,
172 bool ParseFontFamilyListString(const nsSubstring
& aBuffer
,
173 nsIURI
* aURL
, // for error reporting
174 uint32_t aLineNumber
, // for error reporting
177 bool ParseColorString(const nsSubstring
& aBuffer
,
178 nsIURI
* aURL
, // for error reporting
179 uint32_t aLineNumber
, // for error reporting
181 bool aSuppressErrors
/* false */);
183 nsresult
ParseSelectorString(const nsSubstring
& aSelectorString
,
184 nsIURI
* aURL
, // for error reporting
185 uint32_t aLineNumber
, // for error reporting
186 nsCSSSelectorList
**aSelectorList
);
188 already_AddRefed
<nsCSSKeyframeRule
>
189 ParseKeyframeRule(const nsSubstring
& aBuffer
,
191 uint32_t aLineNumber
);
193 bool ParseKeyframeSelectorString(const nsSubstring
& aSelectorString
,
194 nsIURI
* aURL
, // for error reporting
195 uint32_t aLineNumber
, // for error reporting
196 InfallibleTArray
<float>& aSelectorList
);
198 bool EvaluateSupportsDeclaration(const nsAString
& aProperty
,
199 const nsAString
& aValue
,
202 nsIPrincipal
* aDocPrincipal
);
204 bool EvaluateSupportsCondition(const nsAString
& aCondition
,
207 nsIPrincipal
* aDocPrincipal
);
209 bool ParseCounterStyleName(const nsAString
& aBuffer
,
213 bool ParseCounterDescriptor(nsCSSCounterDesc aDescID
,
214 const nsAString
& aBuffer
,
217 nsIPrincipal
* aSheetPrincipal
,
220 bool ParseFontFaceDescriptor(nsCSSFontDesc aDescID
,
221 const nsAString
& aBuffer
,
224 nsIPrincipal
* aSheetPrincipal
,
227 bool IsValueValidForProperty(const nsCSSProperty aPropID
,
228 const nsAString
& aPropValue
);
230 typedef nsCSSParser::VariableEnumFunc VariableEnumFunc
;
233 * Parses a CSS token stream value and invokes a callback function for each
234 * variable reference that is encountered.
236 * @param aPropertyValue The CSS token stream value.
237 * @param aFunc The callback function to invoke; its parameters are the
238 * variable name found and the aData argument passed in to this function.
239 * @param aData User data to pass in to the callback.
240 * @return Whether aPropertyValue could be parsed as a valid CSS token stream
241 * value (e.g., without syntactic errors in variable references).
243 bool EnumerateVariableReferences(const nsAString
& aPropertyValue
,
244 VariableEnumFunc aFunc
,
248 * Parses aPropertyValue as a CSS token stream value and resolves any
249 * variable references using the variables in aVariables.
251 * @param aPropertyValue The CSS token stream value.
252 * @param aVariables The set of variable values to use when resolving variable
254 * @param aResult Out parameter that gets the resolved value.
255 * @param aFirstToken Out parameter that gets the type of the first token in
257 * @param aLastToken Out parameter that gets the type of the last token in
259 * @return Whether aResult could be parsed successfully and variable reference
260 * substitution succeeded.
262 bool ResolveVariableValue(const nsAString
& aPropertyValue
,
263 const CSSVariableValues
* aVariables
,
265 nsCSSTokenSerializationType
& aFirstToken
,
266 nsCSSTokenSerializationType
& aLastToken
);
269 * Parses a string as a CSS token stream value for particular property,
270 * resolving any variable references. The parsed property value is stored
271 * in the specified nsRuleData object. If aShorthandPropertyID has a value
272 * other than eCSSProperty_UNKNOWN, this is the property that will be parsed;
273 * otherwise, aPropertyID will be parsed. Either way, only aPropertyID,
274 * a longhand property, will be copied over to the rule data.
276 * If the property cannot be parsed, it will be treated as if 'initial' or
277 * 'inherit' were specified, for non-inherited and inherited properties
280 * @param aPropertyID The ID of the longhand property whose value is to be
281 * copied to the rule data.
282 * @param aShorthandPropertyID The ID of the shorthand property to be parsed.
283 * If a longhand property is to be parsed, aPropertyID is that property,
284 * and aShorthandPropertyID must be eCSSProperty_UNKNOWN.
285 * @param aValue The CSS token stream value.
286 * @param aVariables The set of variable values to use when resolving variable
288 * @param aRuleData The rule data object into which parsed property value for
289 * aPropertyID will be stored.
291 void ParsePropertyWithVariableReferences(nsCSSProperty aPropertyID
,
292 nsCSSProperty aShorthandPropertyID
,
293 const nsAString
& aValue
,
294 const CSSVariableValues
* aVariables
,
295 nsRuleData
* aRuleData
,
298 nsIPrincipal
* aDocPrincipal
,
299 CSSStyleSheet
* aSheet
,
300 uint32_t aLineNumber
,
301 uint32_t aLineOffset
);
303 nsCSSProperty
LookupEnabledProperty(const nsAString
& aProperty
) {
304 static_assert(nsCSSProps::eEnabledForAllContent
== 0,
305 "nsCSSProps::eEnabledForAllContent should be zero for "
306 "this bitfield to work");
307 nsCSSProps::EnabledState enabledState
= nsCSSProps::eEnabledForAllContent
;
308 if (mUnsafeRulesEnabled
) {
309 enabledState
|= nsCSSProps::eEnabledInUASheets
;
311 if (mIsChromeOrCertifiedApp
) {
312 enabledState
|= nsCSSProps::eEnabledInChromeOrCertifiedApp
;
314 return nsCSSProps::LookupProperty(aProperty
, enabledState
);
318 class nsAutoParseCompoundProperty
;
319 friend class nsAutoParseCompoundProperty
;
321 class nsAutoFailingSupportsRule
;
322 friend class nsAutoFailingSupportsRule
;
324 class nsAutoSuppressErrors
;
325 friend class nsAutoSuppressErrors
;
327 void AppendRule(css::Rule
* aRule
);
328 friend void AppendRuleToSheet(css::Rule
*, void*); // calls AppendRule
331 * This helper class automatically calls SetParsingCompoundProperty in its
332 * constructor and takes care of resetting it to false in its destructor.
334 class nsAutoParseCompoundProperty
{
336 explicit nsAutoParseCompoundProperty(CSSParserImpl
* aParser
) : mParser(aParser
)
338 NS_ASSERTION(!aParser
->IsParsingCompoundProperty(),
339 "already parsing compound property");
340 NS_ASSERTION(aParser
, "Null parser?");
341 aParser
->SetParsingCompoundProperty(true);
344 ~nsAutoParseCompoundProperty()
346 mParser
->SetParsingCompoundProperty(false);
349 CSSParserImpl
* mParser
;
353 * This helper class conditionally sets mInFailingSupportsRule to
354 * true if aCondition = false, and resets it to its original value in its
355 * destructor. If we are already somewhere within a failing @supports
356 * rule, passing in aCondition = true does not change mInFailingSupportsRule.
358 class nsAutoFailingSupportsRule
{
360 nsAutoFailingSupportsRule(CSSParserImpl
* aParser
,
363 mOriginalValue(aParser
->mInFailingSupportsRule
)
366 mParser
->mInFailingSupportsRule
= true;
370 ~nsAutoFailingSupportsRule()
372 mParser
->mInFailingSupportsRule
= mOriginalValue
;
376 CSSParserImpl
* mParser
;
381 * Auto class to set aParser->mSuppressErrors to the specified value
382 * and restore it to its original value later.
384 class nsAutoSuppressErrors
{
386 explicit nsAutoSuppressErrors(CSSParserImpl
* aParser
,
387 bool aSuppressErrors
= true)
389 mOriginalValue(aParser
->mSuppressErrors
)
391 mParser
->mSuppressErrors
= aSuppressErrors
;
394 ~nsAutoSuppressErrors()
396 mParser
->mSuppressErrors
= mOriginalValue
;
400 CSSParserImpl
* mParser
;
404 // the caller must hold on to aString until parsing is done
405 void InitScanner(nsCSSScanner
& aScanner
,
406 css::ErrorReporter
& aReporter
,
407 nsIURI
* aSheetURI
, nsIURI
* aBaseURI
,
408 nsIPrincipal
* aSheetPrincipal
);
409 void ReleaseScanner(void);
410 bool IsSVGMode() const {
411 return mScanner
->IsSVGMode();
415 * Saves the current input state, which includes any currently pushed
416 * back token, and the current position of the scanner.
418 void SaveInputState(CSSParserInputState
& aState
);
421 * Restores the saved input state by pushing back any saved pushback
422 * token and calling RestoreSavedPosition on the scanner.
424 void RestoreSavedInputState(const CSSParserInputState
& aState
);
426 bool GetToken(bool aSkipWS
);
428 bool GetNextTokenLocation(bool aSkipWS
, uint32_t *linenum
, uint32_t *colnum
);
430 bool ExpectSymbol(char16_t aSymbol
, bool aSkipWS
);
431 bool ExpectEndProperty();
432 bool CheckEndProperty();
433 nsSubstring
* NextIdent();
435 // returns true when the stop symbol is found, and false for EOF
436 bool SkipUntil(char16_t aStopSymbol
);
437 void SkipUntilOneOf(const char16_t
* aStopSymbolChars
);
438 // For each character in aStopSymbolChars from the end of the array
439 // to the start, calls SkipUntil with that character.
440 typedef nsAutoTArray
<char16_t
, 16> StopSymbolCharStack
;
441 void SkipUntilAllOf(const StopSymbolCharStack
& aStopSymbolChars
);
442 // returns true if the stop symbol or EOF is found, and false for an
443 // unexpected ')', ']' or '}'; this not safe to call outside variable
444 // resolution, as it doesn't handle mismatched content
445 bool SkipBalancedContentUntil(char16_t aStopSymbol
);
447 void SkipRuleSet(bool aInsideBraces
);
448 bool SkipAtRule(bool aInsideBlock
);
449 bool SkipDeclaration(bool aCheckForBraces
);
451 void PushGroup(css::GroupRule
* aRule
);
454 bool ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aProcessData
,
455 bool aInsideBraces
= false);
456 bool ParseAtRule(RuleAppendFunc aAppendFunc
, void* aProcessData
,
458 bool ParseCharsetRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
459 bool ParseImportRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
460 bool ParseURLOrString(nsString
& aURL
);
461 bool GatherMedia(nsMediaList
* aMedia
, bool aInAtRule
);
463 enum eMediaQueryType
{ eMediaQueryNormal
,
464 // Parsing an at rule
466 // Attempt to consume a single media-condition and
467 // stop. Note that the spec defines "expression and/or
468 // expression" as one condition but "expression,
469 // expression" as two.
470 eMediaQuerySingleCondition
};
471 bool ParseMediaQuery(eMediaQueryType aMode
, nsMediaQuery
**aQuery
,
473 bool ParseMediaQueryExpression(nsMediaQuery
* aQuery
);
474 void ProcessImport(const nsString
& aURLSpec
,
476 RuleAppendFunc aAppendFunc
,
478 uint32_t aLineNumber
,
479 uint32_t aColumnNumber
);
480 bool ParseGroupRule(css::GroupRule
* aRule
, RuleAppendFunc aAppendFunc
,
482 bool ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
483 bool ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
484 bool ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
485 void ProcessNameSpace(const nsString
& aPrefix
,
486 const nsString
& aURLSpec
, RuleAppendFunc aAppendFunc
,
488 uint32_t aLineNumber
, uint32_t aColumnNumber
);
490 bool ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
491 bool ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc
,
493 bool ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule
*aRule
);
494 bool ParseFontDescriptor(nsCSSFontFaceRule
* aRule
);
495 bool ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
498 bool ParsePageRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
499 bool ParseKeyframesRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
500 already_AddRefed
<nsCSSKeyframeRule
> ParseKeyframeRule();
501 bool ParseKeyframeSelectorList(InfallibleTArray
<float>& aSelectorList
);
503 bool ParseSupportsRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
504 bool ParseSupportsCondition(bool& aConditionMet
);
505 bool ParseSupportsConditionNegation(bool& aConditionMet
);
506 bool ParseSupportsConditionInParens(bool& aConditionMet
);
507 bool ParseSupportsConditionInParensInsideParens(bool& aConditionMet
);
508 bool ParseSupportsConditionTerms(bool& aConditionMet
);
509 enum SupportsConditionTermOperator
{ eAnd
, eOr
};
510 bool ParseSupportsConditionTermsAfterOperator(
512 SupportsConditionTermOperator aOperator
);
514 bool ParseCounterStyleRule(RuleAppendFunc aAppendFunc
, void* aProcessData
);
515 bool ParseCounterStyleName(nsAString
& aName
, bool aForDefinition
);
516 bool ParseCounterStyleNameValue(nsCSSValue
& aValue
);
517 bool ParseCounterDescriptor(nsCSSCounterStyleRule
*aRule
);
518 bool ParseCounterDescriptorValue(nsCSSCounterDesc aDescID
,
520 bool ParseCounterRange(nsCSSValuePair
& aPair
);
523 * Parses the current input stream for a CSS token stream value and resolves
524 * any variable references using the variables in aVariables.
526 * @param aVariables The set of variable values to use when resolving variable
528 * @param aResult Out parameter that, if the function returns true, will be
529 * replaced with the resolved value.
530 * @return Whether aResult could be parsed successfully and variable reference
531 * substitution succeeded.
533 bool ResolveValueWithVariableReferences(
534 const CSSVariableValues
* aVariables
,
536 nsCSSTokenSerializationType
& aResultFirstToken
,
537 nsCSSTokenSerializationType
& aResultLastToken
);
538 // Helper function for ResolveValueWithVariableReferences.
539 bool ResolveValueWithVariableReferencesRec(
541 nsCSSTokenSerializationType
& aResultFirstToken
,
542 nsCSSTokenSerializationType
& aResultLastToken
,
543 const CSSVariableValues
* aVariables
);
545 enum nsSelectorParsingStatus
{
546 // we have parsed a selector and we saw a token that cannot be
547 // part of a selector:
548 eSelectorParsingStatus_Done
,
549 // we should continue parsing the selector:
550 eSelectorParsingStatus_Continue
,
551 // we saw an unexpected token or token value,
552 // or we saw end-of-file with an unfinished selector:
553 eSelectorParsingStatus_Error
555 nsSelectorParsingStatus
ParseIDSelector(int32_t& aDataMask
,
556 nsCSSSelector
& aSelector
);
558 nsSelectorParsingStatus
ParseClassSelector(int32_t& aDataMask
,
559 nsCSSSelector
& aSelector
);
561 // aPseudoElement and aPseudoElementArgs are the location where
562 // pseudo-elements (as opposed to pseudo-classes) are stored;
563 // pseudo-classes are stored on aSelector. aPseudoElement and
564 // aPseudoElementArgs must be non-null iff !aIsNegated.
565 nsSelectorParsingStatus
ParsePseudoSelector(int32_t& aDataMask
,
566 nsCSSSelector
& aSelector
,
568 nsIAtom
** aPseudoElement
,
569 nsAtomList
** aPseudoElementArgs
,
570 nsCSSPseudoElements::Type
* aPseudoElementType
);
572 nsSelectorParsingStatus
ParseAttributeSelector(int32_t& aDataMask
,
573 nsCSSSelector
& aSelector
);
575 nsSelectorParsingStatus
ParseTypeOrUniversalSelector(int32_t& aDataMask
,
576 nsCSSSelector
& aSelector
,
579 nsSelectorParsingStatus
ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
580 nsCSSPseudoClasses::Type aType
);
582 nsSelectorParsingStatus
ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
583 nsCSSPseudoClasses::Type aType
);
585 nsSelectorParsingStatus
ParsePseudoClassWithSelectorListArg(nsCSSSelector
& aSelector
,
586 nsCSSPseudoClasses::Type aType
);
588 nsSelectorParsingStatus
ParseNegatedSimpleSelector(int32_t& aDataMask
,
589 nsCSSSelector
& aSelector
);
591 // If aStopChar is non-zero, the selector list is done when we hit
592 // aStopChar. Otherwise, it's done when we hit EOF.
593 bool ParseSelectorList(nsCSSSelectorList
*& aListHead
,
595 bool ParseSelectorGroup(nsCSSSelectorList
*& aListHead
);
596 bool ParseSelector(nsCSSSelectorList
* aList
, char16_t aPrevCombinator
);
599 eParseDeclaration_InBraces
= 1 << 0,
600 eParseDeclaration_AllowImportant
= 1 << 1
602 enum nsCSSContextType
{
607 css::Declaration
* ParseDeclarationBlock(uint32_t aFlags
,
608 nsCSSContextType aContext
= eCSSContext_General
);
609 bool ParseDeclaration(css::Declaration
* aDeclaration
,
611 bool aMustCallValueAppended
,
613 nsCSSContextType aContext
= eCSSContext_General
);
615 bool ParseProperty(nsCSSProperty aPropID
);
616 bool ParsePropertyByFunction(nsCSSProperty aPropID
);
617 bool ParseSingleValueProperty(nsCSSValue
& aValue
,
618 nsCSSProperty aPropID
);
620 enum PriorityParsingStatus
{
625 PriorityParsingStatus
ParsePriority();
628 bool ParseTreePseudoElement(nsAtomList
**aPseudoElementArgs
);
631 void InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
);
633 // Property specific parsing routines
634 bool ParseBackground();
636 struct BackgroundParseState
{
638 nsCSSValueList
* mImage
;
639 nsCSSValuePairList
* mRepeat
;
640 nsCSSValueList
* mAttachment
;
641 nsCSSValueList
* mClip
;
642 nsCSSValueList
* mOrigin
;
643 nsCSSValueList
* mPosition
;
644 nsCSSValuePairList
* mSize
;
645 BackgroundParseState(
646 nsCSSValue
& aColor
, nsCSSValueList
* aImage
, nsCSSValuePairList
* aRepeat
,
647 nsCSSValueList
* aAttachment
, nsCSSValueList
* aClip
,
648 nsCSSValueList
* aOrigin
, nsCSSValueList
* aPosition
,
649 nsCSSValuePairList
* aSize
) :
650 mColor(aColor
), mImage(aImage
), mRepeat(aRepeat
),
651 mAttachment(aAttachment
), mClip(aClip
), mOrigin(aOrigin
),
652 mPosition(aPosition
), mSize(aSize
) {};
655 bool ParseBackgroundItem(BackgroundParseState
& aState
);
657 bool ParseValueList(nsCSSProperty aPropID
); // a single value prop-id
658 bool ParseBackgroundRepeat();
659 bool ParseBackgroundRepeatValues(nsCSSValuePair
& aValue
);
660 bool ParseBackgroundPosition();
662 // ParseBoxPositionValues parses the CSS 2.1 background-position syntax,
663 // which is still used by some properties. See ParsePositionValue
664 // for the css3-background syntax.
665 bool ParseBoxPositionValues(nsCSSValuePair
& aOut
, bool aAcceptsInherit
,
666 bool aAllowExplicitCenter
= true); // deprecated
668 // ParsePositionValue parses a CSS <position> value, which is used by
669 // the 'background-position' property.
670 bool ParsePositionValue(nsCSSValue
& aOut
);
672 bool ParseBackgroundSize();
673 bool ParseBackgroundSizeValues(nsCSSValuePair
& aOut
);
674 bool ParseBorderColor();
675 bool ParseBorderColors(nsCSSProperty aProperty
);
676 void SetBorderImageInitialValues();
677 bool ParseBorderImageRepeat(bool aAcceptsInherit
);
678 // If ParseBorderImageSlice returns false, aConsumedTokens indicates
679 // whether or not any tokens were consumed (in other words, was the property
680 // in error or just not present). If ParseBorderImageSlice returns true
681 // aConsumedTokens is always true.
682 bool ParseBorderImageSlice(bool aAcceptsInherit
, bool* aConsumedTokens
);
683 bool ParseBorderImageWidth(bool aAcceptsInherit
);
684 bool ParseBorderImageOutset(bool aAcceptsInherit
);
685 bool ParseBorderImage();
686 bool ParseBorderSpacing();
687 bool ParseBorderSide(const nsCSSProperty aPropIDs
[],
689 bool ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
690 int32_t aSourceType
);
691 bool ParseBorderStyle();
692 bool ParseBorderWidth();
694 bool ParseCalc(nsCSSValue
&aValue
, int32_t aVariantMask
);
695 bool ParseCalcAdditiveExpression(nsCSSValue
& aValue
,
696 int32_t& aVariantMask
);
697 bool ParseCalcMultiplicativeExpression(nsCSSValue
& aValue
,
698 int32_t& aVariantMask
,
700 bool ParseCalcTerm(nsCSSValue
& aValue
, int32_t& aVariantMask
);
701 bool RequireWhitespace();
703 // For "flex" shorthand property, defined in CSS Flexbox spec
705 // For "flex-flow" shorthand property, defined in CSS Flexbox spec
706 bool ParseFlexFlow();
709 bool ParseGridAutoFlow();
711 // Parse a <line-names> expression.
712 // If successful, either leave aValue untouched,
713 // to indicate that we parsed the empty list,
714 // or set it to a eCSSUnit_List of eCSSUnit_Ident.
716 // To parse an optional <line-names> (ie. if not finding an open paren
717 // is considered the same as an empty list),
718 // treat CSSParseResult::NotFound the same as CSSParseResult::Ok.
720 // If aValue is already a eCSSUnit_List, append to that list.
721 CSSParseResult
ParseGridLineNames(nsCSSValue
& aValue
);
722 bool ParseGridLineNameListRepeat(nsCSSValueList
** aTailPtr
);
723 bool ParseOptionalLineNameListAfterSubgrid(nsCSSValue
& aValue
);
724 bool ParseGridTrackBreadth(nsCSSValue
& aValue
);
725 CSSParseResult
ParseGridTrackSize(nsCSSValue
& aValue
);
726 bool ParseGridAutoColumnsRows(nsCSSProperty aPropID
);
727 bool ParseGridTrackListRepeat(nsCSSValueList
** aTailPtr
);
729 // Assuming a [ <line-names>? ] has already been parsed,
730 // parse the rest of a <track-list>.
732 // This exists because [ <line-names>? ] is ambiguous in the
733 // 'grid-template' shorthand: it can be either the start of a <track-list>,
734 // or of the intertwined syntax that sets both
735 // grid-template-rows and grid-template-areas.
737 // On success, |aValue| will be a list of odd length >= 3,
738 // starting with a <line-names> (which is itself a list)
739 // and alternating between that and <track-size>.
740 bool ParseGridTrackListWithFirstLineNames(nsCSSValue
& aValue
,
741 const nsCSSValue
& aFirstLineNames
);
742 bool ParseGridTemplateColumnsRows(nsCSSProperty aPropID
);
744 // |aAreaIndices| is a lookup table to help us parse faster,
745 // mapping area names to indices in |aResult.mNamedAreas|.
746 bool ParseGridTemplateAreasLine(const nsAutoString
& aInput
,
747 css::GridTemplateAreasValue
* aResult
,
748 nsDataHashtable
<nsStringHashKey
, uint32_t>& aAreaIndices
);
749 bool ParseGridTemplateAreas();
750 bool ParseGridTemplate();
751 bool ParseGridTemplateAfterSlash(bool aColumnsIsTrackList
);
752 bool ParseGridTemplateAfterString(const nsCSSValue
& aFirstLineNames
);
754 bool ParseGridShorthandAutoProps();
755 bool ParseGridLine(nsCSSValue
& aValue
);
756 bool ParseGridColumnRowStartEnd(nsCSSProperty aPropID
);
757 bool ParseGridColumnRow(nsCSSProperty aStartPropID
,
758 nsCSSProperty aEndPropID
);
759 bool ParseGridArea();
761 // for 'clip' and '-moz-image-region'
762 bool ParseRect(nsCSSProperty aPropID
);
765 bool ParseCounterData(nsCSSProperty aPropID
);
768 bool ParseFontSynthesis(nsCSSValue
& aValue
);
769 bool ParseSingleAlternate(int32_t& aWhichFeature
, nsCSSValue
& aValue
);
770 bool ParseFontVariantAlternates(nsCSSValue
& aValue
);
771 bool MergeBitmaskValue(int32_t aNewValue
, const int32_t aMasks
[],
772 int32_t& aMergedValue
);
773 bool ParseBitmaskValues(nsCSSValue
& aValue
,
774 const KTableValue aKeywordTable
[],
775 const int32_t aMasks
[]);
776 bool ParseFontVariantEastAsian(nsCSSValue
& aValue
);
777 bool ParseFontVariantLigatures(nsCSSValue
& aValue
);
778 bool ParseFontVariantNumeric(nsCSSValue
& aValue
);
779 bool ParseFontVariant();
780 bool ParseFontWeight(nsCSSValue
& aValue
);
781 bool ParseOneFamily(nsAString
& aFamily
, bool& aOneKeyword
, bool& aQuoted
);
782 bool ParseFamily(nsCSSValue
& aValue
);
783 bool ParseFontFeatureSettings(nsCSSValue
& aValue
);
784 bool ParseFontSrc(nsCSSValue
& aValue
);
785 bool ParseFontSrcFormat(InfallibleTArray
<nsCSSValue
>& values
);
786 bool ParseFontRanges(nsCSSValue
& aValue
);
787 bool ParseListStyle();
788 bool ParseListStyleType(nsCSSValue
& aValue
);
790 bool ParseMarks(nsCSSValue
& aValue
);
791 bool ParseClipPath();
792 bool ParseTransform(bool aIsPrefixed
);
793 bool ParseObjectPosition();
795 bool ParseOverflow();
798 bool ParseRubyPosition(nsCSSValue
& aValue
);
800 bool ParseTextAlign(nsCSSValue
& aValue
,
801 const KTableValue aTable
[]);
802 bool ParseTextAlign(nsCSSValue
& aValue
);
803 bool ParseTextAlignLast(nsCSSValue
& aValue
);
804 bool ParseTextDecoration();
805 bool ParseTextDecorationLine(nsCSSValue
& aValue
);
806 bool ParseTextCombineUpright(nsCSSValue
& aValue
);
807 bool ParseTextOverflow(nsCSSValue
& aValue
);
808 bool ParseTouchAction(nsCSSValue
& aValue
);
810 bool ParseShadowItem(nsCSSValue
& aValue
, bool aIsBoxShadow
);
811 bool ParseShadowList(nsCSSProperty aProperty
);
812 bool ParseTransitionProperty();
813 bool ParseTransitionTimingFunctionValues(nsCSSValue
& aValue
);
814 bool ParseTransitionTimingFunctionValueComponent(float& aComponent
,
817 bool ParseTransitionStepTimingFunctionValues(nsCSSValue
& aValue
);
818 enum ParseAnimationOrTransitionShorthandResult
{
819 eParseAnimationOrTransitionShorthand_Values
,
820 eParseAnimationOrTransitionShorthand_Inherit
,
821 eParseAnimationOrTransitionShorthand_Error
823 ParseAnimationOrTransitionShorthandResult
824 ParseAnimationOrTransitionShorthand(const nsCSSProperty
* aProperties
,
825 const nsCSSValue
* aInitialValues
,
827 size_t aNumProperties
);
828 bool ParseTransition();
829 bool ParseAnimation();
830 bool ParseWillChange();
832 bool ParsePaint(nsCSSProperty aPropID
);
833 bool ParseDasharray();
835 bool ParsePaintOrder();
839 * Parses a variable value from a custom property declaration.
841 * @param aType Out parameter into which will be stored the type of variable
842 * value, indicating whether the parsed value was a token stream or one of
843 * the CSS-wide keywords.
844 * @param aValue Out parameter into which will be stored the token stream
845 * as a string, if the parsed custom property did take a token stream.
846 * @return Whether parsing succeeded.
848 bool ParseVariableDeclaration(CSSVariableDeclarations::Type
* aType
,
852 * Parses a CSS variable value. This could be 'initial', 'inherit', 'unset'
853 * or a token stream, which may or may not include variable references.
855 * @param aType Out parameter into which the type of the variable value
857 * @param aDropBackslash Out parameter indicating whether during variable
858 * value parsing there was a trailing backslash before EOF that must
859 * be dropped when serializing the variable value.
860 * @param aImpliedCharacters Out parameter appended to which will be any
861 * characters that were implied when encountering EOF and which
862 * must be included at the end of the serialized variable value.
863 * @param aFunc A callback function to invoke when a variable reference
864 * is encountered. May be null. Arguments are the variable name
865 * and the aData argument passed in to this function.
866 * @param User data to pass in to the callback.
867 * @return Whether parsing succeeded.
869 bool ParseValueWithVariables(CSSVariableDeclarations::Type
* aType
,
870 bool* aDropBackslash
,
871 nsString
& aImpliedCharacters
,
872 void (*aFunc
)(const nsAString
&, void*),
876 * Returns whether the scanner dropped a backslash just before EOF.
878 bool BackslashDropped();
881 * Calls AppendImpliedEOFCharacters on mScanner.
883 void AppendImpliedEOFCharacters(nsAString
& aResult
);
885 // Reused utility parsing routines
886 void AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
);
887 bool ParseBoxProperties(const nsCSSProperty aPropIDs
[]);
888 bool ParseGroupedBoxProperty(int32_t aVariantMask
,
890 bool ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
891 int32_t aSourceType
);
892 bool ParseBoxCornerRadius(const nsCSSProperty aPropID
);
893 bool ParseBoxCornerRadiiInternals(nsCSSValue array
[]);
894 bool ParseBoxCornerRadii(const nsCSSProperty aPropIDs
[]);
896 int32_t ParseChoice(nsCSSValue aValues
[],
897 const nsCSSProperty aPropIDs
[], int32_t aNumIDs
);
898 bool ParseColor(nsCSSValue
& aValue
);
899 bool ParseNumberColorComponent(uint8_t& aComponent
, char aStop
);
900 bool ParsePercentageColorComponent(float& aComponent
, char aStop
);
901 // ParseHSLColor parses everything starting with the opening '('
902 // up through and including the aStop char.
903 bool ParseHSLColor(float& aHue
, float& aSaturation
, float& aLightness
,
905 // ParseColorOpacity will enforce that the color ends with a ')'
907 bool ParseColorOpacity(uint8_t& aOpacity
);
908 bool ParseColorOpacity(float& aOpacity
);
909 bool ParseEnum(nsCSSValue
& aValue
,
910 const KTableValue aKeywordTable
[]);
911 bool ParseVariant(nsCSSValue
& aValue
,
912 int32_t aVariantMask
,
913 const KTableValue aKeywordTable
[]);
914 bool ParseNonNegativeVariant(nsCSSValue
& aValue
,
915 int32_t aVariantMask
,
916 const KTableValue aKeywordTable
[]);
917 bool ParseOneOrLargerVariant(nsCSSValue
& aValue
,
918 int32_t aVariantMask
,
919 const KTableValue aKeywordTable
[]);
920 bool ParseNonNegativeInteger(nsCSSValue
& aValue
)
922 return ParseNonNegativeVariant(aValue
, VARIANT_INTEGER
, nullptr);
925 // http://dev.w3.org/csswg/css-values/#custom-idents
926 // Parse an identifier that is none of:
927 // * a CSS-wide keyword
929 // * a keyword in |aExcludedKeywords|
930 // * a keyword in |aPropertyKTable|
932 // |aExcludedKeywords| is an array of nsCSSKeyword
933 // that ends with a eCSSKeyword_UNKNOWN marker.
935 // |aPropertyKTable| can be used if some of the keywords to exclude
936 // also appear in an existing nsCSSProps::KTableValue,
937 // to avoid duplicating them.
938 bool ParseCustomIdent(nsCSSValue
& aValue
,
939 const nsAutoString
& aIdentValue
,
940 const nsCSSKeyword aExcludedKeywords
[] = nullptr,
941 const nsCSSProps::KTableValue aPropertyKTable
[] = nullptr);
942 bool ParseCounter(nsCSSValue
& aValue
);
943 bool ParseAttr(nsCSSValue
& aValue
);
944 bool ParseSymbols(nsCSSValue
& aValue
);
945 bool SetValueToURL(nsCSSValue
& aValue
, const nsString
& aURL
);
946 bool TranslateDimension(nsCSSValue
& aValue
, int32_t aVariantMask
,
947 float aNumber
, const nsString
& aUnit
);
948 bool ParseImageOrientation(nsCSSValue
& aAngle
);
949 bool ParseImageRect(nsCSSValue
& aImage
);
950 bool ParseElement(nsCSSValue
& aValue
);
951 bool ParseColorStop(nsCSSValueGradient
* aGradient
);
952 bool ParseLinearGradient(nsCSSValue
& aValue
, bool aIsRepeating
,
954 bool ParseRadialGradient(nsCSSValue
& aValue
, bool aIsRepeating
,
956 bool IsLegacyGradientLine(const nsCSSTokenType
& aType
,
957 const nsString
& aId
);
958 bool ParseGradientColorStops(nsCSSValueGradient
* aGradient
,
961 void SetParsingCompoundProperty(bool aBool
) {
962 mParsingCompoundProperty
= aBool
;
964 bool IsParsingCompoundProperty(void) const {
965 return mParsingCompoundProperty
;
968 /* Functions for basic shapes */
969 bool ParseBasicShape(nsCSSValue
& aValue
, bool* aConsumedTokens
);
970 bool ParsePolygonFunction(nsCSSValue
& aValue
);
971 bool ParseCircleOrEllipseFunction(nsCSSKeyword
, nsCSSValue
& aValue
);
972 bool ParseInsetFunction(nsCSSValue
& aValue
);
974 /* Functions for transform Parsing */
975 bool ParseSingleTransform(bool aIsPrefixed
, nsCSSValue
& aValue
);
976 bool ParseFunction(nsCSSKeyword aFunction
, const int32_t aAllowedTypes
[],
977 int32_t aVariantMaskAll
, uint16_t aMinElems
,
978 uint16_t aMaxElems
, nsCSSValue
&aValue
);
979 bool ParseFunctionInternals(const int32_t aVariantMask
[],
980 int32_t aVariantMaskAll
,
983 InfallibleTArray
<nsCSSValue
>& aOutput
);
985 /* Functions for transform-origin/perspective-origin Parsing */
986 bool ParseTransformOrigin(bool aPerspective
);
988 /* Functions for filter parsing */
990 bool ParseSingleFilter(nsCSSValue
* aValue
);
991 bool ParseDropShadow(nsCSSValue
* aValue
);
993 /* Find and return the namespace ID associated with aPrefix.
994 If aPrefix has not been declared in an @namespace rule, returns
995 kNameSpaceID_Unknown. */
996 int32_t GetNamespaceIdForPrefix(const nsString
& aPrefix
);
998 /* Find the correct default namespace, and set it on aSelector. */
999 void SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
);
1001 // Current token. The value is valid after calling GetToken and invalidated
1006 nsCSSScanner
* mScanner
;
1008 // Our error reporter.
1009 css::ErrorReporter
* mReporter
;
1011 // The URI to be used as a base for relative URIs.
1012 nsCOMPtr
<nsIURI
> mBaseURI
;
1014 // The URI to be used as an HTTP "Referer" and for error reporting.
1015 nsCOMPtr
<nsIURI
> mSheetURI
;
1017 // The principal of the sheet involved
1018 nsCOMPtr
<nsIPrincipal
> mSheetPrincipal
;
1020 // The sheet we're parsing into
1021 nsRefPtr
<CSSStyleSheet
> mSheet
;
1023 // Used for @import rules
1024 mozilla::css::Loader
* mChildLoader
; // not ref counted, it owns us
1026 // Sheet section we're in. This is used to enforce correct ordering of the
1027 // various rule types (eg the fact that a @charset rule must come before
1028 // anything else). Note that there are checks of similar things in various
1029 // places in CSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
1031 eCSSSection_Charset
,
1033 eCSSSection_NameSpace
,
1036 nsCSSSection mSection
;
1038 nsXMLNameSpaceMap
*mNameSpaceMap
; // weak, mSheet owns it
1040 // After an UngetToken is done this flag is true. The next call to
1041 // GetToken clears the flag.
1042 bool mHavePushBack
: 1;
1044 // True if we are in quirks mode; false in standards or almost standards mode
1045 bool mNavQuirkMode
: 1;
1047 // True when the hashless color quirk applies.
1048 bool mHashlessColorQuirk
: 1;
1050 // True when the unitless length quirk applies.
1051 bool mUnitlessLengthQuirk
: 1;
1053 // True if unsafe rules should be allowed
1054 bool mUnsafeRulesEnabled
: 1;
1056 // True if we are in parsing rules for Chrome or Certified App content,
1057 // in which case CSS properties with the
1058 // CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP
1059 // flag should be allowed.
1060 bool mIsChromeOrCertifiedApp
: 1;
1062 // True if viewport units should be allowed.
1063 bool mViewportUnitsEnabled
: 1;
1065 // True for parsing media lists for HTML attributes, where we have to
1066 // ignore CSS comments.
1067 bool mHTMLMediaMode
: 1;
1069 // This flag is set when parsing a non-box shorthand; it's used to not apply
1070 // some quirks during shorthand parsing
1071 bool mParsingCompoundProperty
: 1;
1073 // True if we are in the middle of parsing an @supports condition.
1074 // This is used to avoid recording the input stream when variable references
1075 // are encountered in a property declaration in the @supports condition.
1076 bool mInSupportsCondition
: 1;
1078 // True if we are somewhere within a @supports rule whose condition is
1080 bool mInFailingSupportsRule
: 1;
1082 // True if we will suppress all parse errors (except unexpected EOFs).
1083 // This is used to prevent errors for declarations inside a failing
1085 bool mSuppressErrors
: 1;
1087 // Stack of rule groups; used for @media and such.
1088 InfallibleTArray
<nsRefPtr
<css::GroupRule
> > mGroupStack
;
1090 // During the parsing of a property (which may be a shorthand), the data
1091 // are stored in |mTempData|. (It is needed to ensure that parser
1092 // errors cause the data to be ignored, and to ensure that a
1093 // non-'!important' declaration does not override an '!important'
1095 nsCSSExpandedDataBlock mTempData
;
1097 // All data from successfully parsed properties are placed into |mData|.
1098 nsCSSExpandedDataBlock mData
;
1101 // Used from nsCSSParser constructors and destructors
1102 CSSParserImpl
* mNextFree
;
1105 static void AssignRuleToPointer(css::Rule
* aRule
, void* aPointer
)
1107 css::Rule
**pointer
= static_cast<css::Rule
**>(aPointer
);
1108 NS_ADDREF(*pointer
= aRule
);
1111 static void AppendRuleToSheet(css::Rule
* aRule
, void* aParser
)
1113 CSSParserImpl
* parser
= (CSSParserImpl
*) aParser
;
1114 parser
->AppendRule(aRule
);
1117 #define REPORT_UNEXPECTED(msg_) \
1118 { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_); }
1120 #define REPORT_UNEXPECTED_P(msg_, param_) \
1121 { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, param_); }
1123 #define REPORT_UNEXPECTED_TOKEN(msg_) \
1124 { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken); }
1126 #define REPORT_UNEXPECTED_TOKEN_CHAR(msg_, ch_) \
1127 { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken, ch_); }
1129 #define REPORT_UNEXPECTED_EOF(lf_) \
1130 mReporter->ReportUnexpectedEOF(#lf_)
1132 #define REPORT_UNEXPECTED_EOF_CHAR(ch_) \
1133 mReporter->ReportUnexpectedEOF(ch_)
1135 #define OUTPUT_ERROR() \
1136 mReporter->OutputError()
1138 #define OUTPUT_ERROR_WITH_POSITION(linenum_, lineoff_) \
1139 mReporter->OutputError(linenum_, lineoff_)
1141 #define CLEAR_ERROR() \
1142 mReporter->ClearError()
1144 CSSParserImpl::CSSParserImpl()
1148 mChildLoader(nullptr),
1149 mSection(eCSSSection_Charset
),
1150 mNameSpaceMap(nullptr),
1151 mHavePushBack(false),
1152 mNavQuirkMode(false),
1153 mHashlessColorQuirk(false),
1154 mUnitlessLengthQuirk(false),
1155 mUnsafeRulesEnabled(false),
1156 mIsChromeOrCertifiedApp(false),
1157 mViewportUnitsEnabled(true),
1158 mHTMLMediaMode(false),
1159 mParsingCompoundProperty(false),
1160 mInSupportsCondition(false),
1161 mInFailingSupportsRule(false),
1162 mSuppressErrors(false),
1167 CSSParserImpl::~CSSParserImpl()
1169 mData
.AssertInitialState();
1170 mTempData
.AssertInitialState();
1174 CSSParserImpl::SetStyleSheet(CSSStyleSheet
* aSheet
)
1176 if (aSheet
!= mSheet
) {
1177 // Switch to using the new sheet, if any
1178 mGroupStack
.Clear();
1181 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
1183 mNameSpaceMap
= nullptr;
1185 } else if (mSheet
) {
1186 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
1193 CSSParserImpl::SetQuirkMode(bool aQuirkMode
)
1195 mNavQuirkMode
= aQuirkMode
;
1200 CSSParserImpl::SetChildLoader(mozilla::css::Loader
* aChildLoader
)
1202 mChildLoader
= aChildLoader
; // not ref counted, it owns us
1207 CSSParserImpl::Reset()
1209 NS_ASSERTION(!mScanner
, "resetting with scanner active");
1210 SetStyleSheet(nullptr);
1211 SetQuirkMode(false);
1212 SetChildLoader(nullptr);
1216 CSSParserImpl::InitScanner(nsCSSScanner
& aScanner
,
1217 css::ErrorReporter
& aReporter
,
1218 nsIURI
* aSheetURI
, nsIURI
* aBaseURI
,
1219 nsIPrincipal
* aSheetPrincipal
)
1221 NS_PRECONDITION(!mHTMLMediaMode
, "Bad initial state");
1222 NS_PRECONDITION(!mParsingCompoundProperty
, "Bad initial state");
1223 NS_PRECONDITION(!mScanner
, "already have scanner");
1225 mScanner
= &aScanner
;
1226 mReporter
= &aReporter
;
1227 mScanner
->SetErrorReporter(mReporter
);
1229 mBaseURI
= aBaseURI
;
1230 mSheetURI
= aSheetURI
;
1231 mSheetPrincipal
= aSheetPrincipal
;
1232 mHavePushBack
= false;
1236 CSSParserImpl::ReleaseScanner()
1239 mReporter
= nullptr;
1241 mSheetURI
= nullptr;
1242 mSheetPrincipal
= nullptr;
1246 CSSParserImpl::ParseSheet(const nsAString
& aInput
,
1249 nsIPrincipal
* aSheetPrincipal
,
1250 uint32_t aLineNumber
,
1251 bool aAllowUnsafeRules
)
1253 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1254 NS_PRECONDITION(aBaseURI
, "need base URI");
1255 NS_PRECONDITION(aSheetURI
, "need sheet URI");
1256 NS_PRECONDITION(mSheet
, "Must have sheet to parse into");
1257 NS_ENSURE_STATE(mSheet
);
1260 nsIURI
* uri
= mSheet
->GetSheetURI();
1262 NS_ASSERTION(NS_SUCCEEDED(aSheetURI
->Equals(uri
, &equal
)) && equal
,
1263 "Sheet URI does not match passed URI");
1264 NS_ASSERTION(NS_SUCCEEDED(mSheet
->Principal()->Equals(aSheetPrincipal
,
1267 "Sheet principal does not match passed principal");
1270 nsCSSScanner
scanner(aInput
, aLineNumber
);
1271 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aSheetURI
);
1272 InitScanner(scanner
, reporter
, aSheetURI
, aBaseURI
, aSheetPrincipal
);
1274 int32_t ruleCount
= mSheet
->StyleRuleCount();
1275 if (0 < ruleCount
) {
1276 const css::Rule
* lastRule
= mSheet
->GetStyleRuleAt(ruleCount
- 1);
1278 switch (lastRule
->GetType()) {
1279 case css::Rule::CHARSET_RULE
:
1280 case css::Rule::IMPORT_RULE
:
1281 mSection
= eCSSSection_Import
;
1283 case css::Rule::NAMESPACE_RULE
:
1284 mSection
= eCSSSection_NameSpace
;
1287 mSection
= eCSSSection_General
;
1293 mSection
= eCSSSection_Charset
; // sheet is empty, any rules are fair
1296 mUnsafeRulesEnabled
= aAllowUnsafeRules
;
1297 mIsChromeOrCertifiedApp
=
1298 dom::IsChromeURI(aSheetURI
) ||
1299 aSheetPrincipal
->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED
;
1301 nsCSSToken
* tk
= &mToken
;
1303 // Get next non-whitespace token
1304 if (!GetToken(true)) {
1308 if (eCSSToken_HTMLComment
== tk
->mType
) {
1309 continue; // legal here only
1311 if (eCSSToken_AtKeyword
== tk
->mType
) {
1312 ParseAtRule(AppendRuleToSheet
, this, false);
1316 if (ParseRuleSet(AppendRuleToSheet
, this)) {
1317 mSection
= eCSSSection_General
;
1322 mUnsafeRulesEnabled
= false;
1323 mIsChromeOrCertifiedApp
= false;
1325 // XXX check for low level errors
1330 * Determines whether the identifier contained in the given string is a
1331 * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1.
1334 NonMozillaVendorIdentifier(const nsAString
& ident
)
1336 return (ident
.First() == char16_t('-') &&
1337 !StringBeginsWith(ident
, NS_LITERAL_STRING("-moz-"))) ||
1338 ident
.First() == char16_t('_');
1343 CSSParserImpl::ParseStyleAttribute(const nsAString
& aAttributeValue
,
1346 nsIPrincipal
* aNodePrincipal
,
1347 css::StyleRule
** aResult
)
1349 NS_PRECONDITION(aNodePrincipal
, "Must have principal here!");
1350 NS_PRECONDITION(aBaseURI
, "need base URI");
1353 nsCSSScanner
scanner(aAttributeValue
, 0);
1354 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aDocURI
);
1355 InitScanner(scanner
, reporter
, aDocURI
, aBaseURI
, aNodePrincipal
);
1357 mSection
= eCSSSection_General
;
1359 uint32_t parseFlags
= eParseDeclaration_AllowImportant
;
1361 css::Declaration
* declaration
= ParseDeclarationBlock(parseFlags
);
1363 // Create a style rule for the declaration
1364 NS_ADDREF(*aResult
= new css::StyleRule(nullptr, declaration
, 0, 0));
1371 // XXX check for low level errors
1376 CSSParserImpl::ParseDeclarations(const nsAString
& aBuffer
,
1379 nsIPrincipal
* aSheetPrincipal
,
1380 css::Declaration
* aDeclaration
,
1385 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1387 nsCSSScanner
scanner(aBuffer
, 0);
1388 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aSheetURI
);
1389 InitScanner(scanner
, reporter
, aSheetURI
, aBaseURI
, aSheetPrincipal
);
1391 mSection
= eCSSSection_General
;
1393 mData
.AssertInitialState();
1394 aDeclaration
->ClearData();
1395 // We could check if it was already empty, but...
1399 // If we cleared the old decl, then we want to be calling
1400 // ValueAppended as we parse.
1401 if (!ParseDeclaration(aDeclaration
, eParseDeclaration_AllowImportant
,
1403 if (!SkipDeclaration(false)) {
1409 aDeclaration
->CompressFrom(&mData
);
1415 CSSParserImpl::ParseRule(const nsAString
& aRule
,
1418 nsIPrincipal
* aSheetPrincipal
,
1419 css::Rule
** aResult
)
1421 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1422 NS_PRECONDITION(aBaseURI
, "need base URI");
1426 nsCSSScanner
scanner(aRule
, 0);
1427 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aSheetURI
);
1428 InitScanner(scanner
, reporter
, aSheetURI
, aBaseURI
, aSheetPrincipal
);
1430 mSection
= eCSSSection_Charset
; // callers are responsible for rejecting invalid rules.
1432 nsCSSToken
* tk
= &mToken
;
1433 // Get first non-whitespace token
1434 nsresult rv
= NS_OK
;
1435 if (!GetToken(true)) {
1436 REPORT_UNEXPECTED(PEParseRuleWSOnly
);
1438 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
1440 if (eCSSToken_AtKeyword
== tk
->mType
) {
1441 // FIXME: perhaps aInsideBlock should be true when we are?
1442 ParseAtRule(AssignRuleToPointer
, aResult
, false);
1445 ParseRuleSet(AssignRuleToPointer
, aResult
);
1448 if (*aResult
&& GetToken(true)) {
1449 // garbage after rule
1450 REPORT_UNEXPECTED_TOKEN(PERuleTrailing
);
1451 NS_RELEASE(*aResult
);
1455 rv
= NS_ERROR_DOM_SYNTAX_ERR
;
1466 #pragma optimize( "", off )
1467 #pragma warning( push )
1468 #pragma warning( disable : 4748 )
1472 CSSParserImpl::ParseProperty(const nsCSSProperty aPropID
,
1473 const nsAString
& aPropValue
,
1476 nsIPrincipal
* aSheetPrincipal
,
1477 css::Declaration
* aDeclaration
,
1482 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1483 NS_PRECONDITION(aBaseURI
, "need base URI");
1484 NS_PRECONDITION(aDeclaration
, "Need declaration to parse into!");
1485 MOZ_ASSERT(aPropID
!= eCSSPropertyExtra_variable
);
1487 mData
.AssertInitialState();
1488 mTempData
.AssertInitialState();
1489 aDeclaration
->AssertMutable();
1491 nsCSSScanner
scanner(aPropValue
, 0);
1492 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aSheetURI
);
1493 InitScanner(scanner
, reporter
, aSheetURI
, aBaseURI
, aSheetPrincipal
);
1494 mSection
= eCSSSection_General
;
1495 scanner
.SetSVGMode(aIsSVGMode
);
1499 // Check for unknown or preffed off properties
1500 if (eCSSProperty_UNKNOWN
== aPropID
||
1501 !(nsCSSProps::IsEnabled(aPropID
) ||
1502 (mUnsafeRulesEnabled
&&
1503 nsCSSProps::PropHasFlags(aPropID
,
1504 CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS
)))) {
1505 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1506 REPORT_UNEXPECTED_P(PEUnknownProperty
, propName
);
1507 REPORT_UNEXPECTED(PEDeclDropped
);
1513 bool parsedOK
= ParseProperty(aPropID
);
1514 // We should now be at EOF
1515 if (parsedOK
&& GetToken(true)) {
1516 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
1521 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropID
));
1522 REPORT_UNEXPECTED_P(PEValueParsingError
, propName
);
1523 REPORT_UNEXPECTED(PEDeclDropped
);
1525 mTempData
.ClearProperty(aPropID
);
1528 // We know we don't need to force a ValueAppended call for the new
1529 // value. So if we are not processing a shorthand, and there's
1530 // already a value for this property in the declaration at the
1531 // same importance level, then we can just copy our parsed value
1532 // directly into the declaration without going through the whole
1533 // expand/compress thing.
1534 if (!aDeclaration
->TryReplaceValue(aPropID
, aIsImportant
, mTempData
,
1536 // Do it the slow way
1537 aDeclaration
->ExpandTo(&mData
);
1538 *aChanged
= mData
.TransferFromBlock(mTempData
, aPropID
, aIsImportant
,
1539 true, false, aDeclaration
);
1540 aDeclaration
->CompressFrom(&mData
);
1545 mTempData
.AssertInitialState();
1552 CSSParserImpl::ParseVariable(const nsAString
& aVariableName
,
1553 const nsAString
& aPropValue
,
1556 nsIPrincipal
* aSheetPrincipal
,
1557 css::Declaration
* aDeclaration
,
1561 NS_PRECONDITION(aSheetPrincipal
, "Must have principal here!");
1562 NS_PRECONDITION(aBaseURI
, "need base URI");
1563 NS_PRECONDITION(aDeclaration
, "Need declaration to parse into!");
1564 NS_PRECONDITION(nsLayoutUtils::CSSVariablesEnabled(),
1565 "expected Variables to be enabled");
1567 mData
.AssertInitialState();
1568 mTempData
.AssertInitialState();
1569 aDeclaration
->AssertMutable();
1571 nsCSSScanner
scanner(aPropValue
, 0);
1572 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aSheetURI
);
1573 InitScanner(scanner
, reporter
, aSheetURI
, aBaseURI
, aSheetPrincipal
);
1574 mSection
= eCSSSection_General
;
1578 CSSVariableDeclarations::Type variableType
;
1579 nsString variableValue
;
1581 bool parsedOK
= ParseVariableDeclaration(&variableType
, variableValue
);
1583 // We should now be at EOF
1584 if (parsedOK
&& GetToken(true)) {
1585 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
1590 REPORT_UNEXPECTED_P(PEValueParsingError
, NS_LITERAL_STRING("--") +
1592 REPORT_UNEXPECTED(PEDeclDropped
);
1596 aDeclaration
->AddVariableDeclaration(aVariableName
, variableType
,
1597 variableValue
, aIsImportant
, true);
1601 mTempData
.AssertInitialState();
1608 #pragma warning( pop )
1609 #pragma optimize( "", on )
1613 CSSParserImpl::ParseMediaList(const nsSubstring
& aBuffer
,
1614 nsIURI
* aURI
, // for error reporting
1615 uint32_t aLineNumber
, // for error reporting
1616 nsMediaList
* aMediaList
,
1619 // XXX Are there cases where the caller wants to keep what it already
1620 // has in case of parser error? If GatherMedia ever changes to return
1621 // a value other than true, we probably should avoid modifying aMediaList.
1622 aMediaList
->Clear();
1624 // fake base URI since media lists don't have URIs in them
1625 nsCSSScanner
scanner(aBuffer
, aLineNumber
);
1626 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURI
);
1627 InitScanner(scanner
, reporter
, aURI
, aURI
, nullptr);
1629 mHTMLMediaMode
= aHTMLMode
;
1631 // XXXldb We need to make the scanner not skip CSS comments! (Or
1634 // For aHTMLMode, we used to follow the parsing rules in
1635 // http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors
1636 // which wouldn't work for media queries since they remove all but the
1637 // first word. However, they're changed in
1638 // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2
1639 // (as of 2008-05-29) which says that the media attribute just points
1640 // to a media query. (The main substative difference is the relative
1641 // precedence of commas and paretheses.)
1643 DebugOnly
<bool> parsedOK
= GatherMedia(aMediaList
, false);
1644 NS_ASSERTION(parsedOK
, "GatherMedia returned false; we probably want to avoid "
1645 "trashing aMediaList");
1649 mHTMLMediaMode
= false;
1652 // <source-size-list> = <source-size>#?
1653 // <source-size> = <media-condition>? <length>
1655 CSSParserImpl::ParseSourceSizeList(const nsAString
& aBuffer
,
1656 nsIURI
* aURI
, // for error reporting
1657 uint32_t aLineNumber
, // for error reporting
1658 InfallibleTArray
< nsAutoPtr
<nsMediaQuery
> >& aQueries
,
1659 InfallibleTArray
<nsCSSValue
>& aValues
,
1665 // fake base URI since media value lists don't have URIs in them
1666 nsCSSScanner
scanner(aBuffer
, aLineNumber
);
1667 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURI
);
1668 InitScanner(scanner
, reporter
, aURI
, aURI
, nullptr);
1670 // See ParseMediaList comment about HTML mode
1671 mHTMLMediaMode
= aHTMLMode
;
1673 bool hitError
= false;
1675 nsAutoPtr
<nsMediaQuery
> query
;
1679 if (!ParseMediaQuery(eMediaQuerySingleCondition
, getter_Transfers(query
),
1681 NS_ASSERTION(!hitStop
, "should return true when hit stop");
1687 REPORT_UNEXPECTED_EOF(PEParseSourceSizeListEOF
);
1688 NS_ASSERTION(hitStop
,
1689 "should return hitStop or an error if returning no query");
1695 // Empty conditions (e.g. just a bare value) should be treated as always
1696 // matching (a query with no expressions fails to match, so a negated one
1698 query
->SetNegated();
1701 if (!ParseNonNegativeVariant(value
, VARIANT_LPCALC
, nullptr)) {
1706 aQueries
.AppendElement(query
.forget());
1707 aValues
.AppendElement(value
);
1709 if (!GetToken(true)) {
1714 if (eCSSToken_Symbol
!= mToken
.mType
|| mToken
.mSymbol
!= ',') {
1715 REPORT_UNEXPECTED_TOKEN(PEParseSourceSizeListNotComma
);
1722 // Per spec, a parse failure in this list invalidates it
1723 // entirely. Currently, this grammar is specified standalone and not part of
1724 // any larger grammar, so it doesn't make sense to try to advance the token
1731 mHTMLMediaMode
= false;
1737 CSSParserImpl::ParseColorString(const nsSubstring
& aBuffer
,
1738 nsIURI
* aURI
, // for error reporting
1739 uint32_t aLineNumber
, // for error reporting
1741 bool aSuppressErrors
/* false */)
1743 nsCSSScanner
scanner(aBuffer
, aLineNumber
);
1744 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURI
);
1745 InitScanner(scanner
, reporter
, aURI
, aURI
, nullptr);
1747 nsAutoSuppressErrors
suppressErrors(this, aSuppressErrors
);
1749 // Parse a color, and check that there's nothing else after it.
1750 bool colorParsed
= ParseColor(aValue
) && !GetToken(true);
1752 if (aSuppressErrors
) {
1763 CSSParserImpl::ParseFontFamilyListString(const nsSubstring
& aBuffer
,
1764 nsIURI
* aURI
, // for error reporting
1765 uint32_t aLineNumber
, // for error reporting
1768 nsCSSScanner
scanner(aBuffer
, aLineNumber
);
1769 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURI
);
1770 InitScanner(scanner
, reporter
, aURI
, aURI
, nullptr);
1772 // Parse a font family list, and check that there's nothing else after it.
1773 bool familyParsed
= ParseFamily(aValue
) && !GetToken(true);
1776 return familyParsed
;
1780 CSSParserImpl::ParseSelectorString(const nsSubstring
& aSelectorString
,
1781 nsIURI
* aURI
, // for error reporting
1782 uint32_t aLineNumber
, // for error reporting
1783 nsCSSSelectorList
**aSelectorList
)
1785 nsCSSScanner
scanner(aSelectorString
, aLineNumber
);
1786 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURI
);
1787 InitScanner(scanner
, reporter
, aURI
, aURI
, nullptr);
1789 bool success
= ParseSelectorList(*aSelectorList
, char16_t(0));
1791 // We deliberately do not call OUTPUT_ERROR here, because all our
1792 // callers map a failure return to a JS exception, and if that JS
1793 // exception is caught, people don't want to see parser diagnostics;
1794 // see e.g. http://bugs.jquery.com/ticket/7535
1795 // It would be nice to be able to save the parser diagnostics into
1796 // the exception, so that if it _isn't_ caught we can report them
1797 // along with the usual uncaught-exception message, but we don't
1798 // have any way to do that at present; see bug 631621.
1803 NS_ASSERTION(*aSelectorList
, "Should have list!");
1807 NS_ASSERTION(!*aSelectorList
, "Shouldn't have list!");
1809 return NS_ERROR_DOM_SYNTAX_ERR
;
1813 already_AddRefed
<nsCSSKeyframeRule
>
1814 CSSParserImpl::ParseKeyframeRule(const nsSubstring
& aBuffer
,
1816 uint32_t aLineNumber
)
1818 nsCSSScanner
scanner(aBuffer
, aLineNumber
);
1819 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURI
);
1820 InitScanner(scanner
, reporter
, aURI
, aURI
, nullptr);
1822 nsRefPtr
<nsCSSKeyframeRule
> result
= ParseKeyframeRule();
1823 if (GetToken(true)) {
1824 // extra garbage at the end
1831 return result
.forget();
1835 CSSParserImpl::ParseKeyframeSelectorString(const nsSubstring
& aSelectorString
,
1836 nsIURI
* aURI
, // for error reporting
1837 uint32_t aLineNumber
, // for error reporting
1838 InfallibleTArray
<float>& aSelectorList
)
1840 NS_ABORT_IF_FALSE(aSelectorList
.IsEmpty(), "given list should start empty");
1842 nsCSSScanner
scanner(aSelectorString
, aLineNumber
);
1843 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURI
);
1844 InitScanner(scanner
, reporter
, aURI
, aURI
, nullptr);
1846 bool success
= ParseKeyframeSelectorList(aSelectorList
) &&
1847 // must consume entire input string
1854 NS_ASSERTION(!aSelectorList
.IsEmpty(), "should not be empty");
1856 aSelectorList
.Clear();
1863 CSSParserImpl::EvaluateSupportsDeclaration(const nsAString
& aProperty
,
1864 const nsAString
& aValue
,
1867 nsIPrincipal
* aDocPrincipal
)
1869 nsCSSProperty propID
= LookupEnabledProperty(aProperty
);
1870 if (propID
== eCSSProperty_UNKNOWN
) {
1874 nsCSSScanner
scanner(aValue
, 0);
1875 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aDocURL
);
1876 InitScanner(scanner
, reporter
, aDocURL
, aBaseURL
, aDocPrincipal
);
1877 nsAutoSuppressErrors
suppressErrors(this);
1881 if (propID
== eCSSPropertyExtra_variable
) {
1882 MOZ_ASSERT(Substring(aProperty
, 0,
1883 CSS_CUSTOM_NAME_PREFIX_LENGTH
).EqualsLiteral("--"));
1884 const nsDependentSubstring varName
=
1885 Substring(aProperty
, CSS_CUSTOM_NAME_PREFIX_LENGTH
); // remove '--'
1886 CSSVariableDeclarations::Type variableType
;
1887 nsString variableValue
;
1888 parsedOK
= ParseVariableDeclaration(&variableType
, variableValue
) &&
1891 parsedOK
= ParseProperty(propID
) && !GetToken(true);
1893 mTempData
.ClearProperty(propID
);
1894 mTempData
.AssertInitialState();
1904 CSSParserImpl::EvaluateSupportsCondition(const nsAString
& aDeclaration
,
1907 nsIPrincipal
* aDocPrincipal
)
1909 nsCSSScanner
scanner(aDeclaration
, 0);
1910 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aDocURL
);
1911 InitScanner(scanner
, reporter
, aDocURL
, aBaseURL
, aDocPrincipal
);
1912 nsAutoSuppressErrors
suppressErrors(this);
1915 bool parsedOK
= ParseSupportsCondition(conditionMet
) && !GetToken(true);
1920 return parsedOK
&& conditionMet
;
1924 CSSParserImpl::EnumerateVariableReferences(const nsAString
& aPropertyValue
,
1925 VariableEnumFunc aFunc
,
1928 nsCSSScanner
scanner(aPropertyValue
, 0);
1929 css::ErrorReporter
reporter(scanner
, nullptr, nullptr, nullptr);
1930 InitScanner(scanner
, reporter
, nullptr, nullptr, nullptr);
1931 nsAutoSuppressErrors
suppressErrors(this);
1933 CSSVariableDeclarations::Type type
;
1935 nsString impliedCharacters
;
1936 bool result
= ParseValueWithVariables(&type
, &dropBackslash
,
1937 impliedCharacters
, aFunc
, aData
) &&
1946 SeparatorRequiredBetweenTokens(nsCSSTokenSerializationType aToken1
,
1947 nsCSSTokenSerializationType aToken2
)
1949 // The two lines marked with (*) do not correspond to entries in
1950 // the table in the css-syntax spec but which we need to handle,
1951 // as we treat them as whole tokens.
1953 case eCSSTokenSerialization_Ident
:
1954 return aToken2
== eCSSTokenSerialization_Ident
||
1955 aToken2
== eCSSTokenSerialization_Function
||
1956 aToken2
== eCSSTokenSerialization_URL_or_BadURL
||
1957 aToken2
== eCSSTokenSerialization_Symbol_Minus
||
1958 aToken2
== eCSSTokenSerialization_Number
||
1959 aToken2
== eCSSTokenSerialization_Percentage
||
1960 aToken2
== eCSSTokenSerialization_Dimension
||
1961 aToken2
== eCSSTokenSerialization_URange
||
1962 aToken2
== eCSSTokenSerialization_CDC
||
1963 aToken2
== eCSSTokenSerialization_Symbol_OpenParen
;
1964 case eCSSTokenSerialization_AtKeyword_or_Hash
:
1965 case eCSSTokenSerialization_Dimension
:
1966 return aToken2
== eCSSTokenSerialization_Ident
||
1967 aToken2
== eCSSTokenSerialization_Function
||
1968 aToken2
== eCSSTokenSerialization_URL_or_BadURL
||
1969 aToken2
== eCSSTokenSerialization_Symbol_Minus
||
1970 aToken2
== eCSSTokenSerialization_Number
||
1971 aToken2
== eCSSTokenSerialization_Percentage
||
1972 aToken2
== eCSSTokenSerialization_Dimension
||
1973 aToken2
== eCSSTokenSerialization_URange
||
1974 aToken2
== eCSSTokenSerialization_CDC
;
1975 case eCSSTokenSerialization_Symbol_Hash
:
1976 return aToken2
== eCSSTokenSerialization_Ident
||
1977 aToken2
== eCSSTokenSerialization_Function
||
1978 aToken2
== eCSSTokenSerialization_URL_or_BadURL
||
1979 aToken2
== eCSSTokenSerialization_Symbol_Minus
||
1980 aToken2
== eCSSTokenSerialization_Number
||
1981 aToken2
== eCSSTokenSerialization_Percentage
||
1982 aToken2
== eCSSTokenSerialization_Dimension
||
1983 aToken2
== eCSSTokenSerialization_URange
;
1984 case eCSSTokenSerialization_Symbol_Minus
:
1985 case eCSSTokenSerialization_Number
:
1986 return aToken2
== eCSSTokenSerialization_Ident
||
1987 aToken2
== eCSSTokenSerialization_Function
||
1988 aToken2
== eCSSTokenSerialization_URL_or_BadURL
||
1989 aToken2
== eCSSTokenSerialization_Number
||
1990 aToken2
== eCSSTokenSerialization_Percentage
||
1991 aToken2
== eCSSTokenSerialization_Dimension
||
1992 aToken2
== eCSSTokenSerialization_URange
;
1993 case eCSSTokenSerialization_Symbol_At
:
1994 return aToken2
== eCSSTokenSerialization_Ident
||
1995 aToken2
== eCSSTokenSerialization_Function
||
1996 aToken2
== eCSSTokenSerialization_URL_or_BadURL
||
1997 aToken2
== eCSSTokenSerialization_Symbol_Minus
||
1998 aToken2
== eCSSTokenSerialization_URange
;
1999 case eCSSTokenSerialization_URange
:
2000 return aToken2
== eCSSTokenSerialization_Ident
||
2001 aToken2
== eCSSTokenSerialization_Function
||
2002 aToken2
== eCSSTokenSerialization_Number
||
2003 aToken2
== eCSSTokenSerialization_Percentage
||
2004 aToken2
== eCSSTokenSerialization_Dimension
||
2005 aToken2
== eCSSTokenSerialization_Symbol_Question
;
2006 case eCSSTokenSerialization_Symbol_Dot_or_Plus
:
2007 return aToken2
== eCSSTokenSerialization_Number
||
2008 aToken2
== eCSSTokenSerialization_Percentage
||
2009 aToken2
== eCSSTokenSerialization_Dimension
;
2010 case eCSSTokenSerialization_Symbol_Assorted
:
2011 case eCSSTokenSerialization_Symbol_Asterisk
:
2012 return aToken2
== eCSSTokenSerialization_Symbol_Equals
;
2013 case eCSSTokenSerialization_Symbol_Bar
:
2014 return aToken2
== eCSSTokenSerialization_Symbol_Equals
||
2015 aToken2
== eCSSTokenSerialization_Symbol_Bar
||
2016 aToken2
== eCSSTokenSerialization_DashMatch
; // (*)
2017 case eCSSTokenSerialization_Symbol_Slash
:
2018 return aToken2
== eCSSTokenSerialization_Symbol_Asterisk
||
2019 aToken2
== eCSSTokenSerialization_ContainsMatch
; // (*)
2021 MOZ_ASSERT(aToken1
== eCSSTokenSerialization_Nothing
||
2022 aToken1
== eCSSTokenSerialization_Whitespace
||
2023 aToken1
== eCSSTokenSerialization_Percentage
||
2024 aToken1
== eCSSTokenSerialization_URL_or_BadURL
||
2025 aToken1
== eCSSTokenSerialization_Function
||
2026 aToken1
== eCSSTokenSerialization_CDC
||
2027 aToken1
== eCSSTokenSerialization_Symbol_OpenParen
||
2028 aToken1
== eCSSTokenSerialization_Symbol_Question
||
2029 aToken1
== eCSSTokenSerialization_Symbol_Assorted
||
2030 aToken1
== eCSSTokenSerialization_Symbol_Asterisk
||
2031 aToken1
== eCSSTokenSerialization_Symbol_Equals
||
2032 aToken1
== eCSSTokenSerialization_Symbol_Bar
||
2033 aToken1
== eCSSTokenSerialization_Symbol_Slash
||
2034 aToken1
== eCSSTokenSerialization_Other
||
2035 "unexpected nsCSSTokenSerializationType value");
2041 * Appends aValue to aResult, possibly inserting an empty CSS
2042 * comment between the two to ensure that tokens from both strings
2046 AppendTokens(nsAString
& aResult
,
2047 nsCSSTokenSerializationType
& aResultFirstToken
,
2048 nsCSSTokenSerializationType
& aResultLastToken
,
2049 nsCSSTokenSerializationType aValueFirstToken
,
2050 nsCSSTokenSerializationType aValueLastToken
,
2051 const nsAString
& aValue
)
2053 if (SeparatorRequiredBetweenTokens(aResultLastToken
, aValueFirstToken
)) {
2054 aResult
.AppendLiteral("/**/");
2056 aResult
.Append(aValue
);
2057 if (aResultFirstToken
== eCSSTokenSerialization_Nothing
) {
2058 aResultFirstToken
= aValueFirstToken
;
2060 if (aValueLastToken
!= eCSSTokenSerialization_Nothing
) {
2061 aResultLastToken
= aValueLastToken
;
2066 * Stops the given scanner recording, and appends the recorded result
2067 * to aResult, possibly inserting an empty CSS comment between the two to
2068 * ensure that tokens from both strings remain separated.
2071 StopRecordingAndAppendTokens(nsString
& aResult
,
2072 nsCSSTokenSerializationType
& aResultFirstToken
,
2073 nsCSSTokenSerializationType
& aResultLastToken
,
2074 nsCSSTokenSerializationType aValueFirstToken
,
2075 nsCSSTokenSerializationType aValueLastToken
,
2076 nsCSSScanner
* aScanner
)
2078 if (SeparatorRequiredBetweenTokens(aResultLastToken
, aValueFirstToken
)) {
2079 aResult
.AppendLiteral("/**/");
2081 aScanner
->StopRecording(aResult
);
2082 if (aResultFirstToken
== eCSSTokenSerialization_Nothing
) {
2083 aResultFirstToken
= aValueFirstToken
;
2085 if (aValueLastToken
!= eCSSTokenSerialization_Nothing
) {
2086 aResultLastToken
= aValueLastToken
;
2091 CSSParserImpl::ResolveValueWithVariableReferencesRec(
2093 nsCSSTokenSerializationType
& aResultFirstToken
,
2094 nsCSSTokenSerializationType
& aResultLastToken
,
2095 const CSSVariableValues
* aVariables
)
2097 // This function assumes we are already recording, and will leave the scanner
2098 // recording when it returns.
2099 MOZ_ASSERT(mScanner
->IsRecording());
2100 MOZ_ASSERT(aResult
.IsEmpty());
2102 // Stack of closing characters for currently open constructs.
2103 nsAutoTArray
<char16_t
, 16> stack
;
2105 // The resolved value for this ResolveValueWithVariableReferencesRec call.
2108 // The length of the scanner's recording before the currently parsed token.
2109 // This is used so that when we encounter a "var(" token, we can strip
2110 // it off the end of the recording, regardless of how long the token was.
2111 // (With escapes, it could be longer than four characters.)
2112 uint32_t lengthBeforeVar
= 0;
2114 // Tracking the type of token that appears at the start and end of |value|
2115 // and that appears at the start and end of the scanner recording. These are
2116 // used to determine whether we need to insert "/**/" when pasting token
2117 // streams together.
2118 nsCSSTokenSerializationType valueFirstToken
= eCSSTokenSerialization_Nothing
,
2119 valueLastToken
= eCSSTokenSerialization_Nothing
,
2120 recFirstToken
= eCSSTokenSerialization_Nothing
,
2121 recLastToken
= eCSSTokenSerialization_Nothing
;
2123 #define UPDATE_RECORDING_TOKENS(type) \
2124 if (recFirstToken == eCSSTokenSerialization_Nothing) { \
2125 recFirstToken = type; \
2127 recLastToken = type;
2129 while (GetToken(false)) {
2130 switch (mToken
.mType
) {
2131 case eCSSToken_Symbol
: {
2132 nsCSSTokenSerializationType type
= eCSSTokenSerialization_Other
;
2133 if (mToken
.mSymbol
== '(') {
2134 stack
.AppendElement(')');
2135 type
= eCSSTokenSerialization_Symbol_OpenParen
;
2136 } else if (mToken
.mSymbol
== '[') {
2137 stack
.AppendElement(']');
2138 } else if (mToken
.mSymbol
== '{') {
2139 stack
.AppendElement('}');
2140 } else if (mToken
.mSymbol
== ';') {
2141 if (stack
.IsEmpty()) {
2142 // A ';' that is at the top level of the value or at the top level
2143 // of a variable reference's fallback is invalid.
2146 } else if (mToken
.mSymbol
== '!') {
2147 if (stack
.IsEmpty()) {
2148 // An '!' that is at the top level of the value or at the top level
2149 // of a variable reference's fallback is invalid.
2152 } else if (mToken
.mSymbol
== ')' &&
2154 // We're closing a "var(".
2155 nsString finalTokens
;
2156 mScanner
->StopRecording(finalTokens
);
2157 MOZ_ASSERT(finalTokens
[finalTokens
.Length() - 1] == ')');
2158 finalTokens
.Truncate(finalTokens
.Length() - 1);
2159 aResult
.Append(value
);
2161 AppendTokens(aResult
, valueFirstToken
, valueLastToken
,
2162 recFirstToken
, recLastToken
, finalTokens
);
2164 mScanner
->StartRecording();
2166 aResultFirstToken
= valueFirstToken
;
2167 aResultLastToken
= valueLastToken
;
2169 } else if (mToken
.mSymbol
== ')' ||
2170 mToken
.mSymbol
== ']' ||
2171 mToken
.mSymbol
== '}') {
2172 if (stack
.IsEmpty() ||
2173 stack
.LastElement() != mToken
.mSymbol
) {
2174 // A mismatched closing bracket is invalid.
2177 stack
.TruncateLength(stack
.Length() - 1);
2178 } else if (mToken
.mSymbol
== '#') {
2179 type
= eCSSTokenSerialization_Symbol_Hash
;
2180 } else if (mToken
.mSymbol
== '@') {
2181 type
= eCSSTokenSerialization_Symbol_At
;
2182 } else if (mToken
.mSymbol
== '.' ||
2183 mToken
.mSymbol
== '+') {
2184 type
= eCSSTokenSerialization_Symbol_Dot_or_Plus
;
2185 } else if (mToken
.mSymbol
== '-') {
2186 type
= eCSSTokenSerialization_Symbol_Minus
;
2187 } else if (mToken
.mSymbol
== '?') {
2188 type
= eCSSTokenSerialization_Symbol_Question
;
2189 } else if (mToken
.mSymbol
== '$' ||
2190 mToken
.mSymbol
== '^' ||
2191 mToken
.mSymbol
== '~') {
2192 type
= eCSSTokenSerialization_Symbol_Assorted
;
2193 } else if (mToken
.mSymbol
== '=') {
2194 type
= eCSSTokenSerialization_Symbol_Equals
;
2195 } else if (mToken
.mSymbol
== '|') {
2196 type
= eCSSTokenSerialization_Symbol_Bar
;
2197 } else if (mToken
.mSymbol
== '/') {
2198 type
= eCSSTokenSerialization_Symbol_Slash
;
2199 } else if (mToken
.mSymbol
== '*') {
2200 type
= eCSSTokenSerialization_Symbol_Asterisk
;
2202 UPDATE_RECORDING_TOKENS(type
);
2206 case eCSSToken_Function
:
2207 if (mToken
.mIdent
.LowerCaseEqualsLiteral("var")) {
2208 // Save the tokens before the "var(" to our resolved value.
2210 mScanner
->StopRecording(recording
);
2211 recording
.Truncate(lengthBeforeVar
);
2212 AppendTokens(value
, valueFirstToken
, valueLastToken
,
2213 recFirstToken
, recLastToken
, recording
);
2214 recFirstToken
= eCSSTokenSerialization_Nothing
;
2215 recLastToken
= eCSSTokenSerialization_Nothing
;
2217 if (!GetToken(true) ||
2218 mToken
.mType
!= eCSSToken_Ident
||
2219 !nsCSSProps::IsCustomPropertyName(mToken
.mIdent
)) {
2220 // "var(" must be followed by an identifier, and it must be a
2221 // custom property name.
2225 // Turn the custom property name into a variable name by removing the
2227 MOZ_ASSERT(Substring(mToken
.mIdent
, 0,
2228 CSS_CUSTOM_NAME_PREFIX_LENGTH
).
2229 EqualsLiteral("--"));
2230 nsDependentString
variableName(mToken
.mIdent
,
2231 CSS_CUSTOM_NAME_PREFIX_LENGTH
);
2233 // Get the value of the identified variable. Note that we
2234 // check if the variable value is the empty string, as that means
2235 // that the variable was invalid at computed value time due to
2236 // unresolveable variable references or cycles.
2237 nsString variableValue
;
2238 nsCSSTokenSerializationType varFirstToken
, varLastToken
;
2239 bool valid
= aVariables
->Get(variableName
, variableValue
,
2240 varFirstToken
, varLastToken
) &&
2241 !variableValue
.IsEmpty();
2243 if (!GetToken(true) ||
2244 mToken
.IsSymbol(')')) {
2245 mScanner
->StartRecording();
2247 // Invalid variable with no fallback.
2250 // Valid variable with no fallback.
2251 AppendTokens(value
, valueFirstToken
, valueLastToken
,
2252 varFirstToken
, varLastToken
, variableValue
);
2253 } else if (mToken
.IsSymbol(',')) {
2254 mScanner
->StartRecording();
2255 if (!GetToken(false) ||
2256 mToken
.IsSymbol(')')) {
2257 // Comma must be followed by at least one fallback token.
2262 // Valid variable with ignored fallback.
2263 mScanner
->StopRecording();
2264 AppendTokens(value
, valueFirstToken
, valueLastToken
,
2265 varFirstToken
, varLastToken
, variableValue
);
2266 bool ok
= SkipBalancedContentUntil(')');
2267 mScanner
->StartRecording();
2273 if (!ResolveValueWithVariableReferencesRec(fallback
,
2277 // Fallback value had invalid tokens or an invalid variable reference
2278 // that itself had no fallback.
2281 AppendTokens(value
, valueFirstToken
, valueLastToken
,
2282 varFirstToken
, varLastToken
, fallback
);
2283 // Now we're either at the pushed back ')' that finished the
2284 // fallback or at EOF.
2285 DebugOnly
<bool> gotToken
= GetToken(false);
2286 MOZ_ASSERT(!gotToken
|| mToken
.IsSymbol(')'));
2289 // Expected ',' or ')' after the variable name.
2290 mScanner
->StartRecording();
2294 stack
.AppendElement(')');
2295 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Function
);
2299 case eCSSToken_Bad_String
:
2300 case eCSSToken_Bad_URL
:
2303 case eCSSToken_Whitespace
:
2304 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Whitespace
);
2307 case eCSSToken_AtKeyword
:
2308 case eCSSToken_Hash
:
2309 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_AtKeyword_or_Hash
);
2312 case eCSSToken_Number
:
2313 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Number
);
2316 case eCSSToken_Dimension
:
2317 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Dimension
);
2320 case eCSSToken_Ident
:
2321 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Ident
);
2324 case eCSSToken_Percentage
:
2325 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Percentage
);
2328 case eCSSToken_URange
:
2329 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_URange
);
2333 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_URL_or_BadURL
);
2336 case eCSSToken_HTMLComment
:
2337 if (mToken
.mIdent
[0] == '-') {
2338 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_CDC
);
2340 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Other
);
2344 case eCSSToken_Dashmatch
:
2345 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_DashMatch
);
2348 case eCSSToken_Containsmatch
:
2349 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_ContainsMatch
);
2353 NS_NOTREACHED("unexpected token type");
2356 case eCSSToken_String
:
2357 case eCSSToken_Includes
:
2358 case eCSSToken_Beginsmatch
:
2359 case eCSSToken_Endsmatch
:
2360 UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Other
);
2364 lengthBeforeVar
= mScanner
->RecordingLength();
2367 #undef UPDATE_RECORDING_TOKENS
2369 aResult
.Append(value
);
2370 StopRecordingAndAppendTokens(aResult
, valueFirstToken
, valueLastToken
,
2371 recFirstToken
, recLastToken
, mScanner
);
2373 // Append any implicitly closed brackets.
2374 if (!stack
.IsEmpty()) {
2376 aResult
.Append(stack
.LastElement());
2377 stack
.TruncateLength(stack
.Length() - 1);
2378 } while (!stack
.IsEmpty());
2379 valueLastToken
= eCSSTokenSerialization_Other
;
2382 mScanner
->StartRecording();
2383 aResultFirstToken
= valueFirstToken
;
2384 aResultLastToken
= valueLastToken
;
2389 CSSParserImpl::ResolveValueWithVariableReferences(
2390 const CSSVariableValues
* aVariables
,
2392 nsCSSTokenSerializationType
& aFirstToken
,
2393 nsCSSTokenSerializationType
& aLastToken
)
2395 aResult
.Truncate(0);
2397 // Start recording before we read the first token.
2398 mScanner
->StartRecording();
2400 if (!GetToken(false)) {
2401 // Value was empty since we reached EOF.
2402 mScanner
->StopRecording();
2409 nsCSSTokenSerializationType firstToken
, lastToken
;
2410 bool ok
= ResolveValueWithVariableReferencesRec(value
, firstToken
, lastToken
, aVariables
) &&
2413 mScanner
->StopRecording();
2417 aFirstToken
= firstToken
;
2418 aLastToken
= lastToken
;
2424 CSSParserImpl::ResolveVariableValue(const nsAString
& aPropertyValue
,
2425 const CSSVariableValues
* aVariables
,
2427 nsCSSTokenSerializationType
& aFirstToken
,
2428 nsCSSTokenSerializationType
& aLastToken
)
2430 nsCSSScanner
scanner(aPropertyValue
, 0);
2432 // At this point, we know that aPropertyValue is syntactically correct
2433 // for a token stream that has variable references. We also won't be
2434 // interpreting any of the stream as we parse it, apart from expanding
2435 // var() references, so we don't need a base URL etc. or any useful
2437 css::ErrorReporter
reporter(scanner
, nullptr, nullptr, nullptr);
2438 InitScanner(scanner
, reporter
, nullptr, nullptr, nullptr);
2440 bool valid
= ResolveValueWithVariableReferences(aVariables
, aResult
,
2441 aFirstToken
, aLastToken
);
2448 CSSParserImpl::ParsePropertyWithVariableReferences(
2449 nsCSSProperty aPropertyID
,
2450 nsCSSProperty aShorthandPropertyID
,
2451 const nsAString
& aValue
,
2452 const CSSVariableValues
* aVariables
,
2453 nsRuleData
* aRuleData
,
2456 nsIPrincipal
* aDocPrincipal
,
2457 CSSStyleSheet
* aSheet
,
2458 uint32_t aLineNumber
,
2459 uint32_t aLineOffset
)
2461 mTempData
.AssertInitialState();
2464 nsString expandedValue
;
2466 // Resolve any variable references in the property value.
2468 nsCSSScanner
scanner(aValue
, 0);
2469 css::ErrorReporter
reporter(scanner
, aSheet
, mChildLoader
, aDocURL
);
2470 InitScanner(scanner
, reporter
, aDocURL
, aBaseURL
, aDocPrincipal
);
2472 nsCSSTokenSerializationType firstToken
, lastToken
;
2473 valid
= ResolveValueWithVariableReferences(aVariables
, expandedValue
,
2474 firstToken
, lastToken
);
2476 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(aPropertyID
));
2477 REPORT_UNEXPECTED(PEInvalidVariableReference
);
2478 REPORT_UNEXPECTED_P(PEValueParsingError
, propName
);
2479 if (nsCSSProps::IsInherited(aPropertyID
)) {
2480 REPORT_UNEXPECTED(PEValueWithVariablesFallbackInherit
);
2482 REPORT_UNEXPECTED(PEValueWithVariablesFallbackInitial
);
2484 OUTPUT_ERROR_WITH_POSITION(aLineNumber
, aLineOffset
);
2489 nsCSSProperty propertyToParse
=
2490 aShorthandPropertyID
!= eCSSProperty_UNKNOWN
? aShorthandPropertyID
:
2493 // Parse the property with that resolved value.
2495 nsCSSScanner
scanner(expandedValue
, 0);
2496 css::ErrorReporter
reporter(scanner
, aSheet
, mChildLoader
, aDocURL
);
2497 InitScanner(scanner
, reporter
, aDocURL
, aBaseURL
, aDocPrincipal
);
2498 valid
= ParseProperty(propertyToParse
);
2499 if (valid
&& GetToken(true)) {
2500 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
2504 NS_ConvertASCIItoUTF16
propName(nsCSSProps::GetStringValue(
2506 REPORT_UNEXPECTED_P(PEValueWithVariablesParsingError
, propName
);
2507 if (nsCSSProps::IsInherited(aPropertyID
)) {
2508 REPORT_UNEXPECTED(PEValueWithVariablesFallbackInherit
);
2510 REPORT_UNEXPECTED(PEValueWithVariablesFallbackInitial
);
2512 OUTPUT_ERROR_WITH_POSITION(aLineNumber
, aLineOffset
);
2517 // If the property could not be parsed with the resolved value, then we
2518 // treat it as if the value were 'initial' or 'inherit', depending on whether
2519 // the property is an inherited property.
2521 nsCSSValue defaultValue
;
2522 if (nsCSSProps::IsInherited(aPropertyID
)) {
2523 defaultValue
.SetInheritValue();
2525 defaultValue
.SetInitialValue();
2527 mTempData
.AddLonghandProperty(aPropertyID
, defaultValue
);
2530 // Copy the property value into the rule data.
2531 mTempData
.MapRuleInfoInto(aPropertyID
, aRuleData
);
2533 mTempData
.ClearProperty(propertyToParse
);
2534 mTempData
.AssertInitialState();
2538 CSSParserImpl::ParseCounterStyleName(const nsAString
& aBuffer
,
2542 nsCSSScanner
scanner(aBuffer
, 0);
2543 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aURL
);
2544 InitScanner(scanner
, reporter
, aURL
, aURL
, nullptr);
2546 bool success
= ParseCounterStyleName(aName
, true) && !GetToken(true);
2555 CSSParserImpl::ParseCounterDescriptor(nsCSSCounterDesc aDescID
,
2556 const nsAString
& aBuffer
,
2559 nsIPrincipal
* aSheetPrincipal
,
2562 nsCSSScanner
scanner(aBuffer
, 0);
2563 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aSheetURL
);
2564 InitScanner(scanner
, reporter
, aSheetURL
, aBaseURL
, aSheetPrincipal
);
2566 bool success
= ParseCounterDescriptorValue(aDescID
, aValue
) &&
2576 CSSParserImpl::ParseFontFaceDescriptor(nsCSSFontDesc aDescID
,
2577 const nsAString
& aBuffer
,
2580 nsIPrincipal
* aSheetPrincipal
,
2583 nsCSSScanner
scanner(aBuffer
, 0);
2584 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, aSheetURL
);
2585 InitScanner(scanner
, reporter
, aSheetURL
, aBaseURL
, aSheetPrincipal
);
2587 bool success
= ParseFontDescriptorValue(aDescID
, aValue
) &&
2596 //----------------------------------------------------------------------
2599 CSSParserImpl::GetToken(bool aSkipWS
)
2601 if (mHavePushBack
) {
2602 mHavePushBack
= false;
2603 if (!aSkipWS
|| mToken
.mType
!= eCSSToken_Whitespace
) {
2607 return mScanner
->Next(mToken
, aSkipWS
);
2611 CSSParserImpl::UngetToken()
2613 NS_PRECONDITION(!mHavePushBack
, "double pushback");
2614 mHavePushBack
= true;
2618 CSSParserImpl::GetNextTokenLocation(bool aSkipWS
, uint32_t *linenum
, uint32_t *colnum
)
2620 // Peek at next token so that mScanner updates line and column vals
2621 if (!GetToken(aSkipWS
)) {
2625 // The scanner uses one-indexing for line numbers but zero-indexing
2626 // for column numbers.
2627 *linenum
= mScanner
->GetLineNumber();
2628 *colnum
= 1 + mScanner
->GetColumnNumber();
2633 CSSParserImpl::ExpectSymbol(char16_t aSymbol
,
2636 if (!GetToken(aSkipWS
)) {
2637 // CSS2.1 specifies that all "open constructs" are to be closed at
2638 // EOF. It simplifies higher layers if we claim to have found an
2639 // ), ], }, or ; if we encounter EOF while looking for one of them.
2640 // Do still issue a diagnostic, to aid debugging.
2641 if (aSymbol
== ')' || aSymbol
== ']' ||
2642 aSymbol
== '}' || aSymbol
== ';') {
2643 REPORT_UNEXPECTED_EOF_CHAR(aSymbol
);
2649 if (mToken
.IsSymbol(aSymbol
)) {
2656 // Checks to see if we're at the end of a property. If an error occurs during
2657 // the check, does not signal a parse error.
2659 CSSParserImpl::CheckEndProperty()
2661 if (!GetToken(true)) {
2662 return true; // properties may end with eof
2664 if ((eCSSToken_Symbol
== mToken
.mType
) &&
2665 ((';' == mToken
.mSymbol
) ||
2666 ('!' == mToken
.mSymbol
) ||
2667 ('}' == mToken
.mSymbol
) ||
2668 (')' == mToken
.mSymbol
))) {
2669 // XXX need to verify that ! is only followed by "important [;|}]
2670 // XXX this requires a multi-token pushback buffer
2678 // Checks if we're at the end of a property, raising an error if we're not.
2680 CSSParserImpl::ExpectEndProperty()
2682 if (CheckEndProperty())
2685 // If we're here, we read something incorrect, so we should report it.
2686 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
2690 // Parses the priority suffix on a property, which at present may be
2691 // either '!important' or nothing.
2692 CSSParserImpl::PriorityParsingStatus
2693 CSSParserImpl::ParsePriority()
2695 if (!GetToken(true)) {
2696 return ePriority_None
; // properties may end with EOF
2698 if (!mToken
.IsSymbol('!')) {
2700 return ePriority_None
; // dunno what it is, but it's not a priority
2703 if (!GetToken(true)) {
2704 // EOF is not ok after !
2705 REPORT_UNEXPECTED_EOF(PEImportantEOF
);
2706 return ePriority_Error
;
2709 if (mToken
.mType
!= eCSSToken_Ident
||
2710 !mToken
.mIdent
.LowerCaseEqualsLiteral("important")) {
2711 REPORT_UNEXPECTED_TOKEN(PEExpectedImportant
);
2713 return ePriority_Error
;
2716 return ePriority_Important
;
2720 CSSParserImpl::NextIdent()
2722 // XXX Error reporting?
2723 if (!GetToken(true)) {
2726 if (eCSSToken_Ident
!= mToken
.mType
) {
2730 return &mToken
.mIdent
;
2734 CSSParserImpl::SkipAtRule(bool aInsideBlock
)
2737 if (!GetToken(true)) {
2738 REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF2
);
2741 if (eCSSToken_Symbol
== mToken
.mType
) {
2742 char16_t symbol
= mToken
.mSymbol
;
2743 if (symbol
== ';') {
2746 if (aInsideBlock
&& symbol
== '}') {
2747 // The closing } doesn't belong to us.
2751 if (symbol
== '{') {
2754 } else if (symbol
== '(') {
2756 } else if (symbol
== '[') {
2759 } else if (eCSSToken_Function
== mToken
.mType
||
2760 eCSSToken_Bad_URL
== mToken
.mType
) {
2768 CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc
,
2773 nsCSSSection newSection
;
2774 bool (CSSParserImpl::*parseFunc
)(RuleAppendFunc
, void*);
2776 if ((mSection
<= eCSSSection_Charset
) &&
2777 (mToken
.mIdent
.LowerCaseEqualsLiteral("charset"))) {
2778 parseFunc
= &CSSParserImpl::ParseCharsetRule
;
2779 newSection
= eCSSSection_Import
; // only one charset allowed
2781 } else if ((mSection
<= eCSSSection_Import
) &&
2782 mToken
.mIdent
.LowerCaseEqualsLiteral("import")) {
2783 parseFunc
= &CSSParserImpl::ParseImportRule
;
2784 newSection
= eCSSSection_Import
;
2786 } else if ((mSection
<= eCSSSection_NameSpace
) &&
2787 mToken
.mIdent
.LowerCaseEqualsLiteral("namespace")) {
2788 parseFunc
= &CSSParserImpl::ParseNameSpaceRule
;
2789 newSection
= eCSSSection_NameSpace
;
2791 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("media")) {
2792 parseFunc
= &CSSParserImpl::ParseMediaRule
;
2793 newSection
= eCSSSection_General
;
2795 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-document")) {
2796 parseFunc
= &CSSParserImpl::ParseMozDocumentRule
;
2797 newSection
= eCSSSection_General
;
2799 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("font-face")) {
2800 parseFunc
= &CSSParserImpl::ParseFontFaceRule
;
2801 newSection
= eCSSSection_General
;
2803 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("font-feature-values")) {
2804 parseFunc
= &CSSParserImpl::ParseFontFeatureValuesRule
;
2805 newSection
= eCSSSection_General
;
2807 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("page")) {
2808 parseFunc
= &CSSParserImpl::ParsePageRule
;
2809 newSection
= eCSSSection_General
;
2811 } else if ((nsCSSProps::IsEnabled(eCSSPropertyAlias_MozAnimation
) &&
2812 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-keyframes")) ||
2813 mToken
.mIdent
.LowerCaseEqualsLiteral("keyframes")) {
2814 parseFunc
= &CSSParserImpl::ParseKeyframesRule
;
2815 newSection
= eCSSSection_General
;
2817 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("supports")) {
2818 parseFunc
= &CSSParserImpl::ParseSupportsRule
;
2819 newSection
= eCSSSection_General
;
2821 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("counter-style")) {
2822 parseFunc
= &CSSParserImpl::ParseCounterStyleRule
;
2823 newSection
= eCSSSection_General
;
2826 if (!NonMozillaVendorIdentifier(mToken
.mIdent
)) {
2827 REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule
);
2830 // Skip over unsupported at rule, don't advance section
2831 return SkipAtRule(aInAtRule
);
2834 // Inside of @-rules, only the rules that can occur anywhere
2836 bool unnestable
= aInAtRule
&& newSection
!= eCSSSection_General
;
2838 REPORT_UNEXPECTED_TOKEN(PEGroupRuleNestedAtRule
);
2841 if (unnestable
|| !(this->*parseFunc
)(aAppendFunc
, aData
)) {
2842 // Skip over invalid at rule, don't advance section
2844 return SkipAtRule(aInAtRule
);
2847 // Nested @-rules don't affect the top-level rule chain requirement
2849 mSection
= newSection
;
2856 CSSParserImpl::ParseCharsetRule(RuleAppendFunc aAppendFunc
,
2859 uint32_t linenum
, colnum
;
2860 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
2862 REPORT_UNEXPECTED_EOF(PECharsetRuleEOF
);
2866 if (eCSSToken_String
!= mToken
.mType
) {
2868 REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString
);
2872 nsAutoString charset
= mToken
.mIdent
;
2874 if (!ExpectSymbol(';', true)) {
2878 nsRefPtr
<css::CharsetRule
> rule
= new css::CharsetRule(charset
,
2880 (*aAppendFunc
)(rule
, aData
);
2886 CSSParserImpl::ParseURLOrString(nsString
& aURL
)
2888 if (!GetToken(true)) {
2891 if (eCSSToken_String
== mToken
.mType
|| eCSSToken_URL
== mToken
.mType
) {
2892 aURL
= mToken
.mIdent
;
2900 CSSParserImpl::ParseMediaQuery(eMediaQueryType aQueryType
,
2901 nsMediaQuery
**aQuery
,
2906 bool inAtRule
= aQueryType
== eMediaQueryAtRule
;
2907 // Attempt to parse a single condition and stop
2908 bool singleCondition
= aQueryType
== eMediaQuerySingleCondition
;
2910 // "If the comma-separated list is the empty list it is assumed to
2911 // specify the media query 'all'." (css3-mediaqueries, section
2913 if (!GetToken(true)) {
2915 // expected termination by EOF
2919 // unexpected termination by EOF
2920 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
2924 if (eCSSToken_Symbol
== mToken
.mType
&& inAtRule
&&
2925 (mToken
.mSymbol
== ';' || mToken
.mSymbol
== '{' || mToken
.mSymbol
== '}' )) {
2932 nsMediaQuery
* query
= new nsMediaQuery
;
2935 if (ExpectSymbol('(', true)) {
2936 // we got an expression without a media type
2937 UngetToken(); // so ParseMediaQueryExpression can handle it
2938 query
->SetType(nsGkAtoms::all
);
2939 query
->SetTypeOmitted();
2940 // Just parse the first expression here.
2941 if (!ParseMediaQueryExpression(query
)) {
2943 query
->SetHadUnknownExpression();
2945 } else if (singleCondition
) {
2946 // Since we are only trying to consume a single condition, which precludes
2947 // media types and not/only, this should be the same as reaching immediate
2948 // EOF (no condition to parse)
2952 nsCOMPtr
<nsIAtom
> mediaType
;
2953 bool gotNotOrOnly
= false;
2955 if (!GetToken(true)) {
2956 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
2959 if (eCSSToken_Ident
!= mToken
.mType
) {
2960 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent
);
2964 // case insensitive from CSS - must be lower cased
2965 nsContentUtils::ASCIIToLower(mToken
.mIdent
);
2966 mediaType
= do_GetAtom(mToken
.mIdent
);
2968 NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
2970 if (!gotNotOrOnly
&& mediaType
== nsGkAtoms::_not
) {
2971 gotNotOrOnly
= true;
2972 query
->SetNegated();
2973 } else if (!gotNotOrOnly
&& mediaType
== nsGkAtoms::only
) {
2974 gotNotOrOnly
= true;
2975 query
->SetHasOnly();
2976 } else if (mediaType
== nsGkAtoms::_not
||
2977 mediaType
== nsGkAtoms::only
||
2978 mediaType
== nsGkAtoms::_and
||
2979 mediaType
== nsGkAtoms::_or
) {
2980 REPORT_UNEXPECTED_TOKEN(PEGatherMediaReservedMediaType
);
2988 query
->SetType(mediaType
);
2992 if (!GetToken(true)) {
2994 // expected termination by EOF
2998 // unexpected termination by EOF
2999 REPORT_UNEXPECTED_EOF(PEGatherMediaEOF
);
3003 if (eCSSToken_Symbol
== mToken
.mType
&& inAtRule
&&
3004 (mToken
.mSymbol
== ';' || mToken
.mSymbol
== '{' || mToken
.mSymbol
== '}')) {
3009 if (!singleCondition
&&
3010 eCSSToken_Symbol
== mToken
.mType
&& mToken
.mSymbol
== ',') {
3011 // Done with the expressions for this query
3014 if (eCSSToken_Ident
!= mToken
.mType
||
3015 !mToken
.mIdent
.LowerCaseEqualsLiteral("and")) {
3016 if (singleCondition
) {
3017 // We have a condition at this point -- if we're not chained to other
3018 // conditions with and/or, we're done.
3022 REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma
);
3027 if (!ParseMediaQueryExpression(query
)) {
3029 query
->SetHadUnknownExpression();
3035 // Returns false only when there is a low-level error in the scanner
3038 CSSParserImpl::GatherMedia(nsMediaList
* aMedia
,
3041 eMediaQueryType type
= aInAtRule
? eMediaQueryAtRule
: eMediaQueryNormal
;
3043 nsAutoPtr
<nsMediaQuery
> query
;
3045 if (!ParseMediaQuery(type
, getter_Transfers(query
), &hitStop
)) {
3046 NS_ASSERTION(!hitStop
, "should return true when hit stop");
3049 query
->SetHadUnknownExpression();
3052 const char16_t stopChars
[] =
3053 { char16_t(','), char16_t('{'), char16_t(';'), char16_t('}'), char16_t(0) };
3054 SkipUntilOneOf(stopChars
);
3058 // Rely on SkipUntilOneOf leaving mToken around as the last token read.
3059 if (mToken
.mType
== eCSSToken_Symbol
&& aInAtRule
&&
3060 (mToken
.mSymbol
== '{' || mToken
.mSymbol
== ';' || mToken
.mSymbol
== '}')) {
3066 aMedia
->AppendQuery(query
);
3076 CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery
* aQuery
)
3078 if (!ExpectSymbol('(', true)) {
3079 REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart
);
3082 if (! GetToken(true)) {
3083 REPORT_UNEXPECTED_EOF(PEMQExpressionEOF
);
3086 if (eCSSToken_Ident
!= mToken
.mType
) {
3087 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
3093 nsMediaExpression
*expr
= aQuery
->NewExpression();
3095 // case insensitive from CSS - must be lower cased
3096 nsContentUtils::ASCIIToLower(mToken
.mIdent
);
3097 const char16_t
*featureString
;
3098 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("min-"))) {
3099 expr
->mRange
= nsMediaExpression::eMin
;
3100 featureString
= mToken
.mIdent
.get() + 4;
3101 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("max-"))) {
3102 expr
->mRange
= nsMediaExpression::eMax
;
3103 featureString
= mToken
.mIdent
.get() + 4;
3105 expr
->mRange
= nsMediaExpression::eEqual
;
3106 featureString
= mToken
.mIdent
.get();
3109 nsCOMPtr
<nsIAtom
> mediaFeatureAtom
= do_GetAtom(featureString
);
3110 if (!mediaFeatureAtom
) {
3111 NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
3113 const nsMediaFeature
*feature
= nsMediaFeatures::features
;
3114 for (; feature
->mName
; ++feature
) {
3115 if (*(feature
->mName
) == mediaFeatureAtom
) {
3119 if (!feature
->mName
||
3120 (expr
->mRange
!= nsMediaExpression::eEqual
&&
3121 feature
->mRangeType
!= nsMediaFeature::eMinMaxAllowed
)) {
3122 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName
);
3126 expr
->mFeature
= feature
;
3128 if (!GetToken(true) || mToken
.IsSymbol(')')) {
3129 // Query expressions for any feature can be given without a value.
3130 // However, min/max prefixes are not allowed.
3131 if (expr
->mRange
!= nsMediaExpression::eEqual
) {
3132 REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue
);
3135 expr
->mValue
.Reset();
3139 if (!mToken
.IsSymbol(':')) {
3140 REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd
);
3147 switch (feature
->mValueType
) {
3148 case nsMediaFeature::eLength
:
3149 rv
= ParseNonNegativeVariant(expr
->mValue
, VARIANT_LENGTH
, nullptr);
3151 case nsMediaFeature::eInteger
:
3152 case nsMediaFeature::eBoolInteger
:
3153 rv
= ParseNonNegativeVariant(expr
->mValue
, VARIANT_INTEGER
, nullptr);
3154 // Enforce extra restrictions for eBoolInteger
3156 feature
->mValueType
== nsMediaFeature::eBoolInteger
&&
3157 expr
->mValue
.GetIntValue() > 1)
3160 case nsMediaFeature::eFloat
:
3161 rv
= ParseNonNegativeVariant(expr
->mValue
, VARIANT_NUMBER
, nullptr);
3163 case nsMediaFeature::eIntRatio
:
3165 // Two integers separated by '/', with optional whitespace on
3166 // either side of the '/'.
3167 nsRefPtr
<nsCSSValue::Array
> a
= nsCSSValue::Array::Create(2);
3168 expr
->mValue
.SetArrayValue(a
, eCSSUnit_Array
);
3169 // We don't bother with ParseNonNegativeVariant since we have to
3170 // check for != 0 as well; no need to worry about the UngetToken
3171 // since we're throwing out up to the next ')' anyway.
3172 rv
= ParseVariant(a
->Item(0), VARIANT_INTEGER
, nullptr) &&
3173 a
->Item(0).GetIntValue() > 0 &&
3174 ExpectSymbol('/', true) &&
3175 ParseVariant(a
->Item(1), VARIANT_INTEGER
, nullptr) &&
3176 a
->Item(1).GetIntValue() > 0;
3179 case nsMediaFeature::eResolution
:
3180 rv
= GetToken(true);
3183 rv
= mToken
.mType
== eCSSToken_Dimension
&& mToken
.mNumber
> 0.0f
;
3188 // No worries about whether unitless zero is allowed, since the
3189 // value must be positive (and we checked that above).
3190 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(), "unit lied");
3191 if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpi")) {
3192 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Inch
);
3193 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("dppx")) {
3194 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Pixel
);
3195 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("dpcm")) {
3196 expr
->mValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_Centimeter
);
3201 case nsMediaFeature::eEnumerated
:
3202 rv
= ParseVariant(expr
->mValue
, VARIANT_KEYWORD
,
3203 feature
->mData
.mKeywordTable
);
3205 case nsMediaFeature::eIdent
:
3206 rv
= ParseVariant(expr
->mValue
, VARIANT_IDENTIFIER
, nullptr);
3209 if (!rv
|| !ExpectSymbol(')', true)) {
3210 REPORT_UNEXPECTED(PEMQExpectedFeatureValue
);
3218 // Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]"
3220 CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc
, void* aData
)
3222 nsRefPtr
<nsMediaList
> media
= new nsMediaList();
3224 uint32_t linenum
, colnum
;
3226 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
3227 !ParseURLOrString(url
)) {
3228 REPORT_UNEXPECTED_TOKEN(PEImportNotURI
);
3232 if (!ExpectSymbol(';', true)) {
3233 if (!GatherMedia(media
, true) ||
3234 !ExpectSymbol(';', true)) {
3235 REPORT_UNEXPECTED_TOKEN(PEImportUnexpected
);
3236 // don't advance section, simply ignore invalid @import
3240 // Safe to assert this, since we ensured that there is something
3241 // other than the ';' coming after the @import's url() token.
3242 NS_ASSERTION(media
->Length() != 0, "media list must be nonempty");
3245 ProcessImport(url
, media
, aAppendFunc
, aData
, linenum
, colnum
);
3250 CSSParserImpl::ProcessImport(const nsString
& aURLSpec
,
3251 nsMediaList
* aMedia
,
3252 RuleAppendFunc aAppendFunc
,
3254 uint32_t aLineNumber
,
3255 uint32_t aColumnNumber
)
3257 nsRefPtr
<css::ImportRule
> rule
= new css::ImportRule(aMedia
, aURLSpec
,
3260 (*aAppendFunc
)(rule
, aData
);
3262 // Diagnose bad URIs even if we don't have a child loader.
3263 nsCOMPtr
<nsIURI
> url
;
3264 // Charset will be deduced from mBaseURI, which is more or less correct.
3265 nsresult rv
= NS_NewURI(getter_AddRefs(url
), aURLSpec
, nullptr, mBaseURI
);
3267 if (NS_FAILED(rv
)) {
3268 if (rv
== NS_ERROR_MALFORMED_URI
) {
3269 // import url is bad
3270 REPORT_UNEXPECTED_P(PEImportBadURI
, aURLSpec
);
3277 mChildLoader
->LoadChildSheet(mSheet
, url
, aMedia
, rule
);
3281 // Parse the {} part of an @media or @-moz-document rule.
3283 CSSParserImpl::ParseGroupRule(css::GroupRule
* aRule
,
3284 RuleAppendFunc aAppendFunc
,
3287 // XXXbz this could use better error reporting throughout the method
3288 if (!ExpectSymbol('{', true)) {
3292 // push rule on stack, loop over children
3294 nsCSSSection holdSection
= mSection
;
3295 mSection
= eCSSSection_General
;
3298 // Get next non-whitespace token
3299 if (! GetToken(true)) {
3300 REPORT_UNEXPECTED_EOF(PEGroupRuleEOF2
);
3303 if (mToken
.IsSymbol('}')) { // done!
3307 if (eCSSToken_AtKeyword
== mToken
.mType
) {
3308 // Parse for nested rules
3309 ParseAtRule(aAppendFunc
, aData
, true);
3313 ParseRuleSet(AppendRuleToSheet
, this, true);
3317 if (!ExpectSymbol('}', true)) {
3318 mSection
= holdSection
;
3321 (*aAppendFunc
)(aRule
, aData
);
3325 // Parse a CSS2 media rule: "@media medium [, medium] { ... }"
3327 CSSParserImpl::ParseMediaRule(RuleAppendFunc aAppendFunc
, void* aData
)
3329 nsRefPtr
<nsMediaList
> media
= new nsMediaList();
3330 uint32_t linenum
, colnum
;
3331 if (GetNextTokenLocation(true, &linenum
, &colnum
) &&
3332 GatherMedia(media
, true)) {
3333 // XXXbz this could use better error reporting throughout the method
3334 nsRefPtr
<css::MediaRule
> rule
= new css::MediaRule(linenum
, colnum
);
3335 // Append first, so when we do SetMedia() the rule
3336 // knows what its stylesheet is.
3337 if (ParseGroupRule(rule
, aAppendFunc
, aData
)) {
3338 rule
->SetMedia(media
);
3346 // Parse a @-moz-document rule. This is like an @media rule, but instead
3347 // of a medium it has a nonempty list of items where each item is either
3348 // url(), url-prefix(), or domain().
3350 CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc
, void* aData
)
3352 css::DocumentRule::URL
*urls
= nullptr;
3353 css::DocumentRule::URL
**next
= &urls
;
3355 uint32_t linenum
, colnum
;
3356 if (!GetNextTokenLocation(true, &linenum
, &colnum
)) {
3361 if (!GetToken(true)) {
3362 REPORT_UNEXPECTED_EOF(PEMozDocRuleEOF
);
3367 if (!(eCSSToken_URL
== mToken
.mType
||
3368 (eCSSToken_Function
== mToken
.mType
&&
3369 (mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix") ||
3370 mToken
.mIdent
.LowerCaseEqualsLiteral("domain") ||
3371 mToken
.mIdent
.LowerCaseEqualsLiteral("regexp"))))) {
3372 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc2
);
3377 css::DocumentRule::URL
*cur
= *next
= new css::DocumentRule::URL
;
3379 if (mToken
.mType
== eCSSToken_URL
) {
3380 cur
->func
= css::DocumentRule::eURL
;
3381 CopyUTF16toUTF8(mToken
.mIdent
, cur
->url
);
3382 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("regexp")) {
3383 // regexp() is different from url-prefix() and domain() (but
3384 // probably the way they *should* have been* in that it requires a
3385 // string argument, and doesn't try to behave like url().
3386 cur
->func
= css::DocumentRule::eRegExp
;
3388 // copy before we know it's valid (but before ExpectSymbol changes
3390 CopyUTF16toUTF8(mToken
.mIdent
, cur
->url
);
3391 if (eCSSToken_String
!= mToken
.mType
|| !ExpectSymbol(')', true)) {
3392 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotString
);
3398 if (mToken
.mIdent
.LowerCaseEqualsLiteral("url-prefix")) {
3399 cur
->func
= css::DocumentRule::eURLPrefix
;
3400 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("domain")) {
3401 cur
->func
= css::DocumentRule::eDomain
;
3404 NS_ASSERTION(!mHavePushBack
, "mustn't have pushback at this point");
3405 mScanner
->NextURL(mToken
);
3406 if (mToken
.mType
!= eCSSToken_URL
) {
3407 REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI
);
3413 // We could try to make the URL (as long as it's not domain())
3414 // canonical and absolute with NS_NewURI and GetSpec, but I'm
3415 // inclined to think we shouldn't.
3416 CopyUTF16toUTF8(mToken
.mIdent
, cur
->url
);
3418 } while (ExpectSymbol(',', true));
3420 nsRefPtr
<css::DocumentRule
> rule
= new css::DocumentRule(linenum
, colnum
);
3421 rule
->SetURLs(urls
);
3423 return ParseGroupRule(rule
, aAppendFunc
, aData
);
3426 // Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;"
3428 CSSParserImpl::ParseNameSpaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
3430 uint32_t linenum
, colnum
;
3431 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
3433 REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF
);
3437 nsAutoString prefix
;
3440 if (eCSSToken_Ident
== mToken
.mType
) {
3441 prefix
= mToken
.mIdent
;
3442 // user-specified identifiers are case-sensitive (bug 416106)
3447 if (!ParseURLOrString(url
) || !ExpectSymbol(';', true)) {
3448 if (mHavePushBack
) {
3449 REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected
);
3451 REPORT_UNEXPECTED_EOF(PEAtNSURIEOF
);
3456 ProcessNameSpace(prefix
, url
, aAppendFunc
, aData
, linenum
, colnum
);
3461 CSSParserImpl::ProcessNameSpace(const nsString
& aPrefix
,
3462 const nsString
& aURLSpec
,
3463 RuleAppendFunc aAppendFunc
,
3465 uint32_t aLineNumber
,
3466 uint32_t aColumnNumber
)
3468 nsCOMPtr
<nsIAtom
> prefix
;
3470 if (!aPrefix
.IsEmpty()) {
3471 prefix
= do_GetAtom(aPrefix
);
3473 NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
3477 nsRefPtr
<css::NameSpaceRule
> rule
= new css::NameSpaceRule(prefix
, aURLSpec
,
3480 (*aAppendFunc
)(rule
, aData
);
3482 // If this was the first namespace rule encountered, it will trigger
3483 // creation of a namespace map.
3484 if (!mNameSpaceMap
) {
3485 mNameSpaceMap
= mSheet
->GetNameSpaceMap();
3489 // font-face-rule: '@font-face' '{' font-description '}'
3490 // font-description: font-descriptor+
3492 CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc
, void* aData
)
3494 uint32_t linenum
, colnum
;
3495 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
3496 !ExpectSymbol('{', true)) {
3497 REPORT_UNEXPECTED_TOKEN(PEBadFontBlockStart
);
3501 nsRefPtr
<nsCSSFontFaceRule
> rule(new nsCSSFontFaceRule(linenum
, colnum
));
3504 if (!GetToken(true)) {
3505 REPORT_UNEXPECTED_EOF(PEFontFaceEOF
);
3508 if (mToken
.IsSymbol('}')) { // done!
3513 // ignore extra semicolons
3514 if (mToken
.IsSymbol(';'))
3517 if (!ParseFontDescriptor(rule
)) {
3518 REPORT_UNEXPECTED(PEDeclSkipped
);
3520 if (!SkipDeclaration(true))
3524 if (!ExpectSymbol('}', true)) {
3525 REPORT_UNEXPECTED_TOKEN(PEBadFontBlockEnd
);
3528 (*aAppendFunc
)(rule
, aData
);
3532 // font-descriptor: font-family-desc
3533 // | font-style-desc
3534 // | font-weight-desc
3535 // | font-stretch-desc
3537 // | unicode-range-desc
3539 // All font-*-desc productions follow the pattern
3540 // IDENT ':' value ';'
3542 // On entry to this function, mToken is the IDENT.
3545 CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule
* aRule
)
3547 if (eCSSToken_Ident
!= mToken
.mType
) {
3548 REPORT_UNEXPECTED_TOKEN(PEFontDescExpected
);
3552 nsString descName
= mToken
.mIdent
;
3553 if (!ExpectSymbol(':', true)) {
3554 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
3559 nsCSSFontDesc descID
= nsCSSProps::LookupFontDesc(descName
);
3562 if (descID
== eCSSFontDesc_UNKNOWN
) {
3563 if (NonMozillaVendorIdentifier(descName
)) {
3564 // silently skip other vendors' extensions
3565 SkipDeclaration(true);
3568 REPORT_UNEXPECTED_P(PEUnknownFontDesc
, descName
);
3573 if (!ParseFontDescriptorValue(descID
, value
)) {
3574 REPORT_UNEXPECTED_P(PEValueParsingError
, descName
);
3578 if (!ExpectEndProperty())
3581 aRule
->SetDesc(descID
, value
);
3585 // @font-feature-values <font-family># {
3586 // @<feature-type> {
3587 // <feature-ident> : <feature-index>+;
3588 // <feature-ident> : <feature-index>+;
3595 CSSParserImpl::ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc
,
3598 uint32_t linenum
, colnum
;
3599 if (!GetNextTokenLocation(true, &linenum
, &colnum
)) {
3603 nsRefPtr
<nsCSSFontFeatureValuesRule
>
3604 valuesRule(new nsCSSFontFeatureValuesRule(linenum
, colnum
));
3606 // parse family list
3607 nsCSSValue fontlistValue
;
3609 if (!ParseFamily(fontlistValue
) ||
3610 fontlistValue
.GetUnit() != eCSSUnit_FontFamilyList
)
3612 REPORT_UNEXPECTED_TOKEN(PEFFVNoFamily
);
3616 // add family to rule
3617 const FontFamilyList
* fontlist
= fontlistValue
.GetFontFamilyListValue();
3619 // family list has generic ==> parse error
3620 if (fontlist
->HasGeneric()) {
3621 REPORT_UNEXPECTED_TOKEN(PEFFVGenericInFamilyList
);
3625 valuesRule
->SetFamilyList(*fontlist
);
3628 if (!ExpectSymbol('{', true)) {
3629 REPORT_UNEXPECTED_TOKEN(PEFFVBlockStart
);
3633 // list of sets of feature values, each set bound to a specific
3634 // feature-type (e.g. swash, annotation)
3636 if (!GetToken(true)) {
3637 REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF
);
3640 if (mToken
.IsSymbol('}')) { // done!
3645 if (!ParseFontFeatureValueSet(valuesRule
)) {
3646 if (!SkipAtRule(false)) {
3651 if (!ExpectSymbol('}', true)) {
3652 REPORT_UNEXPECTED_TOKEN(PEFFVUnexpectedBlockEnd
);
3657 (*aAppendFunc
)(valuesRule
, aData
);
3661 #define NUMVALUES_NO_LIMIT 0xFFFF
3663 // parse a single value set containing name-value pairs for a single feature type
3664 // @<feature-type> { [ <feature-ident> : <feature-index>+ ; ]* }
3665 // Ex: @swash { flowing: 1; delicate: 2; }
3667 CSSParserImpl::ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule
3668 *aFeatureValuesRule
)
3670 // -- @keyword (e.g. swash, styleset)
3671 if (eCSSToken_AtKeyword
!= mToken
.mType
) {
3672 REPORT_UNEXPECTED_TOKEN(PEFontFeatureValuesNoAt
);
3678 // which font-specific variant of font-variant-alternates
3679 int32_t whichVariant
;
3680 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
3681 if (keyword
== eCSSKeyword_UNKNOWN
||
3682 !nsCSSProps::FindKeyword(keyword
,
3683 nsCSSProps::kFontVariantAlternatesFuncsKTable
,
3686 if (!NonMozillaVendorIdentifier(mToken
.mIdent
)) {
3687 REPORT_UNEXPECTED_TOKEN(PEFFVUnknownFontVariantPropValue
);
3694 nsAutoString
featureType(mToken
.mIdent
);
3697 if (!ExpectSymbol('{', true)) {
3698 REPORT_UNEXPECTED_TOKEN(PEFFVValueSetStart
);
3702 // styleset and character-variant can be multi-valued, otherwise single value
3703 int32_t limitNumValues
;
3706 case eCSSKeyword_styleset
:
3707 limitNumValues
= NUMVALUES_NO_LIMIT
;
3709 case eCSSKeyword_character_variant
:
3717 // -- ident integer+ [, ident integer+]
3718 nsAutoTArray
<gfxFontFeatureValueSet::ValueList
, 5> values
;
3720 // list of font-feature-values-declaration's
3722 nsAutoString valueId
;
3724 if (!GetToken(true)) {
3725 REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF
);
3729 // ignore extra semicolons
3730 if (mToken
.IsSymbol(';')) {
3734 // close brace ==> done
3735 if (mToken
.IsSymbol('}')) {
3740 if (eCSSToken_Ident
!= mToken
.mType
) {
3741 REPORT_UNEXPECTED_TOKEN(PEFFVExpectedIdent
);
3742 if (!SkipDeclaration(true)) {
3748 valueId
.Assign(mToken
.mIdent
);
3751 if (!ExpectSymbol(':', true)) {
3752 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
3754 if (!SkipDeclaration(true)) {
3761 nsAutoTArray
<uint32_t,4> featureSelectors
;
3763 nsCSSValue intValue
;
3764 while (ParseNonNegativeVariant(intValue
, VARIANT_INTEGER
, nullptr)) {
3765 featureSelectors
.AppendElement(uint32_t(intValue
.GetIntValue()));
3768 int32_t numValues
= featureSelectors
.Length();
3770 if (numValues
== 0) {
3771 REPORT_UNEXPECTED_TOKEN(PEFFVExpectedValue
);
3773 if (!SkipDeclaration(true)) {
3779 if (numValues
> limitNumValues
) {
3780 REPORT_UNEXPECTED_P(PEFFVTooManyValues
, featureType
);
3782 if (!SkipDeclaration(true)) {
3788 if (!GetToken(true)) {
3789 REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF
);
3790 gfxFontFeatureValueSet::ValueList
v(valueId
, featureSelectors
);
3791 values
.AppendElement(v
);
3795 // ';' or '}' to end definition
3796 if (!mToken
.IsSymbol(';') && !mToken
.IsSymbol('}')) {
3797 REPORT_UNEXPECTED_TOKEN(PEFFVValueDefinitionTrailing
);
3799 if (!SkipDeclaration(true)) {
3805 gfxFontFeatureValueSet::ValueList
v(valueId
, featureSelectors
);
3806 values
.AppendElement(v
);
3808 if (mToken
.IsSymbol('}')) {
3813 aFeatureValuesRule
->AddValueList(whichVariant
, values
);
3818 CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc
, void* aData
)
3820 uint32_t linenum
, colnum
;
3821 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
3823 REPORT_UNEXPECTED_EOF(PEKeyframeNameEOF
);
3827 if (mToken
.mType
!= eCSSToken_Ident
) {
3828 REPORT_UNEXPECTED_TOKEN(PEKeyframeBadName
);
3832 nsString
name(mToken
.mIdent
);
3834 if (!ExpectSymbol('{', true)) {
3835 REPORT_UNEXPECTED_TOKEN(PEKeyframeBrace
);
3839 nsRefPtr
<nsCSSKeyframesRule
> rule
= new nsCSSKeyframesRule(name
,
3842 while (!ExpectSymbol('}', true)) {
3843 nsRefPtr
<nsCSSKeyframeRule
> kid
= ParseKeyframeRule();
3845 rule
->AppendStyleRule(kid
);
3852 (*aAppendFunc
)(rule
, aData
);
3857 CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc
, void* aData
)
3859 uint32_t linenum
, colnum
;
3860 if (!GetNextTokenLocation(true, &linenum
, &colnum
)) {
3864 // TODO: There can be page selectors after @page such as ":first", ":left".
3865 uint32_t parseFlags
= eParseDeclaration_InBraces
|
3866 eParseDeclaration_AllowImportant
;
3868 // Forbid viewport units in @page rules. See bug 811391.
3869 NS_ABORT_IF_FALSE(mViewportUnitsEnabled
,
3870 "Viewport units should be enabled outside of @page rules.");
3871 mViewportUnitsEnabled
= false;
3872 nsAutoPtr
<css::Declaration
> declaration(
3873 ParseDeclarationBlock(parseFlags
,
3875 mViewportUnitsEnabled
= true;
3881 // Takes ownership of declaration.
3882 nsRefPtr
<nsCSSPageRule
> rule
= new nsCSSPageRule(Move(declaration
),
3885 (*aAppendFunc
)(rule
, aData
);
3889 already_AddRefed
<nsCSSKeyframeRule
>
3890 CSSParserImpl::ParseKeyframeRule()
3892 InfallibleTArray
<float> selectorList
;
3893 uint32_t linenum
, colnum
;
3894 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
3895 !ParseKeyframeSelectorList(selectorList
)) {
3896 REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored
);
3900 // Ignore !important in keyframe rules
3901 uint32_t parseFlags
= eParseDeclaration_InBraces
;
3902 nsAutoPtr
<css::Declaration
> declaration(ParseDeclarationBlock(parseFlags
));
3907 // Takes ownership of declaration, and steals contents of selectorList.
3908 nsRefPtr
<nsCSSKeyframeRule
> rule
=
3909 new nsCSSKeyframeRule(selectorList
, Move(declaration
), linenum
, colnum
);
3910 return rule
.forget();
3914 CSSParserImpl::ParseKeyframeSelectorList(InfallibleTArray
<float>& aSelectorList
)
3917 if (!GetToken(true)) {
3918 // The first time through the loop, this means we got an empty
3919 // list. Otherwise, it means we have a trailing comma.
3923 switch (mToken
.mType
) {
3924 case eCSSToken_Percentage
:
3925 value
= mToken
.mNumber
;
3927 case eCSSToken_Ident
:
3928 if (mToken
.mIdent
.LowerCaseEqualsLiteral("from")) {
3932 if (mToken
.mIdent
.LowerCaseEqualsLiteral("to")) {
3939 // The first time through the loop, this means we got an empty
3940 // list. Otherwise, it means we have a trailing comma.
3943 aSelectorList
.AppendElement(value
);
3944 if (!ExpectSymbol(',', true)) {
3951 // : "@supports" supports_condition group_rule_body
3954 CSSParserImpl::ParseSupportsRule(RuleAppendFunc aAppendFunc
, void* aProcessData
)
3956 bool conditionMet
= false;
3959 mScanner
->StartRecording();
3961 uint32_t linenum
, colnum
;
3962 if (!GetNextTokenLocation(true, &linenum
, &colnum
)) {
3966 bool parsed
= ParseSupportsCondition(conditionMet
);
3969 mScanner
->StopRecording();
3973 if (!ExpectSymbol('{', true)) {
3974 REPORT_UNEXPECTED_TOKEN(PESupportsGroupRuleStart
);
3975 mScanner
->StopRecording();
3980 mScanner
->StopRecording(condition
);
3982 // Remove the "{" that would follow the condition.
3983 if (condition
.Length() != 0) {
3984 condition
.Truncate(condition
.Length() - 1);
3987 // Remove spaces from the start and end of the recorded supports condition.
3988 condition
.Trim(" ", true, true, false);
3990 // Record whether we are in a failing @supports, so that property parse
3991 // errors don't get reported.
3992 nsAutoFailingSupportsRule
failing(this, conditionMet
);
3994 nsRefPtr
<css::GroupRule
> rule
= new CSSSupportsRule(conditionMet
, condition
,
3996 return ParseGroupRule(rule
, aAppendFunc
, aProcessData
);
3999 // supports_condition
4000 // : supports_condition_in_parens supports_condition_terms
4001 // | supports_condition_negation
4004 CSSParserImpl::ParseSupportsCondition(bool& aConditionMet
)
4006 mInSupportsCondition
= true;
4008 if (!GetToken(true)) {
4009 REPORT_UNEXPECTED_EOF(PESupportsConditionStartEOF2
);
4015 mScanner
->ClearSeenBadToken();
4017 if (mToken
.IsSymbol('(') ||
4018 mToken
.mType
== eCSSToken_Function
||
4019 mToken
.mType
== eCSSToken_URL
||
4020 mToken
.mType
== eCSSToken_Bad_URL
) {
4021 bool result
= ParseSupportsConditionInParens(aConditionMet
) &&
4022 ParseSupportsConditionTerms(aConditionMet
) &&
4023 !mScanner
->SeenBadToken();
4024 mInSupportsCondition
= false;
4028 if (mToken
.mType
== eCSSToken_Ident
&&
4029 mToken
.mIdent
.LowerCaseEqualsLiteral("not")) {
4030 bool result
= ParseSupportsConditionNegation(aConditionMet
) &&
4031 !mScanner
->SeenBadToken();
4032 mInSupportsCondition
= false;
4036 REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedStart
);
4037 mInSupportsCondition
= false;
4041 // supports_condition_negation
4042 // : 'not' S+ supports_condition_in_parens
4045 CSSParserImpl::ParseSupportsConditionNegation(bool& aConditionMet
)
4047 if (!GetToken(true)) {
4048 REPORT_UNEXPECTED_EOF(PESupportsConditionNotEOF
);
4052 if (mToken
.mType
!= eCSSToken_Ident
||
4053 !mToken
.mIdent
.LowerCaseEqualsLiteral("not")) {
4054 REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedNot
);
4058 if (!RequireWhitespace()) {
4059 REPORT_UNEXPECTED(PESupportsWhitespaceRequired
);
4063 if (ParseSupportsConditionInParens(aConditionMet
)) {
4064 aConditionMet
= !aConditionMet
;
4071 // supports_condition_in_parens
4072 // : '(' S* supports_condition_in_parens_inside_parens ')' S*
4073 // | general_enclosed
4076 CSSParserImpl::ParseSupportsConditionInParens(bool& aConditionMet
)
4078 if (!GetToken(true)) {
4079 REPORT_UNEXPECTED_EOF(PESupportsConditionInParensStartEOF
);
4083 if (mToken
.mType
== eCSSToken_URL
) {
4084 aConditionMet
= false;
4088 if (mToken
.mType
== eCSSToken_Function
||
4089 mToken
.mType
== eCSSToken_Bad_URL
) {
4090 if (!SkipUntil(')')) {
4091 REPORT_UNEXPECTED_EOF(PESupportsConditionInParensEOF
);
4094 aConditionMet
= false;
4098 if (!mToken
.IsSymbol('(')) {
4099 REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedOpenParenOrFunction
);
4104 if (!ParseSupportsConditionInParensInsideParens(aConditionMet
)) {
4105 if (!SkipUntil(')')) {
4106 REPORT_UNEXPECTED_EOF(PESupportsConditionInParensEOF
);
4109 aConditionMet
= false;
4113 if (!(ExpectSymbol(')', true))) {
4115 aConditionMet
= false;
4122 // supports_condition_in_parens_inside_parens
4123 // : core_declaration
4124 // | supports_condition_negation
4125 // | supports_condition_in_parens supports_condition_terms
4128 CSSParserImpl::ParseSupportsConditionInParensInsideParens(bool& aConditionMet
)
4130 if (!GetToken(true)) {
4134 if (mToken
.mType
== eCSSToken_Ident
) {
4135 if (!mToken
.mIdent
.LowerCaseEqualsLiteral("not")) {
4136 nsAutoString propertyName
= mToken
.mIdent
;
4137 if (!ExpectSymbol(':', true)) {
4141 nsCSSProperty propID
= LookupEnabledProperty(propertyName
);
4142 if (propID
== eCSSProperty_UNKNOWN
) {
4143 if (ExpectSymbol(')', true)) {
4147 aConditionMet
= false;
4150 } else if (propID
== eCSSPropertyExtra_variable
) {
4151 if (ExpectSymbol(')', false)) {
4155 CSSVariableDeclarations::Type variableType
;
4156 nsString variableValue
;
4158 ParseVariableDeclaration(&variableType
, variableValue
) &&
4159 ParsePriority() != ePriority_Error
;
4160 if (!aConditionMet
) {
4165 if (ExpectSymbol(')', true)) {
4169 aConditionMet
= ParseProperty(propID
) &&
4170 ParsePriority() != ePriority_Error
;
4171 if (!aConditionMet
) {
4175 mTempData
.ClearProperty(propID
);
4176 mTempData
.AssertInitialState();
4182 return ParseSupportsConditionNegation(aConditionMet
);
4186 return ParseSupportsConditionInParens(aConditionMet
) &&
4187 ParseSupportsConditionTerms(aConditionMet
);
4190 // supports_condition_terms
4191 // : S+ 'and' supports_condition_terms_after_operator('and')
4192 // | S+ 'or' supports_condition_terms_after_operator('or')
4196 CSSParserImpl::ParseSupportsConditionTerms(bool& aConditionMet
)
4198 if (!RequireWhitespace() || !GetToken(false)) {
4202 if (mToken
.mType
!= eCSSToken_Ident
) {
4207 if (mToken
.mIdent
.LowerCaseEqualsLiteral("and")) {
4208 return ParseSupportsConditionTermsAfterOperator(aConditionMet
, eAnd
);
4211 if (mToken
.mIdent
.LowerCaseEqualsLiteral("or")) {
4212 return ParseSupportsConditionTermsAfterOperator(aConditionMet
, eOr
);
4219 // supports_condition_terms_after_operator(operator)
4220 // : S+ supports_condition_in_parens ( <operator> supports_condition_in_parens )*
4223 CSSParserImpl::ParseSupportsConditionTermsAfterOperator(
4224 bool& aConditionMet
,
4225 CSSParserImpl::SupportsConditionTermOperator aOperator
)
4227 if (!RequireWhitespace()) {
4228 REPORT_UNEXPECTED(PESupportsWhitespaceRequired
);
4232 const char* token
= aOperator
== eAnd
? "and" : "or";
4234 bool termConditionMet
= false;
4235 if (!ParseSupportsConditionInParens(termConditionMet
)) {
4238 aConditionMet
= aOperator
== eAnd
? aConditionMet
&& termConditionMet
:
4239 aConditionMet
|| termConditionMet
;
4241 if (!GetToken(true)) {
4245 if (mToken
.mType
!= eCSSToken_Ident
||
4246 !mToken
.mIdent
.LowerCaseEqualsASCII(token
)) {
4254 CSSParserImpl::ParseCounterStyleRule(RuleAppendFunc aAppendFunc
, void* aData
)
4257 uint32_t linenum
, colnum
;
4258 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
4259 !ParseCounterStyleName(name
, true)) {
4260 REPORT_UNEXPECTED_TOKEN(PECounterStyleNotIdent
);
4264 if (!ExpectSymbol('{', true)) {
4265 REPORT_UNEXPECTED_TOKEN(PECounterStyleBadBlockStart
);
4269 nsRefPtr
<nsCSSCounterStyleRule
> rule
= new nsCSSCounterStyleRule(name
,
4273 if (!GetToken(true)) {
4274 REPORT_UNEXPECTED_EOF(PECounterStyleEOF
);
4277 if (mToken
.IsSymbol('}')) {
4280 if (mToken
.IsSymbol(';')) {
4284 if (!ParseCounterDescriptor(rule
)) {
4285 REPORT_UNEXPECTED(PEDeclSkipped
);
4287 if (!SkipDeclaration(true)) {
4288 REPORT_UNEXPECTED_EOF(PECounterStyleEOF
);
4294 int32_t system
= rule
->GetSystem();
4295 bool isCorrect
= false;
4297 case NS_STYLE_COUNTER_SYSTEM_CYCLIC
:
4298 case NS_STYLE_COUNTER_SYSTEM_NUMERIC
:
4299 case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC
:
4300 case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC
:
4301 case NS_STYLE_COUNTER_SYSTEM_FIXED
: {
4302 // check whether symbols is set and the length is sufficient
4303 const nsCSSValue
& symbols
= rule
->GetDesc(eCSSCounterDesc_Symbols
);
4304 if (symbols
.GetUnit() == eCSSUnit_List
&&
4305 nsCSSCounterStyleRule::CheckDescValue(
4306 system
, eCSSCounterDesc_Symbols
, symbols
)) {
4311 case NS_STYLE_COUNTER_SYSTEM_ADDITIVE
: {
4312 // for additive system, additive-symbols must be set
4313 const nsCSSValue
& symbols
=
4314 rule
->GetDesc(eCSSCounterDesc_AdditiveSymbols
);
4315 if (symbols
.GetUnit() == eCSSUnit_PairList
) {
4320 case NS_STYLE_COUNTER_SYSTEM_EXTENDS
: {
4321 // for extends system, symbols & additive-symbols must not be set
4322 const nsCSSValue
& symbols
= rule
->GetDesc(eCSSCounterDesc_Symbols
);
4323 const nsCSSValue
& additiveSymbols
=
4324 rule
->GetDesc(eCSSCounterDesc_AdditiveSymbols
);
4325 if (symbols
.GetUnit() == eCSSUnit_Null
&&
4326 additiveSymbols
.GetUnit() == eCSSUnit_Null
) {
4332 NS_NOTREACHED("unknown system");
4336 (*aAppendFunc
)(rule
, aData
);
4342 CSSParserImpl::ParseCounterStyleName(nsAString
& aName
, bool aForDefinition
)
4344 if (!GetToken(true)) {
4348 if (mToken
.mType
!= eCSSToken_Ident
) {
4353 static const nsCSSKeyword kReservedNames
[] = {
4355 eCSSKeyword_decimal
,
4359 nsCSSValue value
; // we don't actually care about the value
4360 if (!ParseCustomIdent(value
, mToken
.mIdent
,
4361 aForDefinition
? kReservedNames
: nullptr)) {
4362 REPORT_UNEXPECTED_TOKEN(PECounterStyleBadName
);
4367 aName
= mToken
.mIdent
;
4368 if (nsCSSProps::IsPredefinedCounterStyle(aName
)) {
4375 CSSParserImpl::ParseCounterStyleNameValue(nsCSSValue
& aValue
)
4378 if (ParseCounterStyleName(name
, false)) {
4379 aValue
.SetStringValue(name
, eCSSUnit_Ident
);
4386 CSSParserImpl::ParseCounterDescriptor(nsCSSCounterStyleRule
* aRule
)
4388 if (eCSSToken_Ident
!= mToken
.mType
) {
4389 REPORT_UNEXPECTED_TOKEN(PECounterDescExpected
);
4393 nsString descName
= mToken
.mIdent
;
4394 if (!ExpectSymbol(':', true)) {
4395 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
4400 nsCSSCounterDesc descID
= nsCSSProps::LookupCounterDesc(descName
);
4403 if (descID
== eCSSCounterDesc_UNKNOWN
) {
4404 REPORT_UNEXPECTED_P(PEUnknownCounterDesc
, descName
);
4408 if (!ParseCounterDescriptorValue(descID
, value
)) {
4409 REPORT_UNEXPECTED_P(PEValueParsingError
, descName
);
4413 if (!ExpectEndProperty()) {
4417 aRule
->SetDesc(descID
, value
);
4422 CSSParserImpl::ParseCounterDescriptorValue(nsCSSCounterDesc aDescID
,
4425 // Should also include VARIANT_IMAGE, but it is not supported currently.
4427 static const int32_t VARIANT_COUNTER_SYMBOL
=
4428 VARIANT_STRING
| VARIANT_IDENTIFIER
;
4431 case eCSSCounterDesc_System
: {
4433 if (!ParseEnum(system
, nsCSSProps::kCounterSystemKTable
)) {
4436 switch (system
.GetIntValue()) {
4437 case NS_STYLE_COUNTER_SYSTEM_FIXED
: {
4439 if (!ParseVariant(start
, VARIANT_INTEGER
, nullptr)) {
4440 start
.SetIntValue(1, eCSSUnit_Integer
);
4442 aValue
.SetPairValue(system
, start
);
4445 case NS_STYLE_COUNTER_SYSTEM_EXTENDS
: {
4447 if (!ParseCounterStyleNameValue(name
)) {
4448 REPORT_UNEXPECTED_TOKEN(PECounterExtendsNotIdent
);
4451 aValue
.SetPairValue(system
, name
);
4460 case eCSSCounterDesc_Negative
: {
4461 nsCSSValue first
, second
;
4462 if (!ParseVariant(first
, VARIANT_COUNTER_SYMBOL
, nullptr)) {
4465 if (!ParseVariant(second
, VARIANT_COUNTER_SYMBOL
, nullptr)) {
4468 aValue
.SetPairValue(first
, second
);
4473 case eCSSCounterDesc_Prefix
:
4474 case eCSSCounterDesc_Suffix
:
4475 return ParseVariant(aValue
, VARIANT_COUNTER_SYMBOL
, nullptr);
4477 case eCSSCounterDesc_Range
: {
4478 if (ParseVariant(aValue
, VARIANT_AUTO
, nullptr)) {
4481 nsCSSValuePairList
* item
= aValue
.SetPairListValue();
4483 nsCSSValuePair pair
;
4484 if (!ParseCounterRange(pair
)) {
4487 item
->mXValue
= pair
.mXValue
;
4488 item
->mYValue
= pair
.mYValue
;
4489 if (!ExpectSymbol(',', true)) {
4492 item
->mNext
= new nsCSSValuePairList
;
4495 // should always return in the loop
4498 case eCSSCounterDesc_Pad
: {
4499 nsCSSValue width
, symbol
;
4500 bool hasWidth
= ParseNonNegativeInteger(width
);
4501 if (!ParseVariant(symbol
, VARIANT_COUNTER_SYMBOL
, nullptr) ||
4502 (!hasWidth
&& !ParseNonNegativeInteger(width
))) {
4505 aValue
.SetPairValue(width
, symbol
);
4509 case eCSSCounterDesc_Fallback
:
4510 return ParseCounterStyleNameValue(aValue
);
4512 case eCSSCounterDesc_Symbols
: {
4513 nsCSSValueList
* item
= nullptr;
4516 if (!ParseVariant(value
, VARIANT_COUNTER_SYMBOL
, nullptr)) {
4520 item
= aValue
.SetListValue();
4522 item
->mNext
= new nsCSSValueList
;
4525 item
->mValue
= value
;
4527 // should always return in the loop
4530 case eCSSCounterDesc_AdditiveSymbols
: {
4531 nsCSSValuePairList
* item
= nullptr;
4532 int32_t lastWeight
= -1;
4534 nsCSSValue weight
, symbol
;
4535 bool hasWeight
= ParseNonNegativeInteger(weight
);
4536 if (!ParseVariant(symbol
, VARIANT_COUNTER_SYMBOL
, nullptr) ||
4537 (!hasWeight
&& !ParseNonNegativeInteger(weight
))) {
4540 if (lastWeight
!= -1 && weight
.GetIntValue() >= lastWeight
) {
4541 REPORT_UNEXPECTED(PECounterASWeight
);
4544 lastWeight
= weight
.GetIntValue();
4546 item
= aValue
.SetPairListValue();
4548 item
->mNext
= new nsCSSValuePairList
;
4551 item
->mXValue
= weight
;
4552 item
->mYValue
= symbol
;
4553 if (!ExpectSymbol(',', true)) {
4557 // should always return in the loop
4560 case eCSSCounterDesc_SpeakAs
:
4561 if (ParseVariant(aValue
, VARIANT_AUTO
| VARIANT_KEYWORD
,
4562 nsCSSProps::kCounterSpeakAsKTable
)) {
4563 if (aValue
.GetUnit() == eCSSUnit_Enumerated
&&
4564 aValue
.GetIntValue() == NS_STYLE_COUNTER_SPEAKAS_SPELL_OUT
) {
4565 // Currently spell-out is not supported, so it is explicitly
4566 // rejected here rather than parsed as a custom identifier.
4572 return ParseCounterStyleNameValue(aValue
);
4575 NS_NOTREACHED("unknown descriptor");
4581 CSSParserImpl::ParseCounterRange(nsCSSValuePair
& aPair
)
4583 static const int32_t VARIANT_BOUND
= VARIANT_INTEGER
| VARIANT_KEYWORD
;
4584 nsCSSValue lower
, upper
;
4585 if (!ParseVariant(lower
, VARIANT_BOUND
, nsCSSProps::kCounterRangeKTable
) ||
4586 !ParseVariant(upper
, VARIANT_BOUND
, nsCSSProps::kCounterRangeKTable
)) {
4589 if (lower
.GetUnit() != eCSSUnit_Enumerated
&&
4590 upper
.GetUnit() != eCSSUnit_Enumerated
&&
4591 lower
.GetIntValue() > upper
.GetIntValue()) {
4594 aPair
= nsCSSValuePair(lower
, upper
);
4599 CSSParserImpl::SkipUntil(char16_t aStopSymbol
)
4601 nsCSSToken
* tk
= &mToken
;
4602 nsAutoTArray
<char16_t
, 16> stack
;
4603 stack
.AppendElement(aStopSymbol
);
4605 if (!GetToken(true)) {
4608 if (eCSSToken_Symbol
== tk
->mType
) {
4609 char16_t symbol
= tk
->mSymbol
;
4610 uint32_t stackTopIndex
= stack
.Length() - 1;
4611 if (symbol
== stack
.ElementAt(stackTopIndex
)) {
4612 stack
.RemoveElementAt(stackTopIndex
);
4613 if (stackTopIndex
== 0) {
4617 // Just handle out-of-memory by parsing incorrectly. It's
4618 // highly unlikely we're dealing with a legitimate style sheet
4620 } else if ('{' == symbol
) {
4621 stack
.AppendElement('}');
4622 } else if ('[' == symbol
) {
4623 stack
.AppendElement(']');
4624 } else if ('(' == symbol
) {
4625 stack
.AppendElement(')');
4627 } else if (eCSSToken_Function
== tk
->mType
||
4628 eCSSToken_Bad_URL
== tk
->mType
) {
4629 stack
.AppendElement(')');
4635 CSSParserImpl::SkipBalancedContentUntil(char16_t aStopSymbol
)
4637 nsCSSToken
* tk
= &mToken
;
4638 nsAutoTArray
<char16_t
, 16> stack
;
4639 stack
.AppendElement(aStopSymbol
);
4641 if (!GetToken(true)) {
4644 if (eCSSToken_Symbol
== tk
->mType
) {
4645 char16_t symbol
= tk
->mSymbol
;
4646 uint32_t stackTopIndex
= stack
.Length() - 1;
4647 if (symbol
== stack
.ElementAt(stackTopIndex
)) {
4648 stack
.RemoveElementAt(stackTopIndex
);
4649 if (stackTopIndex
== 0) {
4653 // Just handle out-of-memory by parsing incorrectly. It's
4654 // highly unlikely we're dealing with a legitimate style sheet
4656 } else if ('{' == symbol
) {
4657 stack
.AppendElement('}');
4658 } else if ('[' == symbol
) {
4659 stack
.AppendElement(']');
4660 } else if ('(' == symbol
) {
4661 stack
.AppendElement(')');
4662 } else if (')' == symbol
||
4668 } else if (eCSSToken_Function
== tk
->mType
||
4669 eCSSToken_Bad_URL
== tk
->mType
) {
4670 stack
.AppendElement(')');
4676 CSSParserImpl::SkipUntilOneOf(const char16_t
* aStopSymbolChars
)
4678 nsCSSToken
* tk
= &mToken
;
4679 nsDependentString
stopSymbolChars(aStopSymbolChars
);
4681 if (!GetToken(true)) {
4684 if (eCSSToken_Symbol
== tk
->mType
) {
4685 char16_t symbol
= tk
->mSymbol
;
4686 if (stopSymbolChars
.FindChar(symbol
) != -1) {
4688 } else if ('{' == symbol
) {
4690 } else if ('[' == symbol
) {
4692 } else if ('(' == symbol
) {
4695 } else if (eCSSToken_Function
== tk
->mType
||
4696 eCSSToken_Bad_URL
== tk
->mType
) {
4703 CSSParserImpl::SkipUntilAllOf(const StopSymbolCharStack
& aStopSymbolChars
)
4705 uint32_t i
= aStopSymbolChars
.Length();
4707 SkipUntil(aStopSymbolChars
[i
]);
4712 CSSParserImpl::SkipDeclaration(bool aCheckForBraces
)
4714 nsCSSToken
* tk
= &mToken
;
4716 if (!GetToken(true)) {
4717 if (aCheckForBraces
) {
4718 REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF
);
4722 if (eCSSToken_Symbol
== tk
->mType
) {
4723 char16_t symbol
= tk
->mSymbol
;
4724 if (';' == symbol
) {
4727 if (aCheckForBraces
) {
4728 if ('}' == symbol
) {
4733 if ('{' == symbol
) {
4735 } else if ('(' == symbol
) {
4737 } else if ('[' == symbol
) {
4740 } else if (eCSSToken_Function
== tk
->mType
||
4741 eCSSToken_Bad_URL
== tk
->mType
) {
4749 CSSParserImpl::SkipRuleSet(bool aInsideBraces
)
4751 nsCSSToken
* tk
= &mToken
;
4753 if (!GetToken(true)) {
4754 REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF
);
4757 if (eCSSToken_Symbol
== tk
->mType
) {
4758 char16_t symbol
= tk
->mSymbol
;
4759 if ('}' == symbol
&& aInsideBraces
) {
4760 // leave block closer for higher-level grammar to consume
4763 } else if ('{' == symbol
) {
4766 } else if ('(' == symbol
) {
4768 } else if ('[' == symbol
) {
4771 } else if (eCSSToken_Function
== tk
->mType
||
4772 eCSSToken_Bad_URL
== tk
->mType
) {
4779 CSSParserImpl::PushGroup(css::GroupRule
* aRule
)
4781 mGroupStack
.AppendElement(aRule
);
4785 CSSParserImpl::PopGroup()
4787 uint32_t count
= mGroupStack
.Length();
4789 mGroupStack
.RemoveElementAt(count
- 1);
4794 CSSParserImpl::AppendRule(css::Rule
* aRule
)
4796 uint32_t count
= mGroupStack
.Length();
4798 mGroupStack
[count
- 1]->AppendStyleRule(aRule
);
4801 mSheet
->AppendStyleRule(aRule
);
4806 CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc
, void* aData
,
4809 // First get the list of selectors for the rule
4810 nsCSSSelectorList
* slist
= nullptr;
4811 uint32_t linenum
, colnum
;
4812 if (!GetNextTokenLocation(true, &linenum
, &colnum
) ||
4813 !ParseSelectorList(slist
, char16_t('{'))) {
4814 REPORT_UNEXPECTED(PEBadSelectorRSIgnored
);
4816 SkipRuleSet(aInsideBraces
);
4819 NS_ASSERTION(nullptr != slist
, "null selector list");
4822 // Next parse the declaration block
4823 uint32_t parseFlags
= eParseDeclaration_InBraces
|
4824 eParseDeclaration_AllowImportant
;
4825 css::Declaration
* declaration
= ParseDeclarationBlock(parseFlags
);
4826 if (nullptr == declaration
) {
4833 fputs("{\n", stdout
);
4834 declaration
->List();
4835 fputs("}\n", stdout
);
4838 // Translate the selector list and declaration block into style data
4840 nsRefPtr
<css::StyleRule
> rule
= new css::StyleRule(slist
, declaration
,
4842 (*aAppendFunc
)(rule
, aData
);
4848 CSSParserImpl::ParseSelectorList(nsCSSSelectorList
*& aListHead
,
4851 nsCSSSelectorList
* list
= nullptr;
4852 if (! ParseSelectorGroup(list
)) {
4853 // must have at least one selector group
4854 aListHead
= nullptr;
4857 NS_ASSERTION(nullptr != list
, "no selector list");
4860 // After that there must either be a "," or a "{" (the latter if
4861 // StopChar is nonzero)
4862 nsCSSToken
* tk
= &mToken
;
4864 if (! GetToken(true)) {
4865 if (aStopChar
== char16_t(0)) {
4869 REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF
);
4873 if (eCSSToken_Symbol
== tk
->mType
) {
4874 if (',' == tk
->mSymbol
) {
4875 nsCSSSelectorList
* newList
= nullptr;
4876 // Another selector group must follow
4877 if (! ParseSelectorGroup(newList
)) {
4880 // add new list to the end of the selector list
4881 list
->mNext
= newList
;
4884 } else if (aStopChar
== tk
->mSymbol
&& aStopChar
!= char16_t(0)) {
4889 REPORT_UNEXPECTED_TOKEN(PESelectorListExtra
);
4895 aListHead
= nullptr;
4899 static bool IsUniversalSelector(const nsCSSSelector
& aSelector
)
4901 return bool((aSelector
.mNameSpace
== kNameSpaceID_Unknown
) &&
4902 (aSelector
.mLowercaseTag
== nullptr) &&
4903 (aSelector
.mIDList
== nullptr) &&
4904 (aSelector
.mClassList
== nullptr) &&
4905 (aSelector
.mAttrList
== nullptr) &&
4906 (aSelector
.mNegations
== nullptr) &&
4907 (aSelector
.mPseudoClassList
== nullptr));
4911 CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList
*& aList
)
4913 char16_t combinator
= 0;
4914 nsAutoPtr
<nsCSSSelectorList
> list(new nsCSSSelectorList());
4917 if (!ParseSelector(list
, combinator
)) {
4921 // Look for a combinator.
4922 if (!GetToken(false)) {
4923 break; // EOF ok here
4926 combinator
= char16_t(0);
4927 if (mToken
.mType
== eCSSToken_Whitespace
) {
4928 if (!GetToken(true)) {
4929 break; // EOF ok here
4931 combinator
= char16_t(' ');
4934 if (mToken
.mType
!= eCSSToken_Symbol
) {
4935 UngetToken(); // not a combinator
4937 char16_t symbol
= mToken
.mSymbol
;
4938 if (symbol
== '+' || symbol
== '>' || symbol
== '~') {
4939 combinator
= mToken
.mSymbol
;
4941 UngetToken(); // not a combinator
4942 if (symbol
== ',' || symbol
== '{' || symbol
== ')') {
4943 break; // end of selector group
4949 REPORT_UNEXPECTED_TOKEN(PESelectorListExtra
);
4954 aList
= list
.forget();
4958 #define SEL_MASK_NSPACE 0x01
4959 #define SEL_MASK_ELEM 0x02
4960 #define SEL_MASK_ID 0x04
4961 #define SEL_MASK_CLASS 0x08
4962 #define SEL_MASK_ATTRIB 0x10
4963 #define SEL_MASK_PCLASS 0x20
4964 #define SEL_MASK_PELEM 0x40
4967 // Parses an ID selector #name
4969 CSSParserImpl::nsSelectorParsingStatus
4970 CSSParserImpl::ParseIDSelector(int32_t& aDataMask
,
4971 nsCSSSelector
& aSelector
)
4973 NS_ASSERTION(!mToken
.mIdent
.IsEmpty(),
4974 "Empty mIdent in eCSSToken_ID token?");
4975 aDataMask
|= SEL_MASK_ID
;
4976 aSelector
.AddID(mToken
.mIdent
);
4977 return eSelectorParsingStatus_Continue
;
4981 // Parses a class selector .name
4983 CSSParserImpl::nsSelectorParsingStatus
4984 CSSParserImpl::ParseClassSelector(int32_t& aDataMask
,
4985 nsCSSSelector
& aSelector
)
4987 if (! GetToken(false)) { // get ident
4988 REPORT_UNEXPECTED_EOF(PEClassSelEOF
);
4989 return eSelectorParsingStatus_Error
;
4991 if (eCSSToken_Ident
!= mToken
.mType
) { // malformed selector
4992 REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent
);
4994 return eSelectorParsingStatus_Error
;
4996 aDataMask
|= SEL_MASK_CLASS
;
4998 aSelector
.AddClass(mToken
.mIdent
);
5000 return eSelectorParsingStatus_Continue
;
5004 // Parse a type element selector or a universal selector
5005 // namespace|type or namespace|* or *|* or *
5007 CSSParserImpl::nsSelectorParsingStatus
5008 CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask
,
5009 nsCSSSelector
& aSelector
,
5012 nsAutoString buffer
;
5013 if (mToken
.IsSymbol('*')) { // universal element selector, or universal namespace
5014 if (ExpectSymbol('|', false)) { // was namespace
5015 aDataMask
|= SEL_MASK_NSPACE
;
5016 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // namespace wildcard
5018 if (! GetToken(false)) {
5019 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
5020 return eSelectorParsingStatus_Error
;
5022 if (eCSSToken_Ident
== mToken
.mType
) { // element name
5023 aDataMask
|= SEL_MASK_ELEM
;
5025 aSelector
.SetTag(mToken
.mIdent
);
5027 else if (mToken
.IsSymbol('*')) { // universal selector
5028 aDataMask
|= SEL_MASK_ELEM
;
5032 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
5034 return eSelectorParsingStatus_Error
;
5037 else { // was universal element selector
5038 SetDefaultNamespaceOnSelector(aSelector
);
5039 aDataMask
|= SEL_MASK_ELEM
;
5040 // don't set any tag in the selector
5042 if (! GetToken(false)) { // premature eof is ok (here!)
5043 return eSelectorParsingStatus_Done
;
5046 else if (eCSSToken_Ident
== mToken
.mType
) { // element name or namespace name
5047 buffer
= mToken
.mIdent
; // hang on to ident
5049 if (ExpectSymbol('|', false)) { // was namespace
5050 aDataMask
|= SEL_MASK_NSPACE
;
5051 int32_t nameSpaceID
= GetNamespaceIdForPrefix(buffer
);
5052 if (nameSpaceID
== kNameSpaceID_Unknown
) {
5053 return eSelectorParsingStatus_Error
;
5055 aSelector
.SetNameSpace(nameSpaceID
);
5057 if (! GetToken(false)) {
5058 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
5059 return eSelectorParsingStatus_Error
;
5061 if (eCSSToken_Ident
== mToken
.mType
) { // element name
5062 aDataMask
|= SEL_MASK_ELEM
;
5063 aSelector
.SetTag(mToken
.mIdent
);
5065 else if (mToken
.IsSymbol('*')) { // universal selector
5066 aDataMask
|= SEL_MASK_ELEM
;
5070 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
5072 return eSelectorParsingStatus_Error
;
5075 else { // was element name
5076 SetDefaultNamespaceOnSelector(aSelector
);
5077 aSelector
.SetTag(buffer
);
5079 aDataMask
|= SEL_MASK_ELEM
;
5081 if (! GetToken(false)) { // premature eof is ok (here!)
5082 return eSelectorParsingStatus_Done
;
5085 else if (mToken
.IsSymbol('|')) { // No namespace
5086 aDataMask
|= SEL_MASK_NSPACE
;
5087 aSelector
.SetNameSpace(kNameSpaceID_None
); // explicit NO namespace
5089 // get mandatory tag
5090 if (! GetToken(false)) {
5091 REPORT_UNEXPECTED_EOF(PETypeSelEOF
);
5092 return eSelectorParsingStatus_Error
;
5094 if (eCSSToken_Ident
== mToken
.mType
) { // element name
5095 aDataMask
|= SEL_MASK_ELEM
;
5096 aSelector
.SetTag(mToken
.mIdent
);
5098 else if (mToken
.IsSymbol('*')) { // universal selector
5099 aDataMask
|= SEL_MASK_ELEM
;
5103 REPORT_UNEXPECTED_TOKEN(PETypeSelNotType
);
5105 return eSelectorParsingStatus_Error
;
5107 if (! GetToken(false)) { // premature eof is ok (here!)
5108 return eSelectorParsingStatus_Done
;
5112 SetDefaultNamespaceOnSelector(aSelector
);
5116 // restore last token read in case of a negated type selector
5119 return eSelectorParsingStatus_Continue
;
5123 // Parse attribute selectors [attr], [attr=value], [attr|=value],
5124 // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
5126 CSSParserImpl::nsSelectorParsingStatus
5127 CSSParserImpl::ParseAttributeSelector(int32_t& aDataMask
,
5128 nsCSSSelector
& aSelector
)
5130 if (! GetToken(true)) { // premature EOF
5131 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
5132 return eSelectorParsingStatus_Error
;
5135 int32_t nameSpaceID
= kNameSpaceID_None
;
5137 if (mToken
.IsSymbol('*')) { // wildcard namespace
5138 nameSpaceID
= kNameSpaceID_Unknown
;
5139 if (ExpectSymbol('|', false)) {
5140 if (! GetToken(false)) { // premature EOF
5141 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
5142 return eSelectorParsingStatus_Error
;
5144 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
5145 attr
= mToken
.mIdent
;
5148 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
5150 return eSelectorParsingStatus_Error
;
5154 REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar
);
5155 return eSelectorParsingStatus_Error
;
5158 else if (mToken
.IsSymbol('|')) { // NO namespace
5159 if (! GetToken(false)) { // premature EOF
5160 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
5161 return eSelectorParsingStatus_Error
;
5163 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
5164 attr
= mToken
.mIdent
;
5167 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
5169 return eSelectorParsingStatus_Error
;
5172 else if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
5173 attr
= mToken
.mIdent
; // hang on to it
5174 if (ExpectSymbol('|', false)) { // was a namespace
5175 nameSpaceID
= GetNamespaceIdForPrefix(attr
);
5176 if (nameSpaceID
== kNameSpaceID_Unknown
) {
5177 return eSelectorParsingStatus_Error
;
5179 if (! GetToken(false)) { // premature EOF
5180 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
5181 return eSelectorParsingStatus_Error
;
5183 if (eCSSToken_Ident
== mToken
.mType
) { // attr name
5184 attr
= mToken
.mIdent
;
5187 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
5189 return eSelectorParsingStatus_Error
;
5194 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
5196 return eSelectorParsingStatus_Error
;
5199 if (! GetToken(true)) { // premature EOF
5200 REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF
);
5201 return eSelectorParsingStatus_Error
;
5203 if ((eCSSToken_Symbol
== mToken
.mType
) ||
5204 (eCSSToken_Includes
== mToken
.mType
) ||
5205 (eCSSToken_Dashmatch
== mToken
.mType
) ||
5206 (eCSSToken_Beginsmatch
== mToken
.mType
) ||
5207 (eCSSToken_Endsmatch
== mToken
.mType
) ||
5208 (eCSSToken_Containsmatch
== mToken
.mType
)) {
5210 if (eCSSToken_Includes
== mToken
.mType
) {
5211 func
= NS_ATTR_FUNC_INCLUDES
;
5213 else if (eCSSToken_Dashmatch
== mToken
.mType
) {
5214 func
= NS_ATTR_FUNC_DASHMATCH
;
5216 else if (eCSSToken_Beginsmatch
== mToken
.mType
) {
5217 func
= NS_ATTR_FUNC_BEGINSMATCH
;
5219 else if (eCSSToken_Endsmatch
== mToken
.mType
) {
5220 func
= NS_ATTR_FUNC_ENDSMATCH
;
5222 else if (eCSSToken_Containsmatch
== mToken
.mType
) {
5223 func
= NS_ATTR_FUNC_CONTAINSMATCH
;
5225 else if (']' == mToken
.mSymbol
) {
5226 aDataMask
|= SEL_MASK_ATTRIB
;
5227 aSelector
.AddAttribute(nameSpaceID
, attr
);
5228 func
= NS_ATTR_FUNC_SET
;
5230 else if ('=' == mToken
.mSymbol
) {
5231 func
= NS_ATTR_FUNC_EQUALS
;
5234 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
5235 UngetToken(); // bad function
5236 return eSelectorParsingStatus_Error
;
5238 if (NS_ATTR_FUNC_SET
!= func
) { // get value
5239 if (! GetToken(true)) { // premature EOF
5240 REPORT_UNEXPECTED_EOF(PEAttSelValueEOF
);
5241 return eSelectorParsingStatus_Error
;
5243 if ((eCSSToken_Ident
== mToken
.mType
) || (eCSSToken_String
== mToken
.mType
)) {
5244 nsAutoString
value(mToken
.mIdent
);
5245 if (! GetToken(true)) { // premature EOF
5246 REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF
);
5247 return eSelectorParsingStatus_Error
;
5249 if (mToken
.IsSymbol(']')) {
5250 bool isCaseSensitive
= true;
5252 // For cases when this style sheet is applied to an HTML
5253 // element in an HTML document, and the attribute selector is
5254 // for a non-namespaced attribute, then check to see if it's
5255 // one of the known attributes whose VALUE is
5256 // case-insensitive.
5257 if (nameSpaceID
== kNameSpaceID_None
) {
5258 static const char* caseInsensitiveHTMLAttribute
[] = {
5259 // list based on http://www.w3.org/TR/html4/
5305 // additional attributes not in HTML4
5306 "direction", // marquee
5310 const char* htmlAttr
;
5311 while ((htmlAttr
= caseInsensitiveHTMLAttribute
[i
++])) {
5312 if (attr
.LowerCaseEqualsASCII(htmlAttr
)) {
5313 isCaseSensitive
= false;
5318 aDataMask
|= SEL_MASK_ATTRIB
;
5319 aSelector
.AddAttribute(nameSpaceID
, attr
, func
, value
, isCaseSensitive
);
5322 REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose
);
5324 return eSelectorParsingStatus_Error
;
5328 REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue
);
5330 return eSelectorParsingStatus_Error
;
5335 REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected
);
5336 UngetToken(); // bad dog, no biscut!
5337 return eSelectorParsingStatus_Error
;
5339 return eSelectorParsingStatus_Continue
;
5343 // Parse pseudo-classes and pseudo-elements
5345 CSSParserImpl::nsSelectorParsingStatus
5346 CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask
,
5347 nsCSSSelector
& aSelector
,
5349 nsIAtom
** aPseudoElement
,
5350 nsAtomList
** aPseudoElementArgs
,
5351 nsCSSPseudoElements::Type
* aPseudoElementType
)
5353 NS_ASSERTION(aIsNegated
|| (aPseudoElement
&& aPseudoElementArgs
),
5354 "expected location to store pseudo element");
5355 NS_ASSERTION(!aIsNegated
|| (!aPseudoElement
&& !aPseudoElementArgs
),
5356 "negated selectors shouldn't have a place to store "
5358 if (! GetToken(false)) { // premature eof
5359 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
5360 return eSelectorParsingStatus_Error
;
5363 // First, find out whether we are parsing a CSS3 pseudo-element
5364 bool parsingPseudoElement
= false;
5365 if (mToken
.IsSymbol(':')) {
5366 parsingPseudoElement
= true;
5367 if (! GetToken(false)) { // premature eof
5368 REPORT_UNEXPECTED_EOF(PEPseudoSelEOF
);
5369 return eSelectorParsingStatus_Error
;
5373 // Do some sanity-checking on the token
5374 if (eCSSToken_Ident
!= mToken
.mType
&& eCSSToken_Function
!= mToken
.mType
) {
5375 // malformed selector
5376 REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName
);
5378 return eSelectorParsingStatus_Error
;
5381 // OK, now we know we have an mIdent. Atomize it. All the atoms, for
5382 // pseudo-classes as well as pseudo-elements, start with a single ':'.
5383 nsAutoString buffer
;
5384 buffer
.Append(char16_t(':'));
5385 buffer
.Append(mToken
.mIdent
);
5386 nsContentUtils::ASCIIToLower(buffer
);
5387 nsCOMPtr
<nsIAtom
> pseudo
= do_GetAtom(buffer
);
5389 NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
5392 // stash away some info about this pseudo so we only have to get it once.
5393 bool isTreePseudo
= false;
5394 nsCSSPseudoElements::Type pseudoElementType
=
5395 nsCSSPseudoElements::GetPseudoType(pseudo
);
5396 nsCSSPseudoClasses::Type pseudoClassType
=
5397 nsCSSPseudoClasses::GetPseudoType(pseudo
);
5398 bool pseudoClassIsUserAction
=
5399 nsCSSPseudoClasses::IsUserActionPseudoClass(pseudoClassType
);
5401 if (!mUnsafeRulesEnabled
&&
5402 ((pseudoElementType
< nsCSSPseudoElements::ePseudo_PseudoElementCount
&&
5403 nsCSSPseudoElements::PseudoElementIsUASheetOnly(pseudoElementType
)) ||
5404 (pseudoClassType
!= nsCSSPseudoClasses::ePseudoClass_NotPseudoClass
&&
5405 nsCSSPseudoClasses::PseudoClassIsUASheetOnly(pseudoClassType
)))) {
5406 // This pseudo-element or pseudo-class is not exposed to content.
5407 REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown
);
5409 return eSelectorParsingStatus_Error
;
5412 // We currently allow :-moz-placeholder and ::-moz-placeholder. We have to
5413 // be a bit stricter regarding the pseudo-element parsing rules.
5414 if (pseudoElementType
== nsCSSPseudoElements::ePseudo_mozPlaceholder
&&
5415 pseudoClassType
== nsCSSPseudoClasses::ePseudoClass_mozPlaceholder
) {
5416 if (parsingPseudoElement
) {
5417 pseudoClassType
= nsCSSPseudoClasses::ePseudoClass_NotPseudoClass
;
5419 pseudoElementType
= nsCSSPseudoElements::ePseudo_NotPseudoElement
;
5424 isTreePseudo
= (pseudoElementType
== nsCSSPseudoElements::ePseudo_XULTree
);
5425 // If a tree pseudo-element is using the function syntax, it will
5426 // get isTree set here and will pass the check below that only
5427 // allows functions if they are in our list of things allowed to be
5428 // functions. If it is _not_ using the function syntax, isTree will
5429 // be false, and it will still pass that check. So the tree
5430 // pseudo-elements are allowed to be either functions or not, as
5432 bool isTree
= (eCSSToken_Function
== mToken
.mType
) && isTreePseudo
;
5434 bool isPseudoElement
=
5435 (pseudoElementType
< nsCSSPseudoElements::ePseudo_PseudoElementCount
);
5436 // anonymous boxes are only allowed if they're the tree boxes or we have
5437 // enabled unsafe rules
5438 bool isAnonBox
= isTreePseudo
||
5439 (pseudoElementType
== nsCSSPseudoElements::ePseudo_AnonBox
&&
5440 mUnsafeRulesEnabled
);
5441 bool isPseudoClass
=
5442 (pseudoClassType
!= nsCSSPseudoClasses::ePseudoClass_NotPseudoClass
);
5444 NS_ASSERTION(!isPseudoClass
||
5445 pseudoElementType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
,
5446 "Why is this atom both a pseudo-class and a pseudo-element?");
5447 NS_ASSERTION(isPseudoClass
+ isPseudoElement
+ isAnonBox
<= 1,
5448 "Shouldn't be more than one of these");
5450 if (!isPseudoClass
&& !isPseudoElement
&& !isAnonBox
) {
5451 // Not a pseudo-class, not a pseudo-element.... forget it
5452 REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown
);
5454 return eSelectorParsingStatus_Error
;
5457 // If it's a function token, it better be on our "ok" list, and if the name
5458 // is that of a function pseudo it better be a function token
5459 if ((eCSSToken_Function
== mToken
.mType
) !=
5464 nsCSSPseudoClasses::ePseudoClass_notPseudo
== pseudoClassType
||
5465 nsCSSPseudoClasses::HasStringArg(pseudoClassType
) ||
5466 nsCSSPseudoClasses::HasNthPairArg(pseudoClassType
) ||
5467 nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType
))) {
5468 // There are no other function pseudos
5469 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc
);
5471 return eSelectorParsingStatus_Error
;
5474 // If it starts with "::", it better be a pseudo-element
5475 if (parsingPseudoElement
&&
5478 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE
);
5480 return eSelectorParsingStatus_Error
;
5483 if (!parsingPseudoElement
&&
5484 nsCSSPseudoClasses::ePseudoClass_notPseudo
== pseudoClassType
) {
5485 if (aIsNegated
) { // :not() can't be itself negated
5486 REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot
);
5488 return eSelectorParsingStatus_Error
;
5490 // CSS 3 Negation pseudo-class takes one simple selector as argument
5491 nsSelectorParsingStatus parsingStatus
=
5492 ParseNegatedSimpleSelector(aDataMask
, aSelector
);
5493 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
5494 return parsingStatus
;
5497 else if (!parsingPseudoElement
&& isPseudoClass
) {
5498 if (aSelector
.IsPseudoElement()) {
5499 nsCSSPseudoElements::Type type
= aSelector
.PseudoType();
5500 if (!nsCSSPseudoElements::PseudoElementSupportsUserActionState(type
)) {
5501 // We only allow user action pseudo-classes on certain pseudo-elements.
5502 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNoUserActionPC
);
5504 return eSelectorParsingStatus_Error
;
5506 if (!pseudoClassIsUserAction
) {
5507 // CSS 4 Selectors says that pseudo-elements can only be followed by
5508 // a user action pseudo-class.
5509 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNotUserAction
);
5511 return eSelectorParsingStatus_Error
;
5514 aDataMask
|= SEL_MASK_PCLASS
;
5515 if (eCSSToken_Function
== mToken
.mType
) {
5516 nsSelectorParsingStatus parsingStatus
;
5517 if (nsCSSPseudoClasses::HasStringArg(pseudoClassType
)) {
5519 ParsePseudoClassWithIdentArg(aSelector
, pseudoClassType
);
5521 else if (nsCSSPseudoClasses::HasNthPairArg(pseudoClassType
)) {
5523 ParsePseudoClassWithNthPairArg(aSelector
, pseudoClassType
);
5526 NS_ABORT_IF_FALSE(nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType
),
5527 "unexpected pseudo with function token");
5528 parsingStatus
= ParsePseudoClassWithSelectorListArg(aSelector
,
5531 if (eSelectorParsingStatus_Continue
!= parsingStatus
) {
5532 if (eSelectorParsingStatus_Error
== parsingStatus
) {
5535 return parsingStatus
;
5539 aSelector
.AddPseudoClass(pseudoClassType
);
5542 else if (isPseudoElement
|| isAnonBox
) {
5543 // Pseudo-element. Make some more sanity checks.
5545 if (aIsNegated
) { // pseudo-elements can't be negated
5546 REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot
);
5548 return eSelectorParsingStatus_Error
;
5550 // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
5551 // to have a single ':' on them. Others (CSS3+ pseudo-elements and
5552 // various -moz-* pseudo-elements) must have |parsingPseudoElement|
5554 if (!parsingPseudoElement
&&
5555 !nsCSSPseudoElements::IsCSS2PseudoElement(pseudo
)
5560 REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly
);
5562 return eSelectorParsingStatus_Error
;
5565 if (0 == (aDataMask
& SEL_MASK_PELEM
)) {
5566 aDataMask
|= SEL_MASK_PELEM
;
5567 NS_ADDREF(*aPseudoElement
= pseudo
);
5568 *aPseudoElementType
= pseudoElementType
;
5572 // We have encountered a pseudoelement of the form
5573 // -moz-tree-xxxx(a,b,c). We parse (a,b,c) and add each
5574 // item in the list to the pseudoclass list. They will be pulled
5575 // from the list later along with the pseudo-element.
5576 if (!ParseTreePseudoElement(aPseudoElementArgs
)) {
5577 return eSelectorParsingStatus_Error
;
5582 // Pseudo-elements can only be followed by user action pseudo-classes
5583 // or be the end of the selector. So the next non-whitespace token must
5584 // be ':', '{' or ',' or EOF.
5585 if (!GetToken(true)) { // premature eof is ok (here!)
5586 return eSelectorParsingStatus_Done
;
5588 if (parsingPseudoElement
&& mToken
.IsSymbol(':')) {
5590 return eSelectorParsingStatus_Continue
;
5592 if ((mToken
.IsSymbol('{') || mToken
.IsSymbol(','))) {
5594 return eSelectorParsingStatus_Done
;
5596 REPORT_UNEXPECTED_TOKEN(PEPseudoSelEndOrUserActionPC
);
5598 return eSelectorParsingStatus_Error
;
5600 else { // multiple pseudo elements, not legal
5601 REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE
);
5603 return eSelectorParsingStatus_Error
;
5608 // We should never end up here. Indeed, if we ended up here, we know (from
5609 // the current if/else cascade) that !isPseudoElement and !isAnonBox. But
5610 // then due to our earlier check we know that isPseudoClass. Since we
5611 // didn't fall into the isPseudoClass case in this cascade, we must have
5612 // parsingPseudoElement. But we've already checked the
5613 // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if
5615 NS_NOTREACHED("How did this happen?");
5618 return eSelectorParsingStatus_Continue
;
5622 // Parse the argument of a negation pseudo-class :not()
5624 CSSParserImpl::nsSelectorParsingStatus
5625 CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask
,
5626 nsCSSSelector
& aSelector
)
5628 if (! GetToken(true)) { // premature eof
5629 REPORT_UNEXPECTED_EOF(PENegationEOF
);
5630 return eSelectorParsingStatus_Error
;
5633 if (mToken
.IsSymbol(')')) {
5634 REPORT_UNEXPECTED_TOKEN(PENegationBadArg
);
5635 return eSelectorParsingStatus_Error
;
5638 // Create a new nsCSSSelector and add it to the end of
5639 // aSelector.mNegations.
5640 // Given the current parsing rules, every selector in mNegations
5641 // contains only one simple selector (css3 definition) within it.
5642 // This could easily change in future versions of CSS, and the only
5643 // thing we need to change to support that is this parsing code and the
5644 // serialization code for nsCSSSelector.
5645 nsCSSSelector
*newSel
= new nsCSSSelector();
5646 nsCSSSelector
* negations
= &aSelector
;
5647 while (negations
->mNegations
) {
5648 negations
= negations
->mNegations
;
5650 negations
->mNegations
= newSel
;
5652 nsSelectorParsingStatus parsingStatus
;
5653 if (eCSSToken_ID
== mToken
.mType
) { // #id
5654 parsingStatus
= ParseIDSelector(aDataMask
, *newSel
);
5656 else if (mToken
.IsSymbol('.')) { // .class
5657 parsingStatus
= ParseClassSelector(aDataMask
, *newSel
);
5659 else if (mToken
.IsSymbol(':')) { // :pseudo
5660 parsingStatus
= ParsePseudoSelector(aDataMask
, *newSel
, true,
5661 nullptr, nullptr, nullptr);
5663 else if (mToken
.IsSymbol('[')) { // [attribute
5664 parsingStatus
= ParseAttributeSelector(aDataMask
, *newSel
);
5665 if (eSelectorParsingStatus_Error
== parsingStatus
) {
5666 // Skip forward to the matching ']'
5671 // then it should be a type element or universal selector
5672 parsingStatus
= ParseTypeOrUniversalSelector(aDataMask
, *newSel
, true);
5674 if (eSelectorParsingStatus_Error
== parsingStatus
) {
5675 REPORT_UNEXPECTED_TOKEN(PENegationBadInner
);
5677 return parsingStatus
;
5679 // close the parenthesis
5680 if (!ExpectSymbol(')', true)) {
5681 REPORT_UNEXPECTED_TOKEN(PENegationNoClose
);
5683 return eSelectorParsingStatus_Error
;
5686 NS_ASSERTION(newSel
->mNameSpace
== kNameSpaceID_Unknown
||
5687 (!newSel
->mIDList
&& !newSel
->mClassList
&&
5688 !newSel
->mPseudoClassList
&& !newSel
->mAttrList
),
5689 "Need to fix the serialization code to deal with this");
5691 return eSelectorParsingStatus_Continue
;
5695 // Parse the argument of a pseudo-class that has an ident arg
5697 CSSParserImpl::nsSelectorParsingStatus
5698 CSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector
& aSelector
,
5699 nsCSSPseudoClasses::Type aType
)
5701 if (! GetToken(true)) { // premature eof
5702 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
5703 return eSelectorParsingStatus_Error
;
5705 // We expect an identifier with a language abbreviation
5706 if (eCSSToken_Ident
!= mToken
.mType
) {
5707 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent
);
5709 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5712 // -moz-locale-dir and -moz-dir take an identifier argument. While
5713 // only 'ltr' and 'rtl' (case-insensitively) will match anything, any
5714 // other identifier is still valid.
5715 if (aType
== nsCSSPseudoClasses::ePseudoClass_mozLocaleDir
||
5716 aType
== nsCSSPseudoClasses::ePseudoClass_dir
) {
5717 nsContentUtils::ASCIIToLower(mToken
.mIdent
); // case insensitive
5720 // Add the pseudo with the language parameter
5721 aSelector
.AddPseudoClass(aType
, mToken
.mIdent
.get());
5723 // close the parenthesis
5724 if (!ExpectSymbol(')', true)) {
5725 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
5726 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5729 return eSelectorParsingStatus_Continue
;
5732 CSSParserImpl::nsSelectorParsingStatus
5733 CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector
& aSelector
,
5734 nsCSSPseudoClasses::Type aType
)
5736 int32_t numbers
[2] = { 0, 0 };
5737 int32_t sign
[2] = { 1, 1 };
5738 bool hasSign
[2] = { false, false };
5739 bool lookForB
= true;
5741 // Follow the whitespace rules as proposed in
5742 // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
5744 if (! GetToken(true)) {
5745 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
5746 return eSelectorParsingStatus_Error
;
5749 if (mToken
.IsSymbol('+') || mToken
.IsSymbol('-')) {
5751 if (mToken
.IsSymbol('-')) {
5754 if (! GetToken(false)) {
5755 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
5756 return eSelectorParsingStatus_Error
;
5760 if (eCSSToken_Ident
== mToken
.mType
|| eCSSToken_Dimension
== mToken
.mType
) {
5761 // The CSS tokenization doesn't handle :nth-child() containing - well:
5762 // 2n-1 is a dimension
5763 // n-1 is an identifier
5764 // The easiest way to deal with that is to push everything from the
5765 // minus on back onto the scanner's pushback buffer.
5766 uint32_t truncAt
= 0;
5767 if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("n-"))) {
5769 } else if (StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("-n-")) && !hasSign
[0]) {
5773 mScanner
->Backup(mToken
.mIdent
.Length() - truncAt
);
5774 mToken
.mIdent
.Truncate(truncAt
);
5778 if (eCSSToken_Ident
== mToken
.mType
) {
5779 if (mToken
.mIdent
.LowerCaseEqualsLiteral("odd") && !hasSign
[0]) {
5784 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("even") && !hasSign
[0]) {
5789 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("n")) {
5790 numbers
[0] = sign
[0];
5792 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("-n") && !hasSign
[0]) {
5796 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
5797 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5800 else if (eCSSToken_Number
== mToken
.mType
) {
5801 if (!mToken
.mIntegerValid
) {
5802 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
5803 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5806 if (mToken
.mHasSign
&& hasSign
[0]) {
5807 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
5808 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5810 int32_t intValue
= mToken
.mInteger
* sign
[0];
5812 if (! GetToken(false)) {
5813 numbers
[1] = intValue
;
5817 if (eCSSToken_Ident
== mToken
.mType
&& mToken
.mIdent
.LowerCaseEqualsLiteral("n")) {
5818 numbers
[0] = intValue
;
5820 else if (eCSSToken_Ident
== mToken
.mType
&& StringBeginsWith(mToken
.mIdent
, NS_LITERAL_STRING("n-"))) {
5821 numbers
[0] = intValue
;
5822 mScanner
->Backup(mToken
.mIdent
.Length() - 1);
5826 numbers
[1] = intValue
;
5831 else if (eCSSToken_Dimension
== mToken
.mType
) {
5832 if (!mToken
.mIntegerValid
|| !mToken
.mIdent
.LowerCaseEqualsLiteral("n")) {
5833 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
5834 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5837 if ( mToken
.mHasSign
&& hasSign
[0] ) {
5838 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
5839 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5841 numbers
[0] = mToken
.mInteger
* sign
[0];
5843 // XXX If it's a ')', is that valid? (as 0n+0)
5845 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
5847 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5850 if (! GetToken(true)) {
5851 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
5852 return eSelectorParsingStatus_Error
;
5854 if (lookForB
&& !mToken
.IsSymbol(')')) {
5855 // The '+' or '-' sign can optionally be separated by whitespace.
5856 // If it is separated by whitespace from what follows it, it appears
5857 // as a separate token rather than part of the number token.
5858 if (mToken
.IsSymbol('+') || mToken
.IsSymbol('-')) {
5860 if (mToken
.IsSymbol('-')) {
5863 if (! GetToken(true)) {
5864 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
5865 return eSelectorParsingStatus_Error
;
5868 if (eCSSToken_Number
!= mToken
.mType
||
5869 !mToken
.mIntegerValid
|| mToken
.mHasSign
== hasSign
[1]) {
5870 REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth
);
5872 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5874 numbers
[1] = mToken
.mInteger
* sign
[1];
5875 if (! GetToken(true)) {
5876 REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF
);
5877 return eSelectorParsingStatus_Error
;
5880 if (!mToken
.IsSymbol(')')) {
5881 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
5882 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5884 aSelector
.AddPseudoClass(aType
, numbers
);
5885 return eSelectorParsingStatus_Continue
;
5889 // Parse the argument of a pseudo-class that has a selector list argument.
5890 // Such selector lists cannot contain combinators, but can contain
5891 // anything that goes between a pair of combinators.
5893 CSSParserImpl::nsSelectorParsingStatus
5894 CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector
& aSelector
,
5895 nsCSSPseudoClasses::Type aType
)
5897 nsAutoPtr
<nsCSSSelectorList
> slist
;
5898 if (! ParseSelectorList(*getter_Transfers(slist
), char16_t(')'))) {
5899 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5902 // Check that none of the selectors in the list have combinators or
5904 for (nsCSSSelectorList
*l
= slist
; l
; l
= l
->mNext
) {
5905 nsCSSSelector
*s
= l
->mSelectors
;
5906 if (s
->mNext
|| s
->IsPseudoElement()) {
5907 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5911 // Add the pseudo with the selector list parameter
5912 aSelector
.AddPseudoClass(aType
, slist
.forget());
5914 // close the parenthesis
5915 if (!ExpectSymbol(')', true)) {
5916 REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose
);
5917 return eSelectorParsingStatus_Error
; // our caller calls SkipUntil(')')
5920 return eSelectorParsingStatus_Continue
;
5925 * This is the format for selectors:
5926 * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
5929 CSSParserImpl::ParseSelector(nsCSSSelectorList
* aList
,
5930 char16_t aPrevCombinator
)
5932 if (! GetToken(true)) {
5933 REPORT_UNEXPECTED_EOF(PESelectorEOF
);
5937 nsCSSSelector
* selector
= aList
->AddSelector(aPrevCombinator
);
5938 nsCOMPtr
<nsIAtom
> pseudoElement
;
5939 nsAutoPtr
<nsAtomList
> pseudoElementArgs
;
5940 nsCSSPseudoElements::Type pseudoElementType
=
5941 nsCSSPseudoElements::ePseudo_NotPseudoElement
;
5943 int32_t dataMask
= 0;
5944 nsSelectorParsingStatus parsingStatus
=
5945 ParseTypeOrUniversalSelector(dataMask
, *selector
, false);
5947 while (parsingStatus
== eSelectorParsingStatus_Continue
) {
5948 if (eCSSToken_ID
== mToken
.mType
) { // #id
5949 parsingStatus
= ParseIDSelector(dataMask
, *selector
);
5951 else if (mToken
.IsSymbol('.')) { // .class
5952 parsingStatus
= ParseClassSelector(dataMask
, *selector
);
5954 else if (mToken
.IsSymbol(':')) { // :pseudo
5955 parsingStatus
= ParsePseudoSelector(dataMask
, *selector
, false,
5956 getter_AddRefs(pseudoElement
),
5957 getter_Transfers(pseudoElementArgs
),
5958 &pseudoElementType
);
5959 if (pseudoElement
&&
5960 pseudoElementType
!= nsCSSPseudoElements::ePseudo_AnonBox
) {
5961 // Pseudo-elements other than anonymous boxes are represented with
5962 // a special ':' combinator.
5964 aList
->mWeight
+= selector
->CalcWeight();
5966 selector
= aList
->AddSelector(':');
5968 selector
->mLowercaseTag
.swap(pseudoElement
);
5969 selector
->mClassList
= pseudoElementArgs
.forget();
5970 selector
->SetPseudoType(pseudoElementType
);
5973 else if (mToken
.IsSymbol('[')) { // [attribute
5974 parsingStatus
= ParseAttributeSelector(dataMask
, *selector
);
5975 if (eSelectorParsingStatus_Error
== parsingStatus
) {
5979 else { // not a selector token, we're done
5980 parsingStatus
= eSelectorParsingStatus_Done
;
5985 if (parsingStatus
!= eSelectorParsingStatus_Continue
) {
5989 if (! GetToken(false)) { // premature eof is ok (here!)
5990 parsingStatus
= eSelectorParsingStatus_Done
;
5995 if (parsingStatus
== eSelectorParsingStatus_Error
) {
6000 if (selector
->mNext
) {
6001 REPORT_UNEXPECTED(PESelectorGroupExtraCombinator
);
6003 REPORT_UNEXPECTED(PESelectorGroupNoSelector
);
6008 if (pseudoElementType
== nsCSSPseudoElements::ePseudo_AnonBox
) {
6009 // We got an anonymous box pseudo-element; it must be the only
6010 // thing in this selector group.
6011 if (selector
->mNext
|| !IsUniversalSelector(*selector
)) {
6012 REPORT_UNEXPECTED(PEAnonBoxNotAlone
);
6016 // Rewrite the current selector as this pseudo-element.
6017 // It does not contribute to selector weight.
6018 selector
->mLowercaseTag
.swap(pseudoElement
);
6019 selector
->mClassList
= pseudoElementArgs
.forget();
6020 selector
->SetPseudoType(pseudoElementType
);
6024 aList
->mWeight
+= selector
->CalcWeight();
6030 CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags
, nsCSSContextType aContext
)
6032 bool checkForBraces
= (aFlags
& eParseDeclaration_InBraces
) != 0;
6034 if (checkForBraces
) {
6035 if (!ExpectSymbol('{', true)) {
6036 REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart
);
6041 css::Declaration
* declaration
= new css::Declaration();
6042 mData
.AssertInitialState();
6045 if (!ParseDeclaration(declaration
, aFlags
, true, &changed
, aContext
)) {
6046 if (!SkipDeclaration(checkForBraces
)) {
6049 if (checkForBraces
) {
6050 if (ExpectSymbol('}', true)) {
6054 // Since the skipped declaration didn't end the block we parse
6055 // the next declaration.
6058 declaration
->CompressFrom(&mData
);
6063 CSSParserImpl::ParseColor(nsCSSValue
& aValue
)
6065 if (!GetToken(true)) {
6066 REPORT_UNEXPECTED_EOF(PEColorEOF
);
6070 nsCSSToken
* tk
= &mToken
;
6072 switch (tk
->mType
) {
6074 case eCSSToken_Hash
:
6076 if (NS_HexToRGB(tk
->mIdent
, &rgba
)) {
6077 MOZ_ASSERT(tk
->mIdent
.Length() == 3 || tk
->mIdent
.Length() == 6,
6078 "unexpected hex color length");
6079 nsCSSUnit unit
= tk
->mIdent
.Length() == 3 ?
6080 eCSSUnit_ShortHexColor
:
6082 aValue
.SetIntegerColorValue(rgba
, unit
);
6087 case eCSSToken_Ident
:
6088 if (NS_ColorNameToRGB(tk
->mIdent
, &rgba
)) {
6089 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_Ident
);
6093 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
6094 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
6096 if (nsCSSProps::FindKeyword(keyword
, nsCSSProps::kColorKTable
, value
)) {
6097 aValue
.SetIntValue(value
, eCSSUnit_EnumColor
);
6103 case eCSSToken_Function
:
6104 if (mToken
.mIdent
.LowerCaseEqualsLiteral("rgb")) {
6105 // rgb ( component , component , component )
6106 if (GetToken(true)) {
6109 if (mToken
.mType
== eCSSToken_Number
) {
6111 if (ParseNumberColorComponent(r
, ',') &&
6112 ParseNumberColorComponent(g
, ',') &&
6113 ParseNumberColorComponent(b
, ')')) {
6114 aValue
.SetIntegerColorValue(NS_RGB(r
, g
, b
), eCSSUnit_RGBColor
);
6119 if (ParsePercentageColorComponent(r
, ',') &&
6120 ParsePercentageColorComponent(g
, ',') &&
6121 ParsePercentageColorComponent(b
, ')')) {
6122 aValue
.SetFloatColorValue(r
, g
, b
, 1.0f
,
6123 eCSSUnit_PercentageRGBColor
);
6130 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("rgba")) {
6131 // rgba ( component , component , component , opacity )
6132 if (GetToken(true)) {
6135 if (mToken
.mType
== eCSSToken_Number
) {
6137 if (ParseNumberColorComponent(r
, ',') &&
6138 ParseNumberColorComponent(g
, ',') &&
6139 ParseNumberColorComponent(b
, ',') &&
6140 ParseColorOpacity(a
)) {
6141 aValue
.SetIntegerColorValue(NS_RGBA(r
, g
, b
, a
),
6142 eCSSUnit_RGBAColor
);
6147 if (ParsePercentageColorComponent(r
, ',') &&
6148 ParsePercentageColorComponent(g
, ',') &&
6149 ParsePercentageColorComponent(b
, ',') &&
6150 ParseColorOpacity(a
)) {
6151 aValue
.SetFloatColorValue(r
, g
, b
, a
, eCSSUnit_PercentageRGBAColor
);
6158 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("hsl")) {
6159 // hsl ( hue , saturation , lightness )
6160 // "hue" is a number, "saturation" and "lightness" are percentages.
6162 if (ParseHSLColor(h
, s
, l
, ')')) {
6163 aValue
.SetFloatColorValue(h
, s
, l
, 1.0f
, eCSSUnit_HSLColor
);
6169 else if (mToken
.mIdent
.LowerCaseEqualsLiteral("hsla")) {
6170 // hsla ( hue , saturation , lightness , opacity )
6171 // "hue" is a number, "saturation" and "lightness" are percentages,
6172 // "opacity" is a number.
6174 if (ParseHSLColor(h
, s
, l
, ',') &&
6175 ParseColorOpacity(a
)) {
6176 aValue
.SetFloatColorValue(h
, s
, l
, a
, eCSSUnit_HSLAColor
);
6187 // try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804)
6188 if (mHashlessColorQuirk
) {
6189 // - If the string starts with 'a-f', the nsCSSScanner builds the
6190 // token as a eCSSToken_Ident and we can parse the string as a
6191 // 'xxyyzz' RGB color.
6192 // - If it only contains '0-9' digits, the token is a
6193 // eCSSToken_Number and it must be converted back to a 6
6194 // characters string to be parsed as a RGB color.
6195 // - If it starts with '0-9' and contains any 'a-f', the token is a
6196 // eCSSToken_Dimension, the mNumber part must be converted back to
6197 // a string and the mIdent part must be appended to that string so
6198 // that the resulting string has 6 characters.
6199 // Note: This is a hack for Nav compatibility. Do not attempt to
6200 // simplify it by hacking into the ncCSSScanner. This would be very
6204 switch (tk
->mType
) {
6205 case eCSSToken_Ident
:
6206 str
.Assign(tk
->mIdent
);
6209 case eCSSToken_Number
:
6210 if (tk
->mIntegerValid
) {
6211 PR_snprintf(buffer
, sizeof(buffer
), "%06d", tk
->mInteger
);
6212 str
.AssignWithConversion(buffer
);
6216 case eCSSToken_Dimension
:
6217 if (tk
->mIdent
.Length() <= 6) {
6218 PR_snprintf(buffer
, sizeof(buffer
), "%06.0f", tk
->mNumber
);
6220 temp
.AssignWithConversion(buffer
);
6221 temp
.Right(str
, 6 - tk
->mIdent
.Length());
6222 str
.Append(tk
->mIdent
);
6226 // There is a whole bunch of cases that are
6227 // not handled by this switch. Ignore them.
6230 if (NS_HexToRGB(str
, &rgba
)) {
6231 aValue
.SetIntegerColorValue(rgba
, eCSSUnit_HexColor
);
6237 REPORT_UNEXPECTED_TOKEN(PEColorNotColor
);
6243 CSSParserImpl::ParseNumberColorComponent(uint8_t& aComponent
, char aStop
)
6245 if (!GetToken(true)) {
6246 REPORT_UNEXPECTED_EOF(PEColorComponentEOF
);
6250 if (mToken
.mType
!= eCSSToken_Number
|| !mToken
.mIntegerValid
) {
6251 REPORT_UNEXPECTED_TOKEN(PEExpectedInt
);
6256 float value
= mToken
.mNumber
;
6257 if (value
< 0.0f
) value
= 0.0f
;
6258 if (value
> 255.0f
) value
= 255.0f
;
6260 if (ExpectSymbol(aStop
, true)) {
6261 aComponent
= NSToIntRound(value
);
6264 REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm
, aStop
);
6269 CSSParserImpl::ParsePercentageColorComponent(float& aComponent
, char aStop
)
6271 if (!GetToken(true)) {
6272 REPORT_UNEXPECTED_EOF(PEColorComponentEOF
);
6276 if (mToken
.mType
!= eCSSToken_Percentage
) {
6277 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
6282 float value
= mToken
.mNumber
;
6283 if (value
< 0.0f
) value
= 0.0f
;
6284 if (value
> 1.0f
) value
= 1.0f
;
6286 if (ExpectSymbol(aStop
, true)) {
6290 REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm
, aStop
);
6296 CSSParserImpl::ParseHSLColor(float& aHue
, float& aSaturation
, float& aLightness
,
6302 if (!GetToken(true)) {
6303 REPORT_UNEXPECTED_EOF(PEColorHueEOF
);
6306 if (mToken
.mType
!= eCSSToken_Number
) {
6307 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
6313 // hue values are wraparound
6316 if (!ExpectSymbol(',', true)) {
6317 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
6321 // Get the saturation
6322 if (!GetToken(true)) {
6323 REPORT_UNEXPECTED_EOF(PEColorSaturationEOF
);
6326 if (mToken
.mType
!= eCSSToken_Percentage
) {
6327 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
6332 if (s
< 0.0f
) s
= 0.0f
;
6333 if (s
> 1.0f
) s
= 1.0f
;
6335 if (!ExpectSymbol(',', true)) {
6336 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
6340 // Get the lightness
6341 if (!GetToken(true)) {
6342 REPORT_UNEXPECTED_EOF(PEColorLightnessEOF
);
6345 if (mToken
.mType
!= eCSSToken_Percentage
) {
6346 REPORT_UNEXPECTED_TOKEN(PEExpectedPercent
);
6351 if (l
< 0.0f
) l
= 0.0f
;
6352 if (l
> 1.0f
) l
= 1.0f
;
6354 if (ExpectSymbol(aStop
, true)) {
6361 REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm
, aStop
);
6367 CSSParserImpl::ParseColorOpacity(uint8_t& aOpacity
)
6370 if (!ParseColorOpacity(floatOpacity
)) {
6374 uint8_t value
= nsStyleUtil::FloatToColorComponent(floatOpacity
);
6375 // Need to compare to something slightly larger
6376 // than 0.5 due to floating point inaccuracies.
6377 NS_ASSERTION(fabs(255.0f
*mToken
.mNumber
- value
) <= 0.51f
,
6378 "FloatToColorComponent did something weird");
6385 CSSParserImpl::ParseColorOpacity(float& aOpacity
)
6387 if (!GetToken(true)) {
6388 REPORT_UNEXPECTED_EOF(PEColorOpacityEOF
);
6392 if (mToken
.mType
!= eCSSToken_Number
) {
6393 REPORT_UNEXPECTED_TOKEN(PEExpectedNumber
);
6398 if (!ExpectSymbol(')', true)) {
6399 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
6403 if (mToken
.mNumber
< 0.0f
) {
6404 mToken
.mNumber
= 0.0f
;
6405 } else if (mToken
.mNumber
> 1.0f
) {
6406 mToken
.mNumber
= 1.0f
;
6409 aOpacity
= mToken
.mNumber
;
6415 CSSParserImpl::ParseTreePseudoElement(nsAtomList
**aPseudoElementArgs
)
6417 // The argument to a tree pseudo-element is a sequence of identifiers
6418 // that are either space- or comma-separated. (Was the intent to
6419 // allow only comma-separated? That's not what was done.)
6420 nsCSSSelector fakeSelector
; // so we can reuse AddPseudoClass
6422 while (!ExpectSymbol(')', true)) {
6423 if (!GetToken(true)) {
6426 if (eCSSToken_Ident
== mToken
.mType
) {
6427 fakeSelector
.AddClass(mToken
.mIdent
);
6429 else if (!mToken
.IsSymbol(',')) {
6435 *aPseudoElementArgs
= fakeSelector
.mClassList
;
6436 fakeSelector
.mClassList
= nullptr;
6441 //----------------------------------------------------------------------
6444 CSSParserImpl::ParseDeclaration(css::Declaration
* aDeclaration
,
6446 bool aMustCallValueAppended
,
6448 nsCSSContextType aContext
)
6450 NS_PRECONDITION(aContext
== eCSSContext_General
||
6451 aContext
== eCSSContext_Page
,
6452 "Must be page or general context");
6454 bool checkForBraces
= (aFlags
& eParseDeclaration_InBraces
) != 0;
6456 mTempData
.AssertInitialState();
6458 // Get property name
6459 nsCSSToken
* tk
= &mToken
;
6460 nsAutoString propertyName
;
6462 if (!GetToken(true)) {
6463 if (checkForBraces
) {
6464 REPORT_UNEXPECTED_EOF(PEDeclEndEOF
);
6468 if (eCSSToken_Ident
== tk
->mType
) {
6469 propertyName
= tk
->mIdent
;
6470 // grab the ident before the ExpectSymbol trashes the token
6471 if (!ExpectSymbol(':', true)) {
6472 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon
);
6473 REPORT_UNEXPECTED(PEDeclDropped
);
6479 if (tk
->IsSymbol(';')) {
6480 // dangling semicolons are skipped
6484 if (!tk
->IsSymbol('}')) {
6485 REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected
);
6486 REPORT_UNEXPECTED(PEDeclSkipped
);
6489 if (eCSSToken_AtKeyword
== tk
->mType
) {
6490 SkipAtRule(checkForBraces
);
6491 return true; // Not a declaration, but don't skip until ';'
6494 // Not a declaration...
6499 // Don't report property parse errors if we're inside a failing @supports
6501 nsAutoSuppressErrors
suppressErrors(this, mInFailingSupportsRule
);
6503 // Information about a parsed non-custom property.
6504 nsCSSProperty propID
;
6506 // Information about a parsed custom property.
6507 CSSVariableDeclarations::Type variableType
;
6508 nsString variableValue
;
6510 // Check if the property name is a custom property.
6511 bool customProperty
= nsLayoutUtils::CSSVariablesEnabled() &&
6512 nsCSSProps::IsCustomPropertyName(propertyName
) &&
6513 aContext
== eCSSContext_General
;
6515 if (customProperty
) {
6516 if (!ParseVariableDeclaration(&variableType
, variableValue
)) {
6517 REPORT_UNEXPECTED_P(PEValueParsingError
, propertyName
);
6518 REPORT_UNEXPECTED(PEDeclDropped
);
6523 // Map property name to its ID.
6524 propID
= LookupEnabledProperty(propertyName
);
6525 if (eCSSProperty_UNKNOWN
== propID
||
6526 eCSSPropertyExtra_variable
== propID
||
6527 (aContext
== eCSSContext_Page
&&
6528 !nsCSSProps::PropHasFlags(propID
,
6529 CSS_PROPERTY_APPLIES_TO_PAGE_RULE
))) { // unknown property
6530 if (!NonMozillaVendorIdentifier(propertyName
)) {
6531 REPORT_UNEXPECTED_P(PEUnknownProperty
, propertyName
);
6532 REPORT_UNEXPECTED(PEDeclDropped
);
6537 // Then parse the property.
6538 if (!ParseProperty(propID
)) {
6539 // XXX Much better to put stuff in the value parsers instead...
6540 REPORT_UNEXPECTED_P(PEValueParsingError
, propertyName
);
6541 REPORT_UNEXPECTED(PEDeclDropped
);
6543 mTempData
.ClearProperty(propID
);
6544 mTempData
.AssertInitialState();
6551 // Look for "!important".
6552 PriorityParsingStatus status
;
6553 if ((aFlags
& eParseDeclaration_AllowImportant
) != 0) {
6554 status
= ParsePriority();
6556 status
= ePriority_None
;
6559 // Look for a semicolon or close brace.
6560 if (status
!= ePriority_Error
) {
6561 if (!GetToken(true)) {
6563 } else if (mToken
.IsSymbol(';')) {
6564 // semicolon is always ok
6565 } else if (mToken
.IsSymbol('}')) {
6566 // brace is ok if checkForBraces, but don't eat it
6568 if (!checkForBraces
) {
6569 status
= ePriority_Error
;
6573 status
= ePriority_Error
;
6577 if (status
== ePriority_Error
) {
6578 if (checkForBraces
) {
6579 REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2
);
6581 REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd
);
6583 REPORT_UNEXPECTED(PEDeclDropped
);
6585 if (!customProperty
) {
6586 mTempData
.ClearProperty(propID
);
6588 mTempData
.AssertInitialState();
6592 if (customProperty
) {
6593 MOZ_ASSERT(Substring(propertyName
, 0,
6594 CSS_CUSTOM_NAME_PREFIX_LENGTH
).EqualsLiteral("--"));
6596 nsDependentString
varName(propertyName
, CSS_CUSTOM_NAME_PREFIX_LENGTH
);
6597 aDeclaration
->AddVariableDeclaration(varName
, variableType
, variableValue
,
6598 status
== ePriority_Important
, false);
6600 *aChanged
|= mData
.TransferFromBlock(mTempData
, propID
,
6601 status
== ePriority_Important
,
6602 false, aMustCallValueAppended
,
6609 static const nsCSSProperty kBorderTopIDs
[] = {
6610 eCSSProperty_border_top_width
,
6611 eCSSProperty_border_top_style
,
6612 eCSSProperty_border_top_color
6614 static const nsCSSProperty kBorderRightIDs
[] = {
6615 eCSSProperty_border_right_width_value
,
6616 eCSSProperty_border_right_style_value
,
6617 eCSSProperty_border_right_color_value
,
6618 eCSSProperty_border_right_width
,
6619 eCSSProperty_border_right_style
,
6620 eCSSProperty_border_right_color
6622 static const nsCSSProperty kBorderBottomIDs
[] = {
6623 eCSSProperty_border_bottom_width
,
6624 eCSSProperty_border_bottom_style
,
6625 eCSSProperty_border_bottom_color
6627 static const nsCSSProperty kBorderLeftIDs
[] = {
6628 eCSSProperty_border_left_width_value
,
6629 eCSSProperty_border_left_style_value
,
6630 eCSSProperty_border_left_color_value
,
6631 eCSSProperty_border_left_width
,
6632 eCSSProperty_border_left_style
,
6633 eCSSProperty_border_left_color
6635 static const nsCSSProperty kBorderStartIDs
[] = {
6636 eCSSProperty_border_start_width_value
,
6637 eCSSProperty_border_start_style_value
,
6638 eCSSProperty_border_start_color_value
,
6639 eCSSProperty_border_start_width
,
6640 eCSSProperty_border_start_style
,
6641 eCSSProperty_border_start_color
6643 static const nsCSSProperty kBorderEndIDs
[] = {
6644 eCSSProperty_border_end_width_value
,
6645 eCSSProperty_border_end_style_value
,
6646 eCSSProperty_border_end_color_value
,
6647 eCSSProperty_border_end_width
,
6648 eCSSProperty_border_end_style
,
6649 eCSSProperty_border_end_color
6651 static const nsCSSProperty kColumnRuleIDs
[] = {
6652 eCSSProperty__moz_column_rule_width
,
6653 eCSSProperty__moz_column_rule_style
,
6654 eCSSProperty__moz_column_rule_color
6658 CSSParserImpl::ParseEnum(nsCSSValue
& aValue
,
6659 const KTableValue aKeywordTable
[])
6661 nsSubstring
* ident
= NextIdent();
6662 if (nullptr == ident
) {
6665 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(*ident
);
6666 if (eCSSKeyword_UNKNOWN
< keyword
) {
6668 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
6669 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
6674 // Put the unknown identifier back and return
6681 char name
[6]; // needs to be long enough for the longest unit, with
6682 // terminating null.
6688 #define STR_WITH_LEN(_str) \
6689 _str, sizeof(_str) - 1
6691 const UnitInfo UnitData
[] = {
6692 { STR_WITH_LEN("px"), eCSSUnit_Pixel
, VARIANT_LENGTH
},
6693 { STR_WITH_LEN("em"), eCSSUnit_EM
, VARIANT_LENGTH
},
6694 { STR_WITH_LEN("ex"), eCSSUnit_XHeight
, VARIANT_LENGTH
},
6695 { STR_WITH_LEN("pt"), eCSSUnit_Point
, VARIANT_LENGTH
},
6696 { STR_WITH_LEN("in"), eCSSUnit_Inch
, VARIANT_LENGTH
},
6697 { STR_WITH_LEN("cm"), eCSSUnit_Centimeter
, VARIANT_LENGTH
},
6698 { STR_WITH_LEN("ch"), eCSSUnit_Char
, VARIANT_LENGTH
},
6699 { STR_WITH_LEN("rem"), eCSSUnit_RootEM
, VARIANT_LENGTH
},
6700 { STR_WITH_LEN("mm"), eCSSUnit_Millimeter
, VARIANT_LENGTH
},
6701 { STR_WITH_LEN("mozmm"), eCSSUnit_PhysicalMillimeter
, VARIANT_LENGTH
},
6702 { STR_WITH_LEN("vw"), eCSSUnit_ViewportWidth
, VARIANT_LENGTH
},
6703 { STR_WITH_LEN("vh"), eCSSUnit_ViewportHeight
, VARIANT_LENGTH
},
6704 { STR_WITH_LEN("vmin"), eCSSUnit_ViewportMin
, VARIANT_LENGTH
},
6705 { STR_WITH_LEN("vmax"), eCSSUnit_ViewportMax
, VARIANT_LENGTH
},
6706 { STR_WITH_LEN("pc"), eCSSUnit_Pica
, VARIANT_LENGTH
},
6707 { STR_WITH_LEN("deg"), eCSSUnit_Degree
, VARIANT_ANGLE
},
6708 { STR_WITH_LEN("grad"), eCSSUnit_Grad
, VARIANT_ANGLE
},
6709 { STR_WITH_LEN("rad"), eCSSUnit_Radian
, VARIANT_ANGLE
},
6710 { STR_WITH_LEN("turn"), eCSSUnit_Turn
, VARIANT_ANGLE
},
6711 { STR_WITH_LEN("hz"), eCSSUnit_Hertz
, VARIANT_FREQUENCY
},
6712 { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz
, VARIANT_FREQUENCY
},
6713 { STR_WITH_LEN("s"), eCSSUnit_Seconds
, VARIANT_TIME
},
6714 { STR_WITH_LEN("ms"), eCSSUnit_Milliseconds
, VARIANT_TIME
}
6720 CSSParserImpl::TranslateDimension(nsCSSValue
& aValue
,
6721 int32_t aVariantMask
,
6723 const nsString
& aUnit
)
6727 if (!aUnit
.IsEmpty()) {
6729 for (i
= 0; i
< ArrayLength(UnitData
); ++i
) {
6730 if (aUnit
.LowerCaseEqualsASCII(UnitData
[i
].name
,
6731 UnitData
[i
].length
)) {
6732 units
= UnitData
[i
].unit
;
6733 type
= UnitData
[i
].type
;
6738 if (i
== ArrayLength(UnitData
)) {
6743 if (!mViewportUnitsEnabled
&&
6744 (eCSSUnit_ViewportWidth
== units
||
6745 eCSSUnit_ViewportHeight
== units
||
6746 eCSSUnit_ViewportMin
== units
||
6747 eCSSUnit_ViewportMax
== units
)) {
6748 // Viewport units aren't allowed right now, probably because we're
6749 // inside an @page declaration. Fail.
6753 // Must be a zero number...
6754 NS_ASSERTION(0 == aNumber
, "numbers without units must be 0");
6755 if ((VARIANT_LENGTH
& aVariantMask
) != 0) {
6756 units
= eCSSUnit_Pixel
;
6757 type
= VARIANT_LENGTH
;
6759 else if ((VARIANT_ANGLE
& aVariantMask
) != 0) {
6760 NS_ASSERTION(aVariantMask
& VARIANT_ZERO_ANGLE
,
6761 "must have allowed zero angle");
6762 units
= eCSSUnit_Degree
;
6763 type
= VARIANT_ANGLE
;
6766 NS_ERROR("Variant mask does not include dimension; why were we called?");
6770 if ((type
& aVariantMask
) != 0) {
6771 aValue
.SetFloatValue(aNumber
, units
);
6777 // Note that this does include VARIANT_CALC, which is numeric. This is
6778 // because calc() parsing, as proposed, drops range restrictions inside
6779 // the calc() expression and clamps the result of the calculation to the
6781 #define VARIANT_ALL_NONNUMERIC \
6788 VARIANT_IDENTIFIER | \
6789 VARIANT_IDENTIFIER_NO_INHERIT | \
6795 VARIANT_GRADIENT | \
6796 VARIANT_TIMING_FUNCTION | \
6799 VARIANT_OPENTYPE_SVG_KEYWORD
6801 // Note that callers passing VARIANT_CALC in aVariantMask will get
6802 // full-range parsing inside the calc() expression, and the code that
6803 // computes the calc will be required to clamp the resulting value to an
6804 // appropriate range.
6806 CSSParserImpl::ParseNonNegativeVariant(nsCSSValue
& aValue
,
6807 int32_t aVariantMask
,
6808 const KTableValue aKeywordTable
[])
6810 // The variant mask must only contain non-numeric variants or the ones
6811 // that we specifically handle.
6812 NS_ABORT_IF_FALSE((aVariantMask
& ~(VARIANT_ALL_NONNUMERIC
|
6816 VARIANT_INTEGER
)) == 0,
6817 "need to update code below to handle additional variants");
6819 if (ParseVariant(aValue
, aVariantMask
, aKeywordTable
)) {
6820 if (eCSSUnit_Number
== aValue
.GetUnit() ||
6821 aValue
.IsLengthUnit()){
6822 if (aValue
.GetFloatValue() < 0) {
6827 else if (aValue
.GetUnit() == eCSSUnit_Percent
) {
6828 if (aValue
.GetPercentValue() < 0) {
6832 } else if (aValue
.GetUnit() == eCSSUnit_Integer
) {
6833 if (aValue
.GetIntValue() < 0) {
6843 // Note that callers passing VARIANT_CALC in aVariantMask will get
6844 // full-range parsing inside the calc() expression, and the code that
6845 // computes the calc will be required to clamp the resulting value to an
6846 // appropriate range.
6848 CSSParserImpl::ParseOneOrLargerVariant(nsCSSValue
& aValue
,
6849 int32_t aVariantMask
,
6850 const KTableValue aKeywordTable
[])
6852 // The variant mask must only contain non-numeric variants or the ones
6853 // that we specifically handle.
6854 NS_ABORT_IF_FALSE((aVariantMask
& ~(VARIANT_ALL_NONNUMERIC
|
6856 VARIANT_INTEGER
)) == 0,
6857 "need to update code below to handle additional variants");
6859 if (ParseVariant(aValue
, aVariantMask
, aKeywordTable
)) {
6860 if (aValue
.GetUnit() == eCSSUnit_Integer
) {
6861 if (aValue
.GetIntValue() < 1) {
6865 } else if (eCSSUnit_Number
== aValue
.GetUnit()) {
6866 if (aValue
.GetFloatValue() < 1.0f
) {
6876 // Assigns to aValue iff it returns true.
6878 CSSParserImpl::ParseVariant(nsCSSValue
& aValue
,
6879 int32_t aVariantMask
,
6880 const KTableValue aKeywordTable
[])
6882 NS_ASSERTION(!(mHashlessColorQuirk
&& (aVariantMask
& VARIANT_COLOR
)) ||
6883 !(aVariantMask
& VARIANT_NUMBER
),
6884 "can't distinguish colors from numbers");
6885 NS_ASSERTION(!(mHashlessColorQuirk
&& (aVariantMask
& VARIANT_COLOR
)) ||
6886 !(mUnitlessLengthQuirk
&& (aVariantMask
& VARIANT_LENGTH
)),
6887 "can't distinguish colors from lengths");
6888 NS_ASSERTION(!(mUnitlessLengthQuirk
&& (aVariantMask
& VARIANT_LENGTH
)) ||
6889 !(aVariantMask
& VARIANT_NUMBER
),
6890 "can't distinguish lengths from numbers");
6891 NS_ABORT_IF_FALSE(!(aVariantMask
& VARIANT_IDENTIFIER
) ||
6892 !(aVariantMask
& VARIANT_IDENTIFIER_NO_INHERIT
),
6893 "must not set both VARIANT_IDENTIFIER and "
6894 "VARIANT_IDENTIFIER_NO_INHERIT");
6896 if (!GetToken(true)) {
6899 nsCSSToken
* tk
= &mToken
;
6900 if (((aVariantMask
& (VARIANT_AHK
| VARIANT_NORMAL
| VARIANT_NONE
| VARIANT_ALL
)) != 0) &&
6901 (eCSSToken_Ident
== tk
->mType
)) {
6902 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(tk
->mIdent
);
6903 if (eCSSKeyword_UNKNOWN
< keyword
) { // known keyword
6904 if ((aVariantMask
& VARIANT_AUTO
) != 0) {
6905 if (eCSSKeyword_auto
== keyword
) {
6906 aValue
.SetAutoValue();
6910 if ((aVariantMask
& VARIANT_INHERIT
) != 0) {
6911 // XXX Should we check IsParsingCompoundProperty, or do all
6912 // callers handle it? (Not all callers set it, though, since
6913 // they want the quirks that are disabled by setting it.)
6915 // IMPORTANT: If new keywords are added here,
6916 // they probably need to be added in ParseCustomIdent as well.
6917 if (eCSSKeyword_inherit
== keyword
) {
6918 aValue
.SetInheritValue();
6921 else if (eCSSKeyword_initial
== keyword
) {
6922 aValue
.SetInitialValue();
6925 else if (eCSSKeyword_unset
== keyword
&&
6926 nsLayoutUtils::UnsetValueEnabled()) {
6927 aValue
.SetUnsetValue();
6931 if ((aVariantMask
& VARIANT_NONE
) != 0) {
6932 if (eCSSKeyword_none
== keyword
) {
6933 aValue
.SetNoneValue();
6937 if ((aVariantMask
& VARIANT_ALL
) != 0) {
6938 if (eCSSKeyword_all
== keyword
) {
6939 aValue
.SetAllValue();
6943 if ((aVariantMask
& VARIANT_NORMAL
) != 0) {
6944 if (eCSSKeyword_normal
== keyword
) {
6945 aValue
.SetNormalValue();
6949 if ((aVariantMask
& VARIANT_SYSFONT
) != 0) {
6950 if (eCSSKeyword__moz_use_system_font
== keyword
&&
6951 !IsParsingCompoundProperty()) {
6952 aValue
.SetSystemFontValue();
6956 if ((aVariantMask
& VARIANT_OPENTYPE_SVG_KEYWORD
) != 0) {
6957 static bool sOpentypeSVGEnabled
;
6958 static bool sOpentypeSVGEnabledCached
= false;
6959 if (!sOpentypeSVGEnabledCached
) {
6960 sOpentypeSVGEnabledCached
= true;
6961 Preferences::AddBoolVarCache(&sOpentypeSVGEnabled
,
6962 "gfx.font_rendering.opentype_svg.enabled");
6964 if (sOpentypeSVGEnabled
) {
6965 aVariantMask
|= VARIANT_KEYWORD
;
6968 if ((aVariantMask
& VARIANT_KEYWORD
) != 0) {
6970 if (nsCSSProps::FindKeyword(keyword
, aKeywordTable
, value
)) {
6971 aValue
.SetIntValue(value
, eCSSUnit_Enumerated
);
6977 // Check VARIANT_NUMBER and VARIANT_INTEGER before VARIANT_LENGTH or
6978 // VARIANT_ZERO_ANGLE.
6979 if (((aVariantMask
& VARIANT_NUMBER
) != 0) &&
6980 (eCSSToken_Number
== tk
->mType
)) {
6981 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Number
);
6984 if (((aVariantMask
& VARIANT_INTEGER
) != 0) &&
6985 (eCSSToken_Number
== tk
->mType
) && tk
->mIntegerValid
) {
6986 aValue
.SetIntValue(tk
->mInteger
, eCSSUnit_Integer
);
6989 if (((aVariantMask
& (VARIANT_LENGTH
| VARIANT_ANGLE
|
6990 VARIANT_FREQUENCY
| VARIANT_TIME
)) != 0 &&
6991 eCSSToken_Dimension
== tk
->mType
) ||
6992 ((aVariantMask
& (VARIANT_LENGTH
| VARIANT_ZERO_ANGLE
)) != 0 &&
6993 eCSSToken_Number
== tk
->mType
&&
6994 tk
->mNumber
== 0.0f
)) {
6995 if (((aVariantMask
& VARIANT_POSITIVE_DIMENSION
) != 0 &&
6996 tk
->mNumber
<= 0.0) ||
6997 ((aVariantMask
& VARIANT_NONNEGATIVE_DIMENSION
) != 0 &&
6998 tk
->mNumber
< 0.0)) {
7002 if (TranslateDimension(aValue
, aVariantMask
, tk
->mNumber
, tk
->mIdent
)) {
7005 // Put the token back; we didn't parse it, so we shouldn't consume it
7009 if (((aVariantMask
& VARIANT_PERCENT
) != 0) &&
7010 (eCSSToken_Percentage
== tk
->mType
)) {
7011 aValue
.SetPercentValue(tk
->mNumber
);
7014 if (mUnitlessLengthQuirk
) { // NONSTANDARD: Nav interprets unitless numbers as px
7015 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
7016 (eCSSToken_Number
== tk
->mType
)) {
7017 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
7022 if (IsSVGMode() && !IsParsingCompoundProperty()) {
7023 // STANDARD: SVG Spec states that lengths and coordinates can be unitless
7024 // in which case they default to user-units (1 px = 1 user unit)
7025 if (((aVariantMask
& VARIANT_LENGTH
) != 0) &&
7026 (eCSSToken_Number
== tk
->mType
)) {
7027 aValue
.SetFloatValue(tk
->mNumber
, eCSSUnit_Pixel
);
7032 if (((aVariantMask
& VARIANT_URL
) != 0) &&
7033 eCSSToken_URL
== tk
->mType
) {
7034 SetValueToURL(aValue
, tk
->mIdent
);
7037 if ((aVariantMask
& VARIANT_GRADIENT
) != 0 &&
7038 eCSSToken_Function
== tk
->mType
) {
7039 // a generated gradient
7040 nsDependentString
tmp(tk
->mIdent
, 0);
7041 bool isLegacy
= false;
7042 if (StringBeginsWith(tmp
, NS_LITERAL_STRING("-moz-"))) {
7046 bool isRepeating
= false;
7047 if (StringBeginsWith(tmp
, NS_LITERAL_STRING("repeating-"))) {
7048 tmp
.Rebind(tmp
, 10);
7052 if (tmp
.LowerCaseEqualsLiteral("linear-gradient")) {
7053 return ParseLinearGradient(aValue
, isRepeating
, isLegacy
);
7055 if (tmp
.LowerCaseEqualsLiteral("radial-gradient")) {
7056 return ParseRadialGradient(aValue
, isRepeating
, isLegacy
);
7059 if ((aVariantMask
& VARIANT_IMAGE_RECT
) != 0 &&
7060 eCSSToken_Function
== tk
->mType
&&
7061 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-image-rect")) {
7062 return ParseImageRect(aValue
);
7064 if ((aVariantMask
& VARIANT_ELEMENT
) != 0 &&
7065 eCSSToken_Function
== tk
->mType
&&
7066 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-element")) {
7067 return ParseElement(aValue
);
7069 if ((aVariantMask
& VARIANT_COLOR
) != 0) {
7070 if (mHashlessColorQuirk
|| // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix
7071 (eCSSToken_ID
== tk
->mType
) ||
7072 (eCSSToken_Hash
== tk
->mType
) ||
7073 (eCSSToken_Ident
== tk
->mType
) ||
7074 ((eCSSToken_Function
== tk
->mType
) &&
7075 (tk
->mIdent
.LowerCaseEqualsLiteral("rgb") ||
7076 tk
->mIdent
.LowerCaseEqualsLiteral("hsl") ||
7077 tk
->mIdent
.LowerCaseEqualsLiteral("rgba") ||
7078 tk
->mIdent
.LowerCaseEqualsLiteral("hsla"))))
7080 // Put token back so that parse color can get it
7082 if (ParseColor(aValue
)) {
7088 if (((aVariantMask
& VARIANT_STRING
) != 0) &&
7089 (eCSSToken_String
== tk
->mType
)) {
7090 nsAutoString buffer
;
7091 buffer
.Append(tk
->mIdent
);
7092 aValue
.SetStringValue(buffer
, eCSSUnit_String
);
7095 if (((aVariantMask
&
7096 (VARIANT_IDENTIFIER
| VARIANT_IDENTIFIER_NO_INHERIT
)) != 0) &&
7097 (eCSSToken_Ident
== tk
->mType
) &&
7098 ((aVariantMask
& VARIANT_IDENTIFIER
) != 0 ||
7099 !(tk
->mIdent
.LowerCaseEqualsLiteral("inherit") ||
7100 tk
->mIdent
.LowerCaseEqualsLiteral("initial") ||
7101 (tk
->mIdent
.LowerCaseEqualsLiteral("unset") &&
7102 nsLayoutUtils::UnsetValueEnabled())))) {
7103 aValue
.SetStringValue(tk
->mIdent
, eCSSUnit_Ident
);
7106 if (((aVariantMask
& VARIANT_COUNTER
) != 0) &&
7107 (eCSSToken_Function
== tk
->mType
) &&
7108 (tk
->mIdent
.LowerCaseEqualsLiteral("counter") ||
7109 tk
->mIdent
.LowerCaseEqualsLiteral("counters"))) {
7110 return ParseCounter(aValue
);
7112 if (((aVariantMask
& VARIANT_ATTR
) != 0) &&
7113 (eCSSToken_Function
== tk
->mType
) &&
7114 tk
->mIdent
.LowerCaseEqualsLiteral("attr")) {
7115 if (!ParseAttr(aValue
)) {
7121 if (((aVariantMask
& VARIANT_TIMING_FUNCTION
) != 0) &&
7122 (eCSSToken_Function
== tk
->mType
)) {
7123 if (tk
->mIdent
.LowerCaseEqualsLiteral("cubic-bezier")) {
7124 if (!ParseTransitionTimingFunctionValues(aValue
)) {
7130 if (tk
->mIdent
.LowerCaseEqualsLiteral("steps")) {
7131 if (!ParseTransitionStepTimingFunctionValues(aValue
)) {
7138 if ((aVariantMask
& VARIANT_CALC
) &&
7139 (eCSSToken_Function
== tk
->mType
) &&
7140 (tk
->mIdent
.LowerCaseEqualsLiteral("calc") ||
7141 tk
->mIdent
.LowerCaseEqualsLiteral("-moz-calc"))) {
7142 // calc() currently allows only lengths and percents inside it.
7143 return ParseCalc(aValue
, aVariantMask
& VARIANT_LP
);
7151 CSSParserImpl::ParseCustomIdent(nsCSSValue
& aValue
,
7152 const nsAutoString
& aIdentValue
,
7153 const nsCSSKeyword aExcludedKeywords
[],
7154 const nsCSSProps::KTableValue aPropertyKTable
[])
7156 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(aIdentValue
);
7157 if (keyword
== eCSSKeyword_UNKNOWN
) {
7158 // Fast path for identifiers that are not known CSS keywords:
7159 aValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_Ident
);
7162 if (keyword
== eCSSKeyword_inherit
||
7163 keyword
== eCSSKeyword_initial
||
7164 keyword
== eCSSKeyword_unset
||
7165 keyword
== eCSSKeyword_default
||
7167 nsCSSProps::FindIndexOfKeyword(keyword
, aPropertyKTable
) >= 0)) {
7170 if (aExcludedKeywords
) {
7171 for (uint32_t i
= 0;; i
++) {
7172 nsCSSKeyword excludedKeyword
= aExcludedKeywords
[i
];
7173 if (excludedKeyword
== eCSSKeyword_UNKNOWN
) {
7176 if (excludedKeyword
== keyword
) {
7181 aValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_Ident
);
7186 CSSParserImpl::ParseCounter(nsCSSValue
& aValue
)
7188 nsCSSUnit unit
= (mToken
.mIdent
.LowerCaseEqualsLiteral("counter") ?
7189 eCSSUnit_Counter
: eCSSUnit_Counters
);
7191 // A non-iterative for loop to break out when an error occurs.
7193 if (!GetToken(true)) {
7196 if (eCSSToken_Ident
!= mToken
.mType
) {
7201 nsRefPtr
<nsCSSValue::Array
> val
=
7202 nsCSSValue::Array::Create(unit
== eCSSUnit_Counter
? 2 : 3);
7204 val
->Item(0).SetStringValue(mToken
.mIdent
, eCSSUnit_Ident
);
7206 if (eCSSUnit_Counters
== unit
) {
7207 // must have a comma and then a separator string
7208 if (!ExpectSymbol(',', true) || !GetToken(true)) {
7211 if (eCSSToken_String
!= mToken
.mType
) {
7215 val
->Item(1).SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
7218 // get optional type
7219 int32_t typeItem
= eCSSUnit_Counters
== unit
? 2 : 1;
7220 nsCSSValue
& type
= val
->Item(typeItem
);
7221 if (ExpectSymbol(',', true)) {
7222 if (!ParseCounterStyleNameValue(type
) && !ParseSymbols(type
)) {
7226 type
.SetStringValue(NS_LITERAL_STRING("decimal"), eCSSUnit_Ident
);
7229 if (!ExpectSymbol(')', true)) {
7233 aValue
.SetArrayValue(val
, unit
);
7242 CSSParserImpl::ParseAttr(nsCSSValue
& aValue
)
7244 if (!GetToken(true)) {
7249 if (eCSSToken_Ident
== mToken
.mType
) { // attr name or namespace
7250 nsAutoString
holdIdent(mToken
.mIdent
);
7251 if (ExpectSymbol('|', false)) { // namespace
7252 int32_t nameSpaceID
= GetNamespaceIdForPrefix(holdIdent
);
7253 if (nameSpaceID
== kNameSpaceID_Unknown
) {
7256 attr
.AppendInt(nameSpaceID
, 10);
7257 attr
.Append(char16_t('|'));
7258 if (! GetToken(false)) {
7259 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
7262 if (eCSSToken_Ident
== mToken
.mType
) {
7263 attr
.Append(mToken
.mIdent
);
7266 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
7271 else { // no namespace
7275 else if (mToken
.IsSymbol('*')) { // namespace wildcard
7276 // Wildcard namespace makes no sense here and is not allowed
7277 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
7281 else if (mToken
.IsSymbol('|')) { // explicit NO namespace
7282 if (! GetToken(false)) {
7283 REPORT_UNEXPECTED_EOF(PEAttributeNameEOF
);
7286 if (eCSSToken_Ident
== mToken
.mType
) {
7287 attr
.Append(mToken
.mIdent
);
7290 REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected
);
7296 REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected
);
7300 if (!ExpectSymbol(')', true)) {
7303 aValue
.SetStringValue(attr
, eCSSUnit_Attr
);
7308 CSSParserImpl::ParseSymbols(nsCSSValue
& aValue
)
7310 if (!GetToken(true)) {
7313 if (mToken
.mType
!= eCSSToken_Function
&&
7314 !mToken
.mIdent
.LowerCaseEqualsLiteral("symbols")) {
7319 nsRefPtr
<nsCSSValue::Array
> params
= nsCSSValue::Array::Create(2);
7320 nsCSSValue
& type
= params
->Item(0);
7321 nsCSSValue
& symbols
= params
->Item(1);
7323 if (!ParseEnum(type
, nsCSSProps::kCounterSymbolsSystemKTable
)) {
7324 type
.SetIntValue(NS_STYLE_COUNTER_SYSTEM_SYMBOLIC
, eCSSUnit_Enumerated
);
7328 nsCSSValueList
* item
= symbols
.SetListValue();
7330 // FIXME Should also include VARIANT_IMAGE. See bug 1071436.
7331 if (!ParseVariant(item
->mValue
, VARIANT_STRING
, nullptr)) {
7334 if (ExpectSymbol(')', true)) {
7336 switch (type
.GetIntValue()) {
7337 case NS_STYLE_COUNTER_SYSTEM_NUMERIC
:
7338 case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC
:
7339 // require at least two symbols
7343 aValue
.SetArrayValue(params
, eCSSUnit_Symbols
);
7346 item
->mNext
= new nsCSSValueList
;
7356 CSSParserImpl::SetValueToURL(nsCSSValue
& aValue
, const nsString
& aURL
)
7358 if (!mSheetPrincipal
) {
7359 NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an "
7360 "origin principal");
7364 nsRefPtr
<nsStringBuffer
> buffer(nsCSSValue::BufferFromString(aURL
));
7366 // Note: urlVal retains its own reference to |buffer|.
7367 mozilla::css::URLValue
*urlVal
=
7368 new mozilla::css::URLValue(buffer
, mBaseURI
, mSheetURI
, mSheetPrincipal
);
7369 aValue
.SetURLValue(urlVal
);
7374 * Parse the image-orientation property, which has the grammar:
7375 * <angle> flip? | flip | from-image
7378 CSSParserImpl::ParseImageOrientation(nsCSSValue
& aValue
)
7380 if (ParseVariant(aValue
, VARIANT_INHERIT
, nullptr)) {
7381 // 'inherit', 'initial' and 'unset' must be alone
7385 // Check for an angle with optional 'flip'.
7387 if (ParseVariant(angle
, VARIANT_ANGLE
, nullptr)) {
7390 if (ParseVariant(flip
, VARIANT_KEYWORD
, nsCSSProps::kImageOrientationFlipKTable
)) {
7391 nsRefPtr
<nsCSSValue::Array
> array
= nsCSSValue::Array::Create(2);
7392 array
->Item(0) = angle
;
7393 array
->Item(1) = flip
;
7394 aValue
.SetArrayValue(array
, eCSSUnit_Array
);
7402 // The remaining possibilities (bare 'flip' and 'from-image') are both
7403 // keywords, so we can handle them at the same time.
7405 if (ParseVariant(keyword
, VARIANT_KEYWORD
, nsCSSProps::kImageOrientationKTable
)) {
7410 // All possibilities failed.
7415 * Parse the arguments of -moz-image-rect() function.
7416 * -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>)
7419 CSSParserImpl::ParseImageRect(nsCSSValue
& aImage
)
7421 // A non-iterative for loop to break out when an error occurs.
7423 nsCSSValue newFunction
;
7424 static const uint32_t kNumArgs
= 5;
7425 nsCSSValue::Array
* func
=
7426 newFunction
.InitFunction(eCSSKeyword__moz_image_rect
, kNumArgs
);
7428 // func->Item(0) is reserved for the function name.
7429 nsCSSValue
& url
= func
->Item(1);
7430 nsCSSValue
& top
= func
->Item(2);
7431 nsCSSValue
& right
= func
->Item(3);
7432 nsCSSValue
& bottom
= func
->Item(4);
7433 nsCSSValue
& left
= func
->Item(5);
7435 nsAutoString urlString
;
7436 if (!ParseURLOrString(urlString
) ||
7437 !SetValueToURL(url
, urlString
) ||
7438 !ExpectSymbol(',', true)) {
7442 static const int32_t VARIANT_SIDE
= VARIANT_NUMBER
| VARIANT_PERCENT
;
7443 if (!ParseNonNegativeVariant(top
, VARIANT_SIDE
, nullptr) ||
7444 !ExpectSymbol(',', true) ||
7445 !ParseNonNegativeVariant(right
, VARIANT_SIDE
, nullptr) ||
7446 !ExpectSymbol(',', true) ||
7447 !ParseNonNegativeVariant(bottom
, VARIANT_SIDE
, nullptr) ||
7448 !ExpectSymbol(',', true) ||
7449 !ParseNonNegativeVariant(left
, VARIANT_SIDE
, nullptr) ||
7450 !ExpectSymbol(')', true))
7453 aImage
= newFunction
;
7461 // <element>: -moz-element(# <element_id> )
7463 CSSParserImpl::ParseElement(nsCSSValue
& aValue
)
7465 // A non-iterative for loop to break out when an error occurs.
7467 if (!GetToken(true))
7470 if (mToken
.mType
== eCSSToken_ID
) {
7471 aValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_Element
);
7477 if (!ExpectSymbol(')', true))
7483 // If we detect a syntax error, we must match the opening parenthesis of the
7484 // function with the closing parenthesis and skip all the tokens in between.
7489 // flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
7491 CSSParserImpl::ParseFlex()
7493 // First check for inherit / initial / unset
7495 if (ParseVariant(tmpVal
, VARIANT_INHERIT
, nullptr)) {
7496 AppendValue(eCSSProperty_flex_grow
, tmpVal
);
7497 AppendValue(eCSSProperty_flex_shrink
, tmpVal
);
7498 AppendValue(eCSSProperty_flex_basis
, tmpVal
);
7502 // Next, check for 'none' == '0 0 auto'
7503 if (ParseVariant(tmpVal
, VARIANT_NONE
, nullptr)) {
7504 AppendValue(eCSSProperty_flex_grow
, nsCSSValue(0.0f
, eCSSUnit_Number
));
7505 AppendValue(eCSSProperty_flex_shrink
, nsCSSValue(0.0f
, eCSSUnit_Number
));
7506 AppendValue(eCSSProperty_flex_basis
, nsCSSValue(eCSSUnit_Auto
));
7510 // OK, try parsing our value as individual per-subproperty components:
7511 // [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
7513 // Each subproperty has a default value that it takes when it's omitted in a
7514 // "flex" shorthand value. These default values are *only* for the shorthand
7515 // syntax -- they're distinct from the subproperties' own initial values. We
7516 // start with each subproperty at its default, as if we had "flex: 1 1 0%".
7517 nsCSSValue
flexGrow(1.0f
, eCSSUnit_Number
);
7518 nsCSSValue
flexShrink(1.0f
, eCSSUnit_Number
);
7519 nsCSSValue
flexBasis(0.0f
, eCSSUnit_Percent
);
7521 // OVERVIEW OF PARSING STRATEGY:
7522 // =============================
7523 // a) Parse the first component as either flex-basis or flex-grow.
7524 // b) If it wasn't flex-grow, parse the _next_ component as flex-grow.
7525 // c) Now we've just parsed flex-grow -- so try parsing the next thing as
7527 // d) Finally: If we didn't get flex-basis at the beginning, try to parse
7528 // it now, at the end.
7530 // More details in each section below.
7532 uint32_t flexBasisVariantMask
=
7533 (nsCSSProps::ParserVariant(eCSSProperty_flex_basis
) & ~(VARIANT_INHERIT
));
7535 // (a) Parse first component. It can be either be a 'flex-basis' value or a
7536 // 'flex-grow' value, so we use the flex-basis-specific variant mask, along
7537 // with VARIANT_NUMBER to accept 'flex-grow' values.
7539 // NOTE: if we encounter unitless 0 here, we *must* interpret it as a
7540 // 'flex-grow' value (a number), *not* as a 'flex-basis' value (a length).
7541 // Conveniently, that's the behavior this combined variant-mask gives us --
7542 // it'll treat unitless 0 as a number. The flexbox spec requires this:
7543 // "a unitless zero that is not already preceded by two flex factors must be
7544 // interpreted as a flex factor.
7545 if (!ParseNonNegativeVariant(tmpVal
, flexBasisVariantMask
| VARIANT_NUMBER
,
7546 nsCSSProps::kWidthKTable
)) {
7547 // First component was not a valid flex-basis or flex-grow value. Fail.
7551 // Record what we just parsed as either flex-basis or flex-grow:
7552 bool wasFirstComponentFlexBasis
= (tmpVal
.GetUnit() != eCSSUnit_Number
);
7553 (wasFirstComponentFlexBasis
? flexBasis
: flexGrow
) = tmpVal
;
7555 // (b) If we didn't get flex-grow yet, parse _next_ component as flex-grow.
7556 bool doneParsing
= false;
7557 if (wasFirstComponentFlexBasis
) {
7558 if (ParseNonNegativeVariant(tmpVal
, VARIANT_NUMBER
, nullptr)) {
7561 // Failed to parse anything after our flex-basis -- that's fine. We can
7562 // skip the remaining parsing.
7568 // (c) OK -- the last thing we parsed was flex-grow, so look for a
7569 // flex-shrink in the next position.
7570 if (ParseNonNegativeVariant(tmpVal
, VARIANT_NUMBER
, nullptr)) {
7571 flexShrink
= tmpVal
;
7574 // d) Finally: If we didn't get flex-basis at the beginning, try to parse
7575 // it now, at the end.
7577 // NOTE: If we encounter unitless 0 in this final position, we'll parse it
7578 // as a 'flex-basis' value. That's OK, because we know it must have
7579 // been "preceded by 2 flex factors" (justification below), which gets us
7580 // out of the spec's requirement of otherwise having to treat unitless 0
7581 // as a flex factor.
7583 // JUSTIFICATION: How do we know that a unitless 0 here must have been
7584 // preceded by 2 flex factors? Well, suppose we had a unitless 0 that
7585 // was preceded by only 1 flex factor. Then, we would have already
7586 // accepted this unitless 0 as the 'flex-shrink' value, up above (since
7587 // it's a valid flex-shrink value), and we'd have moved on to the next
7588 // token (if any). And of course, if we instead had a unitless 0 preceded
7589 // by *no* flex factors (if it were the first token), we would've already
7590 // parsed it in our very first call to ParseNonNegativeVariant(). So, any
7591 // unitless 0 encountered here *must* have been preceded by 2 flex factors.
7592 if (!wasFirstComponentFlexBasis
&&
7593 ParseNonNegativeVariant(tmpVal
, flexBasisVariantMask
,
7594 nsCSSProps::kWidthKTable
)) {
7599 AppendValue(eCSSProperty_flex_grow
, flexGrow
);
7600 AppendValue(eCSSProperty_flex_shrink
, flexShrink
);
7601 AppendValue(eCSSProperty_flex_basis
, flexBasis
);
7606 // flex-flow: <flex-direction> || <flex-wrap>
7608 CSSParserImpl::ParseFlexFlow()
7610 static const nsCSSProperty kFlexFlowSubprops
[] = {
7611 eCSSProperty_flex_direction
,
7612 eCSSProperty_flex_wrap
7614 const size_t numProps
= MOZ_ARRAY_LENGTH(kFlexFlowSubprops
);
7615 nsCSSValue values
[numProps
];
7617 int32_t found
= ParseChoice(values
, kFlexFlowSubprops
, numProps
);
7619 // Bail if we didn't successfully parse anything
7624 // If either property didn't get an explicit value, use its initial value.
7625 if ((found
& 1) == 0) {
7626 values
[0].SetIntValue(NS_STYLE_FLEX_DIRECTION_ROW
, eCSSUnit_Enumerated
);
7628 if ((found
& 2) == 0) {
7629 values
[1].SetIntValue(NS_STYLE_FLEX_WRAP_NOWRAP
, eCSSUnit_Enumerated
);
7632 // Store these values and declare success!
7633 for (size_t i
= 0; i
< numProps
; i
++) {
7634 AppendValue(kFlexFlowSubprops
[i
], values
[i
]);
7640 CSSParserImpl::ParseGridAutoFlow()
7643 if (ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
7644 AppendValue(eCSSProperty_grid_auto_flow
, value
);
7648 static const int32_t mask
[] = {
7649 NS_STYLE_GRID_AUTO_FLOW_ROW
| NS_STYLE_GRID_AUTO_FLOW_COLUMN
,
7652 if (!ParseBitmaskValues(value
, nsCSSProps::kGridAutoFlowKTable
, mask
)) {
7655 int32_t bitField
= value
.GetIntValue();
7657 // If neither row nor column is provided, row is assumed.
7658 if (!(bitField
& (NS_STYLE_GRID_AUTO_FLOW_ROW
|
7659 NS_STYLE_GRID_AUTO_FLOW_COLUMN
))) {
7660 value
.SetIntValue(bitField
| NS_STYLE_GRID_AUTO_FLOW_ROW
,
7661 eCSSUnit_Enumerated
);
7664 AppendValue(eCSSProperty_grid_auto_flow
, value
);
7669 CSSParserImpl::ParseGridLineNames(nsCSSValue
& aValue
)
7671 if (!ExpectSymbol('(', true)) {
7672 return CSSParseResult::NotFound
;
7674 if (!GetToken(true) || mToken
.IsSymbol(')')) {
7675 return CSSParseResult::Ok
;
7677 // 'return' so far leaves aValue untouched, to represent an empty list.
7679 nsCSSValueList
* item
;
7680 if (aValue
.GetUnit() == eCSSUnit_List
) {
7681 // Find the end of an existing list.
7682 // The grid-template shorthand uses this, at most once for a given list.
7684 // NOTE: we could avoid this traversal by somehow keeping around
7685 // a pointer to the last item from the previous call.
7686 // It's not yet clear if this is worth the additional code complexity.
7687 item
= aValue
.GetListValue();
7688 while (item
->mNext
) {
7691 item
->mNext
= new nsCSSValueList
;
7694 MOZ_ASSERT(aValue
.GetUnit() == eCSSUnit_Null
, "Unexpected unit");
7695 item
= aValue
.SetListValue();
7698 if (!(eCSSToken_Ident
== mToken
.mType
&&
7699 ParseCustomIdent(item
->mValue
, mToken
.mIdent
))) {
7702 return CSSParseResult::Error
;
7704 if (!GetToken(true) || mToken
.IsSymbol(')')) {
7705 return CSSParseResult::Ok
;
7707 item
->mNext
= new nsCSSValueList
;
7712 // Assuming the 'repeat(' function token has already been consumed,
7713 // parse the rest of repeat(<positive-integer>, <line-names>+)
7714 // Append to the linked list whose end is given by |aTailPtr|,
7715 // and updated |aTailPtr| to point to the new end of the list.
7717 CSSParserImpl::ParseGridLineNameListRepeat(nsCSSValueList
** aTailPtr
)
7719 if (!(GetToken(true) &&
7720 mToken
.mType
== eCSSToken_Number
&&
7721 mToken
.mIntegerValid
&&
7722 mToken
.mInteger
> 0)) {
7726 int32_t repetitions
= std::min(mToken
.mInteger
,
7727 GRID_TEMPLATE_MAX_REPETITIONS
);
7728 if (!ExpectSymbol(',', true)) {
7733 // Parse at least one <line-names>
7734 nsCSSValueList
* tail
= *aTailPtr
;
7736 tail
->mNext
= new nsCSSValueList
;
7738 if (ParseGridLineNames(tail
->mValue
) != CSSParseResult::Ok
) {
7742 } while (!ExpectSymbol(')', true));
7743 nsCSSValueList
* firstRepeatedItem
= (*aTailPtr
)->mNext
;
7744 nsCSSValueList
* lastRepeatedItem
= tail
;
7746 // Our repeated items are already in the target list once,
7747 // so they need to be repeated |repetitions - 1| more times.
7748 MOZ_ASSERT(repetitions
> 0, "Expected positive repetitions");
7749 while (--repetitions
) {
7750 nsCSSValueList
* repeatedItem
= firstRepeatedItem
;
7752 tail
->mNext
= new nsCSSValueList
;
7754 tail
->mValue
= repeatedItem
->mValue
;
7755 if (repeatedItem
== lastRepeatedItem
) {
7758 repeatedItem
= repeatedItem
->mNext
;
7765 // Assuming a 'subgrid' keyword was already consumed, parse <line-name-list>?
7767 CSSParserImpl::ParseOptionalLineNameListAfterSubgrid(nsCSSValue
& aValue
)
7769 nsCSSValueList
* item
= aValue
.SetListValue();
7770 // This marker distinguishes the value from a <track-list>.
7771 item
->mValue
.SetIntValue(NS_STYLE_GRID_TEMPLATE_SUBGRID
,
7772 eCSSUnit_Enumerated
);
7774 // First try to parse repeat(<positive-integer>, <line-names>+)
7775 if (!GetToken(true)) {
7778 if (mToken
.mType
== eCSSToken_Function
&&
7779 mToken
.mIdent
.LowerCaseEqualsLiteral("repeat")) {
7780 if (!ParseGridLineNameListRepeat(&item
)) {
7786 // This was not a repeat() function. Try to parse <line-names>.
7787 nsCSSValue lineNames
;
7788 CSSParseResult result
= ParseGridLineNames(lineNames
);
7789 if (result
== CSSParseResult::NotFound
) {
7792 if (result
== CSSParseResult::Error
) {
7795 item
->mNext
= new nsCSSValueList
;
7797 item
->mValue
= lineNames
;
7802 // Parse a <track-breadth>
7804 CSSParserImpl::ParseGridTrackBreadth(nsCSSValue
& aValue
)
7806 if (ParseNonNegativeVariant(aValue
,
7807 VARIANT_LPCALC
| VARIANT_KEYWORD
,
7808 nsCSSProps::kGridTrackBreadthKTable
)) {
7812 // Attempt to parse <flex> (a dimension with the "fr" unit)
7813 if (!GetToken(true)) {
7816 if (!(eCSSToken_Dimension
== mToken
.mType
&&
7817 mToken
.mIdent
.LowerCaseEqualsLiteral("fr") &&
7818 mToken
.mNumber
>= 0)) {
7822 aValue
.SetFloatValue(mToken
.mNumber
, eCSSUnit_FlexFraction
);
7826 // Parse a <track-size>
7828 CSSParserImpl::ParseGridTrackSize(nsCSSValue
& aValue
)
7830 // Attempt to parse 'auto' or a single <track-breadth>
7831 if (ParseGridTrackBreadth(aValue
) ||
7832 ParseVariant(aValue
, VARIANT_AUTO
, nullptr)) {
7833 return CSSParseResult::Ok
;
7836 // Attempt to parse a minmax() function
7837 if (!GetToken(true)) {
7838 return CSSParseResult::NotFound
;
7840 if (!(eCSSToken_Function
== mToken
.mType
&&
7841 mToken
.mIdent
.LowerCaseEqualsLiteral("minmax"))) {
7843 return CSSParseResult::NotFound
;
7845 nsCSSValue::Array
* func
= aValue
.InitFunction(eCSSKeyword_minmax
, 2);
7846 if (ParseGridTrackBreadth(func
->Item(1)) &&
7847 ExpectSymbol(',', true) &&
7848 ParseGridTrackBreadth(func
->Item(2)) &&
7849 ExpectSymbol(')', true)) {
7850 return CSSParseResult::Ok
;
7853 return CSSParseResult::Error
;
7857 CSSParserImpl::ParseGridAutoColumnsRows(nsCSSProperty aPropID
)
7860 if (ParseVariant(value
, VARIANT_INHERIT
, nullptr) ||
7861 ParseGridTrackSize(value
) == CSSParseResult::Ok
) {
7862 AppendValue(aPropID
, value
);
7869 CSSParserImpl::ParseGridTrackListWithFirstLineNames(nsCSSValue
& aValue
,
7870 const nsCSSValue
& aFirstLineNames
)
7872 nsCSSValueList
* firstLineNamesItem
= aValue
.SetListValue();
7873 firstLineNamesItem
->mValue
= aFirstLineNames
;
7875 // This function is trying to parse <track-list>, which is
7876 // [ <line-names>? [ <track-size> | <repeat()> ] ]+ <line-names>?
7877 // and we're already past the first "<line-names>?".
7879 // Each iteration of the following loop attempts to parse either a
7880 // repeat() or a <track-size> expression, and then an (optional)
7881 // <line-names> expression.
7883 // The only successful exit point from this loop is the ::NotFound
7884 // case after ParseGridTrackSize(); i.e. we'll greedily parse
7885 // repeat()/<track-size> until we can't find one.
7886 nsCSSValueList
* item
= firstLineNamesItem
;
7888 // First try to parse repeat()
7889 if (!GetToken(true)) {
7892 if (mToken
.mType
== eCSSToken_Function
&&
7893 mToken
.mIdent
.LowerCaseEqualsLiteral("repeat")) {
7894 if (!ParseGridTrackListRepeat(&item
)) {
7900 // This was not a repeat() function. Try to parse <track-size>.
7901 nsCSSValue trackSize
;
7902 CSSParseResult result
= ParseGridTrackSize(trackSize
);
7903 if (result
== CSSParseResult::Error
) {
7906 if (result
== CSSParseResult::NotFound
) {
7907 // What we've parsed so far is a valid <track-list>
7908 // (modulo the "at least one <track-size>" check below.)
7912 item
->mNext
= new nsCSSValueList
;
7914 item
->mValue
= trackSize
;
7916 item
->mNext
= new nsCSSValueList
;
7919 if (ParseGridLineNames(item
->mValue
) == CSSParseResult::Error
) {
7924 // Require at least one <track-size>.
7925 if (item
== firstLineNamesItem
) {
7929 MOZ_ASSERT(aValue
.GetListValue() &&
7930 aValue
.GetListValue()->mNext
&&
7931 aValue
.GetListValue()->mNext
->mNext
,
7932 "<track-list> should have a minimum length of 3");
7936 // Takes ownership of |aSecond|
7938 ConcatLineNames(nsCSSValue
& aFirst
, nsCSSValue
& aSecond
)
7940 if (aSecond
.GetUnit() == eCSSUnit_Null
) {
7944 if (aFirst
.GetUnit() == eCSSUnit_Null
) {
7945 // Empty or omitted <line-names>. Replace it.
7950 // Join the two <line-names> lists.
7951 nsCSSValueList
* source
= aSecond
.GetListValue();
7952 nsCSSValueList
* target
= aFirst
.GetListValue();
7954 while (target
->mNext
) {
7955 target
= target
->mNext
;
7957 // Copy the first name. We can't take ownership of it
7958 // as it'll be destroyed when |aSecond| goes out of scope.
7959 target
->mNext
= new nsCSSValueList
;
7960 target
= target
->mNext
;
7961 target
->mValue
= source
->mValue
;
7962 // Move the rest of the linked list.
7963 target
->mNext
= source
->mNext
;
7964 source
->mNext
= nullptr;
7967 // Assuming the 'repeat(' function token has already been consumed,
7968 // parse the rest of
7969 // repeat( <positive-integer> ,
7970 // [ <line-names>? <track-size> ]+ <line-names>? )
7971 // Append to the linked list whose end is given by |aTailPtr|,
7972 // and updated |aTailPtr| to point to the new end of the list.
7974 CSSParserImpl::ParseGridTrackListRepeat(nsCSSValueList
** aTailPtr
)
7976 if (!(GetToken(true) &&
7977 mToken
.mType
== eCSSToken_Number
&&
7978 mToken
.mIntegerValid
&&
7979 mToken
.mInteger
> 0)) {
7983 int32_t repetitions
= std::min(mToken
.mInteger
,
7984 GRID_TEMPLATE_MAX_REPETITIONS
);
7985 if (!ExpectSymbol(',', true)) {
7990 // Parse [ <line-names>? <track-size> ]+ <line-names>?
7991 // but keep the first and last <line-names> separate
7992 // because they'll need to be joined.
7993 // http://dev.w3.org/csswg/css-grid/#repeat-notation
7994 nsCSSValue firstLineNames
;
7995 nsCSSValue trackSize
;
7996 nsCSSValue lastLineNames
;
7998 if (ParseGridLineNames(firstLineNames
) == CSSParseResult::Error
) {
8003 if (ParseGridTrackSize(trackSize
) != CSSParseResult::Ok
) {
8007 // Use nsAutoPtr to free the list in case of early return.
8008 nsAutoPtr
<nsCSSValueList
> firstTrackSizeItemAuto(new nsCSSValueList
);
8009 firstTrackSizeItemAuto
->mValue
= trackSize
;
8011 nsCSSValueList
* item
= firstTrackSizeItemAuto
;
8014 if (ParseGridLineNames(lastLineNames
) == CSSParseResult::Error
) {
8019 if (ExpectSymbol(')', true)) {
8024 if (ParseGridTrackSize(trackSize
) != CSSParseResult::Ok
) {
8029 item
->mNext
= new nsCSSValueList
;
8031 item
->mValue
= lastLineNames
;
8032 // Do not append to this list at the next iteration.
8033 lastLineNames
.Reset();
8035 item
->mNext
= new nsCSSValueList
;
8037 item
->mValue
= trackSize
;
8039 nsCSSValueList
* lastTrackSizeItem
= item
;
8041 // [ <line-names>? <track-size> ]+ <line-names>? is now parsed into:
8042 // * firstLineNames: the first <line-names>
8043 // * a linked list of odd length >= 1, from firstTrackSizeItem
8044 // (the first <track-size>) to lastTrackSizeItem (the last),
8045 // with the <line-names> sublists in between
8046 // * lastLineNames: the last <line-names>
8049 // Join the last and first <line-names> (in that order.)
8050 // For example, repeat(3, (a) 100px (b) 200px (c)) results in
8051 // (a) 100px (b) 200px (c a) 100px (b) 200px (c a) 100px (b) 200px (c)
8053 // Make deep copies: the originals will be moved.
8054 nsCSSValue joinerLineNames
;
8056 nsCSSValueList
* target
= nullptr;
8057 if (lastLineNames
.GetUnit() != eCSSUnit_Null
) {
8058 target
= joinerLineNames
.SetListValue();
8059 nsCSSValueList
* source
= lastLineNames
.GetListValue();
8061 target
->mValue
= source
->mValue
;
8062 source
= source
->mNext
;
8066 target
->mNext
= new nsCSSValueList
;
8067 target
= target
->mNext
;
8071 if (firstLineNames
.GetUnit() != eCSSUnit_Null
) {
8073 target
->mNext
= new nsCSSValueList
;
8074 target
= target
->mNext
;
8076 target
= joinerLineNames
.SetListValue();
8078 nsCSSValueList
* source
= firstLineNames
.GetListValue();
8080 target
->mValue
= source
->mValue
;
8081 source
= source
->mNext
;
8085 target
->mNext
= new nsCSSValueList
;
8086 target
= target
->mNext
;
8091 // Join our first <line-names> with the one before repeat().
8092 // (a) repeat(1, (b) 20px) expands to (a b) 20px
8093 nsCSSValueList
* previousItemBeforeRepeat
= *aTailPtr
;
8094 ConcatLineNames(previousItemBeforeRepeat
->mValue
, firstLineNames
);
8096 // Move our linked list
8097 // (first to last <track-size>, with the <line-names> sublists in between).
8098 // This is the first repetition.
8099 NS_ASSERTION(previousItemBeforeRepeat
->mNext
== nullptr,
8100 "Expected the end of a linked list");
8101 previousItemBeforeRepeat
->mNext
= firstTrackSizeItemAuto
.forget();
8102 nsCSSValueList
* firstTrackSizeItem
= previousItemBeforeRepeat
->mNext
;
8103 nsCSSValueList
* tail
= lastTrackSizeItem
;
8105 // Repeat |repetitions - 1| more times:
8106 // * the joiner <line-names>
8107 // * the linked list
8108 // (first to last <track-size>, with the <line-names> sublists in between)
8109 MOZ_ASSERT(repetitions
> 0, "Expected positive repetitions");
8110 while (--repetitions
) {
8111 tail
->mNext
= new nsCSSValueList
;
8113 tail
->mValue
= joinerLineNames
;
8115 nsCSSValueList
* repeatedItem
= firstTrackSizeItem
;
8117 tail
->mNext
= new nsCSSValueList
;
8119 tail
->mValue
= repeatedItem
->mValue
;
8120 if (repeatedItem
== lastTrackSizeItem
) {
8123 repeatedItem
= repeatedItem
->mNext
;
8127 // Finally, move our last <line-names>.
8128 // Any <line-names> immediately after repeat() will append to it.
8129 tail
->mNext
= new nsCSSValueList
;
8131 tail
->mValue
= lastLineNames
;
8138 CSSParserImpl::ParseGridTemplateColumnsRows(nsCSSProperty aPropID
)
8141 if (ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
8142 AppendValue(aPropID
, value
);
8146 nsSubstring
* ident
= NextIdent();
8148 if (ident
->LowerCaseEqualsLiteral("subgrid")) {
8149 if (!ParseOptionalLineNameListAfterSubgrid(value
)) {
8152 AppendValue(aPropID
, value
);
8158 nsCSSValue firstLineNames
;
8159 if (ParseGridLineNames(firstLineNames
) == CSSParseResult::Error
||
8160 !ParseGridTrackListWithFirstLineNames(value
, firstLineNames
)) {
8163 AppendValue(aPropID
, value
);
8168 CSSParserImpl::ParseGridTemplateAreasLine(const nsAutoString
& aInput
,
8169 css::GridTemplateAreasValue
* aAreas
,
8170 nsDataHashtable
<nsStringHashKey
, uint32_t>& aAreaIndices
)
8172 aAreas
->mTemplates
.AppendElement(mToken
.mIdent
);
8174 nsCSSGridTemplateAreaScanner
scanner(aInput
);
8175 nsCSSGridTemplateAreaToken token
;
8176 css::GridNamedArea
* currentArea
= nullptr;
8177 uint32_t row
= aAreas
->NRows();
8178 // Column numbers starts at 1, but we might not have any, eg
8179 // grid-template-areas:""; which will result in mNColumns == 0.
8180 uint32_t column
= 0;
8181 while (scanner
.Next(token
)) {
8183 if (token
.isTrash
) {
8187 if (token
.mName
== currentArea
->mName
) {
8188 if (currentArea
->mRowStart
== row
) {
8189 // Next column in the first row of this named area.
8190 currentArea
->mColumnEnd
++;
8194 // We're exiting |currentArea|, so currentArea is ending at |column|.
8195 // Make sure that this is consistent with currentArea on previous rows:
8196 if (currentArea
->mColumnEnd
!= column
) {
8197 NS_ASSERTION(currentArea
->mRowStart
!= row
,
8198 "Inconsistent column end for the first row of a named area.");
8202 currentArea
= nullptr;
8204 if (!token
.mName
.IsEmpty()) {
8205 // Named cell that doesn't have a cell with the same name on its left.
8207 // Check if this is the continuation of an existing named area:
8209 if (aAreaIndices
.Get(token
.mName
, &index
)) {
8210 MOZ_ASSERT(index
< aAreas
->mNamedAreas
.Length(),
8211 "Invalid aAreaIndices hash table");
8212 currentArea
= &aAreas
->mNamedAreas
[index
];
8213 if (currentArea
->mColumnStart
!= column
||
8214 currentArea
->mRowEnd
!= row
) {
8215 // Existing named area, but not forming a rectangle
8218 // Next row of an existing named area
8219 currentArea
->mRowEnd
++;
8222 aAreaIndices
.Put(token
.mName
, aAreas
->mNamedAreas
.Length());
8223 currentArea
= aAreas
->mNamedAreas
.AppendElement();
8224 currentArea
->mName
= token
.mName
;
8225 // For column or row N (starting at 1),
8226 // the start line is N, the end line is N + 1
8227 currentArea
->mColumnStart
= column
;
8228 currentArea
->mColumnEnd
= column
+ 1;
8229 currentArea
->mRowStart
= row
;
8230 currentArea
->mRowEnd
= row
+ 1;
8234 if (currentArea
&& currentArea
->mColumnEnd
!= column
+ 1) {
8235 NS_ASSERTION(currentArea
->mRowStart
!= row
,
8236 "Inconsistent column end for the first row of a named area.");
8241 // On the first row, set the number of columns
8242 // that grid-template-areas contributes to the explicit grid.
8243 // On other rows, check that the number of columns is consistent
8246 aAreas
->mNColumns
= column
;
8247 } else if (aAreas
->mNColumns
!= column
) {
8254 CSSParserImpl::ParseGridTemplateAreas()
8257 if (ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
8258 AppendValue(eCSSProperty_grid_template_areas
, value
);
8262 nsRefPtr
<css::GridTemplateAreasValue
> areas
=
8263 new css::GridTemplateAreasValue();
8264 nsDataHashtable
<nsStringHashKey
, uint32_t> areaIndices
;
8266 if (!GetToken(true)) {
8269 if (eCSSToken_String
!= mToken
.mType
) {
8273 if (!ParseGridTemplateAreasLine(mToken
.mIdent
, areas
, areaIndices
)) {
8278 if (areas
->NRows() == 0) {
8282 AppendValue(eCSSProperty_grid_template_areas
, nsCSSValue(areas
));
8287 CSSParserImpl::ParseGridTemplate()
8291 // <'grid-template-columns'> / <'grid-template-rows'> |
8292 // [ <track-list> / ]? [ <line-names>? <string> <track-size>? <line-names>? ]+
8294 if (ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
8295 AppendValue(eCSSProperty_grid_template_areas
, value
);
8296 AppendValue(eCSSProperty_grid_template_columns
, value
);
8297 AppendValue(eCSSProperty_grid_template_rows
, value
);
8301 // TODO (bug 983175): add parsing for 'subgrid' by itself
8303 // 'none' can appear either by itself,
8304 // or as the beginning of <'grid-template-columns'> / <'grid-template-rows'>
8305 if (ParseVariant(value
, VARIANT_NONE
, nullptr)) {
8306 AppendValue(eCSSProperty_grid_template_columns
, value
);
8307 if (ExpectSymbol('/', true)) {
8308 return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ false);
8310 AppendValue(eCSSProperty_grid_template_areas
, value
);
8311 AppendValue(eCSSProperty_grid_template_rows
, value
);
8315 // 'subgrid' can appear either by itself,
8316 // or as the beginning of <'grid-template-columns'> / <'grid-template-rows'>
8317 nsSubstring
* ident
= NextIdent();
8319 if (ident
->LowerCaseEqualsLiteral("subgrid")) {
8320 if (!ParseOptionalLineNameListAfterSubgrid(value
)) {
8323 AppendValue(eCSSProperty_grid_template_columns
, value
);
8324 if (ExpectSymbol('/', true)) {
8325 return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ false);
8327 if (value
.GetListValue()->mNext
) {
8328 // Non-empty <line-name-list> after 'subgrid'.
8329 // This is only valid as part of <'grid-template-columns'>,
8330 // which must be followed by a slash.
8333 // 'subgrid' by itself sets both grid-template-columns
8334 // and grid-template-rows.
8335 AppendValue(eCSSProperty_grid_template_rows
, value
);
8336 value
.SetNoneValue();
8337 AppendValue(eCSSProperty_grid_template_areas
, value
);
8343 // [ <line-names>? ] here is ambiguous:
8344 // it can be either the start of a <track-list>,
8345 // or the start of [ <line-names>? <string> <track-size>? <line-names>? ]+
8346 nsCSSValue firstLineNames
;
8347 if (ParseGridLineNames(firstLineNames
) == CSSParseResult::Error
||
8351 if (mToken
.mType
== eCSSToken_String
) {
8352 // [ <track-list> / ]? was omitted
8353 // Parse [ <line-names>? <string> <track-size>? <line-names>? ]+
8354 value
.SetNoneValue();
8355 AppendValue(eCSSProperty_grid_template_columns
, value
);
8356 return ParseGridTemplateAfterString(firstLineNames
);
8360 if (!(ParseGridTrackListWithFirstLineNames(value
, firstLineNames
) &&
8361 ExpectSymbol('/', true))) {
8364 AppendValue(eCSSProperty_grid_template_columns
, value
);
8365 return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ true);
8368 // Helper for parsing the 'grid-template' shorthand
8370 // NOTE: This parses the portion after the slash, for *one* of the
8371 // following types of expressions:
8372 // - <'grid-template-columns'> / <'grid-template-rows'>
8373 // - <track-list> / [ <line-names>? <string> <track-size>? <line-names>? ]+
8375 // We don't know which type of expression we've got until we've parsed the
8376 // second half, since the pre-slash part is ambiguous. The various return
8377 // clauses below are labeled with the type of expression they're completing.
8379 CSSParserImpl::ParseGridTemplateAfterSlash(bool aColumnsIsTrackList
)
8381 nsCSSValue rowsValue
;
8382 if (ParseVariant(rowsValue
, VARIANT_NONE
, nullptr)) {
8383 // <'grid-template-columns'> / <'grid-template-rows'>
8384 AppendValue(eCSSProperty_grid_template_rows
, rowsValue
);
8385 nsCSSValue
areasValue(eCSSUnit_None
); // implied
8386 AppendValue(eCSSProperty_grid_template_areas
, areasValue
);
8390 nsSubstring
* ident
= NextIdent();
8392 if (ident
->LowerCaseEqualsLiteral("subgrid")) {
8393 if (!ParseOptionalLineNameListAfterSubgrid(rowsValue
)) {
8396 // <'grid-template-columns'> / <'grid-template-rows'>
8397 AppendValue(eCSSProperty_grid_template_rows
, rowsValue
);
8398 nsCSSValue
areasValue(eCSSUnit_None
); // implied
8399 AppendValue(eCSSProperty_grid_template_areas
, areasValue
);
8405 nsCSSValue firstLineNames
;
8406 if (ParseGridLineNames(firstLineNames
) == CSSParseResult::Error
||
8410 if (aColumnsIsTrackList
&& mToken
.mType
== eCSSToken_String
) {
8411 // [ <track-list> / ]? [ <line-names>? <string> <track-size>? <line-names>? ]+
8412 return ParseGridTemplateAfterString(firstLineNames
);
8416 if (!ParseGridTrackListWithFirstLineNames(rowsValue
, firstLineNames
)) {
8420 // <'grid-template-columns'> / <'grid-template-rows'>
8421 AppendValue(eCSSProperty_grid_template_rows
, rowsValue
);
8422 nsCSSValue
areasValue(eCSSUnit_None
); // implied
8423 AppendValue(eCSSProperty_grid_template_areas
, areasValue
);
8427 // Helper for parsing the 'grid-template' shorthand:
8428 // Parse [ <line-names>? <string> <track-size>? <line-names>? ]+
8429 // with a <line-names>? already consumed, stored in |aFirstLineNames|,
8430 // and the current token a <string>
8432 CSSParserImpl::ParseGridTemplateAfterString(const nsCSSValue
& aFirstLineNames
)
8434 MOZ_ASSERT(mToken
.mType
== eCSSToken_String
,
8435 "ParseGridTemplateAfterString called with a non-string token");
8437 nsCSSValue rowsValue
;
8438 nsRefPtr
<css::GridTemplateAreasValue
> areas
=
8439 new css::GridTemplateAreasValue();
8440 nsDataHashtable
<nsStringHashKey
, uint32_t> areaIndices
;
8441 nsCSSValueList
* rowsItem
= rowsValue
.SetListValue();
8442 rowsItem
->mValue
= aFirstLineNames
;
8445 if (!ParseGridTemplateAreasLine(mToken
.mIdent
, areas
, areaIndices
)) {
8449 rowsItem
->mNext
= new nsCSSValueList
;
8450 rowsItem
= rowsItem
->mNext
;
8451 CSSParseResult result
= ParseGridTrackSize(rowsItem
->mValue
);
8452 if (result
== CSSParseResult::Error
) {
8455 if (result
== CSSParseResult::NotFound
) {
8456 rowsItem
->mValue
.SetAutoValue();
8459 rowsItem
->mNext
= new nsCSSValueList
;
8460 rowsItem
= rowsItem
->mNext
;
8461 result
= ParseGridLineNames(rowsItem
->mValue
);
8462 if (result
== CSSParseResult::Error
) {
8465 if (result
== CSSParseResult::Ok
) {
8466 // Append to the same list as the previous call to ParseGridLineNames.
8467 result
= ParseGridLineNames(rowsItem
->mValue
);
8468 if (result
== CSSParseResult::Error
) {
8471 if (result
== CSSParseResult::Ok
) {
8472 // Parsed <line-name> twice.
8473 // The property value can not end here, we expect a string next.
8474 if (!GetToken(true)) {
8477 if (eCSSToken_String
!= mToken
.mType
) {
8485 // Did not find a <line-names>.
8486 // Next, we expect either a string or the end of the property value.
8487 if (!GetToken(true)) {
8490 if (eCSSToken_String
!= mToken
.mType
) {
8496 AppendValue(eCSSProperty_grid_template_areas
, nsCSSValue(areas
));
8497 AppendValue(eCSSProperty_grid_template_rows
, rowsValue
);
8501 // <'grid-template'> |
8502 // [ <'grid-auto-flow'> [ <'grid-auto-columns'> [ / <'grid-auto-rows'> ]? ]? ]
8504 CSSParserImpl::ParseGrid()
8507 if (ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
8508 for (const nsCSSProperty
* subprops
=
8509 nsCSSProps::SubpropertyEntryFor(eCSSProperty_grid
);
8510 *subprops
!= eCSSProperty_UNKNOWN
; ++subprops
) {
8511 AppendValue(*subprops
, value
);
8516 // An empty value is always invalid.
8517 if (!GetToken(true)) {
8521 // The values starts with a <'grid-auto-flow'> if and only if
8522 // it starts with a 'dense', 'column' or 'row' keyword.
8523 if (mToken
.mType
== eCSSToken_Ident
) {
8524 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
8525 if (keyword
== eCSSKeyword_dense
||
8526 keyword
== eCSSKeyword_column
||
8527 keyword
== eCSSKeyword_row
) {
8529 return ParseGridAutoFlow() && ParseGridShorthandAutoProps();
8534 // Set other subproperties to their initial values
8535 // and parse <'grid-template'>.
8536 value
.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_ROW
, eCSSUnit_Enumerated
);
8537 AppendValue(eCSSProperty_grid_auto_flow
, value
);
8538 value
.SetAutoValue();
8539 AppendValue(eCSSProperty_grid_auto_columns
, value
);
8540 AppendValue(eCSSProperty_grid_auto_rows
, value
);
8541 return ParseGridTemplate();
8544 // Parse [ <'grid-auto-columns'> [ / <'grid-auto-rows'> ]? ]?
8545 // for the 'grid' shorthand.
8546 // Assumes that <'grid-auto-flow'> was already parsed by the caller.
8548 CSSParserImpl::ParseGridShorthandAutoProps()
8550 nsCSSValue autoColumnsValue
;
8551 nsCSSValue autoRowsValue
;
8552 CSSParseResult result
= ParseGridTrackSize(autoColumnsValue
);
8553 if (result
== CSSParseResult::Error
) {
8556 if (result
== CSSParseResult::NotFound
) {
8557 autoColumnsValue
.SetAutoValue();
8558 autoRowsValue
.SetAutoValue();
8560 if (!ExpectSymbol('/', true)) {
8561 autoRowsValue
.SetAutoValue();
8562 } else if (ParseGridTrackSize(autoRowsValue
) != CSSParseResult::Ok
) {
8566 AppendValue(eCSSProperty_grid_auto_columns
, autoColumnsValue
);
8567 AppendValue(eCSSProperty_grid_auto_rows
, autoRowsValue
);
8568 nsCSSValue
templateValue(eCSSUnit_None
); // Initial values
8569 AppendValue(eCSSProperty_grid_template_areas
, templateValue
);
8570 AppendValue(eCSSProperty_grid_template_columns
, templateValue
);
8571 AppendValue(eCSSProperty_grid_template_rows
, templateValue
);
8575 // Parse a <grid-line>.
8576 // If successful, set aValue to eCSSUnit_Auto,
8577 // or a eCSSUnit_List containing, in that order:
8579 // * An optional eCSSUnit_Enumerated marking a "span" keyword.
8580 // * An optional eCSSUnit_Integer
8581 // * An optional eCSSUnit_Ident
8583 // At least one of eCSSUnit_Integer or eCSSUnit_Ident is present.
8585 CSSParserImpl::ParseGridLine(nsCSSValue
& aValue
)
8590 // [ <integer> && <custom-ident>? ] |
8591 // [ span && [ <integer> || <custom-ident> ] ]
8593 // Syntactically, this simplifies to:
8597 // [ span? && [ <integer> || <custom-ident> ] ]
8599 if (ParseVariant(aValue
, VARIANT_AUTO
, nullptr)) {
8603 static const nsCSSKeyword kGridLineKeywords
[] = {
8605 eCSSKeyword_UNKNOWN
// End-of-array marker
8607 bool hasSpan
= false;
8608 bool hasIdent
= false;
8609 Maybe
<int32_t> integer
;
8612 if (!GetToken(true)) {
8615 if (mToken
.mType
== eCSSToken_Ident
&&
8616 mToken
.mIdent
.LowerCaseEqualsLiteral("span")) {
8618 if (!GetToken(true)) {
8625 mToken
.mType
== eCSSToken_Ident
&&
8626 ParseCustomIdent(ident
, mToken
.mIdent
, kGridLineKeywords
)) {
8628 } else if (integer
.isNothing() &&
8629 mToken
.mType
== eCSSToken_Number
&&
8630 mToken
.mIntegerValid
&&
8631 mToken
.mInteger
!= 0) {
8632 integer
.emplace(mToken
.mInteger
);
8637 } while (!(integer
.isSome() && hasIdent
) && GetToken(true));
8639 // Require at least one of <integer> or <custom-ident>
8640 if (!(integer
.isSome() || hasIdent
)) {
8644 if (!hasSpan
&& GetToken(true)) {
8645 if (mToken
.mType
== eCSSToken_Ident
&&
8646 mToken
.mIdent
.LowerCaseEqualsLiteral("span")) {
8653 nsCSSValueList
* item
= aValue
.SetListValue();
8655 // Given "span", a negative <integer> is invalid.
8656 if (integer
.isSome() && integer
.ref() < 0) {
8659 // '1' here is a dummy value.
8660 // The mere presence of eCSSUnit_Enumerated indicates a "span" keyword.
8661 item
->mValue
.SetIntValue(1, eCSSUnit_Enumerated
);
8662 item
->mNext
= new nsCSSValueList
;
8665 if (integer
.isSome()) {
8666 item
->mValue
.SetIntValue(integer
.ref(), eCSSUnit_Integer
);
8668 item
->mNext
= new nsCSSValueList
;
8673 item
->mValue
= ident
;
8679 CSSParserImpl::ParseGridColumnRowStartEnd(nsCSSProperty aPropID
)
8682 if (ParseVariant(value
, VARIANT_INHERIT
, nullptr) ||
8683 ParseGridLine(value
)) {
8684 AppendValue(aPropID
, value
);
8690 // If |aFallback| is a List containing a single Ident, set |aValue| to that.
8691 // Otherwise, set |aValue| to Auto.
8692 // Used with |aFallback| from ParseGridLine()
8694 HandleGridLineFallback(const nsCSSValue
& aFallback
, nsCSSValue
& aValue
)
8696 if (aFallback
.GetUnit() == eCSSUnit_List
&&
8697 aFallback
.GetListValue()->mValue
.GetUnit() == eCSSUnit_Ident
&&
8698 !aFallback
.GetListValue()->mNext
) {
8701 aValue
.SetAutoValue();
8706 CSSParserImpl::ParseGridColumnRow(nsCSSProperty aStartPropID
,
8707 nsCSSProperty aEndPropID
)
8710 nsCSSValue secondValue
;
8711 if (ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
8712 AppendValue(aStartPropID
, value
);
8713 AppendValue(aEndPropID
, value
);
8717 if (!ParseGridLine(value
)) {
8720 if (GetToken(true)) {
8721 if (mToken
.IsSymbol('/')) {
8722 if (ParseGridLine(secondValue
)) {
8723 AppendValue(aStartPropID
, value
);
8724 AppendValue(aEndPropID
, secondValue
);
8733 // A single <custom-ident> is repeated to both properties,
8734 // anything else sets the grid-{column,row}-end property to 'auto'.
8735 HandleGridLineFallback(value
, secondValue
);
8737 AppendValue(aStartPropID
, value
);
8738 AppendValue(aEndPropID
, secondValue
);
8743 CSSParserImpl::ParseGridArea()
8745 nsCSSValue values
[4];
8746 if (ParseVariant(values
[0], VARIANT_INHERIT
, nullptr)) {
8747 AppendValue(eCSSProperty_grid_row_start
, values
[0]);
8748 AppendValue(eCSSProperty_grid_column_start
, values
[0]);
8749 AppendValue(eCSSProperty_grid_row_end
, values
[0]);
8750 AppendValue(eCSSProperty_grid_column_end
, values
[0]);
8756 if (!ParseGridLine(values
[i
])) {
8759 if (++i
== 4 || !GetToken(true)) {
8762 if (!mToken
.IsSymbol('/')) {
8768 MOZ_ASSERT(i
>= 1, "should have parsed at least one grid-line (or returned)");
8770 HandleGridLineFallback(values
[0], values
[1]);
8773 HandleGridLineFallback(values
[0], values
[2]);
8776 HandleGridLineFallback(values
[1], values
[3]);
8779 AppendValue(eCSSProperty_grid_row_start
, values
[0]);
8780 AppendValue(eCSSProperty_grid_column_start
, values
[1]);
8781 AppendValue(eCSSProperty_grid_row_end
, values
[2]);
8782 AppendValue(eCSSProperty_grid_column_end
, values
[3]);
8786 // <color-stop> : <color> [ <percentage> | <length> ]?
8788 CSSParserImpl::ParseColorStop(nsCSSValueGradient
* aGradient
)
8790 nsCSSValueGradientStop
* stop
= aGradient
->mStops
.AppendElement();
8791 if (!ParseVariant(stop
->mColor
, VARIANT_COLOR
, nullptr)) {
8792 stop
->mIsInterpolationHint
= true;
8795 // Stop positions do not have to fall between the starting-point and
8796 // ending-point, so we don't use ParseNonNegativeVariant.
8797 if (!ParseVariant(stop
->mLocation
, VARIANT_LP
| VARIANT_CALC
, nullptr)) {
8798 if (stop
->mIsInterpolationHint
) {
8801 stop
->mLocation
.SetNoneValue();
8807 // : linear-gradient( <linear-gradient-line>? <color-stops> ')'
8808 // | radial-gradient( <radial-gradient-line>? <color-stops> ')'
8810 // <linear-gradient-line> : [ to [left | right] || [top | bottom] ] ,
8811 // | <legacy-gradient-line>
8812 // <radial-gradient-line> : [ <shape> || <size> ] [ at <position> ]? ,
8813 // | [ at <position> ] ,
8814 // | <legacy-gradient-line>? <legacy-shape-size>?
8815 // <shape> : circle | ellipse
8816 // <size> : closest-side | closest-corner | farthest-side | farthest-corner
8817 // | <length> | [<length> | <percentage>]{2}
8819 // <legacy-gradient-line> : [ <position> || <angle>] ,
8821 // <legacy-shape-size> : [ <shape> || <legacy-size> ] ,
8822 // <legacy-size> : closest-side | closest-corner | farthest-side
8823 // | farthest-corner | contain | cover
8825 // <color-stops> : <color-stop> , <color-stop> [, <color-stop>]*
8827 CSSParserImpl::ParseLinearGradient(nsCSSValue
& aValue
, bool aIsRepeating
,
8830 nsRefPtr
<nsCSSValueGradient
> cssGradient
8831 = new nsCSSValueGradient(false, aIsRepeating
);
8833 if (!GetToken(true)) {
8837 if (mToken
.mType
== eCSSToken_Ident
&&
8838 mToken
.mIdent
.LowerCaseEqualsLiteral("to")) {
8840 // "to" syntax doesn't allow explicit "center"
8841 if (!ParseBoxPositionValues(cssGradient
->mBgPos
, false, false)) {
8846 // [ to [left | right] || [top | bottom] ] ,
8847 const nsCSSValue
& xValue
= cssGradient
->mBgPos
.mXValue
;
8848 const nsCSSValue
& yValue
= cssGradient
->mBgPos
.mYValue
;
8849 if (xValue
.GetUnit() != eCSSUnit_Enumerated
||
8850 !(xValue
.GetIntValue() & (NS_STYLE_BG_POSITION_LEFT
|
8851 NS_STYLE_BG_POSITION_CENTER
|
8852 NS_STYLE_BG_POSITION_RIGHT
)) ||
8853 yValue
.GetUnit() != eCSSUnit_Enumerated
||
8854 !(yValue
.GetIntValue() & (NS_STYLE_BG_POSITION_TOP
|
8855 NS_STYLE_BG_POSITION_CENTER
|
8856 NS_STYLE_BG_POSITION_BOTTOM
))) {
8861 if (!ExpectSymbol(',', true)) {
8866 return ParseGradientColorStops(cssGradient
, aValue
);
8873 if (ParseVariant(cssGradient
->mAngle
, VARIANT_ANGLE
, nullptr) &&
8874 !ExpectSymbol(',', true)) {
8879 return ParseGradientColorStops(cssGradient
, aValue
);
8882 nsCSSTokenType ty
= mToken
.mType
;
8883 nsString id
= mToken
.mIdent
;
8886 // <legacy-gradient-line>
8887 bool haveGradientLine
= IsLegacyGradientLine(ty
, id
);
8888 if (haveGradientLine
) {
8889 cssGradient
->mIsLegacySyntax
= true;
8891 ParseVariant(cssGradient
->mAngle
, VARIANT_ANGLE
, nullptr);
8893 // if we got an angle, we might now have a comma, ending the gradient-line
8894 if (!haveAngle
|| !ExpectSymbol(',', true)) {
8895 if (!ParseBoxPositionValues(cssGradient
->mBgPos
, false)) {
8900 if (!ExpectSymbol(',', true) &&
8901 // if we didn't already get an angle, we might have one now,
8902 // otherwise it's an error
8904 !ParseVariant(cssGradient
->mAngle
, VARIANT_ANGLE
, nullptr) ||
8905 // now we better have a comma
8906 !ExpectSymbol(',', true))) {
8913 return ParseGradientColorStops(cssGradient
, aValue
);
8917 CSSParserImpl::ParseRadialGradient(nsCSSValue
& aValue
, bool aIsRepeating
,
8920 nsRefPtr
<nsCSSValueGradient
> cssGradient
8921 = new nsCSSValueGradient(true, aIsRepeating
);
8923 // [ <shape> || <size> ]
8925 ParseVariant(cssGradient
->GetRadialShape(), VARIANT_KEYWORD
,
8926 nsCSSProps::kRadialGradientShapeKTable
);
8928 bool haveSize
= ParseVariant(cssGradient
->GetRadialSize(), VARIANT_KEYWORD
,
8930 nsCSSProps::kRadialGradientLegacySizeKTable
:
8931 nsCSSProps::kRadialGradientSizeKTable
);
8935 haveShape
= ParseVariant(cssGradient
->GetRadialShape(), VARIANT_KEYWORD
,
8936 nsCSSProps::kRadialGradientShapeKTable
);
8938 } else if (!aIsLegacy
) {
8939 // Save RadialShape before parsing RadiusX because RadialShape and
8940 // RadiusX share the storage.
8942 cssGradient
->GetRadialShape().GetUnit() == eCSSUnit_Enumerated
?
8943 cssGradient
->GetRadialShape().GetIntValue() : -1;
8944 // <length> | [<length> | <percentage>]{2}
8945 cssGradient
->mIsExplicitSize
= true;
8947 ParseNonNegativeVariant(cssGradient
->GetRadiusX(), VARIANT_LP
, nullptr);
8949 // It was not an explicit size after all.
8950 // Note that ParseNonNegativeVariant may have put something
8951 // invalid into our storage, but only in the case where it was
8952 // rejected only for being negative. Since this means the token
8953 // was a length or a percentage, we know it's not valid syntax
8954 // (which must be a comma, the 'at' keyword, or a color), so we
8955 // know this value will be dropped. This means it doesn't matter
8956 // that we have something invalid in our storage.
8957 cssGradient
->mIsExplicitSize
= false;
8959 // vertical extent is optional
8961 ParseNonNegativeVariant(cssGradient
->GetRadiusY(), VARIANT_LP
, nullptr);
8963 nsCSSValue shapeValue
;
8964 haveShape
= ParseVariant(shapeValue
, VARIANT_KEYWORD
,
8965 nsCSSProps::kRadialGradientShapeKTable
);
8967 shape
= shapeValue
.GetIntValue();
8971 ? shape
== NS_STYLE_GRADIENT_SHAPE_CIRCULAR
8972 : cssGradient
->GetRadiusX().GetUnit() == eCSSUnit_Percent
||
8973 shape
== NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL
) {
8980 if ((haveShape
|| haveSize
) && ExpectSymbol(',', true)) {
8981 // [ <shape> || <size> ] ,
8982 return ParseGradientColorStops(cssGradient
, aValue
);
8985 if (!GetToken(true)) {
8990 if (mToken
.mType
== eCSSToken_Ident
&&
8991 mToken
.mIdent
.LowerCaseEqualsLiteral("at")) {
8992 // [ <shape> || <size> ]? at <position> ,
8993 if (!ParseBoxPositionValues(cssGradient
->mBgPos
, false) ||
8994 !ExpectSymbol(',', true)) {
8999 return ParseGradientColorStops(cssGradient
, aValue
);
9002 // <color-stops> only
9004 return ParseGradientColorStops(cssGradient
, aValue
);
9006 MOZ_ASSERT(!cssGradient
->mIsExplicitSize
);
9008 nsCSSTokenType ty
= mToken
.mType
;
9009 nsString id
= mToken
.mIdent
;
9012 // <legacy-gradient-line>
9013 bool haveGradientLine
= false;
9014 // if we already encountered a shape or size,
9015 // we can not have a gradient-line in legacy syntax
9016 if (!haveShape
&& !haveSize
) {
9017 haveGradientLine
= IsLegacyGradientLine(ty
, id
);
9019 if (haveGradientLine
) {
9021 ParseVariant(cssGradient
->mAngle
, VARIANT_ANGLE
, nullptr);
9023 // if we got an angle, we might now have a comma, ending the gradient-line
9024 if (!haveAngle
|| !ExpectSymbol(',', true)) {
9025 if (!ParseBoxPositionValues(cssGradient
->mBgPos
, false)) {
9030 if (!ExpectSymbol(',', true) &&
9031 // if we didn't already get an angle, we might have one now,
9032 // otherwise it's an error
9034 !ParseVariant(cssGradient
->mAngle
, VARIANT_ANGLE
, nullptr) ||
9035 // now we better have a comma
9036 !ExpectSymbol(',', true))) {
9042 if (cssGradient
->mAngle
.GetUnit() != eCSSUnit_None
) {
9043 cssGradient
->mIsLegacySyntax
= true;
9047 // radial gradients might have a shape and size here for legacy syntax
9048 if (!haveShape
&& !haveSize
) {
9050 ParseVariant(cssGradient
->GetRadialShape(), VARIANT_KEYWORD
,
9051 nsCSSProps::kRadialGradientShapeKTable
);
9053 ParseVariant(cssGradient
->GetRadialSize(), VARIANT_KEYWORD
,
9054 nsCSSProps::kRadialGradientLegacySizeKTable
);
9056 // could be in either order
9059 ParseVariant(cssGradient
->GetRadialShape(), VARIANT_KEYWORD
,
9060 nsCSSProps::kRadialGradientShapeKTable
);
9064 if ((haveShape
|| haveSize
) && !ExpectSymbol(',', true)) {
9069 return ParseGradientColorStops(cssGradient
, aValue
);
9073 CSSParserImpl::IsLegacyGradientLine(const nsCSSTokenType
& aType
,
9074 const nsString
& aId
)
9076 // N.B. ParseBoxPositionValues is not guaranteed to put back
9077 // everything it scanned if it fails, so we must only call it
9078 // if there is no alternative to consuming a <box-position>.
9079 // ParseVariant, as used here, will either succeed and consume
9080 // a single token, or fail and consume none, so we can be more
9081 // cavalier about calling it.
9083 bool haveGradientLine
= false;
9085 case eCSSToken_Percentage
:
9086 case eCSSToken_Number
:
9087 case eCSSToken_Dimension
:
9088 haveGradientLine
= true;
9091 case eCSSToken_Function
:
9092 if (aId
.LowerCaseEqualsLiteral("calc") ||
9093 aId
.LowerCaseEqualsLiteral("-moz-calc")) {
9094 haveGradientLine
= true;
9099 case eCSSToken_Hash
:
9103 case eCSSToken_Ident
: {
9104 // This is only a gradient line if it's a box position keyword.
9105 nsCSSKeyword kw
= nsCSSKeywords::LookupKeyword(aId
);
9107 if (kw
!= eCSSKeyword_UNKNOWN
&&
9108 nsCSSProps::FindKeyword(kw
, nsCSSProps::kBackgroundPositionKTable
,
9110 haveGradientLine
= true;
9120 return haveGradientLine
;
9124 CSSParserImpl::ParseGradientColorStops(nsCSSValueGradient
* aGradient
,
9127 // At least two color stops are required
9128 if (!ParseColorStop(aGradient
) ||
9129 !ExpectSymbol(',', true) ||
9130 !ParseColorStop(aGradient
)) {
9135 // Additional color stops
9136 while (ExpectSymbol(',', true)) {
9137 if (!ParseColorStop(aGradient
)) {
9143 if (!ExpectSymbol(')', true)) {
9148 // Check if interpolation hints are in the correct location
9149 bool previousPointWasInterpolationHint
= true;
9150 for (size_t x
= 0; x
< aGradient
->mStops
.Length(); x
++) {
9151 bool isInterpolationHint
= aGradient
->mStops
[x
].mIsInterpolationHint
;
9152 if (isInterpolationHint
&& previousPointWasInterpolationHint
) {
9155 previousPointWasInterpolationHint
= isInterpolationHint
;
9158 if (previousPointWasInterpolationHint
) {
9162 aValue
.SetGradientValue(aGradient
);
9167 CSSParserImpl::ParseChoice(nsCSSValue aValues
[],
9168 const nsCSSProperty aPropIDs
[], int32_t aNumIDs
)
9171 nsAutoParseCompoundProperty
compound(this);
9174 for (loop
= 0; loop
< aNumIDs
; loop
++) {
9175 // Try each property parser in order
9176 int32_t hadFound
= found
;
9178 for (index
= 0; index
< aNumIDs
; index
++) {
9179 int32_t bit
= 1 << index
;
9180 if ((found
& bit
) == 0) {
9181 if (ParseSingleValueProperty(aValues
[index
], aPropIDs
[index
])) {
9183 // It's more efficient to break since it will reset |hadFound|
9184 // to |found|. Furthermore, ParseListStyle depends on our going
9185 // through the properties in order for each value..
9190 if (found
== hadFound
) { // found nothing new
9195 if (1 == found
) { // only first property
9196 if (eCSSUnit_Inherit
== aValues
[0].GetUnit()) { // one inherit, all inherit
9197 for (loop
= 1; loop
< aNumIDs
; loop
++) {
9198 aValues
[loop
].SetInheritValue();
9200 found
= ((1 << aNumIDs
) - 1);
9202 else if (eCSSUnit_Initial
== aValues
[0].GetUnit()) { // one initial, all initial
9203 for (loop
= 1; loop
< aNumIDs
; loop
++) {
9204 aValues
[loop
].SetInitialValue();
9206 found
= ((1 << aNumIDs
) - 1);
9208 else if (eCSSUnit_Unset
== aValues
[0].GetUnit()) { // one unset, all unset
9209 for (loop
= 1; loop
< aNumIDs
; loop
++) {
9210 aValues
[loop
].SetUnsetValue();
9212 found
= ((1 << aNumIDs
) - 1);
9215 else { // more than one value, verify no inherits, initials or unsets
9216 for (loop
= 0; loop
< aNumIDs
; loop
++) {
9217 if (eCSSUnit_Inherit
== aValues
[loop
].GetUnit()) {
9221 else if (eCSSUnit_Initial
== aValues
[loop
].GetUnit()) {
9225 else if (eCSSUnit_Unset
== aValues
[loop
].GetUnit()) {
9236 CSSParserImpl::AppendValue(nsCSSProperty aPropID
, const nsCSSValue
& aValue
)
9238 mTempData
.AddLonghandProperty(aPropID
, aValue
);
9242 * Parse a "box" property. Box properties have 1 to 4 values. When less
9243 * than 4 values are provided a standard mapping is used to replicate
9247 CSSParserImpl::ParseBoxProperties(const nsCSSProperty aPropIDs
[])
9249 // Get up to four values for the property
9252 NS_FOR_CSS_SIDES (index
) {
9253 if (! ParseSingleValueProperty(result
.*(nsCSSRect::sides
[index
]),
9263 if (1 < count
) { // verify no more than single inherit, initial or unset
9264 NS_FOR_CSS_SIDES (index
) {
9265 nsCSSUnit unit
= (result
.*(nsCSSRect::sides
[index
])).GetUnit();
9266 if (eCSSUnit_Inherit
== unit
||
9267 eCSSUnit_Initial
== unit
||
9268 eCSSUnit_Unset
== unit
) {
9274 // Provide missing values by replicating some of the values found
9276 case 1: // Make right == top
9277 result
.mRight
= result
.mTop
;
9278 case 2: // Make bottom == top
9279 result
.mBottom
= result
.mTop
;
9280 case 3: // Make left == right
9281 result
.mLeft
= result
.mRight
;
9284 NS_FOR_CSS_SIDES (index
) {
9285 AppendValue(aPropIDs
[index
], result
.*(nsCSSRect::sides
[index
]));
9290 // Similar to ParseBoxProperties, except there is only one property
9291 // with the result as its value, not four. Requires values be nonnegative.
9293 CSSParserImpl::ParseGroupedBoxProperty(int32_t aVariantMask
,
9294 /** outparam */ nsCSSValue
& aValue
)
9296 nsCSSRect
& result
= aValue
.SetRectValue();
9299 NS_FOR_CSS_SIDES (index
) {
9300 if (!ParseNonNegativeVariant(result
.*(nsCSSRect::sides
[index
]),
9301 aVariantMask
, nullptr)) {
9311 // Provide missing values by replicating some of the values found
9313 case 1: // Make right == top
9314 result
.mRight
= result
.mTop
;
9315 case 2: // Make bottom == top
9316 result
.mBottom
= result
.mTop
;
9317 case 3: // Make left == right
9318 result
.mLeft
= result
.mRight
;
9325 CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty
,
9326 int32_t aSourceType
)
9328 const nsCSSProperty
* subprops
= nsCSSProps::SubpropertyEntryFor(aProperty
);
9329 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
9330 "not box property with physical vs. logical cascading");
9332 if (!ParseSingleValueProperty(value
, subprops
[0])) {
9336 AppendValue(subprops
[0], value
);
9337 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
9338 AppendValue(subprops
[1], typeVal
);
9339 AppendValue(subprops
[2], typeVal
);
9344 CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID
)
9346 nsCSSValue dimenX
, dimenY
;
9347 // required first value
9348 if (! ParseNonNegativeVariant(dimenX
, VARIANT_HLP
| VARIANT_CALC
, nullptr))
9351 // optional second value (forbidden if first value is inherit/initial/unset)
9352 if (dimenX
.GetUnit() != eCSSUnit_Inherit
&&
9353 dimenX
.GetUnit() != eCSSUnit_Initial
&&
9354 dimenX
.GetUnit() != eCSSUnit_Unset
) {
9355 ParseNonNegativeVariant(dimenY
, VARIANT_LP
| VARIANT_CALC
, nullptr);
9358 if (dimenX
== dimenY
|| dimenY
.GetUnit() == eCSSUnit_Null
) {
9359 AppendValue(aPropID
, dimenX
);
9362 value
.SetPairValue(dimenX
, dimenY
);
9363 AppendValue(aPropID
, value
);
9369 CSSParserImpl::ParseBoxCornerRadiiInternals(nsCSSValue array
[])
9371 // Rectangles are used as scratch storage.
9372 // top => top-left, right => top-right,
9373 // bottom => bottom-right, left => bottom-left.
9374 nsCSSRect dimenX
, dimenY
;
9375 int32_t countX
= 0, countY
= 0;
9377 NS_FOR_CSS_SIDES (side
) {
9378 if (! ParseNonNegativeVariant(dimenX
.*nsCSSRect::sides
[side
],
9379 (side
> 0 ? 0 : VARIANT_INHERIT
) |
9380 VARIANT_LP
| VARIANT_CALC
,
9388 if (ExpectSymbol('/', true)) {
9389 NS_FOR_CSS_SIDES (side
) {
9390 if (! ParseNonNegativeVariant(dimenY
.*nsCSSRect::sides
[side
],
9391 VARIANT_LP
| VARIANT_CALC
, nullptr))
9399 // if 'initial', 'inherit' or 'unset' was used, it must be the only value
9400 if (countX
> 1 || countY
> 0) {
9401 nsCSSUnit unit
= dimenX
.mTop
.GetUnit();
9402 if (eCSSUnit_Inherit
== unit
||
9403 eCSSUnit_Initial
== unit
||
9404 eCSSUnit_Unset
== unit
)
9408 // if we have no Y-values, use the X-values
9414 // Provide missing values by replicating some of the values found
9416 case 1: dimenX
.mRight
= dimenX
.mTop
; // top-right same as top-left, and
9417 case 2: dimenX
.mBottom
= dimenX
.mTop
; // bottom-right same as top-left, and
9418 case 3: dimenX
.mLeft
= dimenX
.mRight
; // bottom-left same as top-right
9422 case 1: dimenY
.mRight
= dimenY
.mTop
; // top-right same as top-left, and
9423 case 2: dimenY
.mBottom
= dimenY
.mTop
; // bottom-right same as top-left, and
9424 case 3: dimenY
.mLeft
= dimenY
.mRight
; // bottom-left same as top-right
9427 NS_FOR_CSS_SIDES(side
) {
9428 nsCSSValue
& x
= dimenX
.*nsCSSRect::sides
[side
];
9429 nsCSSValue
& y
= dimenY
.*nsCSSRect::sides
[side
];
9435 pair
.SetPairValue(x
, y
);
9443 CSSParserImpl::ParseBoxCornerRadii(const nsCSSProperty aPropIDs
[])
9445 nsCSSValue value
[4];
9446 if (!ParseBoxCornerRadiiInternals(value
)) {
9450 NS_FOR_CSS_SIDES(side
) {
9451 AppendValue(aPropIDs
[side
], value
[side
]);
9456 // These must be in CSS order (top,right,bottom,left) for indexing to work
9457 static const nsCSSProperty kBorderStyleIDs
[] = {
9458 eCSSProperty_border_top_style
,
9459 eCSSProperty_border_right_style_value
,
9460 eCSSProperty_border_bottom_style
,
9461 eCSSProperty_border_left_style_value
9463 static const nsCSSProperty kBorderWidthIDs
[] = {
9464 eCSSProperty_border_top_width
,
9465 eCSSProperty_border_right_width_value
,
9466 eCSSProperty_border_bottom_width
,
9467 eCSSProperty_border_left_width_value
9469 static const nsCSSProperty kBorderColorIDs
[] = {
9470 eCSSProperty_border_top_color
,
9471 eCSSProperty_border_right_color_value
,
9472 eCSSProperty_border_bottom_color
,
9473 eCSSProperty_border_left_color_value
9475 static const nsCSSProperty kBorderRadiusIDs
[] = {
9476 eCSSProperty_border_top_left_radius
,
9477 eCSSProperty_border_top_right_radius
,
9478 eCSSProperty_border_bottom_right_radius
,
9479 eCSSProperty_border_bottom_left_radius
9481 static const nsCSSProperty kOutlineRadiusIDs
[] = {
9482 eCSSProperty__moz_outline_radius_topLeft
,
9483 eCSSProperty__moz_outline_radius_topRight
,
9484 eCSSProperty__moz_outline_radius_bottomRight
,
9485 eCSSProperty__moz_outline_radius_bottomLeft
9489 CSSParserImpl::SaveInputState(CSSParserInputState
& aState
)
9491 aState
.mToken
= mToken
;
9492 aState
.mHavePushBack
= mHavePushBack
;
9493 mScanner
->SavePosition(aState
.mPosition
);
9497 CSSParserImpl::RestoreSavedInputState(const CSSParserInputState
& aState
)
9499 mToken
= aState
.mToken
;
9500 mHavePushBack
= aState
.mHavePushBack
;
9501 mScanner
->RestoreSavedPosition(aState
.mPosition
);
9505 CSSParserImpl::ParseProperty(nsCSSProperty aPropID
)
9507 // Can't use AutoRestore<bool> because it's a bitfield.
9508 NS_ABORT_IF_FALSE(!mHashlessColorQuirk
,
9509 "hashless color quirk should not be set");
9510 NS_ABORT_IF_FALSE(!mUnitlessLengthQuirk
,
9511 "unitless length quirk should not be set");
9512 MOZ_ASSERT(aPropID
!= eCSSPropertyExtra_variable
);
9514 if (mNavQuirkMode
) {
9515 mHashlessColorQuirk
=
9516 nsCSSProps::PropHasFlags(aPropID
, CSS_PROPERTY_HASHLESS_COLOR_QUIRK
);
9517 mUnitlessLengthQuirk
=
9518 nsCSSProps::PropHasFlags(aPropID
, CSS_PROPERTY_UNITLESS_LENGTH_QUIRK
);
9521 // Save the current input state so that we can restore it later if we
9522 // have to re-parse the property value as a variable-reference-containing
9524 CSSParserInputState stateBeforeProperty
;
9525 SaveInputState(stateBeforeProperty
);
9526 mScanner
->ClearSeenVariableReference();
9528 NS_ASSERTION(aPropID
< eCSSProperty_COUNT
, "index out of range");
9529 bool allowVariables
= true;
9531 switch (nsCSSProps::PropertyParseType(aPropID
)) {
9532 case CSS_PROPERTY_PARSE_INACCESSIBLE
: {
9533 // The user can't use these
9534 REPORT_UNEXPECTED(PEInaccessibleProperty2
);
9535 allowVariables
= false;
9539 case CSS_PROPERTY_PARSE_FUNCTION
: {
9540 result
= ParsePropertyByFunction(aPropID
);
9543 case CSS_PROPERTY_PARSE_VALUE
: {
9546 if (ParseSingleValueProperty(value
, aPropID
)) {
9547 AppendValue(aPropID
, value
);
9550 // XXX Report errors?
9553 case CSS_PROPERTY_PARSE_VALUE_LIST
: {
9554 result
= ParseValueList(aPropID
);
9559 allowVariables
= false;
9560 NS_ABORT_IF_FALSE(false,
9561 "Property's flags field in nsCSSPropList.h is missing "
9562 "one of the CSS_PROPERTY_PARSE_* constants");
9568 // We need to call ExpectEndProperty() to decide whether to reparse
9569 // with variables. This is needed because the property parsing may
9570 // have stopped upon finding a variable (e.g., 'margin: 1px var(a)')
9571 // in a way that future variable substitutions will be valid, or
9572 // because it parsed everything that's possible but we still want to
9573 // act as though the property contains variables even though we know
9574 // the substitution will never work (e.g., for 'margin: 1px 2px 3px
9575 // 4px 5px var(a)').
9577 // It would be nice to find a better solution here
9578 // (and for the SkipUntilOneOf below), though, that doesn't depend
9579 // on using what we don't accept for doing parsing correctly.
9580 if (!ExpectEndProperty()) {
9585 bool seenVariable
= mScanner
->SeenVariableReference() ||
9586 (stateBeforeProperty
.mHavePushBack
&&
9587 stateBeforeProperty
.mToken
.mType
== eCSSToken_Function
&&
9588 stateBeforeProperty
.mToken
.mIdent
.LowerCaseEqualsLiteral("var"));
9589 bool parseAsTokenStream
;
9591 if (!result
&& allowVariables
) {
9592 parseAsTokenStream
= true;
9593 if (!seenVariable
) {
9594 // We might have stopped parsing the property before its end and before
9595 // finding a variable reference. Keep checking until the end of the
9597 CSSParserInputState stateAtError
;
9598 SaveInputState(stateAtError
);
9600 const char16_t stopChars
[] = { ';', '!', '}', ')', 0 };
9601 SkipUntilOneOf(stopChars
);
9603 parseAsTokenStream
= mScanner
->SeenVariableReference();
9605 if (!parseAsTokenStream
) {
9606 // If we parsed to the end of the propery and didn't find any variable
9607 // references, then the real position we want to report the error at
9608 // is |stateAtError|.
9609 RestoreSavedInputState(stateAtError
);
9613 parseAsTokenStream
= false;
9616 if (parseAsTokenStream
) {
9617 // Go back to the start of the property value and parse it to make sure
9618 // its variable references are syntactically valid and is otherwise
9620 RestoreSavedInputState(stateBeforeProperty
);
9622 if (!mInSupportsCondition
) {
9623 mScanner
->StartRecording();
9626 CSSVariableDeclarations::Type type
;
9628 nsString impliedCharacters
;
9630 if (ParseValueWithVariables(&type
, &dropBackslash
, impliedCharacters
,
9631 nullptr, nullptr)) {
9632 MOZ_ASSERT(type
== CSSVariableDeclarations::eTokenStream
,
9633 "a non-custom property reparsed since it contained variable "
9634 "references should not have been 'initial' or 'inherit'");
9636 nsString propertyValue
;
9638 if (!mInSupportsCondition
) {
9639 // If we are in an @supports condition, we don't need to store the
9640 // actual token stream on the nsCSSValue.
9641 mScanner
->StopRecording(propertyValue
);
9642 if (dropBackslash
) {
9643 MOZ_ASSERT(!propertyValue
.IsEmpty() &&
9644 propertyValue
[propertyValue
.Length() - 1] == '\\');
9645 propertyValue
.Truncate(propertyValue
.Length() - 1);
9647 propertyValue
.Append(impliedCharacters
);
9650 if (mHavePushBack
) {
9651 // If we came to the end of a property value that had a variable
9652 // reference and a token was pushed back, then it would have been
9653 // ended by '!', ')', ';', ']' or '}'. We should remove it from the
9654 // recorded property value.
9655 MOZ_ASSERT(mToken
.IsSymbol('!') ||
9656 mToken
.IsSymbol(')') ||
9657 mToken
.IsSymbol(';') ||
9658 mToken
.IsSymbol(']') ||
9659 mToken
.IsSymbol('}'));
9660 if (!mInSupportsCondition
) {
9661 MOZ_ASSERT(!propertyValue
.IsEmpty());
9662 MOZ_ASSERT(propertyValue
[propertyValue
.Length() - 1] ==
9664 propertyValue
.Truncate(propertyValue
.Length() - 1);
9668 if (!mInSupportsCondition
) {
9669 if (nsCSSProps::IsShorthand(aPropID
)) {
9670 // If this is a shorthand property, we store the token stream on each
9671 // of its corresponding longhand properties.
9672 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aPropID
) {
9673 nsCSSValueTokenStream
* tokenStream
= new nsCSSValueTokenStream
;
9674 tokenStream
->mPropertyID
= *p
;
9675 tokenStream
->mShorthandPropertyID
= aPropID
;
9676 tokenStream
->mTokenStream
= propertyValue
;
9677 tokenStream
->mBaseURI
= mBaseURI
;
9678 tokenStream
->mSheetURI
= mSheetURI
;
9679 tokenStream
->mSheetPrincipal
= mSheetPrincipal
;
9680 tokenStream
->mSheet
= mSheet
;
9681 tokenStream
->mLineNumber
= stateBeforeProperty
.mPosition
.LineNumber();
9682 tokenStream
->mLineOffset
= stateBeforeProperty
.mPosition
.LineOffset();
9683 value
.SetTokenStreamValue(tokenStream
);
9684 AppendValue(*p
, value
);
9687 nsCSSValueTokenStream
* tokenStream
= new nsCSSValueTokenStream
;
9688 tokenStream
->mPropertyID
= aPropID
;
9689 tokenStream
->mTokenStream
= propertyValue
;
9690 tokenStream
->mBaseURI
= mBaseURI
;
9691 tokenStream
->mSheetURI
= mSheetURI
;
9692 tokenStream
->mSheetPrincipal
= mSheetPrincipal
;
9693 tokenStream
->mSheet
= mSheet
;
9694 tokenStream
->mLineNumber
= stateBeforeProperty
.mPosition
.LineNumber();
9695 tokenStream
->mLineOffset
= stateBeforeProperty
.mPosition
.LineOffset();
9696 value
.SetTokenStreamValue(tokenStream
);
9697 AppendValue(aPropID
, value
);
9702 if (!mInSupportsCondition
) {
9703 mScanner
->StopRecording();
9708 if (mNavQuirkMode
) {
9709 mHashlessColorQuirk
= false;
9710 mUnitlessLengthQuirk
= false;
9717 CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID
)
9719 switch (aPropID
) { // handle shorthand or multiple properties
9720 case eCSSProperty_background
:
9721 return ParseBackground();
9722 case eCSSProperty_background_repeat
:
9723 return ParseBackgroundRepeat();
9724 case eCSSProperty_background_position
:
9725 return ParseBackgroundPosition();
9726 case eCSSProperty_background_size
:
9727 return ParseBackgroundSize();
9728 case eCSSProperty_border
:
9729 return ParseBorderSide(kBorderTopIDs
, true);
9730 case eCSSProperty_border_color
:
9731 return ParseBorderColor();
9732 case eCSSProperty_border_spacing
:
9733 return ParseBorderSpacing();
9734 case eCSSProperty_border_style
:
9735 return ParseBorderStyle();
9736 case eCSSProperty_border_bottom
:
9737 return ParseBorderSide(kBorderBottomIDs
, false);
9738 case eCSSProperty_border_end
:
9739 return ParseDirectionalBorderSide(kBorderEndIDs
,
9740 NS_BOXPROP_SOURCE_LOGICAL
);
9741 case eCSSProperty_border_left
:
9742 return ParseDirectionalBorderSide(kBorderLeftIDs
,
9743 NS_BOXPROP_SOURCE_PHYSICAL
);
9744 case eCSSProperty_border_right
:
9745 return ParseDirectionalBorderSide(kBorderRightIDs
,
9746 NS_BOXPROP_SOURCE_PHYSICAL
);
9747 case eCSSProperty_border_start
:
9748 return ParseDirectionalBorderSide(kBorderStartIDs
,
9749 NS_BOXPROP_SOURCE_LOGICAL
);
9750 case eCSSProperty_border_top
:
9751 return ParseBorderSide(kBorderTopIDs
, false);
9752 case eCSSProperty_border_bottom_colors
:
9753 case eCSSProperty_border_left_colors
:
9754 case eCSSProperty_border_right_colors
:
9755 case eCSSProperty_border_top_colors
:
9756 return ParseBorderColors(aPropID
);
9757 case eCSSProperty_border_image_slice
:
9758 return ParseBorderImageSlice(true, nullptr);
9759 case eCSSProperty_border_image_width
:
9760 return ParseBorderImageWidth(true);
9761 case eCSSProperty_border_image_outset
:
9762 return ParseBorderImageOutset(true);
9763 case eCSSProperty_border_image_repeat
:
9764 return ParseBorderImageRepeat(true);
9765 case eCSSProperty_border_image
:
9766 return ParseBorderImage();
9767 case eCSSProperty_border_width
:
9768 return ParseBorderWidth();
9769 case eCSSProperty_border_end_color
:
9770 return ParseDirectionalBoxProperty(eCSSProperty_border_end_color
,
9771 NS_BOXPROP_SOURCE_LOGICAL
);
9772 case eCSSProperty_border_left_color
:
9773 return ParseDirectionalBoxProperty(eCSSProperty_border_left_color
,
9774 NS_BOXPROP_SOURCE_PHYSICAL
);
9775 case eCSSProperty_border_right_color
:
9776 return ParseDirectionalBoxProperty(eCSSProperty_border_right_color
,
9777 NS_BOXPROP_SOURCE_PHYSICAL
);
9778 case eCSSProperty_border_start_color
:
9779 return ParseDirectionalBoxProperty(eCSSProperty_border_start_color
,
9780 NS_BOXPROP_SOURCE_LOGICAL
);
9781 case eCSSProperty_border_end_width
:
9782 return ParseDirectionalBoxProperty(eCSSProperty_border_end_width
,
9783 NS_BOXPROP_SOURCE_LOGICAL
);
9784 case eCSSProperty_border_left_width
:
9785 return ParseDirectionalBoxProperty(eCSSProperty_border_left_width
,
9786 NS_BOXPROP_SOURCE_PHYSICAL
);
9787 case eCSSProperty_border_right_width
:
9788 return ParseDirectionalBoxProperty(eCSSProperty_border_right_width
,
9789 NS_BOXPROP_SOURCE_PHYSICAL
);
9790 case eCSSProperty_border_start_width
:
9791 return ParseDirectionalBoxProperty(eCSSProperty_border_start_width
,
9792 NS_BOXPROP_SOURCE_LOGICAL
);
9793 case eCSSProperty_border_end_style
:
9794 return ParseDirectionalBoxProperty(eCSSProperty_border_end_style
,
9795 NS_BOXPROP_SOURCE_LOGICAL
);
9796 case eCSSProperty_border_left_style
:
9797 return ParseDirectionalBoxProperty(eCSSProperty_border_left_style
,
9798 NS_BOXPROP_SOURCE_PHYSICAL
);
9799 case eCSSProperty_border_right_style
:
9800 return ParseDirectionalBoxProperty(eCSSProperty_border_right_style
,
9801 NS_BOXPROP_SOURCE_PHYSICAL
);
9802 case eCSSProperty_border_start_style
:
9803 return ParseDirectionalBoxProperty(eCSSProperty_border_start_style
,
9804 NS_BOXPROP_SOURCE_LOGICAL
);
9805 case eCSSProperty_border_radius
:
9806 return ParseBoxCornerRadii(kBorderRadiusIDs
);
9807 case eCSSProperty__moz_outline_radius
:
9808 return ParseBoxCornerRadii(kOutlineRadiusIDs
);
9810 case eCSSProperty_border_top_left_radius
:
9811 case eCSSProperty_border_top_right_radius
:
9812 case eCSSProperty_border_bottom_right_radius
:
9813 case eCSSProperty_border_bottom_left_radius
:
9814 case eCSSProperty__moz_outline_radius_topLeft
:
9815 case eCSSProperty__moz_outline_radius_topRight
:
9816 case eCSSProperty__moz_outline_radius_bottomRight
:
9817 case eCSSProperty__moz_outline_radius_bottomLeft
:
9818 return ParseBoxCornerRadius(aPropID
);
9820 case eCSSProperty_box_shadow
:
9821 case eCSSProperty_text_shadow
:
9822 return ParseShadowList(aPropID
);
9824 case eCSSProperty_clip
:
9825 return ParseRect(eCSSProperty_clip
);
9826 case eCSSProperty__moz_columns
:
9827 return ParseColumns();
9828 case eCSSProperty__moz_column_rule
:
9829 return ParseBorderSide(kColumnRuleIDs
, false);
9830 case eCSSProperty_content
:
9831 return ParseContent();
9832 case eCSSProperty_counter_increment
:
9833 case eCSSProperty_counter_reset
:
9834 return ParseCounterData(aPropID
);
9835 case eCSSProperty_cursor
:
9836 return ParseCursor();
9837 case eCSSProperty_filter
:
9838 return ParseFilter();
9839 case eCSSProperty_flex
:
9841 case eCSSProperty_flex_flow
:
9842 return ParseFlexFlow();
9843 case eCSSProperty_font
:
9845 case eCSSProperty_font_variant
:
9846 return ParseFontVariant();
9847 case eCSSProperty_grid_auto_flow
:
9848 return ParseGridAutoFlow();
9849 case eCSSProperty_grid_auto_columns
:
9850 case eCSSProperty_grid_auto_rows
:
9851 return ParseGridAutoColumnsRows(aPropID
);
9852 case eCSSProperty_grid_template_areas
:
9853 return ParseGridTemplateAreas();
9854 case eCSSProperty_grid_template_columns
:
9855 case eCSSProperty_grid_template_rows
:
9856 return ParseGridTemplateColumnsRows(aPropID
);
9857 case eCSSProperty_grid_template
:
9858 return ParseGridTemplate();
9859 case eCSSProperty_grid
:
9861 case eCSSProperty_grid_column_start
:
9862 case eCSSProperty_grid_column_end
:
9863 case eCSSProperty_grid_row_start
:
9864 case eCSSProperty_grid_row_end
:
9865 return ParseGridColumnRowStartEnd(aPropID
);
9866 case eCSSProperty_grid_column
:
9867 return ParseGridColumnRow(eCSSProperty_grid_column_start
,
9868 eCSSProperty_grid_column_end
);
9869 case eCSSProperty_grid_row
:
9870 return ParseGridColumnRow(eCSSProperty_grid_row_start
,
9871 eCSSProperty_grid_row_end
);
9872 case eCSSProperty_grid_area
:
9873 return ParseGridArea();
9874 case eCSSProperty_image_region
:
9875 return ParseRect(eCSSProperty_image_region
);
9876 case eCSSProperty_list_style
:
9877 return ParseListStyle();
9878 case eCSSProperty_margin
:
9879 return ParseMargin();
9880 case eCSSProperty_margin_end
:
9881 return ParseDirectionalBoxProperty(eCSSProperty_margin_end
,
9882 NS_BOXPROP_SOURCE_LOGICAL
);
9883 case eCSSProperty_margin_left
:
9884 return ParseDirectionalBoxProperty(eCSSProperty_margin_left
,
9885 NS_BOXPROP_SOURCE_PHYSICAL
);
9886 case eCSSProperty_margin_right
:
9887 return ParseDirectionalBoxProperty(eCSSProperty_margin_right
,
9888 NS_BOXPROP_SOURCE_PHYSICAL
);
9889 case eCSSProperty_margin_start
:
9890 return ParseDirectionalBoxProperty(eCSSProperty_margin_start
,
9891 NS_BOXPROP_SOURCE_LOGICAL
);
9892 case eCSSProperty_object_position
:
9893 return ParseObjectPosition();
9894 case eCSSProperty_outline
:
9895 return ParseOutline();
9896 case eCSSProperty_overflow
:
9897 return ParseOverflow();
9898 case eCSSProperty_padding
:
9899 return ParsePadding();
9900 case eCSSProperty_padding_end
:
9901 return ParseDirectionalBoxProperty(eCSSProperty_padding_end
,
9902 NS_BOXPROP_SOURCE_LOGICAL
);
9903 case eCSSProperty_padding_left
:
9904 return ParseDirectionalBoxProperty(eCSSProperty_padding_left
,
9905 NS_BOXPROP_SOURCE_PHYSICAL
);
9906 case eCSSProperty_padding_right
:
9907 return ParseDirectionalBoxProperty(eCSSProperty_padding_right
,
9908 NS_BOXPROP_SOURCE_PHYSICAL
);
9909 case eCSSProperty_padding_start
:
9910 return ParseDirectionalBoxProperty(eCSSProperty_padding_start
,
9911 NS_BOXPROP_SOURCE_LOGICAL
);
9912 case eCSSProperty_quotes
:
9913 return ParseQuotes();
9914 case eCSSProperty_size
:
9916 case eCSSProperty_text_decoration
:
9917 return ParseTextDecoration();
9918 case eCSSProperty_will_change
:
9919 return ParseWillChange();
9920 case eCSSProperty_transform
:
9921 return ParseTransform(false);
9922 case eCSSProperty__moz_transform
:
9923 return ParseTransform(true);
9924 case eCSSProperty_transform_origin
:
9925 return ParseTransformOrigin(false);
9926 case eCSSProperty_perspective_origin
:
9927 return ParseTransformOrigin(true);
9928 case eCSSProperty_transition
:
9929 return ParseTransition();
9930 case eCSSProperty_animation
:
9931 return ParseAnimation();
9932 case eCSSProperty_transition_property
:
9933 return ParseTransitionProperty();
9934 case eCSSProperty_fill
:
9935 case eCSSProperty_stroke
:
9936 return ParsePaint(aPropID
);
9937 case eCSSProperty_stroke_dasharray
:
9938 return ParseDasharray();
9939 case eCSSProperty_marker
:
9940 return ParseMarker();
9941 case eCSSProperty_paint_order
:
9942 return ParsePaintOrder();
9943 case eCSSProperty_clip_path
:
9944 return ParseClipPath();
9945 case eCSSProperty_all
:
9948 NS_ABORT_IF_FALSE(false, "should not be called");
9953 // Bits used in determining which background position info we have
9954 #define BG_CENTER NS_STYLE_BG_POSITION_CENTER
9955 #define BG_TOP NS_STYLE_BG_POSITION_TOP
9956 #define BG_BOTTOM NS_STYLE_BG_POSITION_BOTTOM
9957 #define BG_LEFT NS_STYLE_BG_POSITION_LEFT
9958 #define BG_RIGHT NS_STYLE_BG_POSITION_RIGHT
9959 #define BG_CTB (BG_CENTER | BG_TOP | BG_BOTTOM)
9960 #define BG_TB (BG_TOP | BG_BOTTOM)
9961 #define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT)
9962 #define BG_LR (BG_LEFT | BG_RIGHT)
9965 CSSParserImpl::ParseSingleValueProperty(nsCSSValue
& aValue
,
9966 nsCSSProperty aPropID
)
9968 if (aPropID
== eCSSPropertyExtra_x_none_value
) {
9969 return ParseVariant(aValue
, VARIANT_NONE
| VARIANT_INHERIT
, nullptr);
9972 if (aPropID
== eCSSPropertyExtra_x_auto_value
) {
9973 return ParseVariant(aValue
, VARIANT_AUTO
| VARIANT_INHERIT
, nullptr);
9976 if (aPropID
< 0 || aPropID
>= eCSSProperty_COUNT_no_shorthands
) {
9977 NS_ABORT_IF_FALSE(false, "not a single value property");
9981 if (nsCSSProps::PropHasFlags(aPropID
, CSS_PROPERTY_VALUE_PARSER_FUNCTION
)) {
9983 case eCSSProperty_font_family
:
9984 return ParseFamily(aValue
);
9985 case eCSSProperty_font_synthesis
:
9986 return ParseFontSynthesis(aValue
);
9987 case eCSSProperty_font_variant_alternates
:
9988 return ParseFontVariantAlternates(aValue
);
9989 case eCSSProperty_font_variant_east_asian
:
9990 return ParseFontVariantEastAsian(aValue
);
9991 case eCSSProperty_font_variant_ligatures
:
9992 return ParseFontVariantLigatures(aValue
);
9993 case eCSSProperty_font_variant_numeric
:
9994 return ParseFontVariantNumeric(aValue
);
9995 case eCSSProperty_font_feature_settings
:
9996 return ParseFontFeatureSettings(aValue
);
9997 case eCSSProperty_font_weight
:
9998 return ParseFontWeight(aValue
);
9999 case eCSSProperty_image_orientation
:
10000 return ParseImageOrientation(aValue
);
10001 case eCSSProperty_list_style_type
:
10002 return ParseListStyleType(aValue
);
10003 case eCSSProperty_marks
:
10004 return ParseMarks(aValue
);
10005 case eCSSProperty_ruby_position
:
10006 return ParseRubyPosition(aValue
);
10007 case eCSSProperty_text_align
:
10008 return ParseTextAlign(aValue
);
10009 case eCSSProperty_text_align_last
:
10010 return ParseTextAlignLast(aValue
);
10011 case eCSSProperty_text_decoration_line
:
10012 return ParseTextDecorationLine(aValue
);
10013 case eCSSProperty_text_combine_upright
:
10014 return ParseTextCombineUpright(aValue
);
10015 case eCSSProperty_text_overflow
:
10016 return ParseTextOverflow(aValue
);
10017 case eCSSProperty_touch_action
:
10018 return ParseTouchAction(aValue
);
10020 NS_ABORT_IF_FALSE(false, "should not reach here");
10025 uint32_t variant
= nsCSSProps::ParserVariant(aPropID
);
10026 if (variant
== 0) {
10027 NS_ABORT_IF_FALSE(false, "not a single value property");
10031 // We only allow 'script-level' when unsafe rules are enabled, because
10032 // otherwise it could interfere with rulenode optimizations if used in
10033 // a non-MathML-enabled document. We also only allow math-display when
10034 // unsafe rules are enabled.
10035 if (!mUnsafeRulesEnabled
&&
10036 (aPropID
== eCSSProperty_script_level
||
10037 aPropID
== eCSSProperty_math_display
))
10040 const KTableValue
*kwtable
= nsCSSProps::kKeywordTableTable
[aPropID
];
10041 switch (nsCSSProps::ValueRestrictions(aPropID
)) {
10043 NS_ABORT_IF_FALSE(false, "should not be reached");
10045 return ParseVariant(aValue
, variant
, kwtable
);
10046 case CSS_PROPERTY_VALUE_NONNEGATIVE
:
10047 return ParseNonNegativeVariant(aValue
, variant
, kwtable
);
10048 case CSS_PROPERTY_VALUE_AT_LEAST_ONE
:
10049 return ParseOneOrLargerVariant(aValue
, variant
, kwtable
);
10053 // font-descriptor: descriptor ':' value ';'
10054 // caller has advanced mToken to point at the descriptor
10056 CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID
,
10057 nsCSSValue
& aValue
)
10060 // These four are similar to the properties of the same name,
10061 // possibly with more restrictions on the values they can take.
10062 case eCSSFontDesc_Family
: {
10064 if (!ParseFamily(value
) ||
10065 value
.GetUnit() != eCSSUnit_FontFamilyList
)
10068 // name can only be a single, non-generic name
10069 const FontFamilyList
* f
= value
.GetFontFamilyListValue();
10070 const nsTArray
<FontFamilyName
>& fontlist
= f
->GetFontlist();
10072 if (fontlist
.Length() != 1 || !fontlist
[0].IsNamed()) {
10076 aValue
.SetStringValue(fontlist
[0].mName
, eCSSUnit_String
);
10080 case eCSSFontDesc_Style
:
10081 // property is VARIANT_HMK|VARIANT_SYSFONT
10082 return ParseVariant(aValue
, VARIANT_KEYWORD
| VARIANT_NORMAL
,
10083 nsCSSProps::kFontStyleKTable
);
10085 case eCSSFontDesc_Weight
:
10086 return (ParseFontWeight(aValue
) &&
10087 aValue
.GetUnit() != eCSSUnit_Inherit
&&
10088 aValue
.GetUnit() != eCSSUnit_Initial
&&
10089 aValue
.GetUnit() != eCSSUnit_Unset
&&
10090 (aValue
.GetUnit() != eCSSUnit_Enumerated
||
10091 (aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER
&&
10092 aValue
.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER
)));
10094 case eCSSFontDesc_Stretch
:
10095 // property is VARIANT_HK|VARIANT_SYSFONT
10096 return ParseVariant(aValue
, VARIANT_KEYWORD
,
10097 nsCSSProps::kFontStretchKTable
);
10099 // These two are unique to @font-face and have their own special grammar.
10100 case eCSSFontDesc_Src
:
10101 return ParseFontSrc(aValue
);
10103 case eCSSFontDesc_UnicodeRange
:
10104 return ParseFontRanges(aValue
);
10106 case eCSSFontDesc_FontFeatureSettings
:
10107 return ParseFontFeatureSettings(aValue
);
10109 case eCSSFontDesc_FontLanguageOverride
:
10110 return ParseVariant(aValue
, VARIANT_NORMAL
| VARIANT_STRING
, nullptr);
10112 case eCSSFontDesc_UNKNOWN
:
10113 case eCSSFontDesc_COUNT
:
10114 NS_NOTREACHED("bad nsCSSFontDesc code");
10116 // explicitly do NOT have a default case to let the compiler
10117 // help find missing descriptors
10122 CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty
*aSourceProperties
)
10124 nsCSSValue
physical(NS_BOXPROP_SOURCE_PHYSICAL
, eCSSUnit_Enumerated
);
10125 for (const nsCSSProperty
*prop
= aSourceProperties
;
10126 *prop
!= eCSSProperty_UNKNOWN
; ++prop
) {
10127 AppendValue(*prop
, physical
);
10132 BoxPositionMaskToCSSValue(int32_t aMask
, bool isX
)
10134 int32_t val
= NS_STYLE_BG_POSITION_CENTER
;
10136 if (aMask
& BG_LEFT
) {
10137 val
= NS_STYLE_BG_POSITION_LEFT
;
10139 else if (aMask
& BG_RIGHT
) {
10140 val
= NS_STYLE_BG_POSITION_RIGHT
;
10144 if (aMask
& BG_TOP
) {
10145 val
= NS_STYLE_BG_POSITION_TOP
;
10147 else if (aMask
& BG_BOTTOM
) {
10148 val
= NS_STYLE_BG_POSITION_BOTTOM
;
10152 return nsCSSValue(val
, eCSSUnit_Enumerated
);
10156 CSSParserImpl::ParseBackground()
10158 nsAutoParseCompoundProperty
compound(this);
10160 // background-color can only be set once, so it's not a list.
10163 // Check first for inherit/initial/unset.
10164 if (ParseVariant(color
, VARIANT_INHERIT
, nullptr)) {
10166 for (const nsCSSProperty
* subprops
=
10167 nsCSSProps::SubpropertyEntryFor(eCSSProperty_background
);
10168 *subprops
!= eCSSProperty_UNKNOWN
; ++subprops
) {
10169 AppendValue(*subprops
, color
);
10174 nsCSSValue image
, repeat
, attachment
, clip
, origin
, position
, size
;
10175 BackgroundParseState
state(color
, image
.SetListValue(),
10176 repeat
.SetPairListValue(),
10177 attachment
.SetListValue(), clip
.SetListValue(),
10178 origin
.SetListValue(), position
.SetListValue(),
10179 size
.SetPairListValue());
10182 if (!ParseBackgroundItem(state
)) {
10185 // If we saw a color, this must be the last item.
10186 if (color
.GetUnit() != eCSSUnit_Null
) {
10189 // If there's a comma, expect another item.
10190 if (!ExpectSymbol(',', true)) {
10193 // Chain another entry on all the lists.
10194 state
.mImage
->mNext
= new nsCSSValueList
;
10195 state
.mImage
= state
.mImage
->mNext
;
10196 state
.mRepeat
->mNext
= new nsCSSValuePairList
;
10197 state
.mRepeat
= state
.mRepeat
->mNext
;
10198 state
.mAttachment
->mNext
= new nsCSSValueList
;
10199 state
.mAttachment
= state
.mAttachment
->mNext
;
10200 state
.mClip
->mNext
= new nsCSSValueList
;
10201 state
.mClip
= state
.mClip
->mNext
;
10202 state
.mOrigin
->mNext
= new nsCSSValueList
;
10203 state
.mOrigin
= state
.mOrigin
->mNext
;
10204 state
.mPosition
->mNext
= new nsCSSValueList
;
10205 state
.mPosition
= state
.mPosition
->mNext
;
10206 state
.mSize
->mNext
= new nsCSSValuePairList
;
10207 state
.mSize
= state
.mSize
->mNext
;
10210 // If we get to this point without seeing a color, provide a default.
10211 if (color
.GetUnit() == eCSSUnit_Null
) {
10212 color
.SetIntegerColorValue(NS_RGBA(0,0,0,0), eCSSUnit_RGBAColor
);
10215 AppendValue(eCSSProperty_background_image
, image
);
10216 AppendValue(eCSSProperty_background_repeat
, repeat
);
10217 AppendValue(eCSSProperty_background_attachment
, attachment
);
10218 AppendValue(eCSSProperty_background_clip
, clip
);
10219 AppendValue(eCSSProperty_background_origin
, origin
);
10220 AppendValue(eCSSProperty_background_position
, position
);
10221 AppendValue(eCSSProperty_background_size
, size
);
10222 AppendValue(eCSSProperty_background_color
, color
);
10226 // Parse one item of the background shorthand property.
10228 CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState
& aState
)
10231 // Fill in the values that the shorthand will set if we don't find
10233 aState
.mImage
->mValue
.SetNoneValue();
10234 aState
.mRepeat
->mXValue
.SetIntValue(NS_STYLE_BG_REPEAT_REPEAT
,
10235 eCSSUnit_Enumerated
);
10236 aState
.mRepeat
->mYValue
.Reset();
10237 aState
.mAttachment
->mValue
.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL
,
10238 eCSSUnit_Enumerated
);
10239 aState
.mClip
->mValue
.SetIntValue(NS_STYLE_BG_CLIP_BORDER
,
10240 eCSSUnit_Enumerated
);
10241 aState
.mOrigin
->mValue
.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING
,
10242 eCSSUnit_Enumerated
);
10243 nsRefPtr
<nsCSSValue::Array
> positionArr
= nsCSSValue::Array::Create(4);
10244 aState
.mPosition
->mValue
.SetArrayValue(positionArr
, eCSSUnit_Array
);
10245 positionArr
->Item(1).SetPercentValue(0.0f
);
10246 positionArr
->Item(3).SetPercentValue(0.0f
);
10247 aState
.mSize
->mXValue
.SetAutoValue();
10248 aState
.mSize
->mYValue
.SetAutoValue();
10250 bool haveColor
= false,
10252 haveRepeat
= false,
10253 haveAttach
= false,
10254 havePositionAndSize
= false,
10255 haveOrigin
= false,
10256 haveSomething
= false;
10258 while (GetToken(true)) {
10259 nsCSSTokenType tt
= mToken
.mType
;
10260 UngetToken(); // ...but we'll still cheat and use mToken
10261 if (tt
== eCSSToken_Symbol
) {
10262 // ExpectEndProperty only looks for symbols, and nothing else will
10267 if (tt
== eCSSToken_Ident
) {
10268 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
10270 if (keyword
== eCSSKeyword_inherit
||
10271 keyword
== eCSSKeyword_initial
||
10272 keyword
== eCSSKeyword_unset
) {
10274 } else if (keyword
== eCSSKeyword_none
) {
10278 if (!ParseSingleValueProperty(aState
.mImage
->mValue
,
10279 eCSSProperty_background_image
)) {
10280 NS_NOTREACHED("should be able to parse");
10283 } else if (nsCSSProps::FindKeyword(keyword
,
10284 nsCSSProps::kBackgroundAttachmentKTable
, dummy
)) {
10288 if (!ParseSingleValueProperty(aState
.mAttachment
->mValue
,
10289 eCSSProperty_background_attachment
)) {
10290 NS_NOTREACHED("should be able to parse");
10293 } else if (nsCSSProps::FindKeyword(keyword
,
10294 nsCSSProps::kBackgroundRepeatKTable
, dummy
)) {
10298 nsCSSValuePair scratch
;
10299 if (!ParseBackgroundRepeatValues(scratch
)) {
10300 NS_NOTREACHED("should be able to parse");
10303 aState
.mRepeat
->mXValue
= scratch
.mXValue
;
10304 aState
.mRepeat
->mYValue
= scratch
.mYValue
;
10305 } else if (nsCSSProps::FindKeyword(keyword
,
10306 nsCSSProps::kBackgroundPositionKTable
, dummy
)) {
10307 if (havePositionAndSize
)
10309 havePositionAndSize
= true;
10310 if (!ParsePositionValue(aState
.mPosition
->mValue
)) {
10313 if (ExpectSymbol('/', true)) {
10314 nsCSSValuePair scratch
;
10315 if (!ParseBackgroundSizeValues(scratch
)) {
10318 aState
.mSize
->mXValue
= scratch
.mXValue
;
10319 aState
.mSize
->mYValue
= scratch
.mYValue
;
10321 } else if (nsCSSProps::FindKeyword(keyword
,
10322 nsCSSProps::kBackgroundOriginKTable
, dummy
)) {
10326 if (!ParseSingleValueProperty(aState
.mOrigin
->mValue
,
10327 eCSSProperty_background_origin
)) {
10328 NS_NOTREACHED("should be able to parse");
10332 // The spec allows a second box value (for background-clip),
10333 // immediately following the first one (for background-origin).
10335 // 'background-clip' and 'background-origin' use the same keyword table
10336 MOZ_ASSERT(nsCSSProps::kKeywordTableTable
[
10337 eCSSProperty_background_origin
] ==
10338 nsCSSProps::kBackgroundOriginKTable
);
10339 MOZ_ASSERT(nsCSSProps::kKeywordTableTable
[
10340 eCSSProperty_background_clip
] ==
10341 nsCSSProps::kBackgroundOriginKTable
);
10342 static_assert(NS_STYLE_BG_CLIP_BORDER
==
10343 NS_STYLE_BG_ORIGIN_BORDER
&&
10344 NS_STYLE_BG_CLIP_PADDING
==
10345 NS_STYLE_BG_ORIGIN_PADDING
&&
10346 NS_STYLE_BG_CLIP_CONTENT
==
10347 NS_STYLE_BG_ORIGIN_CONTENT
,
10348 "bg-clip and bg-origin style constants must agree");
10350 if (!ParseSingleValueProperty(aState
.mClip
->mValue
,
10351 eCSSProperty_background_clip
)) {
10352 // When exactly one <box> value is set, it is used for both
10353 // 'background-origin' and 'background-clip'.
10354 // See assertions above showing these values are compatible.
10355 aState
.mClip
->mValue
= aState
.mOrigin
->mValue
;
10361 if (!ParseSingleValueProperty(aState
.mColor
,
10362 eCSSProperty_background_color
)) {
10366 } else if (tt
== eCSSToken_URL
||
10367 (tt
== eCSSToken_Function
&&
10368 (mToken
.mIdent
.LowerCaseEqualsLiteral("linear-gradient") ||
10369 mToken
.mIdent
.LowerCaseEqualsLiteral("radial-gradient") ||
10370 mToken
.mIdent
.LowerCaseEqualsLiteral("repeating-linear-gradient") ||
10371 mToken
.mIdent
.LowerCaseEqualsLiteral("repeating-radial-gradient") ||
10372 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-linear-gradient") ||
10373 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-radial-gradient") ||
10374 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") ||
10375 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") ||
10376 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-image-rect") ||
10377 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-element")))) {
10381 if (!ParseSingleValueProperty(aState
.mImage
->mValue
,
10382 eCSSProperty_background_image
)) {
10385 } else if (tt
== eCSSToken_Dimension
||
10386 tt
== eCSSToken_Number
||
10387 tt
== eCSSToken_Percentage
||
10388 (tt
== eCSSToken_Function
&&
10389 (mToken
.mIdent
.LowerCaseEqualsLiteral("calc") ||
10390 mToken
.mIdent
.LowerCaseEqualsLiteral("-moz-calc")))) {
10391 if (havePositionAndSize
)
10393 havePositionAndSize
= true;
10394 if (!ParsePositionValue(aState
.mPosition
->mValue
)) {
10397 if (ExpectSymbol('/', true)) {
10398 nsCSSValuePair scratch
;
10399 if (!ParseBackgroundSizeValues(scratch
)) {
10402 aState
.mSize
->mXValue
= scratch
.mXValue
;
10403 aState
.mSize
->mYValue
= scratch
.mYValue
;
10409 // Note: This parses 'inherit', 'initial' and 'unset', but
10410 // we've already checked for them, so it's ok.
10411 if (!ParseSingleValueProperty(aState
.mColor
,
10412 eCSSProperty_background_color
)) {
10416 haveSomething
= true;
10419 return haveSomething
;
10422 // This function is very similar to ParseBackgroundPosition and
10423 // ParseBackgroundSize.
10425 CSSParserImpl::ParseValueList(nsCSSProperty aPropID
)
10427 // aPropID is a single value prop-id
10429 // 'initial', 'inherit' and 'unset' stand alone, no list permitted.
10430 if (!ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
10431 nsCSSValueList
* item
= value
.SetListValue();
10433 if (!ParseSingleValueProperty(item
->mValue
, aPropID
)) {
10436 if (!ExpectSymbol(',', true)) {
10439 item
->mNext
= new nsCSSValueList
;
10440 item
= item
->mNext
;
10443 AppendValue(aPropID
, value
);
10448 CSSParserImpl::ParseBackgroundRepeat()
10451 // 'initial', 'inherit' and 'unset' stand alone, no list permitted.
10452 if (!ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
10453 nsCSSValuePair valuePair
;
10454 if (!ParseBackgroundRepeatValues(valuePair
)) {
10457 nsCSSValuePairList
* item
= value
.SetPairListValue();
10459 item
->mXValue
= valuePair
.mXValue
;
10460 item
->mYValue
= valuePair
.mYValue
;
10461 if (!ExpectSymbol(',', true)) {
10464 if (!ParseBackgroundRepeatValues(valuePair
)) {
10467 item
->mNext
= new nsCSSValuePairList
;
10468 item
= item
->mNext
;
10472 AppendValue(eCSSProperty_background_repeat
, value
);
10477 CSSParserImpl::ParseBackgroundRepeatValues(nsCSSValuePair
& aValue
)
10479 nsCSSValue
& xValue
= aValue
.mXValue
;
10480 nsCSSValue
& yValue
= aValue
.mYValue
;
10482 if (ParseEnum(xValue
, nsCSSProps::kBackgroundRepeatKTable
)) {
10483 int32_t value
= xValue
.GetIntValue();
10484 // For single values set yValue as eCSSUnit_Null.
10485 if (value
== NS_STYLE_BG_REPEAT_REPEAT_X
||
10486 value
== NS_STYLE_BG_REPEAT_REPEAT_Y
||
10487 !ParseEnum(yValue
, nsCSSProps::kBackgroundRepeatPartKTable
)) {
10488 // the caller will fail cases like "repeat-x no-repeat"
10489 // by expecting a list separator or an end property.
10498 // This function is very similar to ParseBackgroundList and ParseBackgroundSize.
10500 CSSParserImpl::ParseBackgroundPosition()
10503 // 'initial', 'inherit' and 'unset' stand alone, no list permitted.
10504 if (!ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
10505 nsCSSValue itemValue
;
10506 if (!ParsePositionValue(itemValue
)) {
10509 nsCSSValueList
* item
= value
.SetListValue();
10511 item
->mValue
= itemValue
;
10512 if (!ExpectSymbol(',', true)) {
10515 if (!ParsePositionValue(itemValue
)) {
10518 item
->mNext
= new nsCSSValueList
;
10519 item
= item
->mNext
;
10522 AppendValue(eCSSProperty_background_position
, value
);
10527 * BoxPositionMaskToCSSValue and ParseBoxPositionValues are used
10528 * for parsing the CSS 2.1 background-position syntax (which has at
10529 * most two values). (Compare to the css3-background syntax which
10530 * takes up to four values.) Some current CSS specifications that
10531 * use background-position-like syntax still use this old syntax.
10533 * Parses two values that correspond to positions in a box. These can be
10534 * values corresponding to percentages of the box, raw offsets, or keywords
10535 * like "top," "left center," etc.
10537 * @param aOut The nsCSSValuePair in which to place the result.
10538 * @param aAcceptsInherit If true, 'inherit', 'initial' and 'unset' are
10540 * @param aAllowExplicitCenter If true, 'center' is a legal value
10541 * @return Whether or not the operation succeeded.
10543 bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair
&aOut
,
10544 bool aAcceptsInherit
,
10545 bool aAllowExplicitCenter
)
10547 // First try a percentage or a length value
10548 nsCSSValue
&xValue
= aOut
.mXValue
,
10549 &yValue
= aOut
.mYValue
;
10550 int32_t variantMask
=
10551 (aAcceptsInherit
? VARIANT_INHERIT
: 0) | VARIANT_LP
| VARIANT_CALC
;
10552 if (ParseVariant(xValue
, variantMask
, nullptr)) {
10553 if (eCSSUnit_Inherit
== xValue
.GetUnit() ||
10554 eCSSUnit_Initial
== xValue
.GetUnit() ||
10555 eCSSUnit_Unset
== xValue
.GetUnit()) { // both are inherit, initial or unset
10559 // We have one percentage/length/calc. Get the optional second
10560 // percentage/length/calc/keyword.
10561 if (ParseVariant(yValue
, VARIANT_LP
| VARIANT_CALC
, nullptr)) {
10562 // We have two numbers
10566 if (ParseEnum(yValue
, nsCSSProps::kBackgroundPositionKTable
)) {
10567 int32_t yVal
= yValue
.GetIntValue();
10568 if (!(yVal
& BG_CTB
)) {
10569 // The second keyword can only be 'center', 'top', or 'bottom'
10572 yValue
= BoxPositionMaskToCSSValue(yVal
, false);
10576 // If only one percentage or length value is given, it sets the
10577 // horizontal position only, and the vertical position will be 50%.
10578 yValue
.SetPercentValue(0.5f
);
10582 // Now try keywords. We do this manually to allow for the first
10583 // appearance of "center" to apply to the either the x or y
10584 // position (it's ambiguous so we have to disambiguate). Each
10585 // allowed keyword value is assigned it's own bit. We don't allow
10586 // any duplicate keywords other than center. We try to get two
10587 // keywords but it's okay if there is only one.
10589 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
10590 int32_t bit
= xValue
.GetIntValue();
10592 if (ParseEnum(xValue
, nsCSSProps::kBackgroundPositionKTable
)) {
10593 bit
= xValue
.GetIntValue();
10594 if (mask
& (bit
& ~BG_CENTER
)) {
10595 // Only the 'center' keyword can be duplicated.
10601 // Only one keyword. See if we have a length, percentage, or calc.
10602 if (ParseVariant(yValue
, VARIANT_LP
| VARIANT_CALC
, nullptr)) {
10603 if (!(mask
& BG_CLR
)) {
10604 // The first keyword can only be 'center', 'left', or 'right'
10608 xValue
= BoxPositionMaskToCSSValue(mask
, true);
10614 // Check for bad input. Bad input consists of no matching keywords,
10615 // or pairs of x keywords or pairs of y keywords.
10616 if ((mask
== 0) || (mask
== (BG_TOP
| BG_BOTTOM
)) ||
10617 (mask
== (BG_LEFT
| BG_RIGHT
)) ||
10618 (!aAllowExplicitCenter
&& (mask
& BG_CENTER
))) {
10622 // Create style values
10623 xValue
= BoxPositionMaskToCSSValue(mask
, true);
10624 yValue
= BoxPositionMaskToCSSValue(mask
, false);
10628 // Parses a CSS <position> value, for e.g. the 'background-position' property.
10629 // Spec reference: http://www.w3.org/TR/css3-background/#ltpositiongt
10631 CSSParserImpl::ParsePositionValue(nsCSSValue
& aOut
)
10633 nsRefPtr
<nsCSSValue::Array
> value
= nsCSSValue::Array::Create(4);
10634 aOut
.SetArrayValue(value
, eCSSUnit_Array
);
10636 // The following clarifies organisation of the array.
10637 nsCSSValue
&xEdge
= value
->Item(0),
10638 &xOffset
= value
->Item(1),
10639 &yEdge
= value
->Item(2),
10640 &yOffset
= value
->Item(3);
10642 // Parse all the values into the array.
10643 uint32_t valueCount
= 0;
10644 for (int32_t i
= 0; i
< 4; i
++) {
10645 if (!ParseVariant(value
->Item(i
), VARIANT_LPCALC
| VARIANT_KEYWORD
,
10646 nsCSSProps::kBackgroundPositionKTable
)) {
10652 switch (valueCount
) {
10654 // "If three or four values are given, then each <percentage> or <length>
10655 // represents an offset and must be preceded by a keyword, which specifies
10656 // from which edge the offset is given."
10657 if (eCSSUnit_Enumerated
!= xEdge
.GetUnit() ||
10658 BG_CENTER
== xEdge
.GetIntValue() ||
10659 eCSSUnit_Enumerated
== xOffset
.GetUnit() ||
10660 eCSSUnit_Enumerated
!= yEdge
.GetUnit() ||
10661 BG_CENTER
== yEdge
.GetIntValue() ||
10662 eCSSUnit_Enumerated
== yOffset
.GetUnit()) {
10667 // "If three or four values are given, then each <percentage> or<length>
10668 // represents an offset and must be preceded by a keyword, which specifies
10669 // from which edge the offset is given." ... "If three values are given,
10670 // the missing offset is assumed to be zero."
10671 if (eCSSUnit_Enumerated
!= value
->Item(1).GetUnit()) {
10672 // keyword offset keyword
10673 // Second value is non-keyword, thus first value must be a non-center
10675 if (eCSSUnit_Enumerated
!= value
->Item(0).GetUnit() ||
10676 BG_CENTER
== value
->Item(0).GetIntValue()) {
10680 // Remaining value must be a keyword.
10681 if (eCSSUnit_Enumerated
!= value
->Item(2).GetUnit()) {
10685 yOffset
.Reset(); // Everything else is in the correct position.
10686 } else if (eCSSUnit_Enumerated
!= value
->Item(2).GetUnit()) {
10687 // keyword keyword offset
10688 // Third value is non-keyword, thus second value must be non-center
10690 if (BG_CENTER
== value
->Item(1).GetIntValue()) {
10694 // Remaining value must be a keyword.
10695 if (eCSSUnit_Enumerated
!= value
->Item(0).GetUnit()) {
10699 // Move the values to the correct position in the array.
10700 value
->Item(3) = value
->Item(2); // yOffset
10701 value
->Item(2) = value
->Item(1); // yEdge
10702 value
->Item(1).Reset(); // xOffset
10708 // "If two values are given and at least one value is not a keyword, then
10709 // the first value represents the horizontal position (or offset) and the
10710 // second represents the vertical position (or offset)"
10711 if (eCSSUnit_Enumerated
== value
->Item(0).GetUnit()) {
10712 if (eCSSUnit_Enumerated
== value
->Item(1).GetUnit()) {
10714 value
->Item(2) = value
->Item(1); // move yEdge to correct position
10719 // First value must represent horizontal position.
10720 if ((BG_TOP
| BG_BOTTOM
) & value
->Item(0).GetIntValue()) {
10723 value
->Item(3) = value
->Item(1); // move yOffset to correct position
10728 if (eCSSUnit_Enumerated
== value
->Item(1).GetUnit()) {
10730 // Second value must represent vertical position.
10731 if ((BG_LEFT
| BG_RIGHT
) & value
->Item(1).GetIntValue()) {
10734 value
->Item(2) = value
->Item(1); // move yEdge to correct position
10735 value
->Item(1) = value
->Item(0); // move xOffset to correct position
10740 value
->Item(3) = value
->Item(1); // move yOffset to correct position
10741 value
->Item(1) = value
->Item(0); // move xOffset to correct position
10748 // "If only one value is specified, the second value is assumed to be
10750 if (eCSSUnit_Enumerated
== value
->Item(0).GetUnit()) {
10753 value
->Item(1) = value
->Item(0); // move xOffset to correct position
10756 yEdge
.SetIntValue(NS_STYLE_BG_POSITION_CENTER
, eCSSUnit_Enumerated
);
10763 // For compatibility with CSS2.1 code the edges can be unspecified.
10764 // Unspecified edges are recorded as nullptr.
10765 NS_ASSERTION((eCSSUnit_Enumerated
== xEdge
.GetUnit() ||
10766 eCSSUnit_Null
== xEdge
.GetUnit()) &&
10767 (eCSSUnit_Enumerated
== yEdge
.GetUnit() ||
10768 eCSSUnit_Null
== yEdge
.GetUnit()) &&
10769 eCSSUnit_Enumerated
!= xOffset
.GetUnit() &&
10770 eCSSUnit_Enumerated
!= yOffset
.GetUnit(),
10771 "Unexpected units");
10773 // Keywords in first and second pairs can not both be vertical or
10774 // horizontal keywords. (eg. left right, bottom top). Additionally,
10775 // non-center keyword can not be duplicated (eg. left left).
10776 int32_t xEdgeEnum
=
10777 xEdge
.GetUnit() == eCSSUnit_Enumerated
? xEdge
.GetIntValue() : 0;
10778 int32_t yEdgeEnum
=
10779 yEdge
.GetUnit() == eCSSUnit_Enumerated
? yEdge
.GetIntValue() : 0;
10780 if ((xEdgeEnum
| yEdgeEnum
) == (BG_LEFT
| BG_RIGHT
) ||
10781 (xEdgeEnum
| yEdgeEnum
) == (BG_TOP
| BG_BOTTOM
) ||
10782 (xEdgeEnum
& yEdgeEnum
& ~BG_CENTER
)) {
10786 // The values could be in an order that is different than expected.
10787 // eg. x contains vertical information, y contains horizontal information.
10788 // Swap if incorrect order.
10789 if (xEdgeEnum
& (BG_TOP
| BG_BOTTOM
) ||
10790 yEdgeEnum
& (BG_LEFT
| BG_RIGHT
)) {
10791 nsCSSValue swapEdge
= xEdge
;
10792 nsCSSValue swapOffset
= xOffset
;
10796 yOffset
= swapOffset
;
10802 // This function is very similar to ParseBackgroundList and
10803 // ParseBackgroundPosition.
10805 CSSParserImpl::ParseBackgroundSize()
10808 // 'initial', 'inherit' and 'unset' stand alone, no list permitted.
10809 if (!ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
10810 nsCSSValuePair valuePair
;
10811 if (!ParseBackgroundSizeValues(valuePair
)) {
10814 nsCSSValuePairList
* item
= value
.SetPairListValue();
10816 item
->mXValue
= valuePair
.mXValue
;
10817 item
->mYValue
= valuePair
.mYValue
;
10818 if (!ExpectSymbol(',', true)) {
10821 if (!ParseBackgroundSizeValues(valuePair
)) {
10824 item
->mNext
= new nsCSSValuePairList
;
10825 item
= item
->mNext
;
10828 AppendValue(eCSSProperty_background_size
, value
);
10833 * Parses two values that correspond to lengths for the background-size
10834 * property. These can be one or two lengths (or the 'auto' keyword) or
10835 * percentages corresponding to the element's dimensions or the single keywords
10836 * 'contain' or 'cover'. 'initial', 'inherit' and 'unset' must be handled by
10837 * the caller if desired.
10839 * @param aOut The nsCSSValuePair in which to place the result.
10840 * @return Whether or not the operation succeeded.
10842 #define BG_SIZE_VARIANT (VARIANT_LP | VARIANT_AUTO | VARIANT_CALC)
10843 bool CSSParserImpl::ParseBackgroundSizeValues(nsCSSValuePair
&aOut
)
10845 // First try a percentage or a length value
10846 nsCSSValue
&xValue
= aOut
.mXValue
,
10847 &yValue
= aOut
.mYValue
;
10848 if (ParseNonNegativeVariant(xValue
, BG_SIZE_VARIANT
, nullptr)) {
10849 // We have one percentage/length/calc/auto. Get the optional second
10850 // percentage/length/calc/keyword.
10851 if (ParseNonNegativeVariant(yValue
, BG_SIZE_VARIANT
, nullptr)) {
10852 // We have a second percentage/length/calc/auto.
10856 // If only one percentage or length value is given, it sets the
10857 // horizontal size only, and the vertical size will be as if by 'auto'.
10858 yValue
.SetAutoValue();
10862 // Now address 'contain' and 'cover'.
10863 if (!ParseEnum(xValue
, nsCSSProps::kBackgroundSizeKTable
))
10868 #undef BG_SIZE_VARIANT
10871 CSSParserImpl::ParseBorderColor()
10873 static const nsCSSProperty kBorderColorSources
[] = {
10874 eCSSProperty_border_left_color_ltr_source
,
10875 eCSSProperty_border_left_color_rtl_source
,
10876 eCSSProperty_border_right_color_ltr_source
,
10877 eCSSProperty_border_right_color_rtl_source
,
10878 eCSSProperty_UNKNOWN
10881 // do this now, in case 4 values weren't specified
10882 InitBoxPropsAsPhysical(kBorderColorSources
);
10883 return ParseBoxProperties(kBorderColorIDs
);
10887 CSSParserImpl::SetBorderImageInitialValues()
10889 // border-image-source: none
10891 source
.SetNoneValue();
10892 AppendValue(eCSSProperty_border_image_source
, source
);
10894 // border-image-slice: 100%
10895 nsCSSValue sliceBoxValue
;
10896 nsCSSRect
& sliceBox
= sliceBoxValue
.SetRectValue();
10897 sliceBox
.SetAllSidesTo(nsCSSValue(1.0f
, eCSSUnit_Percent
));
10899 nsCSSValueList
* sliceList
= slice
.SetListValue();
10900 sliceList
->mValue
= sliceBoxValue
;
10901 AppendValue(eCSSProperty_border_image_slice
, slice
);
10903 // border-image-width: 1
10905 nsCSSRect
& widthBox
= width
.SetRectValue();
10906 widthBox
.SetAllSidesTo(nsCSSValue(1.0f
, eCSSUnit_Number
));
10907 AppendValue(eCSSProperty_border_image_width
, width
);
10909 // border-image-outset: 0
10911 nsCSSRect
& outsetBox
= outset
.SetRectValue();
10912 outsetBox
.SetAllSidesTo(nsCSSValue(0.0f
, eCSSUnit_Number
));
10913 AppendValue(eCSSProperty_border_image_outset
, outset
);
10915 // border-image-repeat: repeat
10917 nsCSSValuePair repeatPair
;
10918 repeatPair
.SetBothValuesTo(nsCSSValue(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH
,
10919 eCSSUnit_Enumerated
));
10920 repeat
.SetPairValue(&repeatPair
);
10921 AppendValue(eCSSProperty_border_image_repeat
, repeat
);
10925 CSSParserImpl::ParseBorderImageSlice(bool aAcceptsInherit
,
10926 bool* aConsumedTokens
)
10928 // border-image-slice: initial | [<number>|<percentage>]{1,4} && fill?
10931 if (aConsumedTokens
) {
10932 *aConsumedTokens
= true;
10935 if (aAcceptsInherit
&& ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
10936 // Keywords "inherit", "initial" and "unset" can not be mixed, so we
10938 AppendValue(eCSSProperty_border_image_slice
, value
);
10942 // Try parsing "fill" value.
10943 nsCSSValue imageSliceFillValue
;
10944 bool hasFill
= ParseEnum(imageSliceFillValue
,
10945 nsCSSProps::kBorderImageSliceKTable
);
10947 // Parse the box dimensions.
10948 nsCSSValue imageSliceBoxValue
;
10949 if (!ParseGroupedBoxProperty(VARIANT_PN
, imageSliceBoxValue
)) {
10950 if (!hasFill
&& aConsumedTokens
) {
10951 *aConsumedTokens
= false;
10957 // Try parsing "fill" keyword again if the first time failed because keyword
10958 // and slice dimensions can be in any order.
10960 hasFill
= ParseEnum(imageSliceFillValue
,
10961 nsCSSProps::kBorderImageSliceKTable
);
10964 nsCSSValueList
* borderImageSlice
= value
.SetListValue();
10965 // Put the box value into the list.
10966 borderImageSlice
->mValue
= imageSliceBoxValue
;
10969 // Put the "fill" value into the list.
10970 borderImageSlice
->mNext
= new nsCSSValueList
;
10971 borderImageSlice
->mNext
->mValue
= imageSliceFillValue
;
10974 AppendValue(eCSSProperty_border_image_slice
, value
);
10979 CSSParserImpl::ParseBorderImageWidth(bool aAcceptsInherit
)
10981 // border-image-width: initial | [<length>|<number>|<percentage>|auto]{1,4}
10984 if (aAcceptsInherit
&& ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
10985 // Keywords "inherit", "initial" and "unset" can not be mixed, so we
10987 AppendValue(eCSSProperty_border_image_width
, value
);
10991 // Parse the box dimensions.
10992 if (!ParseGroupedBoxProperty(VARIANT_ALPN
, value
)) {
10996 AppendValue(eCSSProperty_border_image_width
, value
);
11001 CSSParserImpl::ParseBorderImageOutset(bool aAcceptsInherit
)
11003 // border-image-outset: initial | [<length>|<number>]{1,4}
11006 if (aAcceptsInherit
&& ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
11007 // Keywords "inherit", "initial" and "unset" can not be mixed, so we
11009 AppendValue(eCSSProperty_border_image_outset
, value
);
11013 // Parse the box dimensions.
11014 if (!ParseGroupedBoxProperty(VARIANT_LN
, value
)) {
11018 AppendValue(eCSSProperty_border_image_outset
, value
);
11023 CSSParserImpl::ParseBorderImageRepeat(bool aAcceptsInherit
)
11026 if (aAcceptsInherit
&& ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
11027 // Keywords "inherit", "initial" and "unset" can not be mixed, so we
11029 AppendValue(eCSSProperty_border_image_repeat
, value
);
11033 nsCSSValuePair result
;
11034 if (!ParseEnum(result
.mXValue
, nsCSSProps::kBorderImageRepeatKTable
)) {
11038 // optional second keyword, defaults to first
11039 if (!ParseEnum(result
.mYValue
, nsCSSProps::kBorderImageRepeatKTable
)) {
11040 result
.mYValue
= result
.mXValue
;
11043 value
.SetPairValue(&result
);
11044 AppendValue(eCSSProperty_border_image_repeat
, value
);
11049 CSSParserImpl::ParseBorderImage()
11051 nsAutoParseCompoundProperty
compound(this);
11053 // border-image: inherit | initial |
11054 // <border-image-source> ||
11055 // <border-image-slice>
11056 // [ / <border-image-width> |
11057 // / <border-image-width>? / <border-image-outset> ]? ||
11058 // <border-image-repeat>
11061 if (ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
11062 AppendValue(eCSSProperty_border_image_source
, value
);
11063 AppendValue(eCSSProperty_border_image_slice
, value
);
11064 AppendValue(eCSSProperty_border_image_width
, value
);
11065 AppendValue(eCSSProperty_border_image_outset
, value
);
11066 AppendValue(eCSSProperty_border_image_repeat
, value
);
11067 // Keywords "inherit", "initial" and "unset" can't be mixed, so we are done.
11071 // No empty property.
11072 if (CheckEndProperty()) {
11076 // Shorthand properties are required to set everything they can.
11077 SetBorderImageInitialValues();
11079 bool foundSource
= false;
11080 bool foundSliceWidthOutset
= false;
11081 bool foundRepeat
= false;
11083 // This loop is used to handle the parsing of border-image properties which
11084 // can appear in any order.
11085 nsCSSValue imageSourceValue
;
11086 while (!CheckEndProperty()) {
11087 // <border-image-source>
11088 if (!foundSource
&& ParseVariant(imageSourceValue
, VARIANT_IMAGE
, nullptr)) {
11089 AppendValue(eCSSProperty_border_image_source
, imageSourceValue
);
11090 foundSource
= true;
11094 // <border-image-slice>
11095 // ParseBorderImageSlice is weird. It may consume tokens and then return
11096 // false, because it parses a property with two required components that
11097 // can appear in either order. Since the tokens that were consumed cannot
11098 // parse as anything else we care about, this isn't a problem.
11099 if (!foundSliceWidthOutset
) {
11100 bool sliceConsumedTokens
= false;
11101 if (ParseBorderImageSlice(false, &sliceConsumedTokens
)) {
11102 foundSliceWidthOutset
= true;
11104 // [ / <border-image-width>?
11105 if (ExpectSymbol('/', true)) {
11106 bool foundBorderImageWidth
= ParseBorderImageWidth(false);
11108 // [ / <border-image-outset>
11109 if (ExpectSymbol('/', true)) {
11110 if (!ParseBorderImageOutset(false)) {
11113 } else if (!foundBorderImageWidth
) {
11114 // If this part has an trailing slash, the whole declaration is
11122 // If we consumed some tokens for <border-image-slice> but did not
11123 // successfully parse it, we have an error.
11124 if (sliceConsumedTokens
) {
11130 // <border-image-repeat>
11131 if (!foundRepeat
&& ParseBorderImageRepeat(false)) {
11132 foundRepeat
= true;
11143 CSSParserImpl::ParseBorderSpacing()
11145 nsCSSValue xValue
, yValue
;
11146 if (!ParseNonNegativeVariant(xValue
, VARIANT_HL
| VARIANT_CALC
, nullptr)) {
11150 // If we have one length, get the optional second length.
11151 // set the second value equal to the first.
11152 if (xValue
.IsLengthUnit() || xValue
.IsCalcUnit()) {
11153 ParseNonNegativeVariant(yValue
, VARIANT_LENGTH
| VARIANT_CALC
, nullptr);
11156 if (yValue
== xValue
|| yValue
.GetUnit() == eCSSUnit_Null
) {
11157 AppendValue(eCSSProperty_border_spacing
, xValue
);
11160 pair
.SetPairValue(xValue
, yValue
);
11161 AppendValue(eCSSProperty_border_spacing
, pair
);
11167 CSSParserImpl::ParseBorderSide(const nsCSSProperty aPropIDs
[],
11170 const int32_t numProps
= 3;
11171 nsCSSValue values
[numProps
];
11173 int32_t found
= ParseChoice(values
, aPropIDs
, numProps
);
11178 if ((found
& 1) == 0) { // Provide default border-width
11179 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
11181 if ((found
& 2) == 0) { // Provide default border-style
11182 values
[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE
, eCSSUnit_Enumerated
);
11184 if ((found
& 4) == 0) { // text color will be used
11185 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
11188 if (aSetAllSides
) {
11189 static const nsCSSProperty kBorderSources
[] = {
11190 eCSSProperty_border_left_color_ltr_source
,
11191 eCSSProperty_border_left_color_rtl_source
,
11192 eCSSProperty_border_right_color_ltr_source
,
11193 eCSSProperty_border_right_color_rtl_source
,
11194 eCSSProperty_border_left_style_ltr_source
,
11195 eCSSProperty_border_left_style_rtl_source
,
11196 eCSSProperty_border_right_style_ltr_source
,
11197 eCSSProperty_border_right_style_rtl_source
,
11198 eCSSProperty_border_left_width_ltr_source
,
11199 eCSSProperty_border_left_width_rtl_source
,
11200 eCSSProperty_border_right_width_ltr_source
,
11201 eCSSProperty_border_right_width_rtl_source
,
11202 eCSSProperty_UNKNOWN
11205 InitBoxPropsAsPhysical(kBorderSources
);
11207 // Parsing "border" shorthand; set all four sides to the same thing
11208 for (int32_t index
= 0; index
< 4; index
++) {
11209 NS_ASSERTION(numProps
== 3, "This code needs updating");
11210 AppendValue(kBorderWidthIDs
[index
], values
[0]);
11211 AppendValue(kBorderStyleIDs
[index
], values
[1]);
11212 AppendValue(kBorderColorIDs
[index
], values
[2]);
11215 static const nsCSSProperty kBorderColorsProps
[] = {
11216 eCSSProperty_border_top_colors
,
11217 eCSSProperty_border_right_colors
,
11218 eCSSProperty_border_bottom_colors
,
11219 eCSSProperty_border_left_colors
11222 // Set the other properties that the border shorthand sets to their
11224 nsCSSValue extraValue
;
11225 switch (values
[0].GetUnit()) {
11226 case eCSSUnit_Inherit
:
11227 case eCSSUnit_Initial
:
11228 case eCSSUnit_Unset
:
11229 extraValue
= values
[0];
11230 // Set value of border-image properties to initial/inherit/unset
11231 AppendValue(eCSSProperty_border_image_source
, extraValue
);
11232 AppendValue(eCSSProperty_border_image_slice
, extraValue
);
11233 AppendValue(eCSSProperty_border_image_width
, extraValue
);
11234 AppendValue(eCSSProperty_border_image_outset
, extraValue
);
11235 AppendValue(eCSSProperty_border_image_repeat
, extraValue
);
11238 extraValue
.SetNoneValue();
11239 SetBorderImageInitialValues();
11242 NS_FOR_CSS_SIDES(side
) {
11243 AppendValue(kBorderColorsProps
[side
], extraValue
);
11247 // Just set our one side
11248 for (int32_t index
= 0; index
< numProps
; index
++) {
11249 AppendValue(aPropIDs
[index
], values
[index
]);
11256 CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs
[],
11257 int32_t aSourceType
)
11259 const int32_t numProps
= 3;
11260 nsCSSValue values
[numProps
];
11262 int32_t found
= ParseChoice(values
, aPropIDs
, numProps
);
11267 if ((found
& 1) == 0) { // Provide default border-width
11268 values
[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
11270 if ((found
& 2) == 0) { // Provide default border-style
11271 values
[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE
, eCSSUnit_Enumerated
);
11273 if ((found
& 4) == 0) { // text color will be used
11274 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
11276 for (int32_t index
= 0; index
< numProps
; index
++) {
11277 const nsCSSProperty
* subprops
=
11278 nsCSSProps::SubpropertyEntryFor(aPropIDs
[index
+ numProps
]);
11279 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
11280 "not box property with physical vs. logical cascading");
11281 AppendValue(subprops
[0], values
[index
]);
11282 nsCSSValue
typeVal(aSourceType
, eCSSUnit_Enumerated
);
11283 AppendValue(subprops
[1], typeVal
);
11284 AppendValue(subprops
[2], typeVal
);
11290 CSSParserImpl::ParseBorderStyle()
11292 static const nsCSSProperty kBorderStyleSources
[] = {
11293 eCSSProperty_border_left_style_ltr_source
,
11294 eCSSProperty_border_left_style_rtl_source
,
11295 eCSSProperty_border_right_style_ltr_source
,
11296 eCSSProperty_border_right_style_rtl_source
,
11297 eCSSProperty_UNKNOWN
11300 // do this now, in case 4 values weren't specified
11301 InitBoxPropsAsPhysical(kBorderStyleSources
);
11302 return ParseBoxProperties(kBorderStyleIDs
);
11306 CSSParserImpl::ParseBorderWidth()
11308 static const nsCSSProperty kBorderWidthSources
[] = {
11309 eCSSProperty_border_left_width_ltr_source
,
11310 eCSSProperty_border_left_width_rtl_source
,
11311 eCSSProperty_border_right_width_ltr_source
,
11312 eCSSProperty_border_right_width_rtl_source
,
11313 eCSSProperty_UNKNOWN
11316 // do this now, in case 4 values weren't specified
11317 InitBoxPropsAsPhysical(kBorderWidthSources
);
11318 return ParseBoxProperties(kBorderWidthIDs
);
11322 CSSParserImpl::ParseBorderColors(nsCSSProperty aProperty
)
11325 // 'inherit', 'initial', 'unset' and 'none' are only allowed on their own
11326 if (!ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
11327 nsCSSValueList
*cur
= value
.SetListValue();
11329 if (!ParseVariant(cur
->mValue
, VARIANT_COLOR
| VARIANT_KEYWORD
,
11330 nsCSSProps::kBorderColorKTable
)) {
11333 if (CheckEndProperty()) {
11336 cur
->mNext
= new nsCSSValueList
;
11340 AppendValue(aProperty
, value
);
11344 // Parse the top level of a calc() expression.
11346 CSSParserImpl::ParseCalc(nsCSSValue
&aValue
, int32_t aVariantMask
)
11348 // Parsing calc expressions requires, in a number of cases, looking
11349 // for a token that is *either* a value of the property or a number.
11350 // This can be done without lookahead when we assume that the property
11351 // values cannot themselves be numbers.
11352 NS_ASSERTION(!(aVariantMask
& VARIANT_NUMBER
), "unexpected variant mask");
11353 NS_ABORT_IF_FALSE(aVariantMask
!= 0, "unexpected variant mask");
11355 bool oldUnitlessLengthQuirk
= mUnitlessLengthQuirk
;
11356 mUnitlessLengthQuirk
= false;
11358 // One-iteration loop so we can break to the error-handling case.
11360 // The toplevel of a calc() is always an nsCSSValue::Array of length 1.
11361 nsRefPtr
<nsCSSValue::Array
> arr
= nsCSSValue::Array::Create(1);
11363 if (!ParseCalcAdditiveExpression(arr
->Item(0), aVariantMask
))
11366 if (!ExpectSymbol(')', true))
11369 aValue
.SetArrayValue(arr
, eCSSUnit_Calc
);
11370 mUnitlessLengthQuirk
= oldUnitlessLengthQuirk
;
11375 mUnitlessLengthQuirk
= oldUnitlessLengthQuirk
;
11379 // We optimize away the <value-expression> production given that
11380 // ParseVariant consumes initial whitespace and we call
11381 // ExpectSymbol(')') with true for aSkipWS.
11382 // * If aVariantMask is VARIANT_NUMBER, this function parses the
11383 // <number-additive-expression> production.
11384 // * If aVariantMask does not contain VARIANT_NUMBER, this function
11385 // parses the <value-additive-expression> production.
11386 // * Otherwise (VARIANT_NUMBER and other bits) this function parses
11387 // whichever one of the productions matches ***and modifies
11388 // aVariantMask*** to reflect which one it has parsed by either
11389 // removing VARIANT_NUMBER or removing all other bits.
11390 // It does so iteratively, but builds the correct recursive
11393 CSSParserImpl::ParseCalcAdditiveExpression(nsCSSValue
& aValue
,
11394 int32_t& aVariantMask
)
11396 NS_ABORT_IF_FALSE(aVariantMask
!= 0, "unexpected variant mask");
11397 nsCSSValue
*storage
= &aValue
;
11400 if (!ParseCalcMultiplicativeExpression(*storage
, aVariantMask
, &haveWS
))
11403 if (!haveWS
|| !GetToken(false))
11406 if (mToken
.IsSymbol('+')) {
11407 unit
= eCSSUnit_Calc_Plus
;
11408 } else if (mToken
.IsSymbol('-')) {
11409 unit
= eCSSUnit_Calc_Minus
;
11414 if (!RequireWhitespace())
11417 nsRefPtr
<nsCSSValue::Array
> arr
= nsCSSValue::Array::Create(2);
11418 arr
->Item(0) = aValue
;
11419 storage
= &arr
->Item(1);
11420 aValue
.SetArrayValue(arr
, unit
);
11424 struct ReduceNumberCalcOps
: public mozilla::css::BasicFloatCalcOps
,
11425 public mozilla::css::CSSValueInputCalcOps
11427 result_type
ComputeLeafValue(const nsCSSValue
& aValue
)
11429 NS_ABORT_IF_FALSE(aValue
.GetUnit() == eCSSUnit_Number
, "unexpected unit");
11430 return aValue
.GetFloatValue();
11433 float ComputeNumber(const nsCSSValue
& aValue
)
11435 return mozilla::css::ComputeCalc(aValue
, *this);
11439 // * If aVariantMask is VARIANT_NUMBER, this function parses the
11440 // <number-multiplicative-expression> production.
11441 // * If aVariantMask does not contain VARIANT_NUMBER, this function
11442 // parses the <value-multiplicative-expression> production.
11443 // * Otherwise (VARIANT_NUMBER and other bits) this function parses
11444 // whichever one of the productions matches ***and modifies
11445 // aVariantMask*** to reflect which one it has parsed by either
11446 // removing VARIANT_NUMBER or removing all other bits.
11447 // It does so iteratively, but builds the correct recursive data
11449 // This function always consumes *trailing* whitespace when it returns
11450 // true; whether there was any such whitespace is returned in the
11451 // aHadFinalWS parameter.
11453 CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue
& aValue
,
11454 int32_t& aVariantMask
,
11457 NS_ABORT_IF_FALSE(aVariantMask
!= 0, "unexpected variant mask");
11458 bool gotValue
= false; // already got the part with the unit
11459 bool afterDivision
= false;
11461 nsCSSValue
*storage
= &aValue
;
11463 int32_t variantMask
;
11464 if (afterDivision
|| gotValue
) {
11465 variantMask
= VARIANT_NUMBER
;
11467 variantMask
= aVariantMask
| VARIANT_NUMBER
;
11469 if (!ParseCalcTerm(*storage
, variantMask
))
11471 NS_ABORT_IF_FALSE(variantMask
!= 0,
11472 "ParseCalcTerm did not set variantMask appropriately");
11473 NS_ABORT_IF_FALSE(!(variantMask
& VARIANT_NUMBER
) ||
11474 !(variantMask
& ~int32_t(VARIANT_NUMBER
)),
11475 "ParseCalcTerm did not set variantMask appropriately");
11477 if (variantMask
& VARIANT_NUMBER
) {
11478 // Simplify the value immediately so we can check for division by
11480 ReduceNumberCalcOps ops
;
11481 float number
= mozilla::css::ComputeCalc(*storage
, ops
);
11482 if (number
== 0.0 && afterDivision
)
11484 storage
->SetFloatValue(number
, eCSSUnit_Number
);
11488 if (storage
!= &aValue
) {
11489 // Simplify any numbers in the Times_L position (which are
11490 // not simplified by the check above).
11491 NS_ABORT_IF_FALSE(storage
== &aValue
.GetArrayValue()->Item(1),
11492 "unexpected relationship to current storage");
11493 nsCSSValue
&leftValue
= aValue
.GetArrayValue()->Item(0);
11494 ReduceNumberCalcOps ops
;
11495 float number
= mozilla::css::ComputeCalc(leftValue
, ops
);
11496 leftValue
.SetFloatValue(number
, eCSSUnit_Number
);
11500 bool hadWS
= RequireWhitespace();
11501 if (!GetToken(false)) {
11502 *aHadFinalWS
= hadWS
;
11506 if (mToken
.IsSymbol('*')) {
11507 unit
= gotValue
? eCSSUnit_Calc_Times_R
: eCSSUnit_Calc_Times_L
;
11508 afterDivision
= false;
11509 } else if (mToken
.IsSymbol('/')) {
11510 unit
= eCSSUnit_Calc_Divided
;
11511 afterDivision
= true;
11514 *aHadFinalWS
= hadWS
;
11518 nsRefPtr
<nsCSSValue::Array
> arr
= nsCSSValue::Array::Create(2);
11519 arr
->Item(0) = aValue
;
11520 storage
= &arr
->Item(1);
11521 aValue
.SetArrayValue(arr
, unit
);
11524 // Adjust aVariantMask (see comments above function) to reflect which
11526 if (aVariantMask
& VARIANT_NUMBER
) {
11528 aVariantMask
&= ~int32_t(VARIANT_NUMBER
);
11530 aVariantMask
= VARIANT_NUMBER
;
11534 // We had to find a value, but we didn't.
11542 // * If aVariantMask is VARIANT_NUMBER, this function parses the
11543 // <number-term> production.
11544 // * If aVariantMask does not contain VARIANT_NUMBER, this function
11545 // parses the <value-term> production.
11546 // * Otherwise (VARIANT_NUMBER and other bits) this function parses
11547 // whichever one of the productions matches ***and modifies
11548 // aVariantMask*** to reflect which one it has parsed by either
11549 // removing VARIANT_NUMBER or removing all other bits.
11551 CSSParserImpl::ParseCalcTerm(nsCSSValue
& aValue
, int32_t& aVariantMask
)
11553 NS_ABORT_IF_FALSE(aVariantMask
!= 0, "unexpected variant mask");
11554 if (!GetToken(true))
11556 // Either an additive expression in parentheses...
11557 if (mToken
.IsSymbol('(')) {
11558 if (!ParseCalcAdditiveExpression(aValue
, aVariantMask
) ||
11559 !ExpectSymbol(')', true)) {
11565 // ... or just a value
11567 // Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
11568 // always gets picked up
11569 if (!ParseVariant(aValue
, aVariantMask
| VARIANT_NUMBER
, nullptr)) {
11572 // ...and do the VARIANT_NUMBER check ourselves.
11573 if (!(aVariantMask
& VARIANT_NUMBER
) && aValue
.GetUnit() == eCSSUnit_Number
) {
11576 // If we did the value parsing, we need to adjust aVariantMask to
11577 // reflect which option we took (see above).
11578 if (aVariantMask
& VARIANT_NUMBER
) {
11579 if (aValue
.GetUnit() == eCSSUnit_Number
) {
11580 aVariantMask
= VARIANT_NUMBER
;
11582 aVariantMask
&= ~int32_t(VARIANT_NUMBER
);
11588 // This function consumes all consecutive whitespace and returns whether
11591 CSSParserImpl::RequireWhitespace()
11593 if (!GetToken(false))
11595 if (mToken
.mType
!= eCSSToken_Whitespace
) {
11599 // Skip any additional whitespace tokens.
11600 if (GetToken(true)) {
11607 CSSParserImpl::ParseRect(nsCSSProperty aPropID
)
11610 if (ParseVariant(val
, VARIANT_INHERIT
| VARIANT_AUTO
, nullptr)) {
11611 AppendValue(aPropID
, val
);
11615 if (! GetToken(true)) {
11619 if (mToken
.mType
== eCSSToken_Function
&&
11620 mToken
.mIdent
.LowerCaseEqualsLiteral("rect")) {
11621 nsCSSRect
& rect
= val
.SetRectValue();
11623 NS_FOR_CSS_SIDES(side
) {
11624 if (! ParseVariant(rect
.*(nsCSSRect::sides
[side
]),
11625 VARIANT_AL
, nullptr)) {
11629 useCommas
= ExpectSymbol(',', true);
11630 } else if (useCommas
&& side
< 3) {
11631 // Skip optional commas between elements, but only if the first
11632 // separator was a comma.
11633 if (!ExpectSymbol(',', true)) {
11638 if (!ExpectSymbol(')', true)) {
11646 AppendValue(aPropID
, val
);
11651 CSSParserImpl::ParseColumns()
11653 // We use a similar "fake value" hack to ParseListStyle, because
11654 // "auto" is acceptable for both column-count and column-width.
11655 // If the fake "auto" value is found, and one of the real values isn't,
11656 // that means the fake auto value is meant for the real value we didn't
11658 static const nsCSSProperty columnIDs
[] = {
11659 eCSSPropertyExtra_x_auto_value
,
11660 eCSSProperty__moz_column_count
,
11661 eCSSProperty__moz_column_width
11663 const int32_t numProps
= MOZ_ARRAY_LENGTH(columnIDs
);
11665 nsCSSValue values
[numProps
];
11666 int32_t found
= ParseChoice(values
, columnIDs
, numProps
);
11670 if ((found
& (1|2|4)) == (1|2|4) &&
11671 values
[0].GetUnit() == eCSSUnit_Auto
) {
11672 // We filled all 3 values, which is invalid
11676 if ((found
& 2) == 0) {
11677 // Provide auto column-count
11678 values
[1].SetAutoValue();
11680 if ((found
& 4) == 0) {
11681 // Provide auto column-width
11682 values
[2].SetAutoValue();
11685 // Start at index 1 to skip the fake auto value.
11686 for (int32_t index
= 1; index
< numProps
; index
++) {
11687 AppendValue(columnIDs
[index
], values
[index
]);
11692 #define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
11695 CSSParserImpl::ParseContent()
11697 // We need to divide the 'content' keywords into two classes for
11698 // ParseVariant's sake, so we can't just use nsCSSProps::kContentKTable.
11699 static const KTableValue kContentListKWs
[] = {
11700 eCSSKeyword_open_quote
, NS_STYLE_CONTENT_OPEN_QUOTE
,
11701 eCSSKeyword_close_quote
, NS_STYLE_CONTENT_CLOSE_QUOTE
,
11702 eCSSKeyword_no_open_quote
, NS_STYLE_CONTENT_NO_OPEN_QUOTE
,
11703 eCSSKeyword_no_close_quote
, NS_STYLE_CONTENT_NO_CLOSE_QUOTE
,
11704 eCSSKeyword_UNKNOWN
,-1
11707 static const KTableValue kContentSolitaryKWs
[] = {
11708 eCSSKeyword__moz_alt_content
, NS_STYLE_CONTENT_ALT_CONTENT
,
11709 eCSSKeyword_UNKNOWN
,-1
11712 // Verify that these two lists add up to the size of
11713 // nsCSSProps::kContentKTable.
11714 NS_ABORT_IF_FALSE(nsCSSProps::kContentKTable
[
11715 ArrayLength(kContentListKWs
) +
11716 ArrayLength(kContentSolitaryKWs
) - 4] ==
11717 eCSSKeyword_UNKNOWN
&&
11718 nsCSSProps::kContentKTable
[
11719 ArrayLength(kContentListKWs
) +
11720 ArrayLength(kContentSolitaryKWs
) - 3] == -1,
11721 "content keyword tables out of sync");
11724 // 'inherit', 'initial', 'unset', 'normal', 'none', and 'alt-content' must
11726 if (!ParseVariant(value
, VARIANT_HMK
| VARIANT_NONE
,
11727 kContentSolitaryKWs
)) {
11728 nsCSSValueList
* cur
= value
.SetListValue();
11730 if (!ParseVariant(cur
->mValue
, VARIANT_CONTENT
, kContentListKWs
)) {
11733 if (CheckEndProperty()) {
11736 cur
->mNext
= new nsCSSValueList
;
11740 AppendValue(eCSSProperty_content
, value
);
11745 CSSParserImpl::ParseCounterData(nsCSSProperty aPropID
)
11747 static const nsCSSKeyword kCounterDataKTable
[] = {
11749 eCSSKeyword_UNKNOWN
11752 if (!ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
11753 if (!GetToken(true)) {
11756 if (mToken
.mType
!= eCSSToken_Ident
) {
11761 nsCSSValuePairList
*cur
= value
.SetPairListValue();
11763 if (!ParseCustomIdent(cur
->mXValue
, mToken
.mIdent
, kCounterDataKTable
)) {
11766 if (!GetToken(true)) {
11769 if (mToken
.mType
== eCSSToken_Number
&& mToken
.mIntegerValid
) {
11770 cur
->mYValue
.SetIntValue(mToken
.mInteger
, eCSSUnit_Integer
);
11774 if (!GetToken(true)) {
11777 if (mToken
.mType
!= eCSSToken_Ident
) {
11781 cur
->mNext
= new nsCSSValuePairList
;
11785 AppendValue(aPropID
, value
);
11790 CSSParserImpl::ParseCursor()
11793 // 'inherit', 'initial' and 'unset' must be alone
11794 if (!ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
11795 nsCSSValueList
* cur
= value
.SetListValue();
11797 if (!ParseVariant(cur
->mValue
, VARIANT_UK
, nsCSSProps::kCursorKTable
)) {
11800 if (cur
->mValue
.GetUnit() != eCSSUnit_URL
) { // keyword must be last
11804 // We have a URL, so make a value array with three values.
11805 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(3);
11806 val
->Item(0) = cur
->mValue
;
11808 // Parse optional x and y position of cursor hotspot (css3-ui).
11809 if (ParseVariant(val
->Item(1), VARIANT_NUMBER
, nullptr)) {
11810 // If we have one number, we must have two.
11811 if (!ParseVariant(val
->Item(2), VARIANT_NUMBER
, nullptr)) {
11815 cur
->mValue
.SetArrayValue(val
, eCSSUnit_Array
);
11817 if (!ExpectSymbol(',', true)) { // url must not be last
11820 cur
->mNext
= new nsCSSValueList
;
11824 AppendValue(eCSSProperty_cursor
, value
);
11830 CSSParserImpl::ParseFont()
11832 static const nsCSSProperty fontIDs
[] = {
11833 eCSSProperty_font_style
,
11834 eCSSProperty_font_variant_caps
,
11835 eCSSProperty_font_weight
11839 if (ParseVariant(family
, VARIANT_HK
, nsCSSProps::kFontKTable
)) {
11840 if (eCSSUnit_Inherit
== family
.GetUnit() ||
11841 eCSSUnit_Initial
== family
.GetUnit() ||
11842 eCSSUnit_Unset
== family
.GetUnit()) {
11843 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
11844 AppendValue(eCSSProperty_font_family
, family
);
11845 AppendValue(eCSSProperty_font_style
, family
);
11846 AppendValue(eCSSProperty_font_weight
, family
);
11847 AppendValue(eCSSProperty_font_size
, family
);
11848 AppendValue(eCSSProperty_line_height
, family
);
11849 AppendValue(eCSSProperty_font_stretch
, family
);
11850 AppendValue(eCSSProperty_font_size_adjust
, family
);
11851 AppendValue(eCSSProperty_font_feature_settings
, family
);
11852 AppendValue(eCSSProperty_font_language_override
, family
);
11853 AppendValue(eCSSProperty_font_kerning
, family
);
11854 AppendValue(eCSSProperty_font_synthesis
, family
);
11855 AppendValue(eCSSProperty_font_variant_alternates
, family
);
11856 AppendValue(eCSSProperty_font_variant_caps
, family
);
11857 AppendValue(eCSSProperty_font_variant_east_asian
, family
);
11858 AppendValue(eCSSProperty_font_variant_ligatures
, family
);
11859 AppendValue(eCSSProperty_font_variant_numeric
, family
);
11860 AppendValue(eCSSProperty_font_variant_position
, family
);
11863 AppendValue(eCSSProperty__x_system_font
, family
);
11864 nsCSSValue
systemFont(eCSSUnit_System_Font
);
11865 AppendValue(eCSSProperty_font_family
, systemFont
);
11866 AppendValue(eCSSProperty_font_style
, systemFont
);
11867 AppendValue(eCSSProperty_font_weight
, systemFont
);
11868 AppendValue(eCSSProperty_font_size
, systemFont
);
11869 AppendValue(eCSSProperty_line_height
, systemFont
);
11870 AppendValue(eCSSProperty_font_stretch
, systemFont
);
11871 AppendValue(eCSSProperty_font_size_adjust
, systemFont
);
11872 AppendValue(eCSSProperty_font_feature_settings
, systemFont
);
11873 AppendValue(eCSSProperty_font_language_override
, systemFont
);
11874 AppendValue(eCSSProperty_font_kerning
, systemFont
);
11875 AppendValue(eCSSProperty_font_synthesis
, systemFont
);
11876 AppendValue(eCSSProperty_font_variant_alternates
, systemFont
);
11877 AppendValue(eCSSProperty_font_variant_caps
, systemFont
);
11878 AppendValue(eCSSProperty_font_variant_east_asian
, systemFont
);
11879 AppendValue(eCSSProperty_font_variant_ligatures
, systemFont
);
11880 AppendValue(eCSSProperty_font_variant_numeric
, systemFont
);
11881 AppendValue(eCSSProperty_font_variant_position
, systemFont
);
11886 // Get optional font-style, font-variant and font-weight (in any order)
11887 const int32_t numProps
= 3;
11888 nsCSSValue values
[numProps
];
11889 int32_t found
= ParseChoice(values
, fontIDs
, numProps
);
11891 eCSSUnit_Inherit
== values
[0].GetUnit() ||
11892 eCSSUnit_Initial
== values
[0].GetUnit() ||
11893 eCSSUnit_Unset
== values
[0].GetUnit()) { // illegal data
11896 if ((found
& 1) == 0) {
11897 // Provide default font-style
11898 values
[0].SetIntValue(NS_FONT_STYLE_NORMAL
, eCSSUnit_Enumerated
);
11900 if ((found
& 2) == 0) {
11901 // Provide default font-variant
11902 values
[1].SetNormalValue();
11904 if (values
[1].GetUnit() == eCSSUnit_Enumerated
&&
11905 values
[1].GetIntValue() != NS_FONT_VARIANT_CAPS_SMALLCAPS
) {
11906 // only normal or small-caps is allowed in font shorthand
11907 // this also assumes other values for font-variant-caps never overlap
11908 // possible values for style or weight
11912 if ((found
& 4) == 0) {
11913 // Provide default font-weight
11914 values
[2].SetIntValue(NS_FONT_WEIGHT_NORMAL
, eCSSUnit_Enumerated
);
11917 // Get mandatory font-size
11919 if (! ParseNonNegativeVariant(size
, VARIANT_KEYWORD
| VARIANT_LP
,
11920 nsCSSProps::kFontSizeKTable
)) {
11924 // Get optional "/" line-height
11925 nsCSSValue lineHeight
;
11926 if (ExpectSymbol('/', true)) {
11927 if (! ParseNonNegativeVariant(lineHeight
,
11928 VARIANT_NUMBER
| VARIANT_LP
| VARIANT_NORMAL
,
11934 lineHeight
.SetNormalValue();
11937 // Get final mandatory font-family
11938 nsAutoParseCompoundProperty
compound(this);
11939 if (ParseFamily(family
)) {
11940 if (eCSSUnit_Inherit
!= family
.GetUnit() &&
11941 eCSSUnit_Initial
!= family
.GetUnit() &&
11942 eCSSUnit_Unset
!= family
.GetUnit()) {
11943 AppendValue(eCSSProperty__x_system_font
, nsCSSValue(eCSSUnit_None
));
11944 AppendValue(eCSSProperty_font_family
, family
);
11945 AppendValue(eCSSProperty_font_style
, values
[0]);
11946 AppendValue(eCSSProperty_font_variant_caps
, values
[1]);
11947 AppendValue(eCSSProperty_font_weight
, values
[2]);
11948 AppendValue(eCSSProperty_font_size
, size
);
11949 AppendValue(eCSSProperty_line_height
, lineHeight
);
11950 AppendValue(eCSSProperty_font_stretch
,
11951 nsCSSValue(NS_FONT_STRETCH_NORMAL
, eCSSUnit_Enumerated
));
11952 AppendValue(eCSSProperty_font_size_adjust
, nsCSSValue(eCSSUnit_None
));
11953 AppendValue(eCSSProperty_font_feature_settings
, nsCSSValue(eCSSUnit_Normal
));
11954 AppendValue(eCSSProperty_font_language_override
, nsCSSValue(eCSSUnit_Normal
));
11955 AppendValue(eCSSProperty_font_kerning
,
11956 nsCSSValue(NS_FONT_KERNING_AUTO
, eCSSUnit_Enumerated
));
11957 AppendValue(eCSSProperty_font_synthesis
,
11958 nsCSSValue(NS_FONT_SYNTHESIS_WEIGHT
| NS_FONT_SYNTHESIS_STYLE
,
11959 eCSSUnit_Enumerated
));
11960 AppendValue(eCSSProperty_font_variant_alternates
,
11961 nsCSSValue(eCSSUnit_Normal
));
11962 AppendValue(eCSSProperty_font_variant_east_asian
,
11963 nsCSSValue(eCSSUnit_Normal
));
11964 AppendValue(eCSSProperty_font_variant_ligatures
,
11965 nsCSSValue(eCSSUnit_Normal
));
11966 AppendValue(eCSSProperty_font_variant_numeric
,
11967 nsCSSValue(eCSSUnit_Normal
));
11968 AppendValue(eCSSProperty_font_variant_position
,
11969 nsCSSValue(eCSSUnit_Normal
));
11977 CSSParserImpl::ParseFontSynthesis(nsCSSValue
& aValue
)
11979 if (!ParseVariant(aValue
, VARIANT_HK
| VARIANT_NONE
,
11980 nsCSSProps::kFontSynthesisKTable
)) {
11984 // first value 'none' ==> done
11985 if (eCSSUnit_None
== aValue
.GetUnit() ||
11986 eCSSUnit_Initial
== aValue
.GetUnit() ||
11987 eCSSUnit_Inherit
== aValue
.GetUnit() ||
11988 eCSSUnit_Unset
== aValue
.GetUnit())
11993 // look for a second value
11994 int32_t intValue
= aValue
.GetIntValue();
11995 nsCSSValue nextValue
;
11997 if (ParseEnum(nextValue
, nsCSSProps::kFontSynthesisKTable
)) {
11998 int32_t nextIntValue
= nextValue
.GetIntValue();
11999 if (nextIntValue
& intValue
) {
12002 aValue
.SetIntValue(nextIntValue
| intValue
, eCSSUnit_Enumerated
);
12008 // font-variant-alternates allows for a combination of multiple
12009 // simple enumerated values and functional values. Functional values have
12010 // parameter lists with one or more idents which are later resolved
12011 // based on values defined in @font-feature-value rules.
12013 // font-variant-alternates: swash(flowing) historical-forms styleset(alt-g, alt-m);
12015 // So for this the nsCSSValue is set to a pair value, with one
12016 // value for a bitmask of both simple and functional property values
12017 // and another value containing a ValuePairList with lists of idents
12018 // for each functional property value.
12022 // NS_FONT_VARIANT_ALTERNATES_SWASH |
12023 // NS_FONT_VARIANT_ALTERNATES_STYLESET
12024 // o valuePairList, each element with
12025 // - intValue - indicates which alternate
12026 // - string or valueList of strings
12028 // Note: when only 'historical-forms' is specified, there are no
12029 // functional values to store, in which case the valuePairList is a
12030 // single element dummy list. In all other cases, the length of the
12031 // list will match the number of functional values.
12033 #define MAX_ALLOWED_FEATURES 512
12036 MaxElementsForAlternateType(nsCSSKeyword keyword
)
12038 uint16_t maxElems
= 1;
12039 if (keyword
== eCSSKeyword_styleset
||
12040 keyword
== eCSSKeyword_character_variant
) {
12041 maxElems
= MAX_ALLOWED_FEATURES
;
12047 CSSParserImpl::ParseSingleAlternate(int32_t& aWhichFeature
,
12048 nsCSSValue
& aValue
)
12050 if (!GetToken(true)) {
12054 bool isIdent
= (mToken
.mType
== eCSSToken_Ident
);
12055 if (mToken
.mType
!= eCSSToken_Function
&& !isIdent
) {
12060 // ident ==> simple enumerated prop val (e.g. historical-forms)
12061 // function ==> e.g. swash(flowing) styleset(alt-g, alt-m)
12063 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
12064 if (!(eCSSKeyword_UNKNOWN
< keyword
&&
12065 nsCSSProps::FindKeyword(keyword
,
12067 nsCSSProps::kFontVariantAlternatesKTable
:
12068 nsCSSProps::kFontVariantAlternatesFuncsKTable
),
12071 // failed, pop token
12077 aValue
.SetIntValue(aWhichFeature
, eCSSUnit_Enumerated
);
12081 return ParseFunction(keyword
, nullptr, VARIANT_IDENTIFIER
,
12082 1, MaxElementsForAlternateType(keyword
), aValue
);
12086 CSSParserImpl::ParseFontVariantAlternates(nsCSSValue
& aValue
)
12088 if (ParseVariant(aValue
, VARIANT_INHERIT
| VARIANT_NORMAL
, nullptr)) {
12092 // iterate through parameters
12093 nsCSSValue listValue
;
12094 int32_t feature
, featureFlags
= 0;
12096 // if no functional values, this may be a list with a single, unused element
12097 listValue
.SetListValue();
12099 nsCSSValueList
* list
= nullptr;
12101 while (ParseSingleAlternate(feature
, value
)) {
12103 // check to make sure value not already set
12104 if (feature
== 0 ||
12105 feature
& featureFlags
) {
12109 featureFlags
|= feature
;
12111 // if function, need to add to the list of functions
12112 if (value
.GetUnit() == eCSSUnit_Function
) {
12114 list
= listValue
.GetListValue();
12116 list
->mNext
= new nsCSSValueList
;
12117 list
= list
->mNext
;
12119 list
->mValue
= value
;
12123 if (featureFlags
== 0) {
12124 // ParseSingleAlternate failed the first time through the loop.
12128 nsCSSValue featureValue
;
12129 featureValue
.SetIntValue(featureFlags
, eCSSUnit_Enumerated
);
12130 aValue
.SetPairValue(featureValue
, listValue
);
12136 CSSParserImpl::MergeBitmaskValue(int32_t aNewValue
,
12137 const int32_t aMasks
[],
12138 int32_t& aMergedValue
)
12140 // check to make sure value not already set
12141 if (aNewValue
& aMergedValue
) {
12145 const int32_t *m
= aMasks
;
12148 while (*m
!= MASK_END_VALUE
) {
12149 if (*m
& aNewValue
) {
12150 c
= aMergedValue
& *m
;
12160 aMergedValue
|= aNewValue
;
12164 // aMasks - array of masks for mutually-exclusive property values,
12165 // e.g. proportial-nums, tabular-nums
12168 CSSParserImpl::ParseBitmaskValues(nsCSSValue
& aValue
,
12169 const KTableValue aKeywordTable
[],
12170 const int32_t aMasks
[])
12172 // Parse at least one keyword
12173 if (!ParseEnum(aValue
, aKeywordTable
)) {
12177 // look for more values
12178 nsCSSValue nextValue
;
12179 int32_t mergedValue
= aValue
.GetIntValue();
12181 while (ParseEnum(nextValue
, aKeywordTable
))
12183 if (!MergeBitmaskValue(nextValue
.GetIntValue(), aMasks
, mergedValue
)) {
12188 aValue
.SetIntValue(mergedValue
, eCSSUnit_Enumerated
);
12193 static const int32_t maskEastAsian
[] = {
12194 NS_FONT_VARIANT_EAST_ASIAN_VARIANT_MASK
,
12195 NS_FONT_VARIANT_EAST_ASIAN_WIDTH_MASK
,
12200 CSSParserImpl::ParseFontVariantEastAsian(nsCSSValue
& aValue
)
12202 if (ParseVariant(aValue
, VARIANT_INHERIT
| VARIANT_NORMAL
, nullptr)) {
12206 NS_ASSERTION(maskEastAsian
[ArrayLength(maskEastAsian
) - 1] ==
12208 "incorrectly terminated array");
12210 return ParseBitmaskValues(aValue
, nsCSSProps::kFontVariantEastAsianKTable
,
12214 static const int32_t maskLigatures
[] = {
12215 NS_FONT_VARIANT_LIGATURES_COMMON_MASK
,
12216 NS_FONT_VARIANT_LIGATURES_DISCRETIONARY_MASK
,
12217 NS_FONT_VARIANT_LIGATURES_HISTORICAL_MASK
,
12218 NS_FONT_VARIANT_LIGATURES_CONTEXTUAL_MASK
,
12223 CSSParserImpl::ParseFontVariantLigatures(nsCSSValue
& aValue
)
12225 if (ParseVariant(aValue
,
12226 VARIANT_INHERIT
| VARIANT_NORMAL
| VARIANT_NONE
,
12231 NS_ASSERTION(maskLigatures
[ArrayLength(maskLigatures
) - 1] ==
12233 "incorrectly terminated array");
12235 return ParseBitmaskValues(aValue
, nsCSSProps::kFontVariantLigaturesKTable
,
12239 static const int32_t maskNumeric
[] = {
12240 NS_FONT_VARIANT_NUMERIC_FIGURE_MASK
,
12241 NS_FONT_VARIANT_NUMERIC_SPACING_MASK
,
12242 NS_FONT_VARIANT_NUMERIC_FRACTION_MASK
,
12247 CSSParserImpl::ParseFontVariantNumeric(nsCSSValue
& aValue
)
12249 if (ParseVariant(aValue
, VARIANT_INHERIT
| VARIANT_NORMAL
, nullptr)) {
12253 NS_ASSERTION(maskNumeric
[ArrayLength(maskNumeric
) - 1] ==
12255 "incorrectly terminated array");
12257 return ParseBitmaskValues(aValue
, nsCSSProps::kFontVariantNumericKTable
,
12262 CSSParserImpl::ParseFontVariant()
12264 // parse single values - normal/inherit/none
12266 nsCSSValue
normal(eCSSUnit_Normal
);
12268 if (ParseVariant(value
,
12269 VARIANT_INHERIT
| VARIANT_NORMAL
| VARIANT_NONE
,
12271 AppendValue(eCSSProperty_font_variant_ligatures
, value
);
12272 if (eCSSUnit_None
== value
.GetUnit()) {
12273 // 'none' applies the value 'normal' to all properties other
12274 // than 'font-variant-ligatures'
12275 value
.SetNormalValue();
12277 AppendValue(eCSSProperty_font_variant_alternates
, value
);
12278 AppendValue(eCSSProperty_font_variant_caps
, value
);
12279 AppendValue(eCSSProperty_font_variant_east_asian
, value
);
12280 AppendValue(eCSSProperty_font_variant_numeric
, value
);
12281 AppendValue(eCSSProperty_font_variant_position
, value
);
12285 // set each of the individual subproperties
12286 int32_t altFeatures
= 0, capsFeatures
= 0, eastAsianFeatures
= 0,
12287 ligFeatures
= 0, numericFeatures
= 0, posFeatures
= 0;
12288 nsCSSValue altListValue
;
12289 nsCSSValueList
* altList
= nullptr;
12291 // if no functional values, this may be a list with a single, unused element
12292 altListValue
.SetListValue();
12294 bool foundValid
= false; // found at least one proper value
12295 while (GetToken(true)) {
12296 // only an ident or a function at this point
12297 bool isFunction
= (mToken
.mType
== eCSSToken_Function
);
12298 if (mToken
.mType
!= eCSSToken_Ident
&& !isFunction
) {
12303 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
12304 if (keyword
== eCSSKeyword_UNKNOWN
) {
12311 // function? ==> font-variant-alternates
12313 if (!nsCSSProps::FindKeyword(keyword
,
12314 nsCSSProps::kFontVariantAlternatesFuncsKTable
,
12316 (feature
& altFeatures
)) {
12321 altFeatures
|= feature
;
12322 nsCSSValue funcValue
;
12323 if (!ParseFunction(keyword
, nullptr, VARIANT_IDENTIFIER
, 1,
12324 MaxElementsForAlternateType(keyword
), funcValue
) ||
12325 funcValue
.GetUnit() != eCSSUnit_Function
) {
12331 altList
= altListValue
.GetListValue();
12333 altList
->mNext
= new nsCSSValueList
;
12334 altList
= altList
->mNext
;
12336 altList
->mValue
= funcValue
;
12337 } else if (nsCSSProps::FindKeyword(keyword
,
12338 nsCSSProps::kFontVariantCapsKTable
,
12340 if (capsFeatures
!= 0) {
12341 // multiple values for font-variant-caps
12345 capsFeatures
= feature
;
12346 } else if (nsCSSProps::FindKeyword(keyword
,
12347 nsCSSProps::kFontVariantAlternatesKTable
,
12349 if (feature
& altFeatures
) {
12350 // same value repeated
12354 altFeatures
|= feature
;
12355 } else if (nsCSSProps::FindKeyword(keyword
,
12356 nsCSSProps::kFontVariantEastAsianKTable
,
12358 if (!MergeBitmaskValue(feature
, maskEastAsian
, eastAsianFeatures
)) {
12359 // multiple mutually exclusive values
12363 } else if (nsCSSProps::FindKeyword(keyword
,
12364 nsCSSProps::kFontVariantLigaturesKTable
,
12366 if (keyword
== eCSSKeyword_none
||
12367 !MergeBitmaskValue(feature
, maskLigatures
, ligFeatures
)) {
12368 // none or multiple mutually exclusive values
12372 } else if (nsCSSProps::FindKeyword(keyword
,
12373 nsCSSProps::kFontVariantNumericKTable
,
12375 if (!MergeBitmaskValue(feature
, maskNumeric
, numericFeatures
)) {
12376 // multiple mutually exclusive values
12380 } else if (nsCSSProps::FindKeyword(keyword
,
12381 nsCSSProps::kFontVariantPositionKTable
,
12383 if (posFeatures
!= 0) {
12384 // multiple values for font-variant-caps
12388 posFeatures
= feature
;
12390 // bogus keyword, bail...
12403 nsCSSValue featureValue
;
12404 featureValue
.SetIntValue(altFeatures
, eCSSUnit_Enumerated
);
12405 value
.SetPairValue(featureValue
, altListValue
);
12406 AppendValue(eCSSProperty_font_variant_alternates
, value
);
12408 AppendValue(eCSSProperty_font_variant_alternates
, normal
);
12411 if (capsFeatures
) {
12412 value
.SetIntValue(capsFeatures
, eCSSUnit_Enumerated
);
12413 AppendValue(eCSSProperty_font_variant_caps
, value
);
12415 AppendValue(eCSSProperty_font_variant_caps
, normal
);
12418 if (eastAsianFeatures
) {
12419 value
.SetIntValue(eastAsianFeatures
, eCSSUnit_Enumerated
);
12420 AppendValue(eCSSProperty_font_variant_east_asian
, value
);
12422 AppendValue(eCSSProperty_font_variant_east_asian
, normal
);
12426 value
.SetIntValue(ligFeatures
, eCSSUnit_Enumerated
);
12427 AppendValue(eCSSProperty_font_variant_ligatures
, value
);
12429 AppendValue(eCSSProperty_font_variant_ligatures
, normal
);
12432 if (numericFeatures
) {
12433 value
.SetIntValue(numericFeatures
, eCSSUnit_Enumerated
);
12434 AppendValue(eCSSProperty_font_variant_numeric
, value
);
12436 AppendValue(eCSSProperty_font_variant_numeric
, normal
);
12440 value
.SetIntValue(posFeatures
, eCSSUnit_Enumerated
);
12441 AppendValue(eCSSProperty_font_variant_position
, value
);
12443 AppendValue(eCSSProperty_font_variant_position
, normal
);
12450 CSSParserImpl::ParseFontWeight(nsCSSValue
& aValue
)
12452 if (ParseVariant(aValue
, VARIANT_HKI
| VARIANT_SYSFONT
,
12453 nsCSSProps::kFontWeightKTable
)) {
12454 if (eCSSUnit_Integer
== aValue
.GetUnit()) { // ensure unit value
12455 int32_t intValue
= aValue
.GetIntValue();
12456 if ((100 <= intValue
) &&
12457 (intValue
<= 900) &&
12458 (0 == (intValue
% 100))) {
12471 CSSParserImpl::ParseOneFamily(nsAString
& aFamily
,
12475 if (!GetToken(true))
12478 nsCSSToken
* tk
= &mToken
;
12480 aOneKeyword
= false;
12482 if (eCSSToken_Ident
== tk
->mType
) {
12483 aOneKeyword
= true;
12484 aFamily
.Append(tk
->mIdent
);
12486 if (!GetToken(false))
12489 if (eCSSToken_Ident
== tk
->mType
) {
12490 aOneKeyword
= false;
12491 // We had at least another keyword before.
12492 // "If a sequence of identifiers is given as a font family name,
12493 // the computed value is the name converted to a string by joining
12494 // all the identifiers in the sequence by single spaces."
12495 // -- CSS 2.1, section 15.3
12496 // Whitespace tokens do not actually matter,
12497 // identifier tokens can be separated by comments.
12498 aFamily
.Append(char16_t(' '));
12499 aFamily
.Append(tk
->mIdent
);
12500 } else if (eCSSToken_Whitespace
!= tk
->mType
) {
12507 } else if (eCSSToken_String
== tk
->mType
) {
12509 aFamily
.Append(tk
->mIdent
); // XXX What if it had escaped quotes?
12520 AppendGeneric(nsCSSKeyword aKeyword
, FontFamilyList
*aFamilyList
)
12522 switch (aKeyword
) {
12523 case eCSSKeyword_serif
:
12524 aFamilyList
->Append(FontFamilyName(eFamily_serif
));
12526 case eCSSKeyword_sans_serif
:
12527 aFamilyList
->Append(FontFamilyName(eFamily_sans_serif
));
12529 case eCSSKeyword_monospace
:
12530 aFamilyList
->Append(FontFamilyName(eFamily_monospace
));
12532 case eCSSKeyword_cursive
:
12533 aFamilyList
->Append(FontFamilyName(eFamily_cursive
));
12535 case eCSSKeyword_fantasy
:
12536 aFamilyList
->Append(FontFamilyName(eFamily_fantasy
));
12538 case eCSSKeyword__moz_fixed
:
12539 aFamilyList
->Append(FontFamilyName(eFamily_moz_fixed
));
12549 CSSParserImpl::ParseFamily(nsCSSValue
& aValue
)
12551 nsRefPtr
<css::FontFamilyListRefCnt
> familyList
=
12552 new css::FontFamilyListRefCnt();
12553 nsAutoString family
;
12554 bool single
, quoted
;
12556 // keywords only have meaning in the first position
12557 if (!ParseOneFamily(family
, single
, quoted
))
12560 // check for keywords, but only when keywords appear by themselves
12561 // i.e. not in compounds such as font-family: default blah;
12562 bool foundGeneric
= false;
12564 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(family
);
12566 case eCSSKeyword_inherit
:
12567 aValue
.SetInheritValue();
12569 case eCSSKeyword_default
:
12570 // 605231 - don't parse unquoted 'default' reserved keyword
12572 case eCSSKeyword_initial
:
12573 aValue
.SetInitialValue();
12575 case eCSSKeyword_unset
:
12576 if (nsLayoutUtils::UnsetValueEnabled()) {
12577 aValue
.SetUnsetValue();
12581 case eCSSKeyword__moz_use_system_font
:
12582 if (!IsParsingCompoundProperty()) {
12583 aValue
.SetSystemFontValue();
12588 foundGeneric
= AppendGeneric(keyword
, familyList
);
12592 if (!foundGeneric
) {
12593 familyList
->Append(
12594 FontFamilyName(family
, (quoted
? eQuotedName
: eUnquotedName
)));
12598 if (!ExpectSymbol(',', true))
12601 nsAutoString nextFamily
;
12602 if (!ParseOneFamily(nextFamily
, single
, quoted
))
12605 // at this point unquoted keywords are not allowed
12606 // as font family names but can appear within names
12607 foundGeneric
= false;
12609 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(nextFamily
);
12611 case eCSSKeyword_inherit
:
12612 case eCSSKeyword_initial
:
12613 case eCSSKeyword_default
:
12614 case eCSSKeyword__moz_use_system_font
:
12616 case eCSSKeyword_unset
:
12617 if (nsLayoutUtils::UnsetValueEnabled()) {
12622 foundGeneric
= AppendGeneric(keyword
, familyList
);
12627 if (!foundGeneric
) {
12628 familyList
->Append(
12629 FontFamilyName(nextFamily
, (quoted
? eQuotedName
: eUnquotedName
)));
12633 if (familyList
->IsEmpty()) {
12637 aValue
.SetFontFamilyListValue(familyList
);
12641 // src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )*
12642 // uri-src: uri [ 'format(' string ( ',' string )* ')' ]
12643 // local-src: 'local(' ( string | ident ) ')'
12646 CSSParserImpl::ParseFontSrc(nsCSSValue
& aValue
)
12648 // could we maybe turn nsCSSValue::Array into InfallibleTArray<nsCSSValue>?
12649 InfallibleTArray
<nsCSSValue
> values
;
12652 if (!GetToken(true))
12655 if (mToken
.mType
== eCSSToken_URL
) {
12656 SetValueToURL(cur
, mToken
.mIdent
);
12657 values
.AppendElement(cur
);
12658 if (!ParseFontSrcFormat(values
))
12661 } else if (mToken
.mType
== eCSSToken_Function
&&
12662 mToken
.mIdent
.LowerCaseEqualsLiteral("local")) {
12663 // css3-fonts does not specify a formal grammar for local().
12664 // The text permits both unquoted identifiers and quoted
12665 // strings. We resolve this ambiguity in the spec by
12666 // assuming that the appropriate production is a single
12667 // <family-name>, possibly surrounded by whitespace.
12669 nsAutoString family
;
12670 bool single
, quoted
;
12671 if (!ParseOneFamily(family
, single
, quoted
)) {
12675 if (!ExpectSymbol(')', true)) {
12682 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(family
);
12684 case eCSSKeyword_serif
:
12685 case eCSSKeyword_sans_serif
:
12686 case eCSSKeyword_monospace
:
12687 case eCSSKeyword_cursive
:
12688 case eCSSKeyword_fantasy
:
12689 case eCSSKeyword__moz_fixed
:
12696 cur
.SetStringValue(family
, eCSSUnit_Local_Font
);
12697 values
.AppendElement(cur
);
12699 // We don't know what to do with this token; unget it and error out
12704 if (!ExpectSymbol(',', true))
12708 if (values
.Length() == 0)
12711 nsRefPtr
<nsCSSValue::Array
> srcVals
12712 = nsCSSValue::Array::Create(values
.Length());
12715 for (i
= 0; i
< values
.Length(); i
++)
12716 srcVals
->Item(i
) = values
[i
];
12717 aValue
.SetArrayValue(srcVals
, eCSSUnit_Array
);
12722 CSSParserImpl::ParseFontSrcFormat(InfallibleTArray
<nsCSSValue
> & values
)
12724 if (!GetToken(true))
12725 return true; // EOF harmless here
12726 if (mToken
.mType
!= eCSSToken_Function
||
12727 !mToken
.mIdent
.LowerCaseEqualsLiteral("format")) {
12733 if (!GetToken(true))
12734 return false; // EOF - no need for SkipUntil
12736 if (mToken
.mType
!= eCSSToken_String
) {
12742 nsCSSValue
cur(mToken
.mIdent
, eCSSUnit_Font_Format
);
12743 values
.AppendElement(cur
);
12744 } while (ExpectSymbol(',', true));
12746 if (!ExpectSymbol(')', true)) {
12754 // font-ranges: urange ( ',' urange )*
12756 CSSParserImpl::ParseFontRanges(nsCSSValue
& aValue
)
12758 InfallibleTArray
<uint32_t> ranges
;
12760 if (!GetToken(true))
12763 if (mToken
.mType
!= eCSSToken_URange
) {
12768 // An invalid range token is a parsing error, causing the entire
12769 // descriptor to be ignored.
12770 if (!mToken
.mIntegerValid
)
12773 uint32_t low
= mToken
.mInteger
;
12774 uint32_t high
= mToken
.mInteger2
;
12776 // A range that descends, or a range that is entirely outside the
12777 // current range of Unicode (U+0-10FFFF) is ignored, but does not
12778 // invalidate the descriptor. A range that straddles the high end
12780 if (low
<= 0x10FFFF && low
<= high
) {
12781 if (high
> 0x10FFFF)
12784 ranges
.AppendElement(low
);
12785 ranges
.AppendElement(high
);
12787 if (!ExpectSymbol(',', true))
12791 if (ranges
.Length() == 0)
12794 nsRefPtr
<nsCSSValue::Array
> srcVals
12795 = nsCSSValue::Array::Create(ranges
.Length());
12797 for (uint32_t i
= 0; i
< ranges
.Length(); i
++)
12798 srcVals
->Item(i
).SetIntValue(ranges
[i
], eCSSUnit_Integer
);
12799 aValue
.SetArrayValue(srcVals
, eCSSUnit_Array
);
12803 // font-feature-settings: normal | <feature-tag-value> [, <feature-tag-value>]*
12804 // <feature-tag-value> = <string> [ <integer> | on | off ]?
12806 // minimum - "tagx", "tagy", "tagz"
12807 // edge error case - "tagx" on 1, "tagx" "tagy", "tagx" -1, "tagx" big
12809 // pair value is always x = string, y = int
12811 // font feature tags must be four ASCII characters
12812 #define FEATURE_TAG_LENGTH 4
12815 ValidFontFeatureTag(const nsString
& aTag
)
12817 if (aTag
.Length() != FEATURE_TAG_LENGTH
) {
12821 for (i
= 0; i
< FEATURE_TAG_LENGTH
; i
++) {
12822 uint32_t ch
= aTag
[i
];
12823 if (ch
< 0x20 || ch
> 0x7e) {
12831 CSSParserImpl::ParseFontFeatureSettings(nsCSSValue
& aValue
)
12833 if (ParseVariant(aValue
, VARIANT_INHERIT
| VARIANT_NORMAL
, nullptr)) {
12837 nsCSSValuePairList
*cur
= aValue
.SetPairListValue();
12840 if (!GetToken(true)) {
12844 if (mToken
.mType
!= eCSSToken_String
||
12845 !ValidFontFeatureTag(mToken
.mIdent
)) {
12849 cur
->mXValue
.SetStringValue(mToken
.mIdent
, eCSSUnit_String
);
12851 if (!GetToken(true)) {
12852 cur
->mYValue
.SetIntValue(1, eCSSUnit_Integer
);
12856 // optional value or on/off keyword
12857 if (mToken
.mType
== eCSSToken_Number
&& mToken
.mIntegerValid
&&
12858 mToken
.mInteger
>= 0) {
12859 cur
->mYValue
.SetIntValue(mToken
.mInteger
, eCSSUnit_Integer
);
12860 } else if (mToken
.mType
== eCSSToken_Ident
&&
12861 mToken
.mIdent
.LowerCaseEqualsLiteral("on")) {
12862 cur
->mYValue
.SetIntValue(1, eCSSUnit_Integer
);
12863 } else if (mToken
.mType
== eCSSToken_Ident
&&
12864 mToken
.mIdent
.LowerCaseEqualsLiteral("off")) {
12865 cur
->mYValue
.SetIntValue(0, eCSSUnit_Integer
);
12867 // something other than value/on/off, set default value
12868 cur
->mYValue
.SetIntValue(1, eCSSUnit_Integer
);
12872 if (!ExpectSymbol(',', true)) {
12876 cur
->mNext
= new nsCSSValuePairList
;
12884 CSSParserImpl::ParseListStyle()
12886 // 'list-style' can accept 'none' for two different subproperties,
12887 // 'list-style-type' and 'list-style-image'. In order to accept
12888 // 'none' as the value of either but still allow another value for
12889 // either, we need to ensure that the first 'none' we find gets
12890 // allocated to a dummy property instead. Since parse function for
12891 // 'list-style-type' could accept values for 'list-style-position',
12892 // we put position in front of type.
12893 static const nsCSSProperty listStyleIDs
[] = {
12894 eCSSPropertyExtra_x_none_value
,
12895 eCSSProperty_list_style_position
,
12896 eCSSProperty_list_style_type
,
12897 eCSSProperty_list_style_image
12900 nsCSSValue values
[MOZ_ARRAY_LENGTH(listStyleIDs
)];
12902 ParseChoice(values
, listStyleIDs
, ArrayLength(listStyleIDs
));
12907 if ((found
& (1|4|8)) == (1|4|8)) {
12908 if (values
[0].GetUnit() == eCSSUnit_None
) {
12909 // We found a 'none' plus another value for both of
12910 // 'list-style-type' and 'list-style-image'. This is a parse
12911 // error, since the 'none' has to count for at least one of them.
12914 NS_ASSERTION(found
== (1|2|4|8) && values
[0] == values
[1] &&
12915 values
[0] == values
[2] && values
[0] == values
[3],
12916 "should be a special value");
12920 if ((found
& 2) == 0) {
12921 values
[1].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE
,
12922 eCSSUnit_Enumerated
);
12924 if ((found
& 4) == 0) {
12925 // Provide default values
12926 nsString type
= (found
& 1) ?
12927 NS_LITERAL_STRING("none") : NS_LITERAL_STRING("disc");
12928 values
[2].SetStringValue(type
, eCSSUnit_Ident
);
12930 if ((found
& 8) == 0) {
12931 values
[3].SetNoneValue();
12934 // Start at 1 to avoid appending fake value.
12935 for (uint32_t index
= 1; index
< ArrayLength(listStyleIDs
); ++index
) {
12936 AppendValue(listStyleIDs
[index
], values
[index
]);
12942 CSSParserImpl::ParseListStyleType(nsCSSValue
& aValue
)
12944 if (ParseVariant(aValue
, VARIANT_INHERIT
, nullptr)) {
12948 if (ParseCounterStyleNameValue(aValue
) || ParseSymbols(aValue
)) {
12956 CSSParserImpl::ParseMargin()
12958 static const nsCSSProperty kMarginSideIDs
[] = {
12959 eCSSProperty_margin_top
,
12960 eCSSProperty_margin_right_value
,
12961 eCSSProperty_margin_bottom
,
12962 eCSSProperty_margin_left_value
12964 static const nsCSSProperty kMarginSources
[] = {
12965 eCSSProperty_margin_left_ltr_source
,
12966 eCSSProperty_margin_left_rtl_source
,
12967 eCSSProperty_margin_right_ltr_source
,
12968 eCSSProperty_margin_right_rtl_source
,
12969 eCSSProperty_UNKNOWN
12972 // do this now, in case 4 values weren't specified
12973 InitBoxPropsAsPhysical(kMarginSources
);
12974 return ParseBoxProperties(kMarginSideIDs
);
12978 CSSParserImpl::ParseMarks(nsCSSValue
& aValue
)
12980 if (ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kPageMarksKTable
)) {
12981 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
12982 if (NS_STYLE_PAGE_MARKS_NONE
!= aValue
.GetIntValue() &&
12983 false == CheckEndProperty()) {
12985 if (ParseEnum(second
, nsCSSProps::kPageMarksKTable
)) {
12986 // 'none' keyword in conjuction with others is not allowed
12987 if (NS_STYLE_PAGE_MARKS_NONE
!= second
.GetIntValue()) {
12988 aValue
.SetIntValue(aValue
.GetIntValue() | second
.GetIntValue(),
12989 eCSSUnit_Enumerated
);
13002 CSSParserImpl::ParseObjectPosition()
13005 if (!ParseVariant(value
, VARIANT_INHERIT
, nullptr) &&
13006 !ParsePositionValue(value
)) {
13009 AppendValue(eCSSProperty_object_position
, value
);
13014 CSSParserImpl::ParseOutline()
13016 const int32_t numProps
= 3;
13017 static const nsCSSProperty kOutlineIDs
[] = {
13018 eCSSProperty_outline_color
,
13019 eCSSProperty_outline_style
,
13020 eCSSProperty_outline_width
13023 nsCSSValue values
[numProps
];
13024 int32_t found
= ParseChoice(values
, kOutlineIDs
, numProps
);
13029 // Provide default values
13030 if ((found
& 1) == 0) { // Provide default outline-color
13031 values
[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
, eCSSUnit_Enumerated
);
13033 if ((found
& 2) == 0) { // Provide default outline-style
13034 values
[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE
, eCSSUnit_Enumerated
);
13036 if ((found
& 4) == 0) { // Provide default outline-width
13037 values
[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM
, eCSSUnit_Enumerated
);
13041 for (index
= 0; index
< numProps
; index
++) {
13042 AppendValue(kOutlineIDs
[index
], values
[index
]);
13048 CSSParserImpl::ParseOverflow()
13050 nsCSSValue overflow
;
13051 if (!ParseVariant(overflow
, VARIANT_HK
, nsCSSProps::kOverflowKTable
)) {
13055 nsCSSValue
overflowX(overflow
);
13056 nsCSSValue
overflowY(overflow
);
13057 if (eCSSUnit_Enumerated
== overflow
.GetUnit())
13058 switch(overflow
.GetIntValue()) {
13059 case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL
:
13060 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
13061 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
13063 case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL
:
13064 overflowX
.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN
, eCSSUnit_Enumerated
);
13065 overflowY
.SetIntValue(NS_STYLE_OVERFLOW_SCROLL
, eCSSUnit_Enumerated
);
13068 AppendValue(eCSSProperty_overflow_x
, overflowX
);
13069 AppendValue(eCSSProperty_overflow_y
, overflowY
);
13074 CSSParserImpl::ParsePadding()
13076 static const nsCSSProperty kPaddingSideIDs
[] = {
13077 eCSSProperty_padding_top
,
13078 eCSSProperty_padding_right_value
,
13079 eCSSProperty_padding_bottom
,
13080 eCSSProperty_padding_left_value
13082 static const nsCSSProperty kPaddingSources
[] = {
13083 eCSSProperty_padding_left_ltr_source
,
13084 eCSSProperty_padding_left_rtl_source
,
13085 eCSSProperty_padding_right_ltr_source
,
13086 eCSSProperty_padding_right_rtl_source
,
13087 eCSSProperty_UNKNOWN
13090 // do this now, in case 4 values weren't specified
13091 InitBoxPropsAsPhysical(kPaddingSources
);
13092 return ParseBoxProperties(kPaddingSideIDs
);
13096 CSSParserImpl::ParseQuotes()
13099 if (!ParseVariant(value
, VARIANT_HOS
, nullptr)) {
13102 if (value
.GetUnit() == eCSSUnit_String
) {
13103 nsCSSValue open
= value
;
13104 nsCSSValuePairList
* quotes
= value
.SetPairListValue();
13106 quotes
->mXValue
= open
;
13107 // get mandatory close
13108 if (!ParseVariant(quotes
->mYValue
, VARIANT_STRING
, nullptr)) {
13111 // look for another open
13112 if (!ParseVariant(open
, VARIANT_STRING
, nullptr)) {
13115 quotes
->mNext
= new nsCSSValuePairList
;
13116 quotes
= quotes
->mNext
;
13119 AppendValue(eCSSProperty_quotes
, value
);
13123 static const int32_t gRubyPositionMask
[] = {
13125 NS_STYLE_RUBY_POSITION_OVER
|
13126 NS_STYLE_RUBY_POSITION_UNDER
|
13127 NS_STYLE_RUBY_POSITION_INTER_CHARACTER
,
13128 // horizontal values
13129 NS_STYLE_RUBY_POSITION_RIGHT
|
13130 NS_STYLE_RUBY_POSITION_LEFT
,
13136 CSSParserImpl::ParseRubyPosition(nsCSSValue
& aValue
)
13138 if (ParseVariant(aValue
, VARIANT_INHERIT
, nullptr)) {
13141 if (!ParseBitmaskValues(aValue
, nsCSSProps::kRubyPositionKTable
,
13142 gRubyPositionMask
)) {
13145 auto value
= aValue
.GetIntValue();
13146 // The specified value must include *both* a vertical keyword *and*
13147 // a horizontal keyword. We reject it here if either is missing.
13148 return (value
& gRubyPositionMask
[0]) && (value
& gRubyPositionMask
[1]);
13152 CSSParserImpl::ParseSize()
13154 nsCSSValue width
, height
;
13155 if (!ParseVariant(width
, VARIANT_AHKL
, nsCSSProps::kPageSizeKTable
)) {
13158 if (width
.IsLengthUnit()) {
13159 ParseVariant(height
, VARIANT_LENGTH
, nullptr);
13162 if (width
== height
|| height
.GetUnit() == eCSSUnit_Null
) {
13163 AppendValue(eCSSProperty_size
, width
);
13166 pair
.SetPairValue(width
, height
);
13167 AppendValue(eCSSProperty_size
, pair
);
13173 CSSParserImpl::ParseTextDecoration()
13175 static const nsCSSProperty kTextDecorationIDs
[] = {
13176 eCSSProperty_text_decoration_line
,
13177 eCSSProperty_text_decoration_style
,
13178 eCSSProperty_text_decoration_color
13180 const int32_t numProps
= MOZ_ARRAY_LENGTH(kTextDecorationIDs
);
13181 nsCSSValue values
[numProps
];
13183 int32_t found
= ParseChoice(values
, kTextDecorationIDs
, numProps
);
13188 // Provide default values
13189 if ((found
& 1) == 0) { // Provide default text-decoration-line
13190 values
[0].SetIntValue(NS_STYLE_TEXT_DECORATION_LINE_NONE
,
13191 eCSSUnit_Enumerated
);
13193 if ((found
& 2) == 0) { // Provide default text-decoration-style
13194 values
[1].SetIntValue(NS_STYLE_TEXT_DECORATION_STYLE_SOLID
,
13195 eCSSUnit_Enumerated
);
13197 if ((found
& 4) == 0) { // Provide default text-decoration-color
13198 values
[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
,
13199 eCSSUnit_Enumerated
);
13202 for (int32_t index
= 0; index
< numProps
; index
++) {
13203 AppendValue(kTextDecorationIDs
[index
], values
[index
]);
13209 CSSParserImpl::ParseTextAlign(nsCSSValue
& aValue
, const KTableValue aTable
[])
13211 if (ParseVariant(aValue
, VARIANT_INHERIT
, nullptr)) {
13212 // 'inherit', 'initial' and 'unset' must be alone
13217 if (!ParseVariant(left
, VARIANT_KEYWORD
, aTable
)) {
13221 if (!nsLayoutUtils::IsTextAlignTrueValueEnabled()) {
13227 if (ParseVariant(right
, VARIANT_KEYWORD
, aTable
)) {
13228 // 'true' must be combined with some other value than 'true'.
13229 if (left
.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE
&&
13230 right
.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE
) {
13233 aValue
.SetPairValue(left
, right
);
13235 // Single value 'true' is not allowed.
13236 if (left
.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE
) {
13245 CSSParserImpl::ParseTextAlign(nsCSSValue
& aValue
)
13247 return ParseTextAlign(aValue
, nsCSSProps::kTextAlignKTable
);
13251 CSSParserImpl::ParseTextAlignLast(nsCSSValue
& aValue
)
13253 return ParseTextAlign(aValue
, nsCSSProps::kTextAlignLastKTable
);
13257 CSSParserImpl::ParseTextDecorationLine(nsCSSValue
& aValue
)
13259 static_assert((NS_STYLE_TEXT_DECORATION_LINE_NONE
^
13260 NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE
^
13261 NS_STYLE_TEXT_DECORATION_LINE_OVERLINE
^
13262 NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH
^
13263 NS_STYLE_TEXT_DECORATION_LINE_BLINK
^
13264 NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS
) ==
13265 (NS_STYLE_TEXT_DECORATION_LINE_NONE
|
13266 NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE
|
13267 NS_STYLE_TEXT_DECORATION_LINE_OVERLINE
|
13268 NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH
|
13269 NS_STYLE_TEXT_DECORATION_LINE_BLINK
|
13270 NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS
),
13271 "text decoration constants need to be bitmasks");
13272 if (ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kTextDecorationLineKTable
)) {
13273 if (eCSSUnit_Enumerated
== aValue
.GetUnit()) {
13274 int32_t intValue
= aValue
.GetIntValue();
13275 if (intValue
!= NS_STYLE_TEXT_DECORATION_LINE_NONE
) {
13276 // look for more keywords
13277 nsCSSValue keyword
;
13279 for (index
= 0; index
< 3; index
++) {
13280 if (ParseEnum(keyword
, nsCSSProps::kTextDecorationLineKTable
)) {
13281 int32_t newValue
= keyword
.GetIntValue();
13282 if (newValue
== NS_STYLE_TEXT_DECORATION_LINE_NONE
||
13283 newValue
& intValue
) {
13284 // 'none' keyword in conjuction with others is not allowed, and
13285 // duplicate keyword is not allowed.
13288 intValue
|= newValue
;
13294 aValue
.SetIntValue(intValue
, eCSSUnit_Enumerated
);
13303 CSSParserImpl::ParseTextOverflow(nsCSSValue
& aValue
)
13305 if (ParseVariant(aValue
, VARIANT_INHERIT
, nullptr)) {
13306 // 'inherit', 'initial' and 'unset' must be alone
13311 if (!ParseVariant(left
, VARIANT_KEYWORD
| VARIANT_STRING
,
13312 nsCSSProps::kTextOverflowKTable
))
13316 if (ParseVariant(right
, VARIANT_KEYWORD
| VARIANT_STRING
,
13317 nsCSSProps::kTextOverflowKTable
))
13318 aValue
.SetPairValue(left
, right
);
13326 CSSParserImpl::ParseTouchAction(nsCSSValue
& aValue
)
13328 // Avaliable values of property touch-action:
13329 // auto | none | [pan-x || pan-y] | manipulation
13331 if (!ParseVariant(aValue
, VARIANT_HK
, nsCSSProps::kTouchActionKTable
)) {
13335 // Auto and None keywords aren't allowed in conjunction with others.
13336 // Also inherit, initial and unset values are available.
13337 if (eCSSUnit_Enumerated
!= aValue
.GetUnit()) {
13341 int32_t intValue
= aValue
.GetIntValue();
13342 nsCSSValue nextValue
;
13343 if (ParseEnum(nextValue
, nsCSSProps::kTouchActionKTable
)) {
13344 int32_t nextIntValue
= nextValue
.GetIntValue();
13346 // duplicates aren't allowed.
13347 if (nextIntValue
& intValue
) {
13351 // Auto and None and Manipulation is not allowed in conjunction with others.
13352 if ((intValue
| nextIntValue
) & (NS_STYLE_TOUCH_ACTION_NONE
|
13353 NS_STYLE_TOUCH_ACTION_AUTO
|
13354 NS_STYLE_TOUCH_ACTION_MANIPULATION
)) {
13358 aValue
.SetIntValue(nextIntValue
| intValue
, eCSSUnit_Enumerated
);
13365 CSSParserImpl::ParseTextCombineUpright(nsCSSValue
& aValue
)
13367 if (!ParseVariant(aValue
, VARIANT_HK
,
13368 nsCSSProps::kTextCombineUprightKTable
)) {
13372 // if 'digits', need to check for an explicit number [2, 3, 4]
13373 if (eCSSUnit_Enumerated
== aValue
.GetUnit() &&
13374 aValue
.GetIntValue() == NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2
) {
13375 if (!GetToken(true)) {
13378 if (mToken
.mType
== eCSSToken_Number
&& mToken
.mIntegerValid
) {
13379 switch (mToken
.mInteger
) {
13380 case 2: // already set, nothing to do
13383 aValue
.SetIntValue(NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3
,
13384 eCSSUnit_Enumerated
);
13387 aValue
.SetIntValue(NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_4
,
13388 eCSSUnit_Enumerated
);
13391 // invalid digits value
13401 ///////////////////////////////////////////////////////
13402 // transform Parsing Implementation
13404 /* Reads a function list of arguments and consumes the closing parenthesis.
13405 * Do not call this function directly; it's meant to be called from
13409 CSSParserImpl::ParseFunctionInternals(const int32_t aVariantMask
[],
13410 int32_t aVariantMaskAll
,
13411 uint16_t aMinElems
,
13412 uint16_t aMaxElems
,
13413 InfallibleTArray
<nsCSSValue
> &aOutput
)
13415 NS_ASSERTION((aVariantMask
&& !aVariantMaskAll
) ||
13416 (!aVariantMask
&& aVariantMaskAll
),
13417 "only one of the two variant mask parameters can be set");
13419 for (uint16_t index
= 0; index
< aMaxElems
; ++index
) {
13420 nsCSSValue newValue
;
13421 int32_t m
= aVariantMaskAll
? aVariantMaskAll
: aVariantMask
[index
];
13422 if (!ParseVariant(newValue
, m
, nullptr)) {
13426 aOutput
.AppendElement(newValue
);
13428 if (ExpectSymbol(',', true)) {
13429 // Move on to the next argument if we see a comma.
13433 if (ExpectSymbol(')', true)) {
13434 // Make sure we've read enough symbols if we see a closing parenthesis.
13435 return (index
+ 1) >= aMinElems
;
13438 // Only a comma or a closing parenthesis is valid after an argument.
13442 // If we're here, we've hit an error without seeing a closing parenthesis or
13443 // we've read too many elements without seeing a closing parenthesis.
13448 /* Parses a function [ input of the form (a [, b]*) ] and stores it
13449 * as an nsCSSValue that holds a function of the form
13450 * function-name arg1 arg2 ... argN
13452 * On error, the return value is false.
13454 * @param aFunction The name of the function that we're reading.
13455 * @param aAllowedTypes An array of values corresponding to the legal
13456 * types for each element in the function. The zeroth element in the
13457 * array corresponds to the first function parameter, etc. The length
13458 * of this array _must_ be greater than or equal to aMaxElems or the
13459 * behavior is undefined. If not null, aAllowTypesAll must be 0.
13460 * @param aAllowedTypesAll If set, every element tested for these types
13461 * @param aMinElems Minimum number of elements to read. Reading fewer than
13462 * this many elements will result in the function failing.
13463 * @param aMaxElems Maximum number of elements to read. Reading more than
13464 * this many elements will result in the function failing.
13465 * @param aValue (out) The value that was parsed.
13468 CSSParserImpl::ParseFunction(nsCSSKeyword aFunction
,
13469 const int32_t aAllowedTypes
[],
13470 int32_t aAllowedTypesAll
,
13471 uint16_t aMinElems
, uint16_t aMaxElems
,
13472 nsCSSValue
&aValue
)
13474 NS_ASSERTION((aAllowedTypes
&& !aAllowedTypesAll
) ||
13475 (!aAllowedTypes
&& aAllowedTypesAll
),
13476 "only one of the two allowed type parameter can be set");
13477 typedef InfallibleTArray
<nsCSSValue
>::size_type arrlen_t
;
13479 /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
13480 * elements stored in the the nsCSSValue::Array.
13482 static const arrlen_t MAX_ALLOWED_ELEMS
= 0xFFFE;
13484 /* Read in a list of values as an array, failing if we can't or if
13485 * it's out of bounds.
13487 * We reserve 16 entries in the foundValues array in order to avoid
13488 * having to resize the array dynamically when parsing some well-formed
13489 * functions. The number 16 is coming from the number of arguments that
13490 * matrix3d() accepts.
13492 AutoInfallibleTArray
<nsCSSValue
, 16> foundValues
;
13493 if (!ParseFunctionInternals(aAllowedTypes
, aAllowedTypesAll
, aMinElems
,
13494 aMaxElems
, foundValues
)) {
13499 * In case the user has given us more than 2^16 - 2 arguments,
13500 * we'll truncate them at 2^16 - 2 arguments.
13502 uint16_t numArgs
= std::min(foundValues
.Length(), MAX_ALLOWED_ELEMS
);
13503 nsRefPtr
<nsCSSValue::Array
> convertedArray
=
13504 aValue
.InitFunction(aFunction
, numArgs
);
13506 /* Copy things over. */
13507 for (uint16_t index
= 0; index
< numArgs
; ++index
)
13508 convertedArray
->Item(index
+ 1) = foundValues
[static_cast<arrlen_t
>(index
)];
13515 * Given a token, determines the minimum and maximum number of function
13516 * parameters to read, along with the mask that should be used to read
13517 * those function parameters. If the token isn't a transform function,
13518 * returns an error.
13520 * @param aToken The token identifying the function.
13521 * @param aMinElems [out] The minimum number of elements to read.
13522 * @param aMaxElems [out] The maximum number of elements to read
13523 * @param aVariantMask [out] The variant mask to use during parsing
13524 * @return Whether the information was loaded successfully.
13526 static bool GetFunctionParseInformation(nsCSSKeyword aToken
,
13528 uint16_t &aMinElems
,
13529 uint16_t &aMaxElems
,
13530 const int32_t *& aVariantMask
)
13532 /* These types represent the common variant masks that will be used to
13533 * parse out the individual functions. The order in the enumeration
13534 * must match the order in which the masks are declared.
13536 enum { eLengthPercentCalc
,
13538 eTwoLengthPercentCalcs
,
13539 eTwoLengthPercentCalcsOneLengthCalc
,
13546 eThreeNumbersOneAngle
,
13551 eNumVariantMasks
};
13552 static const int32_t kMaxElemsPerFunction
= 16;
13553 static const int32_t kVariantMasks
[eNumVariantMasks
][kMaxElemsPerFunction
] = {
13555 {VARIANT_LENGTH
|VARIANT_CALC
},
13556 {VARIANT_LPCALC
, VARIANT_LPCALC
},
13557 {VARIANT_LPCALC
, VARIANT_LPCALC
, VARIANT_LENGTH
|VARIANT_CALC
},
13558 {VARIANT_ANGLE_OR_ZERO
},
13559 {VARIANT_ANGLE_OR_ZERO
, VARIANT_ANGLE_OR_ZERO
},
13561 {VARIANT_LENGTH
|VARIANT_POSITIVE_DIMENSION
},
13562 {VARIANT_NUMBER
, VARIANT_NUMBER
},
13563 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
},
13564 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_ANGLE_OR_ZERO
},
13565 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13566 VARIANT_NUMBER
, VARIANT_NUMBER
},
13567 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13568 VARIANT_LPNCALC
, VARIANT_LPNCALC
},
13569 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13570 VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13571 VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13572 VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
},
13573 {VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13574 VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13575 VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
, VARIANT_NUMBER
,
13576 VARIANT_LPNCALC
, VARIANT_LPNCALC
, VARIANT_LNCALC
, VARIANT_NUMBER
}};
13579 static const uint8_t kVariantMaskLengths
[eNumVariantMasks
] =
13580 {1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 6, 16, 16};
13583 int32_t variantIndex
= eNumVariantMasks
;
13586 case eCSSKeyword_translatex
:
13587 case eCSSKeyword_translatey
:
13588 /* Exactly one length or percent. */
13589 variantIndex
= eLengthPercentCalc
;
13593 case eCSSKeyword_translatez
:
13594 /* Exactly one length */
13595 variantIndex
= eLengthCalc
;
13599 case eCSSKeyword_translate3d
:
13600 /* Exactly two lengthds or percents and a number */
13601 variantIndex
= eTwoLengthPercentCalcsOneLengthCalc
;
13605 case eCSSKeyword_scalez
:
13606 case eCSSKeyword_scalex
:
13607 case eCSSKeyword_scaley
:
13608 /* Exactly one scale factor. */
13609 variantIndex
= eNumber
;
13613 case eCSSKeyword_scale3d
:
13614 /* Exactly three scale factors. */
13615 variantIndex
= eThreeNumbers
;
13619 case eCSSKeyword_rotatex
:
13620 case eCSSKeyword_rotatey
:
13621 case eCSSKeyword_rotate
:
13622 case eCSSKeyword_rotatez
:
13623 /* Exactly one angle. */
13624 variantIndex
= eAngle
;
13628 case eCSSKeyword_rotate3d
:
13629 variantIndex
= eThreeNumbersOneAngle
;
13633 case eCSSKeyword_translate
:
13634 /* One or two lengths or percents. */
13635 variantIndex
= eTwoLengthPercentCalcs
;
13639 case eCSSKeyword_skew
:
13640 /* Exactly one or two angles. */
13641 variantIndex
= eTwoAngles
;
13645 case eCSSKeyword_scale
:
13646 /* One or two scale factors. */
13647 variantIndex
= eTwoNumbers
;
13651 case eCSSKeyword_skewx
:
13652 /* Exactly one angle. */
13653 variantIndex
= eAngle
;
13657 case eCSSKeyword_skewy
:
13658 /* Exactly one angle. */
13659 variantIndex
= eAngle
;
13663 case eCSSKeyword_matrix
:
13664 /* Six values, all numbers. */
13665 variantIndex
= aIsPrefixed
? eMatrixPrefixed
: eMatrix
;
13669 case eCSSKeyword_matrix3d
:
13670 /* 16 matrix values, all numbers */
13671 variantIndex
= aIsPrefixed
? eMatrix3dPrefixed
: eMatrix3d
;
13675 case eCSSKeyword_perspective
:
13676 /* Exactly one scale number. */
13677 variantIndex
= ePositiveLength
;
13682 /* Oh dear, we didn't match. Report an error. */
13686 NS_ASSERTION(aMinElems
> 0, "Didn't update minimum elements!");
13687 NS_ASSERTION(aMaxElems
> 0, "Didn't update maximum elements!");
13688 NS_ASSERTION(aMinElems
<= aMaxElems
, "aMinElems > aMaxElems!");
13689 NS_ASSERTION(variantIndex
>= 0, "Invalid variant mask!");
13690 NS_ASSERTION(variantIndex
< eNumVariantMasks
, "Invalid variant mask!");
13692 NS_ASSERTION(aMaxElems
<= kVariantMaskLengths
[variantIndex
],
13693 "Invalid aMaxElems for this variant mask.");
13696 // Convert the index into a mask.
13697 aVariantMask
= kVariantMasks
[variantIndex
];
13702 bool CSSParserImpl::ParseWillChange()
13704 nsCSSValue listValue
;
13705 nsCSSValueList
* currentListValue
= listValue
.SetListValue();
13708 const uint32_t variantMask
= VARIANT_IDENTIFIER
|
13714 if (!ParseVariant(value
, variantMask
, nullptr)) {
13718 if (value
.GetUnit() == eCSSUnit_None
||
13719 value
.GetUnit() == eCSSUnit_All
)
13724 if (value
.GetUnit() != eCSSUnit_Ident
) {
13726 AppendValue(eCSSProperty_will_change
, value
);
13734 value
.GetStringValue(str
);
13735 if (str
.LowerCaseEqualsLiteral("default")) {
13739 currentListValue
->mValue
= value
;
13741 if (!ExpectSymbol(',', true)) {
13744 currentListValue
->mNext
= new nsCSSValueList
;
13745 currentListValue
= currentListValue
->mNext
;
13749 AppendValue(eCSSProperty_will_change
, listValue
);
13753 /* Reads a single transform function from the tokenizer stream, reporting an
13754 * error if something goes wrong.
13757 CSSParserImpl::ParseSingleTransform(bool aIsPrefixed
, nsCSSValue
& aValue
)
13759 if (!GetToken(true))
13762 if (mToken
.mType
!= eCSSToken_Function
) {
13767 const int32_t* variantMask
;
13768 uint16_t minElems
, maxElems
;
13769 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
13771 if (!GetFunctionParseInformation(keyword
, aIsPrefixed
,
13772 minElems
, maxElems
, variantMask
))
13775 return ParseFunction(keyword
, variantMask
, 0, minElems
, maxElems
, aValue
);
13778 /* Parses a transform property list by continuously reading in properties
13779 * and constructing a matrix from it.
13781 bool CSSParserImpl::ParseTransform(bool aIsPrefixed
)
13784 // 'inherit', 'initial', 'unset' and 'none' must be alone
13785 if (!ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
13786 nsCSSValueSharedList
* list
= new nsCSSValueSharedList
;
13787 value
.SetSharedListValue(list
);
13788 list
->mHead
= new nsCSSValueList
;
13789 nsCSSValueList
* cur
= list
->mHead
;
13791 if (!ParseSingleTransform(aIsPrefixed
, cur
->mValue
)) {
13794 if (CheckEndProperty()) {
13797 cur
->mNext
= new nsCSSValueList
;
13801 AppendValue(eCSSProperty_transform
, value
);
13805 /* Reads a polygon function's argument list.
13808 CSSParserImpl::ParsePolygonFunction(nsCSSValue
& aValue
)
13810 uint16_t numArgs
= 1;
13812 nsCSSValue fillRuleValue
;
13813 if (ParseEnum(fillRuleValue
, nsCSSProps::kFillRuleKTable
)) {
13816 // The fill-rule must be comma separated from the polygon points.
13817 if (!ExpectSymbol(',', true)) {
13818 REPORT_UNEXPECTED_TOKEN(PEExpectedComma
);
13824 nsCSSValue coordinates
;
13825 nsCSSValuePairList
* item
= coordinates
.SetPairListValue();
13827 nsCSSValue xValue
, yValue
;
13828 if (!ParseVariant(xValue
, VARIANT_LPCALC
, nullptr) ||
13829 !ParseVariant(yValue
, VARIANT_LPCALC
, nullptr)) {
13830 REPORT_UNEXPECTED_TOKEN(PECoordinatePair
);
13834 item
->mXValue
= xValue
;
13835 item
->mYValue
= yValue
;
13837 // See whether to continue or whether to look for end of function.
13838 if (!ExpectSymbol(',', true)) {
13839 // We need to read the closing parenthesis.
13840 if (!ExpectSymbol(')', true)) {
13841 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
13847 item
->mNext
= new nsCSSValuePairList
;
13848 item
= item
->mNext
;
13851 nsRefPtr
<nsCSSValue::Array
> functionArray
=
13852 aValue
.InitFunction(eCSSKeyword_polygon
, numArgs
);
13853 functionArray
->Item(numArgs
) = coordinates
;
13855 functionArray
->Item(1) = fillRuleValue
;
13862 CSSParserImpl::ParseCircleOrEllipseFunction(nsCSSKeyword aKeyword
,
13863 nsCSSValue
& aValue
)
13865 nsCSSValue radiusX
, radiusY
, position
;
13866 bool hasRadius
= false, hasPosition
= false;
13868 int32_t mask
= VARIANT_LPCALC
| VARIANT_NONNEGATIVE_DIMENSION
|
13870 if (ParseVariant(radiusX
, mask
, nsCSSProps::kShapeRadiusKTable
)) {
13871 if (aKeyword
== eCSSKeyword_ellipse
) {
13872 if (!ParseVariant(radiusY
, mask
, nsCSSProps::kShapeRadiusKTable
)) {
13873 REPORT_UNEXPECTED_TOKEN(PEExpectedRadius
);
13881 if (!ExpectSymbol(')', true)) {
13882 if (!GetToken(true)) {
13883 REPORT_UNEXPECTED_EOF(PEPositionEOF
);
13887 if (mToken
.mType
!= eCSSToken_Ident
||
13888 !mToken
.mIdent
.LowerCaseEqualsLiteral("at") ||
13889 !ParsePositionValue(position
)) {
13890 REPORT_UNEXPECTED_TOKEN(PEExpectedPosition
);
13894 if (!ExpectSymbol(')', true)) {
13895 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
13899 hasPosition
= true;
13902 size_t count
= aKeyword
== eCSSKeyword_circle
? 2 : 3;
13903 nsRefPtr
<nsCSSValue::Array
> functionArray
=
13904 aValue
.InitFunction(aKeyword
, count
);
13906 functionArray
->Item(1) = radiusX
;
13907 if (aKeyword
== eCSSKeyword_ellipse
) {
13908 functionArray
->Item(2) = radiusY
;
13912 functionArray
->Item(count
) = position
;
13919 CSSParserImpl::ParseInsetFunction(nsCSSValue
& aValue
)
13921 nsRefPtr
<nsCSSValue::Array
> functionArray
=
13922 aValue
.InitFunction(eCSSKeyword_inset
, 5);
13924 if (ParseVariant(functionArray
->Item(1), VARIANT_LPCALC
, nullptr)) {
13925 // Consume up to 4, but only require one.
13926 ParseVariant(functionArray
->Item(2), VARIANT_LPCALC
, nullptr) &&
13927 ParseVariant(functionArray
->Item(3), VARIANT_LPCALC
, nullptr) &&
13928 ParseVariant(functionArray
->Item(4), VARIANT_LPCALC
, nullptr);
13930 REPORT_UNEXPECTED_TOKEN(PEExpectedShapeArg
);
13935 if (!ExpectSymbol(')', true)) {
13936 if (!GetToken(true)) {
13937 NS_NOTREACHED("ExpectSymbol should have returned true");
13941 nsRefPtr
<nsCSSValue::Array
> radiusArray
= nsCSSValue::Array::Create(4);
13942 functionArray
->Item(5).SetArrayValue(radiusArray
, eCSSUnit_Array
);
13943 if (mToken
.mType
!= eCSSToken_Ident
||
13944 !mToken
.mIdent
.LowerCaseEqualsLiteral("round") ||
13945 !ParseBoxCornerRadiiInternals(radiusArray
->ItemStorage())) {
13946 REPORT_UNEXPECTED_TOKEN(PEExpectedRadius
);
13951 if (!ExpectSymbol(')', true)) {
13952 REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen
);
13962 CSSParserImpl::ParseBasicShape(nsCSSValue
& aValue
, bool* aConsumedTokens
)
13964 if (!GetToken(true)) {
13968 if (mToken
.mType
!= eCSSToken_Function
) {
13973 // Specific shape function parsing always consumes tokens.
13974 *aConsumedTokens
= true;
13975 nsCSSKeyword keyword
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
13977 case eCSSKeyword_polygon
:
13978 return ParsePolygonFunction(aValue
);
13979 case eCSSKeyword_circle
:
13980 case eCSSKeyword_ellipse
:
13981 return ParseCircleOrEllipseFunction(keyword
, aValue
);
13982 case eCSSKeyword_inset
:
13983 return ParseInsetFunction(aValue
);
13989 /* Parse a clip-path url to a <clipPath> element or a basic shape. */
13990 bool CSSParserImpl::ParseClipPath()
13993 if (!ParseVariant(value
, VARIANT_HUO
, nullptr)) {
13994 if (!nsLayoutUtils::CSSClipPathShapesEnabled()) {
13995 // With CSS Clip Path Shapes disabled, we should only accept
13996 // SVG clipPath reference and none.
13997 REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURL
);
14001 nsCSSValueList
* cur
= value
.SetListValue();
14003 nsCSSValue referenceBox
;
14004 bool hasBox
= ParseEnum(referenceBox
, nsCSSProps::kClipShapeSizingKTable
);
14006 nsCSSValue basicShape
;
14007 bool basicShapeConsumedTokens
= false;
14008 bool hasShape
= ParseBasicShape(basicShape
, &basicShapeConsumedTokens
);
14010 // Parsing wasn't successful if ParseBasicShape consumed tokens but failed
14011 // or if the token was neither a reference box nor a basic shape.
14012 if ((!hasShape
&& basicShapeConsumedTokens
) || (!hasBox
&& !hasShape
)) {
14016 // We need to preserve the specified order of arguments for inline style.
14018 cur
->mValue
= referenceBox
;
14023 cur
->mNext
= new nsCSSValueList
;
14026 cur
->mValue
= basicShape
;
14029 // Check if the second argument is a reference box if the first wasn't.
14031 ParseEnum(referenceBox
, nsCSSProps::kClipShapeSizingKTable
)) {
14032 cur
->mNext
= new nsCSSValueList
;
14034 cur
->mValue
= referenceBox
;
14038 AppendValue(eCSSProperty_clip_path
, value
);
14042 bool CSSParserImpl::ParseTransformOrigin(bool aPerspective
)
14044 nsCSSValuePair position
;
14045 if (!ParseBoxPositionValues(position
, true))
14048 nsCSSProperty prop
= eCSSProperty_transform_origin
;
14049 if (aPerspective
) {
14050 prop
= eCSSProperty_perspective_origin
;
14053 // Unlike many other uses of pairs, this position should always be stored
14054 // as a pair, even if the values are the same, so it always serializes as
14055 // a pair, and to keep the computation code simple.
14056 if (position
.mXValue
.GetUnit() == eCSSUnit_Inherit
||
14057 position
.mXValue
.GetUnit() == eCSSUnit_Initial
||
14058 position
.mXValue
.GetUnit() == eCSSUnit_Unset
) {
14059 NS_ABORT_IF_FALSE(position
.mXValue
== position
.mYValue
,
14060 "inherit/initial/unset only half?");
14061 AppendValue(prop
, position
.mXValue
);
14064 if (aPerspective
) {
14065 value
.SetPairValue(position
.mXValue
, position
.mYValue
);
14068 if (!ParseVariant(depth
, VARIANT_LENGTH
| VARIANT_CALC
, nullptr)) {
14069 depth
.SetFloatValue(0.0f
, eCSSUnit_Pixel
);
14071 value
.SetTripletValue(position
.mXValue
, position
.mYValue
, depth
);
14074 AppendValue(prop
, value
);
14080 * Reads a drop-shadow value. At the moment the Filter Effects specification
14081 * just expects one shadow item. Should this ever change to a list of shadow
14082 * items, use ParseShadowList instead.
14085 CSSParserImpl::ParseDropShadow(nsCSSValue
* aValue
)
14087 // Use nsCSSValueList to reuse the shadow resolving code in
14088 // nsRuleNode and nsComputedDOMStyle.
14090 nsCSSValueList
* cur
= shadow
.SetListValue();
14091 if (!ParseShadowItem(cur
->mValue
, false))
14094 if (!ExpectSymbol(')', true))
14097 nsCSSValue::Array
* dropShadow
= aValue
->InitFunction(eCSSKeyword_drop_shadow
, 1);
14099 // Copy things over.
14100 dropShadow
->Item(1) = shadow
;
14106 * Reads a single url or filter function from the tokenizer stream, reporting an
14107 * error if something goes wrong.
14110 CSSParserImpl::ParseSingleFilter(nsCSSValue
* aValue
)
14112 if (ParseVariant(*aValue
, VARIANT_URL
, nullptr)) {
14116 if (!nsLayoutUtils::CSSFiltersEnabled()) {
14117 // With CSS Filters disabled, we should only accept an SVG reference filter.
14118 REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURL
);
14122 if (!GetToken(true)) {
14123 REPORT_UNEXPECTED_EOF(PEFilterEOF
);
14127 if (mToken
.mType
!= eCSSToken_Function
) {
14128 REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURLOrFilterFunction
);
14133 nsCSSKeyword functionName
= nsCSSKeywords::LookupKeyword(mToken
.mIdent
);
14134 // Parse drop-shadow independently of the other filter functions
14135 // because of its more complex characteristics.
14136 if (functionName
== eCSSKeyword_drop_shadow
) {
14137 if (ParseDropShadow(aValue
)) {
14140 // Unrecognized filter function.
14141 REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURLOrFilterFunction
);
14147 // Set up the parsing rules based on the filter function.
14148 int32_t variantMask
= VARIANT_PN
;
14149 bool rejectNegativeArgument
= true;
14150 bool clampArgumentToOne
= false;
14151 switch (functionName
) {
14152 case eCSSKeyword_blur
:
14153 variantMask
= VARIANT_LCALC
| VARIANT_NONNEGATIVE_DIMENSION
;
14154 // VARIANT_NONNEGATIVE_DIMENSION will already reject negative lengths.
14155 rejectNegativeArgument
= false;
14157 case eCSSKeyword_brightness
:
14158 case eCSSKeyword_contrast
:
14159 case eCSSKeyword_saturate
:
14161 case eCSSKeyword_grayscale
:
14162 case eCSSKeyword_invert
:
14163 case eCSSKeyword_sepia
:
14164 case eCSSKeyword_opacity
:
14165 clampArgumentToOne
= true;
14167 case eCSSKeyword_hue_rotate
:
14168 variantMask
= VARIANT_ANGLE
;
14169 rejectNegativeArgument
= false;
14172 // Unrecognized filter function.
14173 REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURLOrFilterFunction
);
14178 // Parse the function.
14179 uint16_t minElems
= 1U;
14180 uint16_t maxElems
= 1U;
14181 uint32_t allVariants
= 0;
14182 if (!ParseFunction(functionName
, &variantMask
, allVariants
,
14183 minElems
, maxElems
, *aValue
)) {
14184 REPORT_UNEXPECTED(PEFilterFunctionArgumentsParsingError
);
14188 // Get the first and only argument to the filter function.
14189 NS_ABORT_IF_FALSE(aValue
->GetUnit() == eCSSUnit_Function
,
14190 "expected a filter function");
14191 NS_ABORT_IF_FALSE(aValue
->UnitHasArrayValue(),
14192 "filter function should be an array");
14193 NS_ABORT_IF_FALSE(aValue
->GetArrayValue()->Count() == 2,
14194 "filter function should have exactly one argument");
14195 nsCSSValue
& arg
= aValue
->GetArrayValue()->Item(1);
14197 if (rejectNegativeArgument
&&
14198 ((arg
.GetUnit() == eCSSUnit_Percent
&& arg
.GetPercentValue() < 0.0f
) ||
14199 (arg
.GetUnit() == eCSSUnit_Number
&& arg
.GetFloatValue() < 0.0f
))) {
14200 REPORT_UNEXPECTED(PEExpectedNonnegativeNP
);
14204 if (clampArgumentToOne
) {
14205 if (arg
.GetUnit() == eCSSUnit_Number
&&
14206 arg
.GetFloatValue() > 1.0f
) {
14207 arg
.SetFloatValue(1.0f
, arg
.GetUnit());
14208 } else if (arg
.GetUnit() == eCSSUnit_Percent
&&
14209 arg
.GetPercentValue() > 1.0f
) {
14210 arg
.SetPercentValue(1.0f
);
14218 * Parses a filter property value by continuously reading in urls and/or filter
14219 * functions and constructing a list.
14221 * When CSS Filters are enabled, the filter property accepts one or more SVG
14222 * reference filters and/or CSS filter functions.
14223 * e.g. filter: url(#my-filter-1) blur(3px) url(#my-filter-2) grayscale(50%);
14225 * When CSS Filters are disabled, the filter property only accepts one SVG
14226 * reference filter.
14227 * e.g. filter: url(#my-filter);
14230 CSSParserImpl::ParseFilter()
14233 // 'inherit', 'initial', 'unset' and 'none' must be alone
14234 if (!ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
14235 nsCSSValueList
* cur
= value
.SetListValue();
14237 if (!ParseSingleFilter(&cur
->mValue
)) {
14240 if (CheckEndProperty()) {
14243 if (!nsLayoutUtils::CSSFiltersEnabled()) {
14244 // With CSS Filters disabled, we should only accept one SVG reference
14246 REPORT_UNEXPECTED_TOKEN(PEExpectEndValue
);
14249 cur
->mNext
= new nsCSSValueList
;
14253 AppendValue(eCSSProperty_filter
, value
);
14258 CSSParserImpl::ParseTransitionProperty()
14261 // 'inherit', 'initial', 'unset' and 'none' must be alone
14262 if (!ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
14263 // Accept a list of arbitrary identifiers. They should be
14264 // CSS properties, but we want to accept any so that we
14265 // accept properties that we don't know about yet, e.g.
14266 // transition-property: invalid-property, left, opacity;
14267 nsCSSValueList
* cur
= value
.SetListValue();
14269 if (!ParseVariant(cur
->mValue
, VARIANT_IDENTIFIER
| VARIANT_ALL
, nullptr)) {
14272 if (cur
->mValue
.GetUnit() == eCSSUnit_Ident
) {
14273 nsDependentString
str(cur
->mValue
.GetStringBufferValue());
14274 // Exclude 'none', 'inherit', 'initial' and 'unset' according to the
14275 // same rules as for 'counter-reset' in CSS 2.1.
14276 if (str
.LowerCaseEqualsLiteral("none") ||
14277 str
.LowerCaseEqualsLiteral("inherit") ||
14278 str
.LowerCaseEqualsLiteral("initial") ||
14279 (str
.LowerCaseEqualsLiteral("unset") &&
14280 nsLayoutUtils::UnsetValueEnabled())) {
14284 if (!ExpectSymbol(',', true)) {
14287 cur
->mNext
= new nsCSSValueList
;
14291 AppendValue(eCSSProperty_transition_property
, value
);
14296 CSSParserImpl::ParseTransitionTimingFunctionValues(nsCSSValue
& aValue
)
14298 NS_ASSERTION(!mHavePushBack
&&
14299 mToken
.mType
== eCSSToken_Function
&&
14300 mToken
.mIdent
.LowerCaseEqualsLiteral("cubic-bezier"),
14301 "unexpected initial state");
14303 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(4);
14305 float x1
, x2
, y1
, y2
;
14306 if (!ParseTransitionTimingFunctionValueComponent(x1
, ',', true) ||
14307 !ParseTransitionTimingFunctionValueComponent(y1
, ',', false) ||
14308 !ParseTransitionTimingFunctionValueComponent(x2
, ',', true) ||
14309 !ParseTransitionTimingFunctionValueComponent(y2
, ')', false)) {
14313 val
->Item(0).SetFloatValue(x1
, eCSSUnit_Number
);
14314 val
->Item(1).SetFloatValue(y1
, eCSSUnit_Number
);
14315 val
->Item(2).SetFloatValue(x2
, eCSSUnit_Number
);
14316 val
->Item(3).SetFloatValue(y2
, eCSSUnit_Number
);
14318 aValue
.SetArrayValue(val
, eCSSUnit_Cubic_Bezier
);
14324 CSSParserImpl::ParseTransitionTimingFunctionValueComponent(float& aComponent
,
14328 if (!GetToken(true)) {
14331 nsCSSToken
* tk
= &mToken
;
14332 if (tk
->mType
== eCSSToken_Number
) {
14333 float num
= tk
->mNumber
;
14334 if (aCheckRange
&& (num
< 0.0 || num
> 1.0)) {
14338 if (ExpectSymbol(aStop
, true)) {
14346 CSSParserImpl::ParseTransitionStepTimingFunctionValues(nsCSSValue
& aValue
)
14348 NS_ASSERTION(!mHavePushBack
&&
14349 mToken
.mType
== eCSSToken_Function
&&
14350 mToken
.mIdent
.LowerCaseEqualsLiteral("steps"),
14351 "unexpected initial state");
14353 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(2);
14355 if (!ParseOneOrLargerVariant(val
->Item(0), VARIANT_INTEGER
, nullptr)) {
14359 int32_t type
= NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END
;
14360 if (ExpectSymbol(',', true)) {
14361 if (!GetToken(true)) {
14365 if (mToken
.mType
== eCSSToken_Ident
) {
14366 if (mToken
.mIdent
.LowerCaseEqualsLiteral("start")) {
14367 type
= NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START
;
14368 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("end")) {
14369 type
= NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END
;
14377 val
->Item(1).SetIntValue(type
, eCSSUnit_Enumerated
);
14379 if (!ExpectSymbol(')', true)) {
14383 aValue
.SetArrayValue(val
, eCSSUnit_Steps
);
14387 static nsCSSValueList
*
14388 AppendValueToList(nsCSSValue
& aContainer
,
14389 nsCSSValueList
* aTail
,
14390 const nsCSSValue
& aValue
)
14392 nsCSSValueList
* entry
;
14393 if (aContainer
.GetUnit() == eCSSUnit_Null
) {
14394 NS_ABORT_IF_FALSE(!aTail
, "should not have an entry");
14395 entry
= aContainer
.SetListValue();
14397 NS_ABORT_IF_FALSE(!aTail
->mNext
, "should not have a next entry");
14398 NS_ABORT_IF_FALSE(aContainer
.GetUnit() == eCSSUnit_List
, "not a list");
14399 entry
= new nsCSSValueList
;
14400 aTail
->mNext
= entry
;
14402 entry
->mValue
= aValue
;
14406 CSSParserImpl::ParseAnimationOrTransitionShorthandResult
14407 CSSParserImpl::ParseAnimationOrTransitionShorthand(
14408 const nsCSSProperty
* aProperties
,
14409 const nsCSSValue
* aInitialValues
,
14410 nsCSSValue
* aValues
,
14411 size_t aNumProperties
)
14413 nsCSSValue tempValue
;
14414 // first see if 'inherit', 'initial' or 'unset' is specified. If one is,
14415 // it can be the only thing specified, so don't attempt to parse any
14416 // additional properties
14417 if (ParseVariant(tempValue
, VARIANT_INHERIT
, nullptr)) {
14418 for (uint32_t i
= 0; i
< aNumProperties
; ++i
) {
14419 AppendValue(aProperties
[i
], tempValue
);
14421 return eParseAnimationOrTransitionShorthand_Inherit
;
14424 static const size_t maxNumProperties
= 8;
14425 NS_ABORT_IF_FALSE(aNumProperties
<= maxNumProperties
,
14426 "can't handle this many properties");
14427 nsCSSValueList
*cur
[maxNumProperties
];
14428 bool parsedProperty
[maxNumProperties
];
14430 for (size_t i
= 0; i
< aNumProperties
; ++i
) {
14433 bool atEOP
= false; // at end of property?
14434 for (;;) { // loop over comma-separated transitions or animations
14435 // whether a particular subproperty was specified for this
14436 // transition or animation
14437 bool haveAnyProperty
= false;
14438 for (size_t i
= 0; i
< aNumProperties
; ++i
) {
14439 parsedProperty
[i
] = false;
14441 for (;;) { // loop over values within a transition or animation
14442 bool foundProperty
= false;
14443 // check to see if we're at the end of one full transition or
14444 // animation definition (either because we hit a comma or because
14445 // we hit the end of the property definition)
14446 if (ExpectSymbol(',', true))
14448 if (CheckEndProperty()) {
14453 // else, try to parse the next transition or animation sub-property
14454 for (uint32_t i
= 0; !foundProperty
&& i
< aNumProperties
; ++i
) {
14455 if (!parsedProperty
[i
]) {
14456 // if we haven't found this property yet, try to parse it
14457 if (ParseSingleValueProperty(tempValue
, aProperties
[i
])) {
14458 parsedProperty
[i
] = true;
14459 cur
[i
] = AppendValueToList(aValues
[i
], cur
[i
], tempValue
);
14460 foundProperty
= true;
14461 haveAnyProperty
= true;
14462 break; // out of inner loop; continue looking for next sub-property
14466 if (!foundProperty
) {
14467 // We're not at a ',' or at the end of the property, but we couldn't
14468 // parse any of the sub-properties, so the declaration is invalid.
14469 return eParseAnimationOrTransitionShorthand_Error
;
14473 if (!haveAnyProperty
) {
14474 // Got an empty item.
14475 return eParseAnimationOrTransitionShorthand_Error
;
14478 // We hit the end of the property or the end of one transition
14479 // or animation definition, add its components to the list.
14480 for (uint32_t i
= 0; i
< aNumProperties
; ++i
) {
14481 // If all of the subproperties were not explicitly specified, fill
14482 // in the missing ones with initial values.
14483 if (!parsedProperty
[i
]) {
14484 cur
[i
] = AppendValueToList(aValues
[i
], cur
[i
], aInitialValues
[i
]);
14490 // else we just hit a ',' so continue parsing the next compound transition
14493 return eParseAnimationOrTransitionShorthand_Values
;
14497 CSSParserImpl::ParseTransition()
14499 static const nsCSSProperty kTransitionProperties
[] = {
14500 eCSSProperty_transition_duration
,
14501 eCSSProperty_transition_timing_function
,
14502 // Must check 'transition-delay' after 'transition-duration', since
14503 // that's our assumption about what the spec means for the shorthand
14504 // syntax (the first time given is the duration, and the second
14505 // given is the delay).
14506 eCSSProperty_transition_delay
,
14507 // Must check 'transition-property' after
14508 // 'transition-timing-function' since 'transition-property' accepts
14510 eCSSProperty_transition_property
14512 static const uint32_t numProps
= MOZ_ARRAY_LENGTH(kTransitionProperties
);
14513 // this is a shorthand property that accepts -property, -delay,
14514 // -duration, and -timing-function with some components missing.
14515 // there can be multiple transitions, separated with commas
14517 nsCSSValue initialValues
[numProps
];
14518 initialValues
[0].SetFloatValue(0.0, eCSSUnit_Seconds
);
14519 initialValues
[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE
,
14520 eCSSUnit_Enumerated
);
14521 initialValues
[2].SetFloatValue(0.0, eCSSUnit_Seconds
);
14522 initialValues
[3].SetAllValue();
14524 nsCSSValue values
[numProps
];
14526 ParseAnimationOrTransitionShorthandResult spres
=
14527 ParseAnimationOrTransitionShorthand(kTransitionProperties
,
14528 initialValues
, values
, numProps
);
14529 if (spres
!= eParseAnimationOrTransitionShorthand_Values
) {
14530 return spres
!= eParseAnimationOrTransitionShorthand_Error
;
14533 // Make two checks on the list for 'transition-property':
14534 // + If there is more than one item, then none of the items can be
14536 // + None of the items can be 'inherit', 'initial' or 'unset'.
14538 NS_ABORT_IF_FALSE(kTransitionProperties
[3] ==
14539 eCSSProperty_transition_property
,
14540 "array index mismatch");
14541 nsCSSValueList
*l
= values
[3].GetListValue();
14542 bool multipleItems
= !!l
->mNext
;
14544 const nsCSSValue
& val
= l
->mValue
;
14545 if (val
.GetUnit() == eCSSUnit_None
) {
14546 if (multipleItems
) {
14547 // This is a syntax error.
14551 // Unbox a solitary 'none'.
14552 values
[3].SetNoneValue();
14555 if (val
.GetUnit() == eCSSUnit_Ident
) {
14556 nsDependentString
str(val
.GetStringBufferValue());
14557 if (str
.EqualsLiteral("inherit") ||
14558 str
.EqualsLiteral("initial") ||
14559 (str
.EqualsLiteral("unset") &&
14560 nsLayoutUtils::UnsetValueEnabled())) {
14564 } while ((l
= l
->mNext
));
14567 // Save all parsed transition sub-properties in mTempData
14568 for (uint32_t i
= 0; i
< numProps
; ++i
) {
14569 AppendValue(kTransitionProperties
[i
], values
[i
]);
14575 CSSParserImpl::ParseAnimation()
14577 static const nsCSSProperty kAnimationProperties
[] = {
14578 eCSSProperty_animation_duration
,
14579 eCSSProperty_animation_timing_function
,
14580 // Must check 'animation-delay' after 'animation-duration', since
14581 // that's our assumption about what the spec means for the shorthand
14582 // syntax (the first time given is the duration, and the second
14583 // given is the delay).
14584 eCSSProperty_animation_delay
,
14585 eCSSProperty_animation_direction
,
14586 eCSSProperty_animation_fill_mode
,
14587 eCSSProperty_animation_iteration_count
,
14588 eCSSProperty_animation_play_state
,
14589 // Must check 'animation-name' after 'animation-timing-function',
14590 // 'animation-direction', 'animation-fill-mode',
14591 // 'animation-iteration-count', and 'animation-play-state' since
14592 // 'animation-name' accepts any keyword.
14593 eCSSProperty_animation_name
14595 static const uint32_t numProps
= MOZ_ARRAY_LENGTH(kAnimationProperties
);
14596 // this is a shorthand property that accepts -property, -delay,
14597 // -duration, and -timing-function with some components missing.
14598 // there can be multiple animations, separated with commas
14600 nsCSSValue initialValues
[numProps
];
14601 initialValues
[0].SetFloatValue(0.0, eCSSUnit_Seconds
);
14602 initialValues
[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE
,
14603 eCSSUnit_Enumerated
);
14604 initialValues
[2].SetFloatValue(0.0, eCSSUnit_Seconds
);
14605 initialValues
[3].SetIntValue(NS_STYLE_ANIMATION_DIRECTION_NORMAL
, eCSSUnit_Enumerated
);
14606 initialValues
[4].SetIntValue(NS_STYLE_ANIMATION_FILL_MODE_NONE
, eCSSUnit_Enumerated
);
14607 initialValues
[5].SetFloatValue(1.0f
, eCSSUnit_Number
);
14608 initialValues
[6].SetIntValue(NS_STYLE_ANIMATION_PLAY_STATE_RUNNING
, eCSSUnit_Enumerated
);
14609 initialValues
[7].SetNoneValue();
14611 nsCSSValue values
[numProps
];
14613 ParseAnimationOrTransitionShorthandResult spres
=
14614 ParseAnimationOrTransitionShorthand(kAnimationProperties
,
14615 initialValues
, values
, numProps
);
14616 if (spres
!= eParseAnimationOrTransitionShorthand_Values
) {
14617 return spres
!= eParseAnimationOrTransitionShorthand_Error
;
14620 // Save all parsed animation sub-properties in mTempData
14621 for (uint32_t i
= 0; i
< numProps
; ++i
) {
14622 AppendValue(kAnimationProperties
[i
], values
[i
]);
14628 CSSParserImpl::ParseShadowItem(nsCSSValue
& aValue
, bool aIsBoxShadow
)
14630 // A shadow list item is an array, with entries in this sequence:
14635 IndexSpread
, // only for box-shadow
14637 IndexInset
// only for box-shadow
14640 nsRefPtr
<nsCSSValue::Array
> val
= nsCSSValue::Array::Create(6);
14642 if (aIsBoxShadow
) {
14643 // Optional inset keyword (ignore errors)
14644 ParseVariant(val
->Item(IndexInset
), VARIANT_KEYWORD
,
14645 nsCSSProps::kBoxShadowTypeKTable
);
14648 nsCSSValue xOrColor
;
14649 bool haveColor
= false;
14650 if (!ParseVariant(xOrColor
, VARIANT_COLOR
| VARIANT_LENGTH
| VARIANT_CALC
,
14654 if (xOrColor
.IsLengthUnit() || xOrColor
.IsCalcUnit()) {
14655 val
->Item(IndexX
) = xOrColor
;
14657 // Must be a color (as string or color value)
14658 NS_ASSERTION(xOrColor
.GetUnit() == eCSSUnit_Ident
||
14659 xOrColor
.GetUnit() == eCSSUnit_EnumColor
||
14660 xOrColor
.IsNumericColorUnit(),
14661 "Must be a color value");
14662 val
->Item(IndexColor
) = xOrColor
;
14665 // X coordinate mandatory after color
14666 if (!ParseVariant(val
->Item(IndexX
), VARIANT_LENGTH
| VARIANT_CALC
,
14672 // Y coordinate; mandatory
14673 if (!ParseVariant(val
->Item(IndexY
), VARIANT_LENGTH
| VARIANT_CALC
,
14678 // Optional radius. Ignore errors except if they pass a negative
14679 // value which we must reject. If we use ParseNonNegativeVariant
14680 // we can't tell the difference between an unspecified radius
14681 // and a negative radius.
14682 if (ParseVariant(val
->Item(IndexRadius
), VARIANT_LENGTH
| VARIANT_CALC
,
14684 val
->Item(IndexRadius
).IsLengthUnit() &&
14685 val
->Item(IndexRadius
).GetFloatValue() < 0) {
14689 if (aIsBoxShadow
) {
14691 ParseVariant(val
->Item(IndexSpread
), VARIANT_LENGTH
| VARIANT_CALC
, nullptr);
14696 ParseVariant(val
->Item(IndexColor
), VARIANT_COLOR
, nullptr);
14699 if (aIsBoxShadow
&& val
->Item(IndexInset
).GetUnit() == eCSSUnit_Null
) {
14700 // Optional inset keyword
14701 ParseVariant(val
->Item(IndexInset
), VARIANT_KEYWORD
,
14702 nsCSSProps::kBoxShadowTypeKTable
);
14705 aValue
.SetArrayValue(val
, eCSSUnit_Array
);
14710 CSSParserImpl::ParseShadowList(nsCSSProperty aProperty
)
14712 nsAutoParseCompoundProperty
compound(this);
14713 bool isBoxShadow
= aProperty
== eCSSProperty_box_shadow
;
14716 // 'inherit', 'initial', 'unset' and 'none' must be alone
14717 if (!ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
, nullptr)) {
14718 nsCSSValueList
* cur
= value
.SetListValue();
14720 if (!ParseShadowItem(cur
->mValue
, isBoxShadow
)) {
14723 if (!ExpectSymbol(',', true)) {
14726 cur
->mNext
= new nsCSSValueList
;
14730 AppendValue(aProperty
, value
);
14735 CSSParserImpl::GetNamespaceIdForPrefix(const nsString
& aPrefix
)
14737 NS_PRECONDITION(!aPrefix
.IsEmpty(), "Must have a prefix here");
14739 int32_t nameSpaceID
= kNameSpaceID_Unknown
;
14740 if (mNameSpaceMap
) {
14741 // user-specified identifiers are case-sensitive (bug 416106)
14742 nsCOMPtr
<nsIAtom
> prefix
= do_GetAtom(aPrefix
);
14744 NS_RUNTIMEABORT("do_GetAtom failed - out of memory?");
14746 nameSpaceID
= mNameSpaceMap
->FindNameSpaceID(prefix
);
14748 // else no declared namespaces
14750 if (nameSpaceID
== kNameSpaceID_Unknown
) { // unknown prefix, dump it
14751 REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix
, aPrefix
);
14754 return nameSpaceID
;
14758 CSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector
& aSelector
)
14760 if (mNameSpaceMap
) {
14761 aSelector
.SetNameSpace(mNameSpaceMap
->FindNameSpaceID(nullptr));
14763 aSelector
.SetNameSpace(kNameSpaceID_Unknown
); // wildcard
14768 CSSParserImpl::ParsePaint(nsCSSProperty aPropID
)
14772 if (!ParseVariant(x
, VARIANT_HC
| VARIANT_NONE
| VARIANT_URL
|
14773 VARIANT_OPENTYPE_SVG_KEYWORD
,
14774 nsCSSProps::kContextPatternKTable
)) {
14778 bool canHaveFallback
= x
.GetUnit() == eCSSUnit_URL
||
14779 x
.GetUnit() == eCSSUnit_Enumerated
;
14780 if (canHaveFallback
) {
14781 if (!ParseVariant(y
, VARIANT_COLOR
| VARIANT_NONE
, nullptr))
14785 if (!canHaveFallback
) {
14786 AppendValue(aPropID
, x
);
14789 val
.SetPairValue(x
, y
);
14790 AppendValue(aPropID
, val
);
14796 CSSParserImpl::ParseDasharray()
14800 // 'inherit', 'initial', 'unset' and 'none' are only allowed on their own
14801 if (!ParseVariant(value
, VARIANT_INHERIT
| VARIANT_NONE
|
14802 VARIANT_OPENTYPE_SVG_KEYWORD
,
14803 nsCSSProps::kStrokeContextValueKTable
)) {
14804 nsCSSValueList
*cur
= value
.SetListValue();
14806 if (!ParseNonNegativeVariant(cur
->mValue
, VARIANT_LPN
, nullptr)) {
14809 if (CheckEndProperty()) {
14812 // skip optional commas between elements
14813 (void)ExpectSymbol(',', true);
14815 cur
->mNext
= new nsCSSValueList
;
14819 AppendValue(eCSSProperty_stroke_dasharray
, value
);
14824 CSSParserImpl::ParseMarker()
14827 if (ParseSingleValueProperty(marker
, eCSSProperty_marker_end
)) {
14828 AppendValue(eCSSProperty_marker_end
, marker
);
14829 AppendValue(eCSSProperty_marker_mid
, marker
);
14830 AppendValue(eCSSProperty_marker_start
, marker
);
14837 CSSParserImpl::ParsePaintOrder()
14840 ((1 << NS_STYLE_PAINT_ORDER_BITWIDTH
) > NS_STYLE_PAINT_ORDER_LAST_VALUE
,
14841 "bitfield width insufficient for paint-order constants");
14843 static const KTableValue kPaintOrderKTable
[] = {
14844 eCSSKeyword_normal
, NS_STYLE_PAINT_ORDER_NORMAL
,
14845 eCSSKeyword_fill
, NS_STYLE_PAINT_ORDER_FILL
,
14846 eCSSKeyword_stroke
, NS_STYLE_PAINT_ORDER_STROKE
,
14847 eCSSKeyword_markers
, NS_STYLE_PAINT_ORDER_MARKERS
,
14848 eCSSKeyword_UNKNOWN
,-1
14851 static_assert(MOZ_ARRAY_LENGTH(kPaintOrderKTable
) ==
14852 2 * (NS_STYLE_PAINT_ORDER_LAST_VALUE
+ 2),
14853 "missing paint-order values in kPaintOrderKTable");
14856 if (!ParseVariant(value
, VARIANT_HK
, kPaintOrderKTable
)) {
14861 uint32_t order
= 0;
14862 uint32_t position
= 0;
14864 // Ensure that even cast to a signed int32_t when stored in CSSValue,
14865 // we have enough space for the entire paint-order value.
14867 (NS_STYLE_PAINT_ORDER_BITWIDTH
* NS_STYLE_PAINT_ORDER_LAST_VALUE
< 32,
14868 "seen and order not big enough");
14870 if (value
.GetUnit() == eCSSUnit_Enumerated
) {
14871 uint32_t component
= static_cast<uint32_t>(value
.GetIntValue());
14872 if (component
!= NS_STYLE_PAINT_ORDER_NORMAL
) {
14873 bool parsedOK
= true;
14875 if (seen
& (1 << component
)) {
14876 // Already seen this component.
14881 seen
|= (1 << component
);
14882 order
|= (component
<< position
);
14883 position
+= NS_STYLE_PAINT_ORDER_BITWIDTH
;
14884 if (!ParseEnum(value
, kPaintOrderKTable
)) {
14887 component
= value
.GetIntValue();
14888 if (component
== NS_STYLE_PAINT_ORDER_NORMAL
) {
14889 // Can't have "normal" in the middle of the list of paint components.
14896 // Fill in the remaining paint-order components in the order of their
14897 // constant values.
14899 for (component
= 1;
14900 component
<= NS_STYLE_PAINT_ORDER_LAST_VALUE
;
14902 if (!(seen
& (1 << component
))) {
14903 order
|= (component
<< position
);
14904 position
+= NS_STYLE_PAINT_ORDER_BITWIDTH
;
14910 static_assert(NS_STYLE_PAINT_ORDER_NORMAL
== 0,
14911 "unexpected value for NS_STYLE_PAINT_ORDER_NORMAL");
14912 value
.SetIntValue(static_cast<int32_t>(order
), eCSSUnit_Enumerated
);
14915 AppendValue(eCSSProperty_paint_order
, value
);
14920 CSSParserImpl::BackslashDropped()
14922 return mScanner
->GetEOFCharacters() &
14923 nsCSSScanner::eEOFCharacters_DropBackslash
;
14927 CSSParserImpl::AppendImpliedEOFCharacters(nsAString
& aResult
)
14929 nsCSSScanner::AppendImpliedEOFCharacters(mScanner
->GetEOFCharacters(),
14934 CSSParserImpl::ParseAll()
14937 if (!ParseVariant(value
, VARIANT_INHERIT
, nullptr)) {
14941 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, eCSSProperty_all
) {
14942 AppendValue(*p
, value
);
14948 CSSParserImpl::ParseVariableDeclaration(CSSVariableDeclarations::Type
* aType
,
14951 CSSVariableDeclarations::Type type
;
14952 nsString variableValue
;
14953 bool dropBackslash
;
14954 nsString impliedCharacters
;
14956 // Record the token stream while parsing a variable value.
14957 if (!mInSupportsCondition
) {
14958 mScanner
->StartRecording();
14960 if (!ParseValueWithVariables(&type
, &dropBackslash
, impliedCharacters
,
14961 nullptr, nullptr)) {
14962 if (!mInSupportsCondition
) {
14963 mScanner
->StopRecording();
14968 if (!mInSupportsCondition
) {
14969 if (type
== CSSVariableDeclarations::eTokenStream
) {
14970 // This was indeed a token stream value, so store it in variableValue.
14971 mScanner
->StopRecording(variableValue
);
14972 if (dropBackslash
) {
14973 MOZ_ASSERT(!variableValue
.IsEmpty() &&
14974 variableValue
[variableValue
.Length() - 1] == '\\');
14975 variableValue
.Truncate(variableValue
.Length() - 1);
14977 variableValue
.Append(impliedCharacters
);
14979 // This was either 'inherit' or 'initial'; we don't need the recorded
14981 mScanner
->StopRecording();
14985 if (mHavePushBack
&& type
== CSSVariableDeclarations::eTokenStream
) {
14986 // If we came to the end of a valid variable declaration and a token was
14987 // pushed back, then it would have been ended by '!', ')', ';', ']' or '}'.
14988 // We need to remove it from the recorded variable value.
14989 MOZ_ASSERT(mToken
.IsSymbol('!') ||
14990 mToken
.IsSymbol(')') ||
14991 mToken
.IsSymbol(';') ||
14992 mToken
.IsSymbol(']') ||
14993 mToken
.IsSymbol('}'));
14994 if (!mInSupportsCondition
) {
14995 MOZ_ASSERT(!variableValue
.IsEmpty());
14996 MOZ_ASSERT(variableValue
[variableValue
.Length() - 1] == mToken
.mSymbol
);
14997 variableValue
.Truncate(variableValue
.Length() - 1);
15002 aValue
= variableValue
;
15007 CSSParserImpl::ParseValueWithVariables(CSSVariableDeclarations::Type
* aType
,
15008 bool* aDropBackslash
,
15009 nsString
& aImpliedCharacters
,
15010 void (*aFunc
)(const nsAString
&, void*),
15013 // A property value is invalid if it contains variable references and also:
15015 // * has unbalanced parens, brackets or braces
15016 // * has any BAD_STRING or BAD_URL tokens
15017 // * has any ';' or '!' tokens at the top level of a variable reference's
15020 // If the property is a custom property (i.e. a variable declaration), then
15021 // it is also invalid if it consists of no tokens, such as:
15025 // Note that is valid for a custom property to have a value that consists
15026 // solely of white space, such as:
15030 // Stack of closing characters for currently open constructs.
15031 StopSymbolCharStack stack
;
15033 // Indexes into ')' characters in |stack| that correspond to "var(". This
15034 // is used to stop parsing when we encounter a '!' or ';' at the top level
15035 // of a variable reference's fallback.
15036 nsAutoTArray
<uint32_t, 16> references
;
15038 if (!GetToken(false)) {
15039 // Variable value was empty since we reached EOF.
15040 REPORT_UNEXPECTED_EOF(PEVariableEOF
);
15044 if (mToken
.mType
== eCSSToken_Symbol
&&
15045 (mToken
.mSymbol
== '!' ||
15046 mToken
.mSymbol
== ')' ||
15047 mToken
.mSymbol
== ';' ||
15048 mToken
.mSymbol
== ']' ||
15049 mToken
.mSymbol
== '}')) {
15050 // Variable value was empty since we reached the end of the construct.
15052 REPORT_UNEXPECTED_TOKEN(PEVariableEmpty
);
15056 if (mToken
.mType
== eCSSToken_Whitespace
) {
15057 if (!GetToken(true)) {
15058 // Variable value was white space only. This is valid.
15059 MOZ_ASSERT(!BackslashDropped());
15060 *aType
= CSSVariableDeclarations::eTokenStream
;
15061 *aDropBackslash
= false;
15062 AppendImpliedEOFCharacters(aImpliedCharacters
);
15067 // Look for 'initial', 'inherit' or 'unset' as the first non-white space
15069 CSSVariableDeclarations::Type type
= CSSVariableDeclarations::eTokenStream
;
15070 if (mToken
.mType
== eCSSToken_Ident
) {
15071 if (mToken
.mIdent
.LowerCaseEqualsLiteral("initial")) {
15072 type
= CSSVariableDeclarations::eInitial
;
15073 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("inherit")) {
15074 type
= CSSVariableDeclarations::eInherit
;
15075 } else if (mToken
.mIdent
.LowerCaseEqualsLiteral("unset")) {
15076 type
= CSSVariableDeclarations::eUnset
;
15080 if (type
!= CSSVariableDeclarations::eTokenStream
) {
15081 if (!GetToken(true)) {
15082 // Variable value was 'initial' or 'inherit' followed by EOF.
15083 MOZ_ASSERT(!BackslashDropped());
15085 *aDropBackslash
= false;
15086 AppendImpliedEOFCharacters(aImpliedCharacters
);
15090 if (mToken
.mType
== eCSSToken_Symbol
&&
15091 (mToken
.mSymbol
== '!' ||
15092 mToken
.mSymbol
== ')' ||
15093 mToken
.mSymbol
== ';' ||
15094 mToken
.mSymbol
== ']' ||
15095 mToken
.mSymbol
== '}')) {
15096 // Variable value was 'initial' or 'inherit' followed by the end
15097 // of the declaration.
15098 MOZ_ASSERT(!BackslashDropped());
15100 *aDropBackslash
= false;
15106 switch (mToken
.mType
) {
15107 case eCSSToken_Symbol
:
15108 if (mToken
.mSymbol
== '(') {
15109 stack
.AppendElement(')');
15110 } else if (mToken
.mSymbol
== '[') {
15111 stack
.AppendElement(']');
15112 } else if (mToken
.mSymbol
== '{') {
15113 stack
.AppendElement('}');
15114 } else if (mToken
.mSymbol
== ';' ||
15115 mToken
.mSymbol
== '!') {
15116 if (stack
.IsEmpty()) {
15118 MOZ_ASSERT(!BackslashDropped());
15119 *aType
= CSSVariableDeclarations::eTokenStream
;
15120 *aDropBackslash
= false;
15122 } else if (!references
.IsEmpty() &&
15123 references
.LastElement() == stack
.Length() - 1) {
15124 REPORT_UNEXPECTED_TOKEN(PEInvalidVariableTokenFallback
);
15125 SkipUntilAllOf(stack
);
15128 } else if (mToken
.mSymbol
== ')' ||
15129 mToken
.mSymbol
== ']' ||
15130 mToken
.mSymbol
== '}') {
15132 if (stack
.IsEmpty()) {
15134 MOZ_ASSERT(!BackslashDropped());
15135 *aType
= CSSVariableDeclarations::eTokenStream
;
15136 *aDropBackslash
= false;
15139 char16_t c
= stack
.LastElement();
15140 stack
.TruncateLength(stack
.Length() - 1);
15141 if (!references
.IsEmpty() &&
15142 references
.LastElement() == stack
.Length()) {
15143 references
.TruncateLength(references
.Length() - 1);
15145 if (mToken
.mSymbol
== c
) {
15152 case eCSSToken_Function
:
15153 if (mToken
.mIdent
.LowerCaseEqualsLiteral("var")) {
15154 if (!GetToken(true)) {
15155 // EOF directly after "var(".
15156 REPORT_UNEXPECTED_EOF(PEExpectedVariableNameEOF
);
15159 if (mToken
.mType
!= eCSSToken_Ident
||
15160 !nsCSSProps::IsCustomPropertyName(mToken
.mIdent
)) {
15161 // There must be an identifier directly after the "var(" and
15162 // it must be a custom property name.
15164 REPORT_UNEXPECTED_TOKEN(PEExpectedVariableName
);
15166 SkipUntilAllOf(stack
);
15170 MOZ_ASSERT(Substring(mToken
.mIdent
, 0,
15171 CSS_CUSTOM_NAME_PREFIX_LENGTH
).
15172 EqualsLiteral("--"));
15174 const nsDependentSubstring varName
=
15175 Substring(mToken
.mIdent
, CSS_CUSTOM_NAME_PREFIX_LENGTH
);
15176 aFunc(varName
, aData
);
15178 if (!GetToken(true)) {
15179 // EOF right after "var(<ident>".
15180 stack
.AppendElement(')');
15181 } else if (mToken
.IsSymbol(',')) {
15182 // Variable reference with fallback.
15183 if (!GetToken(false) || mToken
.IsSymbol(')')) {
15184 // Comma must be followed by at least one fallback token.
15185 REPORT_UNEXPECTED(PEExpectedVariableFallback
);
15186 SkipUntilAllOf(stack
);
15190 references
.AppendElement(stack
.Length());
15191 stack
.AppendElement(')');
15192 } else if (mToken
.IsSymbol(')')) {
15193 // Correctly closed variable reference.
15195 // Malformed variable reference.
15196 REPORT_UNEXPECTED_TOKEN(PEExpectedVariableCommaOrCloseParen
);
15198 SkipUntilAllOf(stack
);
15202 stack
.AppendElement(')');
15206 case eCSSToken_Bad_String
:
15207 SkipUntilAllOf(stack
);
15210 case eCSSToken_Bad_URL
:
15212 SkipUntilAllOf(stack
);
15218 } while (GetToken(true));
15220 // Append any implied closing characters.
15221 *aDropBackslash
= BackslashDropped();
15222 AppendImpliedEOFCharacters(aImpliedCharacters
);
15223 uint32_t i
= stack
.Length();
15225 aImpliedCharacters
.Append(stack
[i
]);
15233 CSSParserImpl::IsValueValidForProperty(const nsCSSProperty aPropID
,
15234 const nsAString
& aPropValue
)
15236 mData
.AssertInitialState();
15237 mTempData
.AssertInitialState();
15239 nsCSSScanner
scanner(aPropValue
, 0);
15240 css::ErrorReporter
reporter(scanner
, mSheet
, mChildLoader
, nullptr);
15241 InitScanner(scanner
, reporter
, nullptr, nullptr, nullptr);
15243 nsAutoSuppressErrors
suppressErrors(this);
15245 mSection
= eCSSSection_General
;
15246 scanner
.SetSVGMode(false);
15248 // Check for unknown properties
15249 if (eCSSProperty_UNKNOWN
== aPropID
) {
15254 // Check that the property and value parse successfully
15255 bool parsedOK
= ParseProperty(aPropID
);
15257 // Check for priority
15258 parsedOK
= parsedOK
&& ParsePriority() != ePriority_Error
;
15260 // We should now be at EOF
15261 parsedOK
= parsedOK
&& !GetToken(true);
15263 mTempData
.ClearProperty(aPropID
);
15264 mTempData
.AssertInitialState();
15265 mData
.AssertInitialState();
15273 } // anonymous namespace
15275 // Recycling of parser implementation objects
15277 static CSSParserImpl
* gFreeList
= nullptr;
15279 nsCSSParser::nsCSSParser(mozilla::css::Loader
* aLoader
,
15280 CSSStyleSheet
* aSheet
)
15282 CSSParserImpl
*impl
= gFreeList
;
15284 gFreeList
= impl
->mNextFree
;
15285 impl
->mNextFree
= nullptr;
15287 impl
= new CSSParserImpl();
15291 impl
->SetChildLoader(aLoader
);
15292 impl
->SetQuirkMode(aLoader
->GetCompatibilityMode() ==
15293 eCompatibility_NavQuirks
);
15296 impl
->SetStyleSheet(aSheet
);
15299 mImpl
= static_cast<void*>(impl
);
15302 nsCSSParser::~nsCSSParser()
15304 CSSParserImpl
*impl
= static_cast<CSSParserImpl
*>(mImpl
);
15306 impl
->mNextFree
= gFreeList
;
15311 nsCSSParser::Shutdown()
15313 CSSParserImpl
*tofree
= gFreeList
;
15314 CSSParserImpl
*next
;
15317 next
= tofree
->mNextFree
;
15326 nsCSSParser::SetStyleSheet(CSSStyleSheet
* aSheet
)
15328 return static_cast<CSSParserImpl
*>(mImpl
)->
15329 SetStyleSheet(aSheet
);
15333 nsCSSParser::SetQuirkMode(bool aQuirkMode
)
15335 return static_cast<CSSParserImpl
*>(mImpl
)->
15336 SetQuirkMode(aQuirkMode
);
15340 nsCSSParser::SetChildLoader(mozilla::css::Loader
* aChildLoader
)
15342 return static_cast<CSSParserImpl
*>(mImpl
)->
15343 SetChildLoader(aChildLoader
);
15347 nsCSSParser::ParseSheet(const nsAString
& aInput
,
15350 nsIPrincipal
* aSheetPrincipal
,
15351 uint32_t aLineNumber
,
15352 bool aAllowUnsafeRules
)
15354 return static_cast<CSSParserImpl
*>(mImpl
)->
15355 ParseSheet(aInput
, aSheetURI
, aBaseURI
, aSheetPrincipal
, aLineNumber
,
15356 aAllowUnsafeRules
);
15360 nsCSSParser::ParseStyleAttribute(const nsAString
& aAttributeValue
,
15363 nsIPrincipal
* aNodePrincipal
,
15364 css::StyleRule
** aResult
)
15366 return static_cast<CSSParserImpl
*>(mImpl
)->
15367 ParseStyleAttribute(aAttributeValue
, aDocURI
, aBaseURI
,
15368 aNodePrincipal
, aResult
);
15372 nsCSSParser::ParseDeclarations(const nsAString
& aBuffer
,
15375 nsIPrincipal
* aSheetPrincipal
,
15376 css::Declaration
* aDeclaration
,
15379 return static_cast<CSSParserImpl
*>(mImpl
)->
15380 ParseDeclarations(aBuffer
, aSheetURI
, aBaseURI
, aSheetPrincipal
,
15381 aDeclaration
, aChanged
);
15385 nsCSSParser::ParseRule(const nsAString
& aRule
,
15388 nsIPrincipal
* aSheetPrincipal
,
15389 css::Rule
** aResult
)
15391 return static_cast<CSSParserImpl
*>(mImpl
)->
15392 ParseRule(aRule
, aSheetURI
, aBaseURI
, aSheetPrincipal
, aResult
);
15396 nsCSSParser::ParseProperty(const nsCSSProperty aPropID
,
15397 const nsAString
& aPropValue
,
15400 nsIPrincipal
* aSheetPrincipal
,
15401 css::Declaration
* aDeclaration
,
15406 return static_cast<CSSParserImpl
*>(mImpl
)->
15407 ParseProperty(aPropID
, aPropValue
, aSheetURI
, aBaseURI
,
15408 aSheetPrincipal
, aDeclaration
, aChanged
,
15409 aIsImportant
, aIsSVGMode
);
15413 nsCSSParser::ParseVariable(const nsAString
& aVariableName
,
15414 const nsAString
& aPropValue
,
15417 nsIPrincipal
* aSheetPrincipal
,
15418 css::Declaration
* aDeclaration
,
15422 return static_cast<CSSParserImpl
*>(mImpl
)->
15423 ParseVariable(aVariableName
, aPropValue
, aSheetURI
, aBaseURI
,
15424 aSheetPrincipal
, aDeclaration
, aChanged
, aIsImportant
);
15428 nsCSSParser::ParseMediaList(const nsSubstring
& aBuffer
,
15430 uint32_t aLineNumber
,
15431 nsMediaList
* aMediaList
,
15434 static_cast<CSSParserImpl
*>(mImpl
)->
15435 ParseMediaList(aBuffer
, aURI
, aLineNumber
, aMediaList
, aHTMLMode
);
15439 nsCSSParser::ParseSourceSizeList(const nsAString
& aBuffer
,
15441 uint32_t aLineNumber
,
15442 InfallibleTArray
< nsAutoPtr
<nsMediaQuery
> >& aQueries
,
15443 InfallibleTArray
<nsCSSValue
>& aValues
,
15446 return static_cast<CSSParserImpl
*>(mImpl
)->
15447 ParseSourceSizeList(aBuffer
, aURI
, aLineNumber
, aQueries
, aValues
,
15452 nsCSSParser::ParseFontFamilyListString(const nsSubstring
& aBuffer
,
15454 uint32_t aLineNumber
,
15455 nsCSSValue
& aValue
)
15457 return static_cast<CSSParserImpl
*>(mImpl
)->
15458 ParseFontFamilyListString(aBuffer
, aURI
, aLineNumber
, aValue
);
15462 nsCSSParser::ParseColorString(const nsSubstring
& aBuffer
,
15464 uint32_t aLineNumber
,
15465 nsCSSValue
& aValue
,
15466 bool aSuppressErrors
/* false */)
15468 return static_cast<CSSParserImpl
*>(mImpl
)->
15469 ParseColorString(aBuffer
, aURI
, aLineNumber
, aValue
, aSuppressErrors
);
15473 nsCSSParser::ParseSelectorString(const nsSubstring
& aSelectorString
,
15475 uint32_t aLineNumber
,
15476 nsCSSSelectorList
** aSelectorList
)
15478 return static_cast<CSSParserImpl
*>(mImpl
)->
15479 ParseSelectorString(aSelectorString
, aURI
, aLineNumber
, aSelectorList
);
15482 already_AddRefed
<nsCSSKeyframeRule
>
15483 nsCSSParser::ParseKeyframeRule(const nsSubstring
& aBuffer
,
15485 uint32_t aLineNumber
)
15487 return static_cast<CSSParserImpl
*>(mImpl
)->
15488 ParseKeyframeRule(aBuffer
, aURI
, aLineNumber
);
15492 nsCSSParser::ParseKeyframeSelectorString(const nsSubstring
& aSelectorString
,
15494 uint32_t aLineNumber
,
15495 InfallibleTArray
<float>& aSelectorList
)
15497 return static_cast<CSSParserImpl
*>(mImpl
)->
15498 ParseKeyframeSelectorString(aSelectorString
, aURI
, aLineNumber
,
15503 nsCSSParser::EvaluateSupportsDeclaration(const nsAString
& aProperty
,
15504 const nsAString
& aValue
,
15507 nsIPrincipal
* aDocPrincipal
)
15509 return static_cast<CSSParserImpl
*>(mImpl
)->
15510 EvaluateSupportsDeclaration(aProperty
, aValue
, aDocURL
, aBaseURL
,
15515 nsCSSParser::EvaluateSupportsCondition(const nsAString
& aCondition
,
15518 nsIPrincipal
* aDocPrincipal
)
15520 return static_cast<CSSParserImpl
*>(mImpl
)->
15521 EvaluateSupportsCondition(aCondition
, aDocURL
, aBaseURL
, aDocPrincipal
);
15525 nsCSSParser::EnumerateVariableReferences(const nsAString
& aPropertyValue
,
15526 VariableEnumFunc aFunc
,
15529 return static_cast<CSSParserImpl
*>(mImpl
)->
15530 EnumerateVariableReferences(aPropertyValue
, aFunc
, aData
);
15534 nsCSSParser::ResolveVariableValue(const nsAString
& aPropertyValue
,
15535 const CSSVariableValues
* aVariables
,
15537 nsCSSTokenSerializationType
& aFirstToken
,
15538 nsCSSTokenSerializationType
& aLastToken
)
15540 return static_cast<CSSParserImpl
*>(mImpl
)->
15541 ResolveVariableValue(aPropertyValue
, aVariables
,
15542 aResult
, aFirstToken
, aLastToken
);
15546 nsCSSParser::ParsePropertyWithVariableReferences(
15547 nsCSSProperty aPropertyID
,
15548 nsCSSProperty aShorthandPropertyID
,
15549 const nsAString
& aValue
,
15550 const CSSVariableValues
* aVariables
,
15551 nsRuleData
* aRuleData
,
15554 nsIPrincipal
* aDocPrincipal
,
15555 CSSStyleSheet
* aSheet
,
15556 uint32_t aLineNumber
,
15557 uint32_t aLineOffset
)
15559 static_cast<CSSParserImpl
*>(mImpl
)->
15560 ParsePropertyWithVariableReferences(aPropertyID
, aShorthandPropertyID
,
15561 aValue
, aVariables
, aRuleData
, aDocURL
,
15562 aBaseURL
, aDocPrincipal
, aSheet
,
15563 aLineNumber
, aLineOffset
);
15567 nsCSSParser::ParseCounterStyleName(const nsAString
& aBuffer
,
15571 return static_cast<CSSParserImpl
*>(mImpl
)->
15572 ParseCounterStyleName(aBuffer
, aURL
, aName
);
15576 nsCSSParser::ParseCounterDescriptor(nsCSSCounterDesc aDescID
,
15577 const nsAString
& aBuffer
,
15580 nsIPrincipal
* aSheetPrincipal
,
15581 nsCSSValue
& aValue
)
15583 return static_cast<CSSParserImpl
*>(mImpl
)->
15584 ParseCounterDescriptor(aDescID
, aBuffer
,
15585 aSheetURL
, aBaseURL
, aSheetPrincipal
, aValue
);
15589 nsCSSParser::ParseFontFaceDescriptor(nsCSSFontDesc aDescID
,
15590 const nsAString
& aBuffer
,
15593 nsIPrincipal
* aSheetPrincipal
,
15594 nsCSSValue
& aValue
)
15596 return static_cast<CSSParserImpl
*>(mImpl
)->
15597 ParseFontFaceDescriptor(aDescID
, aBuffer
,
15598 aSheetURL
, aBaseURL
, aSheetPrincipal
, aValue
);
15602 nsCSSParser::IsValueValidForProperty(const nsCSSProperty aPropID
,
15603 const nsAString
& aPropValue
)
15605 return static_cast<CSSParserImpl
*>(mImpl
)->
15606 IsValueValidForProperty(aPropID
, aPropValue
);