1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsCSSParser.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,14340 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=78: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* parsing of CSS stylesheets, based on a token stream from the CSS scanner */ 1.11 + 1.12 +#include "mozilla/ArrayUtils.h" 1.13 +#include "mozilla/DebugOnly.h" 1.14 + 1.15 +#include "nsCSSParser.h" 1.16 +#include "nsCSSProps.h" 1.17 +#include "nsCSSKeywords.h" 1.18 +#include "nsCSSScanner.h" 1.19 +#include "mozilla/css/ErrorReporter.h" 1.20 +#include "mozilla/css/Loader.h" 1.21 +#include "mozilla/css/StyleRule.h" 1.22 +#include "mozilla/css/ImportRule.h" 1.23 +#include "nsCSSRules.h" 1.24 +#include "mozilla/css/NameSpaceRule.h" 1.25 +#include "nsTArray.h" 1.26 +#include "nsCSSStyleSheet.h" 1.27 +#include "mozilla/css/Declaration.h" 1.28 +#include "nsStyleConsts.h" 1.29 +#include "nsNetUtil.h" 1.30 +#include "nsCOMPtr.h" 1.31 +#include "nsString.h" 1.32 +#include "nsIAtom.h" 1.33 +#include "nsColor.h" 1.34 +#include "nsCSSPseudoClasses.h" 1.35 +#include "nsCSSPseudoElements.h" 1.36 +#include "nsNameSpaceManager.h" 1.37 +#include "nsXMLNameSpaceMap.h" 1.38 +#include "nsError.h" 1.39 +#include "nsIMediaList.h" 1.40 +#include "nsStyleUtil.h" 1.41 +#include "nsIPrincipal.h" 1.42 +#include "prprf.h" 1.43 +#include "nsContentUtils.h" 1.44 +#include "nsAutoPtr.h" 1.45 +#include "CSSCalc.h" 1.46 +#include "nsMediaFeatures.h" 1.47 +#include "nsLayoutUtils.h" 1.48 +#include "mozilla/Preferences.h" 1.49 +#include "nsRuleData.h" 1.50 +#include "mozilla/CSSVariableValues.h" 1.51 +#include "mozilla/dom/URL.h" 1.52 + 1.53 +using namespace mozilla; 1.54 + 1.55 +typedef nsCSSProps::KTableValue KTableValue; 1.56 + 1.57 +const uint32_t 1.58 +nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = { 1.59 +#define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \ 1.60 + stylestruct_, stylestructoffset_, animtype_) \ 1.61 + parsevariant_, 1.62 +#include "nsCSSPropList.h" 1.63 +#undef CSS_PROP 1.64 +}; 1.65 + 1.66 +// Maximum number of repetitions for the repeat() function 1.67 +// in the grid-template-columns and grid-template-rows properties, 1.68 +// to limit high memory usage from small stylesheets. 1.69 +// Must be a positive integer. Should be large-ish. 1.70 +#define GRID_TEMPLATE_MAX_REPETITIONS 10000 1.71 + 1.72 +// End-of-array marker for mask arguments to ParseBitmaskValues 1.73 +#define MASK_END_VALUE (-1) 1.74 + 1.75 +MOZ_BEGIN_ENUM_CLASS(CSSParseResult, int32_t) 1.76 + // Parsed something successfully: 1.77 + Ok, 1.78 + // Did not find what we were looking for, but did not consume any token: 1.79 + NotFound, 1.80 + // Unexpected token or token value, too late for UngetToken() to be enough: 1.81 + Error 1.82 +MOZ_END_ENUM_CLASS(CSSParseResult) 1.83 + 1.84 +namespace { 1.85 + 1.86 +// Rule processing function 1.87 +typedef void (* RuleAppendFunc) (css::Rule* aRule, void* aData); 1.88 +static void AssignRuleToPointer(css::Rule* aRule, void* aPointer); 1.89 +static void AppendRuleToSheet(css::Rule* aRule, void* aParser); 1.90 + 1.91 +struct CSSParserInputState { 1.92 + nsCSSScannerPosition mPosition; 1.93 + nsCSSToken mToken; 1.94 + bool mHavePushBack; 1.95 +}; 1.96 + 1.97 +// Your basic top-down recursive descent style parser 1.98 +// The exposed methods and members of this class are precisely those 1.99 +// needed by nsCSSParser, far below. 1.100 +class CSSParserImpl { 1.101 +public: 1.102 + CSSParserImpl(); 1.103 + ~CSSParserImpl(); 1.104 + 1.105 + nsresult SetStyleSheet(nsCSSStyleSheet* aSheet); 1.106 + 1.107 + nsresult SetQuirkMode(bool aQuirkMode); 1.108 + 1.109 + nsresult SetChildLoader(mozilla::css::Loader* aChildLoader); 1.110 + 1.111 + // Clears everything set by the above Set*() functions. 1.112 + void Reset(); 1.113 + 1.114 + nsresult ParseSheet(const nsAString& aInput, 1.115 + nsIURI* aSheetURI, 1.116 + nsIURI* aBaseURI, 1.117 + nsIPrincipal* aSheetPrincipal, 1.118 + uint32_t aLineNumber, 1.119 + bool aAllowUnsafeRules); 1.120 + 1.121 + nsresult ParseStyleAttribute(const nsAString& aAttributeValue, 1.122 + nsIURI* aDocURL, 1.123 + nsIURI* aBaseURL, 1.124 + nsIPrincipal* aNodePrincipal, 1.125 + css::StyleRule** aResult); 1.126 + 1.127 + nsresult ParseDeclarations(const nsAString& aBuffer, 1.128 + nsIURI* aSheetURL, 1.129 + nsIURI* aBaseURL, 1.130 + nsIPrincipal* aSheetPrincipal, 1.131 + css::Declaration* aDeclaration, 1.132 + bool* aChanged); 1.133 + 1.134 + nsresult ParseRule(const nsAString& aRule, 1.135 + nsIURI* aSheetURL, 1.136 + nsIURI* aBaseURL, 1.137 + nsIPrincipal* aSheetPrincipal, 1.138 + css::Rule** aResult); 1.139 + 1.140 + nsresult ParseProperty(const nsCSSProperty aPropID, 1.141 + const nsAString& aPropValue, 1.142 + nsIURI* aSheetURL, 1.143 + nsIURI* aBaseURL, 1.144 + nsIPrincipal* aSheetPrincipal, 1.145 + css::Declaration* aDeclaration, 1.146 + bool* aChanged, 1.147 + bool aIsImportant, 1.148 + bool aIsSVGMode); 1.149 + 1.150 + void ParseMediaList(const nsSubstring& aBuffer, 1.151 + nsIURI* aURL, // for error reporting 1.152 + uint32_t aLineNumber, // for error reporting 1.153 + nsMediaList* aMediaList, 1.154 + bool aHTMLMode); 1.155 + 1.156 + nsresult ParseVariable(const nsAString& aVariableName, 1.157 + const nsAString& aPropValue, 1.158 + nsIURI* aSheetURL, 1.159 + nsIURI* aBaseURL, 1.160 + nsIPrincipal* aSheetPrincipal, 1.161 + css::Declaration* aDeclaration, 1.162 + bool* aChanged, 1.163 + bool aIsImportant); 1.164 + 1.165 + bool ParseColorString(const nsSubstring& aBuffer, 1.166 + nsIURI* aURL, // for error reporting 1.167 + uint32_t aLineNumber, // for error reporting 1.168 + nsCSSValue& aValue); 1.169 + 1.170 + nsresult ParseSelectorString(const nsSubstring& aSelectorString, 1.171 + nsIURI* aURL, // for error reporting 1.172 + uint32_t aLineNumber, // for error reporting 1.173 + nsCSSSelectorList **aSelectorList); 1.174 + 1.175 + already_AddRefed<nsCSSKeyframeRule> 1.176 + ParseKeyframeRule(const nsSubstring& aBuffer, 1.177 + nsIURI* aURL, 1.178 + uint32_t aLineNumber); 1.179 + 1.180 + bool ParseKeyframeSelectorString(const nsSubstring& aSelectorString, 1.181 + nsIURI* aURL, // for error reporting 1.182 + uint32_t aLineNumber, // for error reporting 1.183 + InfallibleTArray<float>& aSelectorList); 1.184 + 1.185 + bool EvaluateSupportsDeclaration(const nsAString& aProperty, 1.186 + const nsAString& aValue, 1.187 + nsIURI* aDocURL, 1.188 + nsIURI* aBaseURL, 1.189 + nsIPrincipal* aDocPrincipal); 1.190 + 1.191 + bool EvaluateSupportsCondition(const nsAString& aCondition, 1.192 + nsIURI* aDocURL, 1.193 + nsIURI* aBaseURL, 1.194 + nsIPrincipal* aDocPrincipal); 1.195 + 1.196 + typedef nsCSSParser::VariableEnumFunc VariableEnumFunc; 1.197 + 1.198 + /** 1.199 + * Parses a CSS token stream value and invokes a callback function for each 1.200 + * variable reference that is encountered. 1.201 + * 1.202 + * @param aPropertyValue The CSS token stream value. 1.203 + * @param aFunc The callback function to invoke; its parameters are the 1.204 + * variable name found and the aData argument passed in to this function. 1.205 + * @param aData User data to pass in to the callback. 1.206 + * @return Whether aPropertyValue could be parsed as a valid CSS token stream 1.207 + * value (e.g., without syntactic errors in variable references). 1.208 + */ 1.209 + bool EnumerateVariableReferences(const nsAString& aPropertyValue, 1.210 + VariableEnumFunc aFunc, 1.211 + void* aData); 1.212 + 1.213 + /** 1.214 + * Parses aPropertyValue as a CSS token stream value and resolves any 1.215 + * variable references using the variables in aVariables. 1.216 + * 1.217 + * @param aPropertyValue The CSS token stream value. 1.218 + * @param aVariables The set of variable values to use when resolving variable 1.219 + * references. 1.220 + * @param aResult Out parameter that gets the resolved value. 1.221 + * @param aFirstToken Out parameter that gets the type of the first token in 1.222 + * aResult. 1.223 + * @param aLastToken Out parameter that gets the type of the last token in 1.224 + * aResult. 1.225 + * @return Whether aResult could be parsed successfully and variable reference 1.226 + * substitution succeeded. 1.227 + */ 1.228 + bool ResolveVariableValue(const nsAString& aPropertyValue, 1.229 + const CSSVariableValues* aVariables, 1.230 + nsString& aResult, 1.231 + nsCSSTokenSerializationType& aFirstToken, 1.232 + nsCSSTokenSerializationType& aLastToken); 1.233 + 1.234 + /** 1.235 + * Parses a string as a CSS token stream value for particular property, 1.236 + * resolving any variable references. The parsed property value is stored 1.237 + * in the specified nsRuleData object. If aShorthandPropertyID has a value 1.238 + * other than eCSSProperty_UNKNOWN, this is the property that will be parsed; 1.239 + * otherwise, aPropertyID will be parsed. Either way, only aPropertyID, 1.240 + * a longhand property, will be copied over to the rule data. 1.241 + * 1.242 + * If the property cannot be parsed, it will be treated as if 'initial' or 1.243 + * 'inherit' were specified, for non-inherited and inherited properties 1.244 + * respectively. 1.245 + * 1.246 + * @param aPropertyID The ID of the longhand property whose value is to be 1.247 + * copied to the rule data. 1.248 + * @param aShorthandPropertyID The ID of the shorthand property to be parsed. 1.249 + * If a longhand property is to be parsed, aPropertyID is that property, 1.250 + * and aShorthandPropertyID must be eCSSProperty_UNKNOWN. 1.251 + * @param aValue The CSS token stream value. 1.252 + * @param aVariables The set of variable values to use when resolving variable 1.253 + * references. 1.254 + * @param aRuleData The rule data object into which parsed property value for 1.255 + * aPropertyID will be stored. 1.256 + */ 1.257 + void ParsePropertyWithVariableReferences(nsCSSProperty aPropertyID, 1.258 + nsCSSProperty aShorthandPropertyID, 1.259 + const nsAString& aValue, 1.260 + const CSSVariableValues* aVariables, 1.261 + nsRuleData* aRuleData, 1.262 + nsIURI* aDocURL, 1.263 + nsIURI* aBaseURL, 1.264 + nsIPrincipal* aDocPrincipal, 1.265 + nsCSSStyleSheet* aSheet, 1.266 + uint32_t aLineNumber, 1.267 + uint32_t aLineOffset); 1.268 + 1.269 + nsCSSProperty LookupEnabledProperty(const nsAString& aProperty) { 1.270 + static_assert(nsCSSProps::eEnabledForAllContent == 0, 1.271 + "nsCSSProps::eEnabledForAllContent should be zero for " 1.272 + "this bitfield to work"); 1.273 + nsCSSProps::EnabledState enabledState = nsCSSProps::eEnabledForAllContent; 1.274 + if (mUnsafeRulesEnabled) { 1.275 + enabledState |= nsCSSProps::eEnabledInUASheets; 1.276 + } 1.277 + if (mIsChromeOrCertifiedApp) { 1.278 + enabledState |= nsCSSProps::eEnabledInChromeOrCertifiedApp; 1.279 + } 1.280 + return nsCSSProps::LookupProperty(aProperty, enabledState); 1.281 + } 1.282 + 1.283 +protected: 1.284 + class nsAutoParseCompoundProperty; 1.285 + friend class nsAutoParseCompoundProperty; 1.286 + 1.287 + class nsAutoFailingSupportsRule; 1.288 + friend class nsAutoFailingSupportsRule; 1.289 + 1.290 + class nsAutoSuppressErrors; 1.291 + friend class nsAutoSuppressErrors; 1.292 + 1.293 + void AppendRule(css::Rule* aRule); 1.294 + friend void AppendRuleToSheet(css::Rule*, void*); // calls AppendRule 1.295 + 1.296 + /** 1.297 + * This helper class automatically calls SetParsingCompoundProperty in its 1.298 + * constructor and takes care of resetting it to false in its destructor. 1.299 + */ 1.300 + class nsAutoParseCompoundProperty { 1.301 + public: 1.302 + nsAutoParseCompoundProperty(CSSParserImpl* aParser) : mParser(aParser) 1.303 + { 1.304 + NS_ASSERTION(!aParser->IsParsingCompoundProperty(), 1.305 + "already parsing compound property"); 1.306 + NS_ASSERTION(aParser, "Null parser?"); 1.307 + aParser->SetParsingCompoundProperty(true); 1.308 + } 1.309 + 1.310 + ~nsAutoParseCompoundProperty() 1.311 + { 1.312 + mParser->SetParsingCompoundProperty(false); 1.313 + } 1.314 + private: 1.315 + CSSParserImpl* mParser; 1.316 + }; 1.317 + 1.318 + /** 1.319 + * This helper class conditionally sets mInFailingSupportsRule to 1.320 + * true if aCondition = false, and resets it to its original value in its 1.321 + * destructor. If we are already somewhere within a failing @supports 1.322 + * rule, passing in aCondition = true does not change mInFailingSupportsRule. 1.323 + */ 1.324 + class nsAutoFailingSupportsRule { 1.325 + public: 1.326 + nsAutoFailingSupportsRule(CSSParserImpl* aParser, 1.327 + bool aCondition) 1.328 + : mParser(aParser), 1.329 + mOriginalValue(aParser->mInFailingSupportsRule) 1.330 + { 1.331 + if (!aCondition) { 1.332 + mParser->mInFailingSupportsRule = true; 1.333 + } 1.334 + } 1.335 + 1.336 + ~nsAutoFailingSupportsRule() 1.337 + { 1.338 + mParser->mInFailingSupportsRule = mOriginalValue; 1.339 + } 1.340 + 1.341 + private: 1.342 + CSSParserImpl* mParser; 1.343 + bool mOriginalValue; 1.344 + }; 1.345 + 1.346 + /** 1.347 + * Auto class to set aParser->mSuppressErrors to the specified value 1.348 + * and restore it to its original value later. 1.349 + */ 1.350 + class nsAutoSuppressErrors { 1.351 + public: 1.352 + nsAutoSuppressErrors(CSSParserImpl* aParser, 1.353 + bool aSuppressErrors = true) 1.354 + : mParser(aParser), 1.355 + mOriginalValue(aParser->mSuppressErrors) 1.356 + { 1.357 + mParser->mSuppressErrors = aSuppressErrors; 1.358 + } 1.359 + 1.360 + ~nsAutoSuppressErrors() 1.361 + { 1.362 + mParser->mSuppressErrors = mOriginalValue; 1.363 + } 1.364 + 1.365 + private: 1.366 + CSSParserImpl* mParser; 1.367 + bool mOriginalValue; 1.368 + }; 1.369 + 1.370 + // the caller must hold on to aString until parsing is done 1.371 + void InitScanner(nsCSSScanner& aScanner, 1.372 + css::ErrorReporter& aReporter, 1.373 + nsIURI* aSheetURI, nsIURI* aBaseURI, 1.374 + nsIPrincipal* aSheetPrincipal); 1.375 + void ReleaseScanner(void); 1.376 + bool IsSVGMode() const { 1.377 + return mScanner->IsSVGMode(); 1.378 + } 1.379 + 1.380 + /** 1.381 + * Saves the current input state, which includes any currently pushed 1.382 + * back token, and the current position of the scanner. 1.383 + */ 1.384 + void SaveInputState(CSSParserInputState& aState); 1.385 + 1.386 + /** 1.387 + * Restores the saved input state by pushing back any saved pushback 1.388 + * token and calling RestoreSavedPosition on the scanner. 1.389 + */ 1.390 + void RestoreSavedInputState(const CSSParserInputState& aState); 1.391 + 1.392 + bool GetToken(bool aSkipWS); 1.393 + void UngetToken(); 1.394 + bool GetNextTokenLocation(bool aSkipWS, uint32_t *linenum, uint32_t *colnum); 1.395 + 1.396 + bool ExpectSymbol(char16_t aSymbol, bool aSkipWS); 1.397 + bool ExpectEndProperty(); 1.398 + bool CheckEndProperty(); 1.399 + nsSubstring* NextIdent(); 1.400 + 1.401 + // returns true when the stop symbol is found, and false for EOF 1.402 + bool SkipUntil(char16_t aStopSymbol); 1.403 + void SkipUntilOneOf(const char16_t* aStopSymbolChars); 1.404 + // For each character in aStopSymbolChars from the end of the array 1.405 + // to the start, calls SkipUntil with that character. 1.406 + typedef nsAutoTArray<char16_t, 16> StopSymbolCharStack; 1.407 + void SkipUntilAllOf(const StopSymbolCharStack& aStopSymbolChars); 1.408 + // returns true if the stop symbol or EOF is found, and false for an 1.409 + // unexpected ')', ']' or '}'; this not safe to call outside variable 1.410 + // resolution, as it doesn't handle mismatched content 1.411 + bool SkipBalancedContentUntil(char16_t aStopSymbol); 1.412 + 1.413 + void SkipRuleSet(bool aInsideBraces); 1.414 + bool SkipAtRule(bool aInsideBlock); 1.415 + bool SkipDeclaration(bool aCheckForBraces); 1.416 + 1.417 + void PushGroup(css::GroupRule* aRule); 1.418 + void PopGroup(); 1.419 + 1.420 + bool ParseRuleSet(RuleAppendFunc aAppendFunc, void* aProcessData, 1.421 + bool aInsideBraces = false); 1.422 + bool ParseAtRule(RuleAppendFunc aAppendFunc, void* aProcessData, 1.423 + bool aInAtRule); 1.424 + bool ParseCharsetRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.425 + bool ParseImportRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.426 + bool ParseURLOrString(nsString& aURL); 1.427 + bool GatherMedia(nsMediaList* aMedia, 1.428 + bool aInAtRule); 1.429 + bool ParseMediaQuery(bool aInAtRule, nsMediaQuery **aQuery, 1.430 + bool *aHitStop); 1.431 + bool ParseMediaQueryExpression(nsMediaQuery* aQuery); 1.432 + void ProcessImport(const nsString& aURLSpec, 1.433 + nsMediaList* aMedia, 1.434 + RuleAppendFunc aAppendFunc, 1.435 + void* aProcessData); 1.436 + bool ParseGroupRule(css::GroupRule* aRule, RuleAppendFunc aAppendFunc, 1.437 + void* aProcessData); 1.438 + bool ParseMediaRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.439 + bool ParseMozDocumentRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.440 + bool ParseNameSpaceRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.441 + void ProcessNameSpace(const nsString& aPrefix, 1.442 + const nsString& aURLSpec, RuleAppendFunc aAppendFunc, 1.443 + void* aProcessData); 1.444 + 1.445 + bool ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.446 + bool ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc, 1.447 + void* aProcessData); 1.448 + bool ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule *aRule); 1.449 + bool ParseFontDescriptor(nsCSSFontFaceRule* aRule); 1.450 + bool ParseFontDescriptorValue(nsCSSFontDesc aDescID, 1.451 + nsCSSValue& aValue); 1.452 + 1.453 + bool ParsePageRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.454 + bool ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.455 + already_AddRefed<nsCSSKeyframeRule> ParseKeyframeRule(); 1.456 + bool ParseKeyframeSelectorList(InfallibleTArray<float>& aSelectorList); 1.457 + 1.458 + bool ParseSupportsRule(RuleAppendFunc aAppendFunc, void* aProcessData); 1.459 + bool ParseSupportsCondition(bool& aConditionMet); 1.460 + bool ParseSupportsConditionNegation(bool& aConditionMet); 1.461 + bool ParseSupportsConditionInParens(bool& aConditionMet); 1.462 + bool ParseSupportsConditionInParensInsideParens(bool& aConditionMet); 1.463 + bool ParseSupportsConditionTerms(bool& aConditionMet); 1.464 + enum SupportsConditionTermOperator { eAnd, eOr }; 1.465 + bool ParseSupportsConditionTermsAfterOperator( 1.466 + bool& aConditionMet, 1.467 + SupportsConditionTermOperator aOperator); 1.468 + 1.469 + /** 1.470 + * Parses the current input stream for a CSS token stream value and resolves 1.471 + * any variable references using the variables in aVariables. 1.472 + * 1.473 + * @param aVariables The set of variable values to use when resolving variable 1.474 + * references. 1.475 + * @param aResult Out parameter that, if the function returns true, will be 1.476 + * replaced with the resolved value. 1.477 + * @return Whether aResult could be parsed successfully and variable reference 1.478 + * substitution succeeded. 1.479 + */ 1.480 + bool ResolveValueWithVariableReferences( 1.481 + const CSSVariableValues* aVariables, 1.482 + nsString& aResult, 1.483 + nsCSSTokenSerializationType& aResultFirstToken, 1.484 + nsCSSTokenSerializationType& aResultLastToken); 1.485 + // Helper function for ResolveValueWithVariableReferences. 1.486 + bool ResolveValueWithVariableReferencesRec( 1.487 + nsString& aResult, 1.488 + nsCSSTokenSerializationType& aResultFirstToken, 1.489 + nsCSSTokenSerializationType& aResultLastToken, 1.490 + const CSSVariableValues* aVariables); 1.491 + 1.492 + enum nsSelectorParsingStatus { 1.493 + // we have parsed a selector and we saw a token that cannot be 1.494 + // part of a selector: 1.495 + eSelectorParsingStatus_Done, 1.496 + // we should continue parsing the selector: 1.497 + eSelectorParsingStatus_Continue, 1.498 + // we saw an unexpected token or token value, 1.499 + // or we saw end-of-file with an unfinished selector: 1.500 + eSelectorParsingStatus_Error 1.501 + }; 1.502 + nsSelectorParsingStatus ParseIDSelector(int32_t& aDataMask, 1.503 + nsCSSSelector& aSelector); 1.504 + 1.505 + nsSelectorParsingStatus ParseClassSelector(int32_t& aDataMask, 1.506 + nsCSSSelector& aSelector); 1.507 + 1.508 + // aPseudoElement and aPseudoElementArgs are the location where 1.509 + // pseudo-elements (as opposed to pseudo-classes) are stored; 1.510 + // pseudo-classes are stored on aSelector. aPseudoElement and 1.511 + // aPseudoElementArgs must be non-null iff !aIsNegated. 1.512 + nsSelectorParsingStatus ParsePseudoSelector(int32_t& aDataMask, 1.513 + nsCSSSelector& aSelector, 1.514 + bool aIsNegated, 1.515 + nsIAtom** aPseudoElement, 1.516 + nsAtomList** aPseudoElementArgs, 1.517 + nsCSSPseudoElements::Type* aPseudoElementType); 1.518 + 1.519 + nsSelectorParsingStatus ParseAttributeSelector(int32_t& aDataMask, 1.520 + nsCSSSelector& aSelector); 1.521 + 1.522 + nsSelectorParsingStatus ParseTypeOrUniversalSelector(int32_t& aDataMask, 1.523 + nsCSSSelector& aSelector, 1.524 + bool aIsNegated); 1.525 + 1.526 + nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector, 1.527 + nsCSSPseudoClasses::Type aType); 1.528 + 1.529 + nsSelectorParsingStatus ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector, 1.530 + nsCSSPseudoClasses::Type aType); 1.531 + 1.532 + nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, 1.533 + nsCSSPseudoClasses::Type aType); 1.534 + 1.535 + nsSelectorParsingStatus ParseNegatedSimpleSelector(int32_t& aDataMask, 1.536 + nsCSSSelector& aSelector); 1.537 + 1.538 + // If aStopChar is non-zero, the selector list is done when we hit 1.539 + // aStopChar. Otherwise, it's done when we hit EOF. 1.540 + bool ParseSelectorList(nsCSSSelectorList*& aListHead, 1.541 + char16_t aStopChar); 1.542 + bool ParseSelectorGroup(nsCSSSelectorList*& aListHead); 1.543 + bool ParseSelector(nsCSSSelectorList* aList, char16_t aPrevCombinator); 1.544 + 1.545 + enum { 1.546 + eParseDeclaration_InBraces = 1 << 0, 1.547 + eParseDeclaration_AllowImportant = 1 << 1 1.548 + }; 1.549 + enum nsCSSContextType { 1.550 + eCSSContext_General, 1.551 + eCSSContext_Page 1.552 + }; 1.553 + 1.554 + css::Declaration* ParseDeclarationBlock(uint32_t aFlags, 1.555 + nsCSSContextType aContext = eCSSContext_General); 1.556 + bool ParseDeclaration(css::Declaration* aDeclaration, 1.557 + uint32_t aFlags, 1.558 + bool aMustCallValueAppended, 1.559 + bool* aChanged, 1.560 + nsCSSContextType aContext = eCSSContext_General); 1.561 + 1.562 + bool ParseProperty(nsCSSProperty aPropID); 1.563 + bool ParsePropertyByFunction(nsCSSProperty aPropID); 1.564 + bool ParseSingleValueProperty(nsCSSValue& aValue, 1.565 + nsCSSProperty aPropID); 1.566 + 1.567 + enum PriorityParsingStatus { 1.568 + ePriority_None, 1.569 + ePriority_Important, 1.570 + ePriority_Error 1.571 + }; 1.572 + PriorityParsingStatus ParsePriority(); 1.573 + 1.574 +#ifdef MOZ_XUL 1.575 + bool ParseTreePseudoElement(nsAtomList **aPseudoElementArgs); 1.576 +#endif 1.577 + 1.578 + void InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties); 1.579 + 1.580 + // Property specific parsing routines 1.581 + bool ParseBackground(); 1.582 + 1.583 + struct BackgroundParseState { 1.584 + nsCSSValue& mColor; 1.585 + nsCSSValueList* mImage; 1.586 + nsCSSValuePairList* mRepeat; 1.587 + nsCSSValueList* mAttachment; 1.588 + nsCSSValueList* mClip; 1.589 + nsCSSValueList* mOrigin; 1.590 + nsCSSValueList* mPosition; 1.591 + nsCSSValuePairList* mSize; 1.592 + BackgroundParseState( 1.593 + nsCSSValue& aColor, nsCSSValueList* aImage, nsCSSValuePairList* aRepeat, 1.594 + nsCSSValueList* aAttachment, nsCSSValueList* aClip, 1.595 + nsCSSValueList* aOrigin, nsCSSValueList* aPosition, 1.596 + nsCSSValuePairList* aSize) : 1.597 + mColor(aColor), mImage(aImage), mRepeat(aRepeat), 1.598 + mAttachment(aAttachment), mClip(aClip), mOrigin(aOrigin), 1.599 + mPosition(aPosition), mSize(aSize) {}; 1.600 + }; 1.601 + 1.602 + bool ParseBackgroundItem(BackgroundParseState& aState); 1.603 + 1.604 + bool ParseValueList(nsCSSProperty aPropID); // a single value prop-id 1.605 + bool ParseBackgroundRepeat(); 1.606 + bool ParseBackgroundRepeatValues(nsCSSValuePair& aValue); 1.607 + bool ParseBackgroundPosition(); 1.608 + 1.609 + // ParseBoxPositionValues parses the CSS 2.1 background-position syntax, 1.610 + // which is still used by some properties. See ParseBackgroundPositionValues 1.611 + // for the css3-background syntax. 1.612 + bool ParseBoxPositionValues(nsCSSValuePair& aOut, bool aAcceptsInherit, 1.613 + bool aAllowExplicitCenter = true); // deprecated 1.614 + bool ParseBackgroundPositionValues(nsCSSValue& aOut, bool aAcceptsInherit); 1.615 + 1.616 + bool ParseBackgroundSize(); 1.617 + bool ParseBackgroundSizeValues(nsCSSValuePair& aOut); 1.618 + bool ParseBorderColor(); 1.619 + bool ParseBorderColors(nsCSSProperty aProperty); 1.620 + void SetBorderImageInitialValues(); 1.621 + bool ParseBorderImageRepeat(bool aAcceptsInherit); 1.622 + // If ParseBorderImageSlice returns false, aConsumedTokens indicates 1.623 + // whether or not any tokens were consumed (in other words, was the property 1.624 + // in error or just not present). If ParseBorderImageSlice returns true 1.625 + // aConsumedTokens is always true. 1.626 + bool ParseBorderImageSlice(bool aAcceptsInherit, bool* aConsumedTokens); 1.627 + bool ParseBorderImageWidth(bool aAcceptsInherit); 1.628 + bool ParseBorderImageOutset(bool aAcceptsInherit); 1.629 + bool ParseBorderImage(); 1.630 + bool ParseBorderSpacing(); 1.631 + bool ParseBorderSide(const nsCSSProperty aPropIDs[], 1.632 + bool aSetAllSides); 1.633 + bool ParseDirectionalBorderSide(const nsCSSProperty aPropIDs[], 1.634 + int32_t aSourceType); 1.635 + bool ParseBorderStyle(); 1.636 + bool ParseBorderWidth(); 1.637 + 1.638 + bool ParseCalc(nsCSSValue &aValue, int32_t aVariantMask); 1.639 + bool ParseCalcAdditiveExpression(nsCSSValue& aValue, 1.640 + int32_t& aVariantMask); 1.641 + bool ParseCalcMultiplicativeExpression(nsCSSValue& aValue, 1.642 + int32_t& aVariantMask, 1.643 + bool *aHadFinalWS); 1.644 + bool ParseCalcTerm(nsCSSValue& aValue, int32_t& aVariantMask); 1.645 + bool RequireWhitespace(); 1.646 + 1.647 + // For "flex" shorthand property, defined in CSS Flexbox spec 1.648 + bool ParseFlex(); 1.649 + // For "flex-flow" shorthand property, defined in CSS Flexbox spec 1.650 + bool ParseFlexFlow(); 1.651 + 1.652 + // CSS Grid 1.653 + bool ParseGridAutoFlow(); 1.654 + 1.655 + // Parse a <line-names> expression. 1.656 + // If successful, either leave aValue untouched, 1.657 + // to indicate that we parsed the empty list, 1.658 + // or set it to a eCSSUnit_List of eCSSUnit_Ident. 1.659 + // 1.660 + // To parse an optional <line-names> (ie. if not finding an open paren 1.661 + // is considered the same as an empty list), 1.662 + // treat CSSParseResult::NotFound the same as CSSParseResult::Ok. 1.663 + // 1.664 + // If aValue is already a eCSSUnit_List, append to that list. 1.665 + CSSParseResult ParseGridLineNames(nsCSSValue& aValue); 1.666 + bool ParseGridLineNameListRepeat(nsCSSValueList** aTailPtr); 1.667 + bool ParseOptionalLineNameListAfterSubgrid(nsCSSValue& aValue); 1.668 + bool ParseGridTrackBreadth(nsCSSValue& aValue); 1.669 + CSSParseResult ParseGridTrackSize(nsCSSValue& aValue); 1.670 + bool ParseGridAutoColumnsRows(nsCSSProperty aPropID); 1.671 + bool ParseGridTrackListRepeat(nsCSSValueList** aTailPtr); 1.672 + 1.673 + // Assuming a [ <line-names>? ] has already been parsed, 1.674 + // parse the rest of a <track-list>. 1.675 + // 1.676 + // This exists because [ <line-names>? ] is ambiguous in the 1.677 + // 'grid-template' shorthand: it can be either the start of a <track-list>, 1.678 + // or of the intertwined syntax that sets both 1.679 + // grid-template-rows and grid-template-areas. 1.680 + // 1.681 + // On success, |aValue| will be a list of odd length >= 3, 1.682 + // starting with a <line-names> (which is itself a list) 1.683 + // and alternating between that and <track-size>. 1.684 + bool ParseGridTrackListWithFirstLineNames(nsCSSValue& aValue, 1.685 + const nsCSSValue& aFirstLineNames); 1.686 + bool ParseGridTemplateColumnsRows(nsCSSProperty aPropID); 1.687 + 1.688 + // |aAreaIndices| is a lookup table to help us parse faster, 1.689 + // mapping area names to indices in |aResult.mNamedAreas|. 1.690 + bool ParseGridTemplateAreasLine(const nsAutoString& aInput, 1.691 + css::GridTemplateAreasValue* aResult, 1.692 + nsDataHashtable<nsStringHashKey, uint32_t>& aAreaIndices); 1.693 + bool ParseGridTemplateAreas(); 1.694 + bool ParseGridTemplate(); 1.695 + bool ParseGridTemplateAfterSlash(bool aColumnsIsTrackList); 1.696 + bool ParseGridTemplateAfterString(const nsCSSValue& aFirstLineNames); 1.697 + bool ParseGrid(); 1.698 + bool ParseGridShorthandAutoProps(); 1.699 + bool ParseGridLine(nsCSSValue& aValue); 1.700 + bool ParseGridAutoPosition(); 1.701 + bool ParseGridColumnRowStartEnd(nsCSSProperty aPropID); 1.702 + bool ParseGridColumnRow(nsCSSProperty aStartPropID, 1.703 + nsCSSProperty aEndPropID); 1.704 + bool ParseGridArea(); 1.705 + 1.706 + // for 'clip' and '-moz-image-region' 1.707 + bool ParseRect(nsCSSProperty aPropID); 1.708 + bool ParseColumns(); 1.709 + bool ParseContent(); 1.710 + bool ParseCounterData(nsCSSProperty aPropID); 1.711 + bool ParseCursor(); 1.712 + bool ParseFont(); 1.713 + bool ParseFontSynthesis(nsCSSValue& aValue); 1.714 + bool ParseSingleAlternate(int32_t& aWhichFeature, nsCSSValue& aValue); 1.715 + bool ParseFontVariantAlternates(nsCSSValue& aValue); 1.716 + bool ParseBitmaskValues(nsCSSValue& aValue, 1.717 + const KTableValue aKeywordTable[], 1.718 + const int32_t aMasks[]); 1.719 + bool ParseFontVariantEastAsian(nsCSSValue& aValue); 1.720 + bool ParseFontVariantLigatures(nsCSSValue& aValue); 1.721 + bool ParseFontVariantNumeric(nsCSSValue& aValue); 1.722 + bool ParseFontWeight(nsCSSValue& aValue); 1.723 + bool ParseOneFamily(nsAString& aFamily, bool& aOneKeyword); 1.724 + bool ParseFamily(nsCSSValue& aValue); 1.725 + bool ParseFontFeatureSettings(nsCSSValue& aValue); 1.726 + bool ParseFontSrc(nsCSSValue& aValue); 1.727 + bool ParseFontSrcFormat(InfallibleTArray<nsCSSValue>& values); 1.728 + bool ParseFontRanges(nsCSSValue& aValue); 1.729 + bool ParseListStyle(); 1.730 + bool ParseMargin(); 1.731 + bool ParseMarks(nsCSSValue& aValue); 1.732 + bool ParseTransform(bool aIsPrefixed); 1.733 + bool ParseOutline(); 1.734 + bool ParseOverflow(); 1.735 + bool ParsePadding(); 1.736 + bool ParseQuotes(); 1.737 + bool ParseSize(); 1.738 + bool ParseTextAlign(nsCSSValue& aValue, 1.739 + const KTableValue aTable[]); 1.740 + bool ParseTextAlign(nsCSSValue& aValue); 1.741 + bool ParseTextAlignLast(nsCSSValue& aValue); 1.742 + bool ParseTextDecoration(); 1.743 + bool ParseTextDecorationLine(nsCSSValue& aValue); 1.744 + bool ParseTextCombineUpright(nsCSSValue& aValue); 1.745 + bool ParseTextOverflow(nsCSSValue& aValue); 1.746 + bool ParseTouchAction(nsCSSValue& aValue); 1.747 + 1.748 + bool ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow); 1.749 + bool ParseShadowList(nsCSSProperty aProperty); 1.750 + bool ParseTransitionProperty(); 1.751 + bool ParseTransitionTimingFunctionValues(nsCSSValue& aValue); 1.752 + bool ParseTransitionTimingFunctionValueComponent(float& aComponent, 1.753 + char aStop, 1.754 + bool aCheckRange); 1.755 + bool ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue); 1.756 + enum ParseAnimationOrTransitionShorthandResult { 1.757 + eParseAnimationOrTransitionShorthand_Values, 1.758 + eParseAnimationOrTransitionShorthand_Inherit, 1.759 + eParseAnimationOrTransitionShorthand_Error 1.760 + }; 1.761 + ParseAnimationOrTransitionShorthandResult 1.762 + ParseAnimationOrTransitionShorthand(const nsCSSProperty* aProperties, 1.763 + const nsCSSValue* aInitialValues, 1.764 + nsCSSValue* aValues, 1.765 + size_t aNumProperties); 1.766 + bool ParseTransition(); 1.767 + bool ParseAnimation(); 1.768 + bool ParseWillChange(); 1.769 + 1.770 + bool ParsePaint(nsCSSProperty aPropID); 1.771 + bool ParseDasharray(); 1.772 + bool ParseMarker(); 1.773 + bool ParsePaintOrder(); 1.774 + bool ParseAll(); 1.775 + 1.776 + /** 1.777 + * Parses a variable value from a custom property declaration. 1.778 + * 1.779 + * @param aType Out parameter into which will be stored the type of variable 1.780 + * value, indicating whether the parsed value was a token stream or one of 1.781 + * the CSS-wide keywords. 1.782 + * @param aValue Out parameter into which will be stored the token stream 1.783 + * as a string, if the parsed custom property did take a token stream. 1.784 + * @return Whether parsing succeeded. 1.785 + */ 1.786 + bool ParseVariableDeclaration(CSSVariableDeclarations::Type* aType, 1.787 + nsString& aValue); 1.788 + 1.789 + /** 1.790 + * Parses a CSS variable value. This could be 'initial', 'inherit', 'unset' 1.791 + * or a token stream, which may or may not include variable references. 1.792 + * 1.793 + * @param aType Out parameter into which the type of the variable value 1.794 + * will be stored. 1.795 + * @param aDropBackslash Out parameter indicating whether during variable 1.796 + * value parsing there was a trailing backslash before EOF that must 1.797 + * be dropped when serializing the variable value. 1.798 + * @param aImpliedCharacters Out parameter appended to which will be any 1.799 + * characters that were implied when encountering EOF and which 1.800 + * must be included at the end of the serialized variable value. 1.801 + * @param aFunc A callback function to invoke when a variable reference 1.802 + * is encountered. May be null. Arguments are the variable name 1.803 + * and the aData argument passed in to this function. 1.804 + * @param User data to pass in to the callback. 1.805 + * @return Whether parsing succeeded. 1.806 + */ 1.807 + bool ParseValueWithVariables(CSSVariableDeclarations::Type* aType, 1.808 + bool* aDropBackslash, 1.809 + nsString& aImpliedCharacters, 1.810 + void (*aFunc)(const nsAString&, void*), 1.811 + void* aData); 1.812 + 1.813 + /** 1.814 + * Returns whether the scanner dropped a backslash just before EOF. 1.815 + */ 1.816 + bool BackslashDropped(); 1.817 + 1.818 + /** 1.819 + * Calls AppendImpliedEOFCharacters on mScanner. 1.820 + */ 1.821 + void AppendImpliedEOFCharacters(nsAString& aResult); 1.822 + 1.823 + // Reused utility parsing routines 1.824 + void AppendValue(nsCSSProperty aPropID, const nsCSSValue& aValue); 1.825 + bool ParseBoxProperties(const nsCSSProperty aPropIDs[]); 1.826 + bool ParseGroupedBoxProperty(int32_t aVariantMask, 1.827 + nsCSSValue& aValue); 1.828 + bool ParseDirectionalBoxProperty(nsCSSProperty aProperty, 1.829 + int32_t aSourceType); 1.830 + bool ParseBoxCornerRadius(const nsCSSProperty aPropID); 1.831 + bool ParseBoxCornerRadii(const nsCSSProperty aPropIDs[]); 1.832 + int32_t ParseChoice(nsCSSValue aValues[], 1.833 + const nsCSSProperty aPropIDs[], int32_t aNumIDs); 1.834 + bool ParseColor(nsCSSValue& aValue); 1.835 + bool ParseNumberColorComponent(uint8_t& aComponent, char aStop); 1.836 + bool ParsePercentageColorComponent(float& aComponent, char aStop); 1.837 + // ParseHSLColor parses everything starting with the opening '(' 1.838 + // up through and including the aStop char. 1.839 + bool ParseHSLColor(float& aHue, float& aSaturation, float& aLightness, 1.840 + char aStop); 1.841 + // ParseColorOpacity will enforce that the color ends with a ')' 1.842 + // after the opacity 1.843 + bool ParseColorOpacity(uint8_t& aOpacity); 1.844 + bool ParseColorOpacity(float& aOpacity); 1.845 + bool ParseEnum(nsCSSValue& aValue, 1.846 + const KTableValue aKeywordTable[]); 1.847 + bool ParseVariant(nsCSSValue& aValue, 1.848 + int32_t aVariantMask, 1.849 + const KTableValue aKeywordTable[]); 1.850 + bool ParseNonNegativeVariant(nsCSSValue& aValue, 1.851 + int32_t aVariantMask, 1.852 + const KTableValue aKeywordTable[]); 1.853 + bool ParseOneOrLargerVariant(nsCSSValue& aValue, 1.854 + int32_t aVariantMask, 1.855 + const KTableValue aKeywordTable[]); 1.856 + 1.857 + // http://dev.w3.org/csswg/css-values/#custom-idents 1.858 + // Parse an identifier that is none of: 1.859 + // * a CSS-wide keyword 1.860 + // * "default" 1.861 + // * a keyword in |aExcludedKeywords| 1.862 + // * a keyword in |aPropertyKTable| 1.863 + // 1.864 + // |aExcludedKeywords| is an array of nsCSSKeyword 1.865 + // that ends with a eCSSKeyword_UNKNOWN marker. 1.866 + // 1.867 + // |aPropertyKTable| can be used if some of the keywords to exclude 1.868 + // also appear in an existing nsCSSProps::KTableValue, 1.869 + // to avoid duplicating them. 1.870 + bool ParseCustomIdent(nsCSSValue& aValue, 1.871 + const nsAutoString& aIdentValue, 1.872 + const nsCSSKeyword aExcludedKeywords[] = nullptr, 1.873 + const nsCSSProps::KTableValue aPropertyKTable[] = nullptr); 1.874 + bool ParseCounter(nsCSSValue& aValue); 1.875 + bool ParseAttr(nsCSSValue& aValue); 1.876 + bool SetValueToURL(nsCSSValue& aValue, const nsString& aURL); 1.877 + bool TranslateDimension(nsCSSValue& aValue, int32_t aVariantMask, 1.878 + float aNumber, const nsString& aUnit); 1.879 + bool ParseImageOrientation(nsCSSValue& aAngle); 1.880 + bool ParseImageRect(nsCSSValue& aImage); 1.881 + bool ParseElement(nsCSSValue& aValue); 1.882 + bool ParseColorStop(nsCSSValueGradient* aGradient); 1.883 + bool ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating, 1.884 + bool aIsLegacy); 1.885 + bool ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating, 1.886 + bool aIsLegacy); 1.887 + bool IsLegacyGradientLine(const nsCSSTokenType& aType, 1.888 + const nsString& aId); 1.889 + bool ParseGradientColorStops(nsCSSValueGradient* aGradient, 1.890 + nsCSSValue& aValue); 1.891 + 1.892 + void SetParsingCompoundProperty(bool aBool) { 1.893 + mParsingCompoundProperty = aBool; 1.894 + } 1.895 + bool IsParsingCompoundProperty(void) const { 1.896 + return mParsingCompoundProperty; 1.897 + } 1.898 + 1.899 + /* Functions for transform Parsing */ 1.900 + bool ParseSingleTransform(bool aIsPrefixed, nsCSSValue& aValue); 1.901 + bool ParseFunction(nsCSSKeyword aFunction, const int32_t aAllowedTypes[], 1.902 + int32_t aVariantMaskAll, uint16_t aMinElems, 1.903 + uint16_t aMaxElems, nsCSSValue &aValue); 1.904 + bool ParseFunctionInternals(const int32_t aVariantMask[], 1.905 + int32_t aVariantMaskAll, 1.906 + uint16_t aMinElems, 1.907 + uint16_t aMaxElems, 1.908 + InfallibleTArray<nsCSSValue>& aOutput); 1.909 + 1.910 + /* Functions for transform-origin/perspective-origin Parsing */ 1.911 + bool ParseTransformOrigin(bool aPerspective); 1.912 + 1.913 + /* Functions for filter parsing */ 1.914 + bool ParseFilter(); 1.915 + bool ParseSingleFilter(nsCSSValue* aValue); 1.916 + bool ParseDropShadow(nsCSSValue* aValue); 1.917 + 1.918 + /* Find and return the namespace ID associated with aPrefix. 1.919 + If aPrefix has not been declared in an @namespace rule, returns 1.920 + kNameSpaceID_Unknown. */ 1.921 + int32_t GetNamespaceIdForPrefix(const nsString& aPrefix); 1.922 + 1.923 + /* Find the correct default namespace, and set it on aSelector. */ 1.924 + void SetDefaultNamespaceOnSelector(nsCSSSelector& aSelector); 1.925 + 1.926 + // Current token. The value is valid after calling GetToken and invalidated 1.927 + // by UngetToken. 1.928 + nsCSSToken mToken; 1.929 + 1.930 + // Our scanner. 1.931 + nsCSSScanner* mScanner; 1.932 + 1.933 + // Our error reporter. 1.934 + css::ErrorReporter* mReporter; 1.935 + 1.936 + // The URI to be used as a base for relative URIs. 1.937 + nsCOMPtr<nsIURI> mBaseURI; 1.938 + 1.939 + // The URI to be used as an HTTP "Referer" and for error reporting. 1.940 + nsCOMPtr<nsIURI> mSheetURI; 1.941 + 1.942 + // The principal of the sheet involved 1.943 + nsCOMPtr<nsIPrincipal> mSheetPrincipal; 1.944 + 1.945 + // The sheet we're parsing into 1.946 + nsRefPtr<nsCSSStyleSheet> mSheet; 1.947 + 1.948 + // Used for @import rules 1.949 + mozilla::css::Loader* mChildLoader; // not ref counted, it owns us 1.950 + 1.951 + // Sheet section we're in. This is used to enforce correct ordering of the 1.952 + // various rule types (eg the fact that a @charset rule must come before 1.953 + // anything else). Note that there are checks of similar things in various 1.954 + // places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList). 1.955 + enum nsCSSSection { 1.956 + eCSSSection_Charset, 1.957 + eCSSSection_Import, 1.958 + eCSSSection_NameSpace, 1.959 + eCSSSection_General 1.960 + }; 1.961 + nsCSSSection mSection; 1.962 + 1.963 + nsXMLNameSpaceMap *mNameSpaceMap; // weak, mSheet owns it 1.964 + 1.965 + // After an UngetToken is done this flag is true. The next call to 1.966 + // GetToken clears the flag. 1.967 + bool mHavePushBack : 1; 1.968 + 1.969 + // True if we are in quirks mode; false in standards or almost standards mode 1.970 + bool mNavQuirkMode : 1; 1.971 + 1.972 + // True when the hashless color quirk applies. 1.973 + bool mHashlessColorQuirk : 1; 1.974 + 1.975 + // True when the unitless length quirk applies. 1.976 + bool mUnitlessLengthQuirk : 1; 1.977 + 1.978 + // True if unsafe rules should be allowed 1.979 + bool mUnsafeRulesEnabled : 1; 1.980 + 1.981 + // True if we are in parsing rules for Chrome or Certified App content, 1.982 + // in which case CSS properties with the 1.983 + // CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP 1.984 + // flag should be allowed. 1.985 + bool mIsChromeOrCertifiedApp : 1; 1.986 + 1.987 + // True if viewport units should be allowed. 1.988 + bool mViewportUnitsEnabled : 1; 1.989 + 1.990 + // True for parsing media lists for HTML attributes, where we have to 1.991 + // ignore CSS comments. 1.992 + bool mHTMLMediaMode : 1; 1.993 + 1.994 + // This flag is set when parsing a non-box shorthand; it's used to not apply 1.995 + // some quirks during shorthand parsing 1.996 + bool mParsingCompoundProperty : 1; 1.997 + 1.998 + // True if we are in the middle of parsing an @supports condition. 1.999 + // This is used to avoid recording the input stream when variable references 1.1000 + // are encountered in a property declaration in the @supports condition. 1.1001 + bool mInSupportsCondition : 1; 1.1002 + 1.1003 + // True if we are somewhere within a @supports rule whose condition is 1.1004 + // false. 1.1005 + bool mInFailingSupportsRule : 1; 1.1006 + 1.1007 + // True if we will suppress all parse errors (except unexpected EOFs). 1.1008 + // This is used to prevent errors for declarations inside a failing 1.1009 + // @supports rule. 1.1010 + bool mSuppressErrors : 1; 1.1011 + 1.1012 + // Stack of rule groups; used for @media and such. 1.1013 + InfallibleTArray<nsRefPtr<css::GroupRule> > mGroupStack; 1.1014 + 1.1015 + // During the parsing of a property (which may be a shorthand), the data 1.1016 + // are stored in |mTempData|. (It is needed to ensure that parser 1.1017 + // errors cause the data to be ignored, and to ensure that a 1.1018 + // non-'!important' declaration does not override an '!important' 1.1019 + // one.) 1.1020 + nsCSSExpandedDataBlock mTempData; 1.1021 + 1.1022 + // All data from successfully parsed properties are placed into |mData|. 1.1023 + nsCSSExpandedDataBlock mData; 1.1024 + 1.1025 +public: 1.1026 + // Used from nsCSSParser constructors and destructors 1.1027 + CSSParserImpl* mNextFree; 1.1028 +}; 1.1029 + 1.1030 +static void AssignRuleToPointer(css::Rule* aRule, void* aPointer) 1.1031 +{ 1.1032 + css::Rule **pointer = static_cast<css::Rule**>(aPointer); 1.1033 + NS_ADDREF(*pointer = aRule); 1.1034 +} 1.1035 + 1.1036 +static void AppendRuleToSheet(css::Rule* aRule, void* aParser) 1.1037 +{ 1.1038 + CSSParserImpl* parser = (CSSParserImpl*) aParser; 1.1039 + parser->AppendRule(aRule); 1.1040 +} 1.1041 + 1.1042 +#define REPORT_UNEXPECTED(msg_) \ 1.1043 + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_); } 1.1044 + 1.1045 +#define REPORT_UNEXPECTED_P(msg_, param_) \ 1.1046 + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, param_); } 1.1047 + 1.1048 +#define REPORT_UNEXPECTED_TOKEN(msg_) \ 1.1049 + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken); } 1.1050 + 1.1051 +#define REPORT_UNEXPECTED_TOKEN_CHAR(msg_, ch_) \ 1.1052 + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken, ch_); } 1.1053 + 1.1054 +#define REPORT_UNEXPECTED_EOF(lf_) \ 1.1055 + mReporter->ReportUnexpectedEOF(#lf_) 1.1056 + 1.1057 +#define REPORT_UNEXPECTED_EOF_CHAR(ch_) \ 1.1058 + mReporter->ReportUnexpectedEOF(ch_) 1.1059 + 1.1060 +#define OUTPUT_ERROR() \ 1.1061 + mReporter->OutputError() 1.1062 + 1.1063 +#define OUTPUT_ERROR_WITH_POSITION(linenum_, lineoff_) \ 1.1064 + mReporter->OutputError(linenum_, lineoff_) 1.1065 + 1.1066 +#define CLEAR_ERROR() \ 1.1067 + mReporter->ClearError() 1.1068 + 1.1069 +CSSParserImpl::CSSParserImpl() 1.1070 + : mToken(), 1.1071 + mScanner(nullptr), 1.1072 + mReporter(nullptr), 1.1073 + mChildLoader(nullptr), 1.1074 + mSection(eCSSSection_Charset), 1.1075 + mNameSpaceMap(nullptr), 1.1076 + mHavePushBack(false), 1.1077 + mNavQuirkMode(false), 1.1078 + mHashlessColorQuirk(false), 1.1079 + mUnitlessLengthQuirk(false), 1.1080 + mUnsafeRulesEnabled(false), 1.1081 + mIsChromeOrCertifiedApp(false), 1.1082 + mViewportUnitsEnabled(true), 1.1083 + mHTMLMediaMode(false), 1.1084 + mParsingCompoundProperty(false), 1.1085 + mInSupportsCondition(false), 1.1086 + mInFailingSupportsRule(false), 1.1087 + mSuppressErrors(false), 1.1088 + mNextFree(nullptr) 1.1089 +{ 1.1090 +} 1.1091 + 1.1092 +CSSParserImpl::~CSSParserImpl() 1.1093 +{ 1.1094 + mData.AssertInitialState(); 1.1095 + mTempData.AssertInitialState(); 1.1096 +} 1.1097 + 1.1098 +nsresult 1.1099 +CSSParserImpl::SetStyleSheet(nsCSSStyleSheet* aSheet) 1.1100 +{ 1.1101 + if (aSheet != mSheet) { 1.1102 + // Switch to using the new sheet, if any 1.1103 + mGroupStack.Clear(); 1.1104 + mSheet = aSheet; 1.1105 + if (mSheet) { 1.1106 + mNameSpaceMap = mSheet->GetNameSpaceMap(); 1.1107 + } else { 1.1108 + mNameSpaceMap = nullptr; 1.1109 + } 1.1110 + } else if (mSheet) { 1.1111 + mNameSpaceMap = mSheet->GetNameSpaceMap(); 1.1112 + } 1.1113 + 1.1114 + return NS_OK; 1.1115 +} 1.1116 + 1.1117 +nsresult 1.1118 +CSSParserImpl::SetQuirkMode(bool aQuirkMode) 1.1119 +{ 1.1120 + mNavQuirkMode = aQuirkMode; 1.1121 + return NS_OK; 1.1122 +} 1.1123 + 1.1124 +nsresult 1.1125 +CSSParserImpl::SetChildLoader(mozilla::css::Loader* aChildLoader) 1.1126 +{ 1.1127 + mChildLoader = aChildLoader; // not ref counted, it owns us 1.1128 + return NS_OK; 1.1129 +} 1.1130 + 1.1131 +void 1.1132 +CSSParserImpl::Reset() 1.1133 +{ 1.1134 + NS_ASSERTION(!mScanner, "resetting with scanner active"); 1.1135 + SetStyleSheet(nullptr); 1.1136 + SetQuirkMode(false); 1.1137 + SetChildLoader(nullptr); 1.1138 +} 1.1139 + 1.1140 +void 1.1141 +CSSParserImpl::InitScanner(nsCSSScanner& aScanner, 1.1142 + css::ErrorReporter& aReporter, 1.1143 + nsIURI* aSheetURI, nsIURI* aBaseURI, 1.1144 + nsIPrincipal* aSheetPrincipal) 1.1145 +{ 1.1146 + NS_PRECONDITION(!mHTMLMediaMode, "Bad initial state"); 1.1147 + NS_PRECONDITION(!mParsingCompoundProperty, "Bad initial state"); 1.1148 + NS_PRECONDITION(!mScanner, "already have scanner"); 1.1149 + 1.1150 + mScanner = &aScanner; 1.1151 + mReporter = &aReporter; 1.1152 + mScanner->SetErrorReporter(mReporter); 1.1153 + 1.1154 + mBaseURI = aBaseURI; 1.1155 + mSheetURI = aSheetURI; 1.1156 + mSheetPrincipal = aSheetPrincipal; 1.1157 + mHavePushBack = false; 1.1158 +} 1.1159 + 1.1160 +void 1.1161 +CSSParserImpl::ReleaseScanner() 1.1162 +{ 1.1163 + mScanner = nullptr; 1.1164 + mReporter = nullptr; 1.1165 + mBaseURI = nullptr; 1.1166 + mSheetURI = nullptr; 1.1167 + mSheetPrincipal = nullptr; 1.1168 +} 1.1169 + 1.1170 +nsresult 1.1171 +CSSParserImpl::ParseSheet(const nsAString& aInput, 1.1172 + nsIURI* aSheetURI, 1.1173 + nsIURI* aBaseURI, 1.1174 + nsIPrincipal* aSheetPrincipal, 1.1175 + uint32_t aLineNumber, 1.1176 + bool aAllowUnsafeRules) 1.1177 +{ 1.1178 + NS_PRECONDITION(aSheetPrincipal, "Must have principal here!"); 1.1179 + NS_PRECONDITION(aBaseURI, "need base URI"); 1.1180 + NS_PRECONDITION(aSheetURI, "need sheet URI"); 1.1181 + NS_PRECONDITION(mSheet, "Must have sheet to parse into"); 1.1182 + NS_ENSURE_STATE(mSheet); 1.1183 + 1.1184 +#ifdef DEBUG 1.1185 + nsIURI* uri = mSheet->GetSheetURI(); 1.1186 + bool equal; 1.1187 + NS_ASSERTION(NS_SUCCEEDED(aSheetURI->Equals(uri, &equal)) && equal, 1.1188 + "Sheet URI does not match passed URI"); 1.1189 + NS_ASSERTION(NS_SUCCEEDED(mSheet->Principal()->Equals(aSheetPrincipal, 1.1190 + &equal)) && 1.1191 + equal, 1.1192 + "Sheet principal does not match passed principal"); 1.1193 +#endif 1.1194 + 1.1195 + nsCSSScanner scanner(aInput, aLineNumber); 1.1196 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI); 1.1197 + InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal); 1.1198 + 1.1199 + int32_t ruleCount = mSheet->StyleRuleCount(); 1.1200 + if (0 < ruleCount) { 1.1201 + const css::Rule* lastRule = mSheet->GetStyleRuleAt(ruleCount - 1); 1.1202 + if (lastRule) { 1.1203 + switch (lastRule->GetType()) { 1.1204 + case css::Rule::CHARSET_RULE: 1.1205 + case css::Rule::IMPORT_RULE: 1.1206 + mSection = eCSSSection_Import; 1.1207 + break; 1.1208 + case css::Rule::NAMESPACE_RULE: 1.1209 + mSection = eCSSSection_NameSpace; 1.1210 + break; 1.1211 + default: 1.1212 + mSection = eCSSSection_General; 1.1213 + break; 1.1214 + } 1.1215 + } 1.1216 + } 1.1217 + else { 1.1218 + mSection = eCSSSection_Charset; // sheet is empty, any rules are fair 1.1219 + } 1.1220 + 1.1221 + mUnsafeRulesEnabled = aAllowUnsafeRules; 1.1222 + mIsChromeOrCertifiedApp = 1.1223 + dom::IsChromeURI(aSheetURI) || 1.1224 + aSheetPrincipal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED; 1.1225 + 1.1226 + nsCSSToken* tk = &mToken; 1.1227 + for (;;) { 1.1228 + // Get next non-whitespace token 1.1229 + if (!GetToken(true)) { 1.1230 + OUTPUT_ERROR(); 1.1231 + break; 1.1232 + } 1.1233 + if (eCSSToken_HTMLComment == tk->mType) { 1.1234 + continue; // legal here only 1.1235 + } 1.1236 + if (eCSSToken_AtKeyword == tk->mType) { 1.1237 + ParseAtRule(AppendRuleToSheet, this, false); 1.1238 + continue; 1.1239 + } 1.1240 + UngetToken(); 1.1241 + if (ParseRuleSet(AppendRuleToSheet, this)) { 1.1242 + mSection = eCSSSection_General; 1.1243 + } 1.1244 + } 1.1245 + ReleaseScanner(); 1.1246 + 1.1247 + mUnsafeRulesEnabled = false; 1.1248 + mIsChromeOrCertifiedApp = false; 1.1249 + 1.1250 + // XXX check for low level errors 1.1251 + return NS_OK; 1.1252 +} 1.1253 + 1.1254 +/** 1.1255 + * Determines whether the identifier contained in the given string is a 1.1256 + * vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1. 1.1257 + */ 1.1258 +static bool 1.1259 +NonMozillaVendorIdentifier(const nsAString& ident) 1.1260 +{ 1.1261 + return (ident.First() == char16_t('-') && 1.1262 + !StringBeginsWith(ident, NS_LITERAL_STRING("-moz-"))) || 1.1263 + ident.First() == char16_t('_'); 1.1264 + 1.1265 +} 1.1266 + 1.1267 +nsresult 1.1268 +CSSParserImpl::ParseStyleAttribute(const nsAString& aAttributeValue, 1.1269 + nsIURI* aDocURI, 1.1270 + nsIURI* aBaseURI, 1.1271 + nsIPrincipal* aNodePrincipal, 1.1272 + css::StyleRule** aResult) 1.1273 +{ 1.1274 + NS_PRECONDITION(aNodePrincipal, "Must have principal here!"); 1.1275 + NS_PRECONDITION(aBaseURI, "need base URI"); 1.1276 + 1.1277 + // XXX line number? 1.1278 + nsCSSScanner scanner(aAttributeValue, 0); 1.1279 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURI); 1.1280 + InitScanner(scanner, reporter, aDocURI, aBaseURI, aNodePrincipal); 1.1281 + 1.1282 + mSection = eCSSSection_General; 1.1283 + 1.1284 + uint32_t parseFlags = eParseDeclaration_AllowImportant; 1.1285 + 1.1286 + css::Declaration* declaration = ParseDeclarationBlock(parseFlags); 1.1287 + if (declaration) { 1.1288 + // Create a style rule for the declaration 1.1289 + NS_ADDREF(*aResult = new css::StyleRule(nullptr, declaration)); 1.1290 + } else { 1.1291 + *aResult = nullptr; 1.1292 + } 1.1293 + 1.1294 + ReleaseScanner(); 1.1295 + 1.1296 + // XXX check for low level errors 1.1297 + return NS_OK; 1.1298 +} 1.1299 + 1.1300 +nsresult 1.1301 +CSSParserImpl::ParseDeclarations(const nsAString& aBuffer, 1.1302 + nsIURI* aSheetURI, 1.1303 + nsIURI* aBaseURI, 1.1304 + nsIPrincipal* aSheetPrincipal, 1.1305 + css::Declaration* aDeclaration, 1.1306 + bool* aChanged) 1.1307 +{ 1.1308 + *aChanged = false; 1.1309 + 1.1310 + NS_PRECONDITION(aSheetPrincipal, "Must have principal here!"); 1.1311 + 1.1312 + nsCSSScanner scanner(aBuffer, 0); 1.1313 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI); 1.1314 + InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal); 1.1315 + 1.1316 + mSection = eCSSSection_General; 1.1317 + 1.1318 + mData.AssertInitialState(); 1.1319 + aDeclaration->ClearData(); 1.1320 + // We could check if it was already empty, but... 1.1321 + *aChanged = true; 1.1322 + 1.1323 + for (;;) { 1.1324 + // If we cleared the old decl, then we want to be calling 1.1325 + // ValueAppended as we parse. 1.1326 + if (!ParseDeclaration(aDeclaration, eParseDeclaration_AllowImportant, 1.1327 + true, aChanged)) { 1.1328 + if (!SkipDeclaration(false)) { 1.1329 + break; 1.1330 + } 1.1331 + } 1.1332 + } 1.1333 + 1.1334 + aDeclaration->CompressFrom(&mData); 1.1335 + ReleaseScanner(); 1.1336 + return NS_OK; 1.1337 +} 1.1338 + 1.1339 +nsresult 1.1340 +CSSParserImpl::ParseRule(const nsAString& aRule, 1.1341 + nsIURI* aSheetURI, 1.1342 + nsIURI* aBaseURI, 1.1343 + nsIPrincipal* aSheetPrincipal, 1.1344 + css::Rule** aResult) 1.1345 +{ 1.1346 + NS_PRECONDITION(aSheetPrincipal, "Must have principal here!"); 1.1347 + NS_PRECONDITION(aBaseURI, "need base URI"); 1.1348 + 1.1349 + *aResult = nullptr; 1.1350 + 1.1351 + nsCSSScanner scanner(aRule, 0); 1.1352 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI); 1.1353 + InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal); 1.1354 + 1.1355 + mSection = eCSSSection_Charset; // callers are responsible for rejecting invalid rules. 1.1356 + 1.1357 + nsCSSToken* tk = &mToken; 1.1358 + // Get first non-whitespace token 1.1359 + nsresult rv = NS_OK; 1.1360 + if (!GetToken(true)) { 1.1361 + REPORT_UNEXPECTED(PEParseRuleWSOnly); 1.1362 + OUTPUT_ERROR(); 1.1363 + rv = NS_ERROR_DOM_SYNTAX_ERR; 1.1364 + } else { 1.1365 + if (eCSSToken_AtKeyword == tk->mType) { 1.1366 + // FIXME: perhaps aInsideBlock should be true when we are? 1.1367 + ParseAtRule(AssignRuleToPointer, aResult, false); 1.1368 + } else { 1.1369 + UngetToken(); 1.1370 + ParseRuleSet(AssignRuleToPointer, aResult); 1.1371 + } 1.1372 + 1.1373 + if (*aResult && GetToken(true)) { 1.1374 + // garbage after rule 1.1375 + REPORT_UNEXPECTED_TOKEN(PERuleTrailing); 1.1376 + NS_RELEASE(*aResult); 1.1377 + } 1.1378 + 1.1379 + if (!*aResult) { 1.1380 + rv = NS_ERROR_DOM_SYNTAX_ERR; 1.1381 + OUTPUT_ERROR(); 1.1382 + } 1.1383 + } 1.1384 + 1.1385 + ReleaseScanner(); 1.1386 + return rv; 1.1387 +} 1.1388 + 1.1389 +// See Bug 723197 1.1390 +#ifdef _MSC_VER 1.1391 +#pragma optimize( "", off ) 1.1392 +#pragma warning( push ) 1.1393 +#pragma warning( disable : 4748 ) 1.1394 +#endif 1.1395 + 1.1396 +nsresult 1.1397 +CSSParserImpl::ParseProperty(const nsCSSProperty aPropID, 1.1398 + const nsAString& aPropValue, 1.1399 + nsIURI* aSheetURI, 1.1400 + nsIURI* aBaseURI, 1.1401 + nsIPrincipal* aSheetPrincipal, 1.1402 + css::Declaration* aDeclaration, 1.1403 + bool* aChanged, 1.1404 + bool aIsImportant, 1.1405 + bool aIsSVGMode) 1.1406 +{ 1.1407 + NS_PRECONDITION(aSheetPrincipal, "Must have principal here!"); 1.1408 + NS_PRECONDITION(aBaseURI, "need base URI"); 1.1409 + NS_PRECONDITION(aDeclaration, "Need declaration to parse into!"); 1.1410 + 1.1411 + mData.AssertInitialState(); 1.1412 + mTempData.AssertInitialState(); 1.1413 + aDeclaration->AssertMutable(); 1.1414 + 1.1415 + nsCSSScanner scanner(aPropValue, 0); 1.1416 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI); 1.1417 + InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal); 1.1418 + mSection = eCSSSection_General; 1.1419 + scanner.SetSVGMode(aIsSVGMode); 1.1420 + 1.1421 + *aChanged = false; 1.1422 + 1.1423 + // Check for unknown or preffed off properties 1.1424 + if (eCSSProperty_UNKNOWN == aPropID || 1.1425 + !(nsCSSProps::IsEnabled(aPropID) || 1.1426 + (mUnsafeRulesEnabled && 1.1427 + nsCSSProps::PropHasFlags(aPropID, 1.1428 + CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS)))) { 1.1429 + NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID)); 1.1430 + REPORT_UNEXPECTED_P(PEUnknownProperty, propName); 1.1431 + REPORT_UNEXPECTED(PEDeclDropped); 1.1432 + OUTPUT_ERROR(); 1.1433 + ReleaseScanner(); 1.1434 + return NS_OK; 1.1435 + } 1.1436 + 1.1437 + bool parsedOK = ParseProperty(aPropID); 1.1438 + // We should now be at EOF 1.1439 + if (parsedOK && GetToken(true)) { 1.1440 + REPORT_UNEXPECTED_TOKEN(PEExpectEndValue); 1.1441 + parsedOK = false; 1.1442 + } 1.1443 + 1.1444 + if (!parsedOK) { 1.1445 + NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID)); 1.1446 + REPORT_UNEXPECTED_P(PEValueParsingError, propName); 1.1447 + REPORT_UNEXPECTED(PEDeclDropped); 1.1448 + OUTPUT_ERROR(); 1.1449 + mTempData.ClearProperty(aPropID); 1.1450 + } else { 1.1451 + 1.1452 + // We know we don't need to force a ValueAppended call for the new 1.1453 + // value. So if we are not processing a shorthand, and there's 1.1454 + // already a value for this property in the declaration at the 1.1455 + // same importance level, then we can just copy our parsed value 1.1456 + // directly into the declaration without going through the whole 1.1457 + // expand/compress thing. 1.1458 + if (!aDeclaration->TryReplaceValue(aPropID, aIsImportant, mTempData, 1.1459 + aChanged)) { 1.1460 + // Do it the slow way 1.1461 + aDeclaration->ExpandTo(&mData); 1.1462 + *aChanged = mData.TransferFromBlock(mTempData, aPropID, aIsImportant, 1.1463 + true, false, aDeclaration); 1.1464 + aDeclaration->CompressFrom(&mData); 1.1465 + } 1.1466 + CLEAR_ERROR(); 1.1467 + } 1.1468 + 1.1469 + mTempData.AssertInitialState(); 1.1470 + 1.1471 + ReleaseScanner(); 1.1472 + return NS_OK; 1.1473 +} 1.1474 + 1.1475 +nsresult 1.1476 +CSSParserImpl::ParseVariable(const nsAString& aVariableName, 1.1477 + const nsAString& aPropValue, 1.1478 + nsIURI* aSheetURI, 1.1479 + nsIURI* aBaseURI, 1.1480 + nsIPrincipal* aSheetPrincipal, 1.1481 + css::Declaration* aDeclaration, 1.1482 + bool* aChanged, 1.1483 + bool aIsImportant) 1.1484 +{ 1.1485 + NS_PRECONDITION(aSheetPrincipal, "Must have principal here!"); 1.1486 + NS_PRECONDITION(aBaseURI, "need base URI"); 1.1487 + NS_PRECONDITION(aDeclaration, "Need declaration to parse into!"); 1.1488 + NS_PRECONDITION(nsLayoutUtils::CSSVariablesEnabled(), 1.1489 + "expected Variables to be enabled"); 1.1490 + 1.1491 + mData.AssertInitialState(); 1.1492 + mTempData.AssertInitialState(); 1.1493 + aDeclaration->AssertMutable(); 1.1494 + 1.1495 + nsCSSScanner scanner(aPropValue, 0); 1.1496 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI); 1.1497 + InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal); 1.1498 + mSection = eCSSSection_General; 1.1499 + 1.1500 + *aChanged = false; 1.1501 + 1.1502 + CSSVariableDeclarations::Type variableType; 1.1503 + nsString variableValue; 1.1504 + 1.1505 + bool parsedOK = ParseVariableDeclaration(&variableType, variableValue); 1.1506 + 1.1507 + // We should now be at EOF 1.1508 + if (parsedOK && GetToken(true)) { 1.1509 + REPORT_UNEXPECTED_TOKEN(PEExpectEndValue); 1.1510 + parsedOK = false; 1.1511 + } 1.1512 + 1.1513 + if (!parsedOK) { 1.1514 + REPORT_UNEXPECTED_P(PEValueParsingError, NS_LITERAL_STRING("--") + 1.1515 + aVariableName); 1.1516 + REPORT_UNEXPECTED(PEDeclDropped); 1.1517 + OUTPUT_ERROR(); 1.1518 + } else { 1.1519 + CLEAR_ERROR(); 1.1520 + aDeclaration->AddVariableDeclaration(aVariableName, variableType, 1.1521 + variableValue, aIsImportant, true); 1.1522 + *aChanged = true; 1.1523 + } 1.1524 + 1.1525 + mTempData.AssertInitialState(); 1.1526 + 1.1527 + ReleaseScanner(); 1.1528 + return NS_OK; 1.1529 +} 1.1530 + 1.1531 +#ifdef _MSC_VER 1.1532 +#pragma warning( pop ) 1.1533 +#pragma optimize( "", on ) 1.1534 +#endif 1.1535 + 1.1536 +void 1.1537 +CSSParserImpl::ParseMediaList(const nsSubstring& aBuffer, 1.1538 + nsIURI* aURI, // for error reporting 1.1539 + uint32_t aLineNumber, // for error reporting 1.1540 + nsMediaList* aMediaList, 1.1541 + bool aHTMLMode) 1.1542 +{ 1.1543 + // XXX Are there cases where the caller wants to keep what it already 1.1544 + // has in case of parser error? If GatherMedia ever changes to return 1.1545 + // a value other than true, we probably should avoid modifying aMediaList. 1.1546 + aMediaList->Clear(); 1.1547 + 1.1548 + // fake base URI since media lists don't have URIs in them 1.1549 + nsCSSScanner scanner(aBuffer, aLineNumber); 1.1550 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI); 1.1551 + InitScanner(scanner, reporter, aURI, aURI, nullptr); 1.1552 + 1.1553 + mHTMLMediaMode = aHTMLMode; 1.1554 + 1.1555 + // XXXldb We need to make the scanner not skip CSS comments! (Or 1.1556 + // should we?) 1.1557 + 1.1558 + // For aHTMLMode, we used to follow the parsing rules in 1.1559 + // http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-media-descriptors 1.1560 + // which wouldn't work for media queries since they remove all but the 1.1561 + // first word. However, they're changed in 1.1562 + // http://www.whatwg.org/specs/web-apps/current-work/multipage/section-document.html#media2 1.1563 + // (as of 2008-05-29) which says that the media attribute just points 1.1564 + // to a media query. (The main substative difference is the relative 1.1565 + // precedence of commas and paretheses.) 1.1566 + 1.1567 + DebugOnly<bool> parsedOK = GatherMedia(aMediaList, false); 1.1568 + NS_ASSERTION(parsedOK, "GatherMedia returned false; we probably want to avoid " 1.1569 + "trashing aMediaList"); 1.1570 + 1.1571 + CLEAR_ERROR(); 1.1572 + ReleaseScanner(); 1.1573 + mHTMLMediaMode = false; 1.1574 +} 1.1575 + 1.1576 +bool 1.1577 +CSSParserImpl::ParseColorString(const nsSubstring& aBuffer, 1.1578 + nsIURI* aURI, // for error reporting 1.1579 + uint32_t aLineNumber, // for error reporting 1.1580 + nsCSSValue& aValue) 1.1581 +{ 1.1582 + nsCSSScanner scanner(aBuffer, aLineNumber); 1.1583 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI); 1.1584 + InitScanner(scanner, reporter, aURI, aURI, nullptr); 1.1585 + 1.1586 + // Parse a color, and check that there's nothing else after it. 1.1587 + bool colorParsed = ParseColor(aValue) && !GetToken(true); 1.1588 + OUTPUT_ERROR(); 1.1589 + ReleaseScanner(); 1.1590 + return colorParsed; 1.1591 +} 1.1592 + 1.1593 +nsresult 1.1594 +CSSParserImpl::ParseSelectorString(const nsSubstring& aSelectorString, 1.1595 + nsIURI* aURI, // for error reporting 1.1596 + uint32_t aLineNumber, // for error reporting 1.1597 + nsCSSSelectorList **aSelectorList) 1.1598 +{ 1.1599 + nsCSSScanner scanner(aSelectorString, aLineNumber); 1.1600 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI); 1.1601 + InitScanner(scanner, reporter, aURI, aURI, nullptr); 1.1602 + 1.1603 + bool success = ParseSelectorList(*aSelectorList, char16_t(0)); 1.1604 + 1.1605 + // We deliberately do not call OUTPUT_ERROR here, because all our 1.1606 + // callers map a failure return to a JS exception, and if that JS 1.1607 + // exception is caught, people don't want to see parser diagnostics; 1.1608 + // see e.g. http://bugs.jquery.com/ticket/7535 1.1609 + // It would be nice to be able to save the parser diagnostics into 1.1610 + // the exception, so that if it _isn't_ caught we can report them 1.1611 + // along with the usual uncaught-exception message, but we don't 1.1612 + // have any way to do that at present; see bug 631621. 1.1613 + CLEAR_ERROR(); 1.1614 + ReleaseScanner(); 1.1615 + 1.1616 + if (success) { 1.1617 + NS_ASSERTION(*aSelectorList, "Should have list!"); 1.1618 + return NS_OK; 1.1619 + } 1.1620 + 1.1621 + NS_ASSERTION(!*aSelectorList, "Shouldn't have list!"); 1.1622 + 1.1623 + return NS_ERROR_DOM_SYNTAX_ERR; 1.1624 +} 1.1625 + 1.1626 + 1.1627 +already_AddRefed<nsCSSKeyframeRule> 1.1628 +CSSParserImpl::ParseKeyframeRule(const nsSubstring& aBuffer, 1.1629 + nsIURI* aURI, 1.1630 + uint32_t aLineNumber) 1.1631 +{ 1.1632 + nsCSSScanner scanner(aBuffer, aLineNumber); 1.1633 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI); 1.1634 + InitScanner(scanner, reporter, aURI, aURI, nullptr); 1.1635 + 1.1636 + nsRefPtr<nsCSSKeyframeRule> result = ParseKeyframeRule(); 1.1637 + if (GetToken(true)) { 1.1638 + // extra garbage at the end 1.1639 + result = nullptr; 1.1640 + } 1.1641 + 1.1642 + OUTPUT_ERROR(); 1.1643 + ReleaseScanner(); 1.1644 + 1.1645 + return result.forget(); 1.1646 +} 1.1647 + 1.1648 +bool 1.1649 +CSSParserImpl::ParseKeyframeSelectorString(const nsSubstring& aSelectorString, 1.1650 + nsIURI* aURI, // for error reporting 1.1651 + uint32_t aLineNumber, // for error reporting 1.1652 + InfallibleTArray<float>& aSelectorList) 1.1653 +{ 1.1654 + NS_ABORT_IF_FALSE(aSelectorList.IsEmpty(), "given list should start empty"); 1.1655 + 1.1656 + nsCSSScanner scanner(aSelectorString, aLineNumber); 1.1657 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI); 1.1658 + InitScanner(scanner, reporter, aURI, aURI, nullptr); 1.1659 + 1.1660 + bool success = ParseKeyframeSelectorList(aSelectorList) && 1.1661 + // must consume entire input string 1.1662 + !GetToken(true); 1.1663 + 1.1664 + OUTPUT_ERROR(); 1.1665 + ReleaseScanner(); 1.1666 + 1.1667 + if (success) { 1.1668 + NS_ASSERTION(!aSelectorList.IsEmpty(), "should not be empty"); 1.1669 + } else { 1.1670 + aSelectorList.Clear(); 1.1671 + } 1.1672 + 1.1673 + return success; 1.1674 +} 1.1675 + 1.1676 +bool 1.1677 +CSSParserImpl::EvaluateSupportsDeclaration(const nsAString& aProperty, 1.1678 + const nsAString& aValue, 1.1679 + nsIURI* aDocURL, 1.1680 + nsIURI* aBaseURL, 1.1681 + nsIPrincipal* aDocPrincipal) 1.1682 +{ 1.1683 + nsCSSProperty propID = LookupEnabledProperty(aProperty); 1.1684 + if (propID == eCSSProperty_UNKNOWN) { 1.1685 + return false; 1.1686 + } 1.1687 + 1.1688 + nsCSSScanner scanner(aValue, 0); 1.1689 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL); 1.1690 + InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal); 1.1691 + nsAutoSuppressErrors suppressErrors(this); 1.1692 + 1.1693 + bool parsedOK; 1.1694 + 1.1695 + if (propID == eCSSPropertyExtra_variable) { 1.1696 + MOZ_ASSERT(Substring(aProperty, 0, 1.1697 + CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--")); 1.1698 + const nsDependentSubstring varName = 1.1699 + Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH); // remove '--' 1.1700 + CSSVariableDeclarations::Type variableType; 1.1701 + nsString variableValue; 1.1702 + parsedOK = ParseVariableDeclaration(&variableType, variableValue) && 1.1703 + !GetToken(true); 1.1704 + } else { 1.1705 + parsedOK = ParseProperty(propID) && !GetToken(true); 1.1706 + 1.1707 + mTempData.ClearProperty(propID); 1.1708 + mTempData.AssertInitialState(); 1.1709 + } 1.1710 + 1.1711 + CLEAR_ERROR(); 1.1712 + ReleaseScanner(); 1.1713 + 1.1714 + return parsedOK; 1.1715 +} 1.1716 + 1.1717 +bool 1.1718 +CSSParserImpl::EvaluateSupportsCondition(const nsAString& aDeclaration, 1.1719 + nsIURI* aDocURL, 1.1720 + nsIURI* aBaseURL, 1.1721 + nsIPrincipal* aDocPrincipal) 1.1722 +{ 1.1723 + nsCSSScanner scanner(aDeclaration, 0); 1.1724 + css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL); 1.1725 + InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal); 1.1726 + nsAutoSuppressErrors suppressErrors(this); 1.1727 + 1.1728 + bool conditionMet; 1.1729 + bool parsedOK = ParseSupportsCondition(conditionMet) && !GetToken(true); 1.1730 + 1.1731 + CLEAR_ERROR(); 1.1732 + ReleaseScanner(); 1.1733 + 1.1734 + return parsedOK && conditionMet; 1.1735 +} 1.1736 + 1.1737 +bool 1.1738 +CSSParserImpl::EnumerateVariableReferences(const nsAString& aPropertyValue, 1.1739 + VariableEnumFunc aFunc, 1.1740 + void* aData) 1.1741 +{ 1.1742 + nsCSSScanner scanner(aPropertyValue, 0); 1.1743 + css::ErrorReporter reporter(scanner, nullptr, nullptr, nullptr); 1.1744 + InitScanner(scanner, reporter, nullptr, nullptr, nullptr); 1.1745 + nsAutoSuppressErrors suppressErrors(this); 1.1746 + 1.1747 + CSSVariableDeclarations::Type type; 1.1748 + bool dropBackslash; 1.1749 + nsString impliedCharacters; 1.1750 + bool result = ParseValueWithVariables(&type, &dropBackslash, 1.1751 + impliedCharacters, aFunc, aData) && 1.1752 + !GetToken(true); 1.1753 + 1.1754 + ReleaseScanner(); 1.1755 + 1.1756 + return result; 1.1757 +} 1.1758 + 1.1759 +static bool 1.1760 +SeparatorRequiredBetweenTokens(nsCSSTokenSerializationType aToken1, 1.1761 + nsCSSTokenSerializationType aToken2) 1.1762 +{ 1.1763 + // The two lines marked with (*) do not correspond to entries in 1.1764 + // the table in the css-syntax spec but which we need to handle, 1.1765 + // as we treat them as whole tokens. 1.1766 + switch (aToken1) { 1.1767 + case eCSSTokenSerialization_Ident: 1.1768 + return aToken2 == eCSSTokenSerialization_Ident || 1.1769 + aToken2 == eCSSTokenSerialization_Function || 1.1770 + aToken2 == eCSSTokenSerialization_URL_or_BadURL || 1.1771 + aToken2 == eCSSTokenSerialization_Symbol_Minus || 1.1772 + aToken2 == eCSSTokenSerialization_Number || 1.1773 + aToken2 == eCSSTokenSerialization_Percentage || 1.1774 + aToken2 == eCSSTokenSerialization_Dimension || 1.1775 + aToken2 == eCSSTokenSerialization_URange || 1.1776 + aToken2 == eCSSTokenSerialization_CDC || 1.1777 + aToken2 == eCSSTokenSerialization_Symbol_OpenParen; 1.1778 + case eCSSTokenSerialization_AtKeyword_or_Hash: 1.1779 + case eCSSTokenSerialization_Dimension: 1.1780 + return aToken2 == eCSSTokenSerialization_Ident || 1.1781 + aToken2 == eCSSTokenSerialization_Function || 1.1782 + aToken2 == eCSSTokenSerialization_URL_or_BadURL || 1.1783 + aToken2 == eCSSTokenSerialization_Symbol_Minus || 1.1784 + aToken2 == eCSSTokenSerialization_Number || 1.1785 + aToken2 == eCSSTokenSerialization_Percentage || 1.1786 + aToken2 == eCSSTokenSerialization_Dimension || 1.1787 + aToken2 == eCSSTokenSerialization_URange || 1.1788 + aToken2 == eCSSTokenSerialization_CDC; 1.1789 + case eCSSTokenSerialization_Symbol_Hash: 1.1790 + return aToken2 == eCSSTokenSerialization_Ident || 1.1791 + aToken2 == eCSSTokenSerialization_Function || 1.1792 + aToken2 == eCSSTokenSerialization_URL_or_BadURL || 1.1793 + aToken2 == eCSSTokenSerialization_Symbol_Minus || 1.1794 + aToken2 == eCSSTokenSerialization_Number || 1.1795 + aToken2 == eCSSTokenSerialization_Percentage || 1.1796 + aToken2 == eCSSTokenSerialization_Dimension || 1.1797 + aToken2 == eCSSTokenSerialization_URange; 1.1798 + case eCSSTokenSerialization_Symbol_Minus: 1.1799 + case eCSSTokenSerialization_Number: 1.1800 + return aToken2 == eCSSTokenSerialization_Ident || 1.1801 + aToken2 == eCSSTokenSerialization_Function || 1.1802 + aToken2 == eCSSTokenSerialization_URL_or_BadURL || 1.1803 + aToken2 == eCSSTokenSerialization_Number || 1.1804 + aToken2 == eCSSTokenSerialization_Percentage || 1.1805 + aToken2 == eCSSTokenSerialization_Dimension || 1.1806 + aToken2 == eCSSTokenSerialization_URange; 1.1807 + case eCSSTokenSerialization_Symbol_At: 1.1808 + return aToken2 == eCSSTokenSerialization_Ident || 1.1809 + aToken2 == eCSSTokenSerialization_Function || 1.1810 + aToken2 == eCSSTokenSerialization_URL_or_BadURL || 1.1811 + aToken2 == eCSSTokenSerialization_Symbol_Minus || 1.1812 + aToken2 == eCSSTokenSerialization_URange; 1.1813 + case eCSSTokenSerialization_URange: 1.1814 + return aToken2 == eCSSTokenSerialization_Ident || 1.1815 + aToken2 == eCSSTokenSerialization_Function || 1.1816 + aToken2 == eCSSTokenSerialization_Number || 1.1817 + aToken2 == eCSSTokenSerialization_Percentage || 1.1818 + aToken2 == eCSSTokenSerialization_Dimension || 1.1819 + aToken2 == eCSSTokenSerialization_Symbol_Question; 1.1820 + case eCSSTokenSerialization_Symbol_Dot_or_Plus: 1.1821 + return aToken2 == eCSSTokenSerialization_Number || 1.1822 + aToken2 == eCSSTokenSerialization_Percentage || 1.1823 + aToken2 == eCSSTokenSerialization_Dimension; 1.1824 + case eCSSTokenSerialization_Symbol_Assorted: 1.1825 + case eCSSTokenSerialization_Symbol_Asterisk: 1.1826 + return aToken2 == eCSSTokenSerialization_Symbol_Equals; 1.1827 + case eCSSTokenSerialization_Symbol_Bar: 1.1828 + return aToken2 == eCSSTokenSerialization_Symbol_Equals || 1.1829 + aToken2 == eCSSTokenSerialization_Symbol_Bar || 1.1830 + aToken2 == eCSSTokenSerialization_DashMatch; // (*) 1.1831 + case eCSSTokenSerialization_Symbol_Slash: 1.1832 + return aToken2 == eCSSTokenSerialization_Symbol_Asterisk || 1.1833 + aToken2 == eCSSTokenSerialization_ContainsMatch; // (*) 1.1834 + default: 1.1835 + MOZ_ASSERT(aToken1 == eCSSTokenSerialization_Nothing || 1.1836 + aToken1 == eCSSTokenSerialization_Whitespace || 1.1837 + aToken1 == eCSSTokenSerialization_Percentage || 1.1838 + aToken1 == eCSSTokenSerialization_URL_or_BadURL || 1.1839 + aToken1 == eCSSTokenSerialization_Function || 1.1840 + aToken1 == eCSSTokenSerialization_CDC || 1.1841 + aToken1 == eCSSTokenSerialization_Symbol_OpenParen || 1.1842 + aToken1 == eCSSTokenSerialization_Symbol_Question || 1.1843 + aToken1 == eCSSTokenSerialization_Symbol_Assorted || 1.1844 + aToken1 == eCSSTokenSerialization_Symbol_Asterisk || 1.1845 + aToken1 == eCSSTokenSerialization_Symbol_Equals || 1.1846 + aToken1 == eCSSTokenSerialization_Symbol_Bar || 1.1847 + aToken1 == eCSSTokenSerialization_Symbol_Slash || 1.1848 + aToken1 == eCSSTokenSerialization_Other || 1.1849 + "unexpected nsCSSTokenSerializationType value"); 1.1850 + return false; 1.1851 + } 1.1852 +} 1.1853 + 1.1854 +/** 1.1855 + * Appends aValue to aResult, possibly inserting an empty CSS 1.1856 + * comment between the two to ensure that tokens from both strings 1.1857 + * remain separated. 1.1858 + */ 1.1859 +static void 1.1860 +AppendTokens(nsAString& aResult, 1.1861 + nsCSSTokenSerializationType& aResultFirstToken, 1.1862 + nsCSSTokenSerializationType& aResultLastToken, 1.1863 + nsCSSTokenSerializationType aValueFirstToken, 1.1864 + nsCSSTokenSerializationType aValueLastToken, 1.1865 + const nsAString& aValue) 1.1866 +{ 1.1867 + if (SeparatorRequiredBetweenTokens(aResultLastToken, aValueFirstToken)) { 1.1868 + aResult.AppendLiteral("/**/"); 1.1869 + } 1.1870 + aResult.Append(aValue); 1.1871 + if (aResultFirstToken == eCSSTokenSerialization_Nothing) { 1.1872 + aResultFirstToken = aValueFirstToken; 1.1873 + } 1.1874 + if (aValueLastToken != eCSSTokenSerialization_Nothing) { 1.1875 + aResultLastToken = aValueLastToken; 1.1876 + } 1.1877 +} 1.1878 + 1.1879 +/** 1.1880 + * Stops the given scanner recording, and appends the recorded result 1.1881 + * to aResult, possibly inserting an empty CSS comment between the two to 1.1882 + * ensure that tokens from both strings remain separated. 1.1883 + */ 1.1884 +static void 1.1885 +StopRecordingAndAppendTokens(nsString& aResult, 1.1886 + nsCSSTokenSerializationType& aResultFirstToken, 1.1887 + nsCSSTokenSerializationType& aResultLastToken, 1.1888 + nsCSSTokenSerializationType aValueFirstToken, 1.1889 + nsCSSTokenSerializationType aValueLastToken, 1.1890 + nsCSSScanner* aScanner) 1.1891 +{ 1.1892 + if (SeparatorRequiredBetweenTokens(aResultLastToken, aValueFirstToken)) { 1.1893 + aResult.AppendLiteral("/**/"); 1.1894 + } 1.1895 + aScanner->StopRecording(aResult); 1.1896 + if (aResultFirstToken == eCSSTokenSerialization_Nothing) { 1.1897 + aResultFirstToken = aValueFirstToken; 1.1898 + } 1.1899 + if (aValueLastToken != eCSSTokenSerialization_Nothing) { 1.1900 + aResultLastToken = aValueLastToken; 1.1901 + } 1.1902 +} 1.1903 + 1.1904 +bool 1.1905 +CSSParserImpl::ResolveValueWithVariableReferencesRec( 1.1906 + nsString& aResult, 1.1907 + nsCSSTokenSerializationType& aResultFirstToken, 1.1908 + nsCSSTokenSerializationType& aResultLastToken, 1.1909 + const CSSVariableValues* aVariables) 1.1910 +{ 1.1911 + // This function assumes we are already recording, and will leave the scanner 1.1912 + // recording when it returns. 1.1913 + MOZ_ASSERT(mScanner->IsRecording()); 1.1914 + MOZ_ASSERT(aResult.IsEmpty()); 1.1915 + 1.1916 + // Stack of closing characters for currently open constructs. 1.1917 + nsAutoTArray<char16_t, 16> stack; 1.1918 + 1.1919 + // The resolved value for this ResolveValueWithVariableReferencesRec call. 1.1920 + nsString value; 1.1921 + 1.1922 + // The length of the scanner's recording before the currently parsed token. 1.1923 + // This is used so that when we encounter a "var(" token, we can strip 1.1924 + // it off the end of the recording, regardless of how long the token was. 1.1925 + // (With escapes, it could be longer than four characters.) 1.1926 + uint32_t lengthBeforeVar = 0; 1.1927 + 1.1928 + // Tracking the type of token that appears at the start and end of |value| 1.1929 + // and that appears at the start and end of the scanner recording. These are 1.1930 + // used to determine whether we need to insert "/**/" when pasting token 1.1931 + // streams together. 1.1932 + nsCSSTokenSerializationType valueFirstToken = eCSSTokenSerialization_Nothing, 1.1933 + valueLastToken = eCSSTokenSerialization_Nothing, 1.1934 + recFirstToken = eCSSTokenSerialization_Nothing, 1.1935 + recLastToken = eCSSTokenSerialization_Nothing; 1.1936 + 1.1937 +#define UPDATE_RECORDING_TOKENS(type) \ 1.1938 + if (recFirstToken == eCSSTokenSerialization_Nothing) { \ 1.1939 + recFirstToken = type; \ 1.1940 + } \ 1.1941 + recLastToken = type; 1.1942 + 1.1943 + while (GetToken(false)) { 1.1944 + switch (mToken.mType) { 1.1945 + case eCSSToken_Symbol: { 1.1946 + nsCSSTokenSerializationType type = eCSSTokenSerialization_Other; 1.1947 + if (mToken.mSymbol == '(') { 1.1948 + stack.AppendElement(')'); 1.1949 + type = eCSSTokenSerialization_Symbol_OpenParen; 1.1950 + } else if (mToken.mSymbol == '[') { 1.1951 + stack.AppendElement(']'); 1.1952 + } else if (mToken.mSymbol == '{') { 1.1953 + stack.AppendElement('}'); 1.1954 + } else if (mToken.mSymbol == ';') { 1.1955 + if (stack.IsEmpty()) { 1.1956 + // A ';' that is at the top level of the value or at the top level 1.1957 + // of a variable reference's fallback is invalid. 1.1958 + return false; 1.1959 + } 1.1960 + } else if (mToken.mSymbol == '!') { 1.1961 + if (stack.IsEmpty()) { 1.1962 + // An '!' that is at the top level of the value or at the top level 1.1963 + // of a variable reference's fallback is invalid. 1.1964 + return false; 1.1965 + } 1.1966 + } else if (mToken.mSymbol == ')' && 1.1967 + stack.IsEmpty()) { 1.1968 + // We're closing a "var(". 1.1969 + nsString finalTokens; 1.1970 + mScanner->StopRecording(finalTokens); 1.1971 + MOZ_ASSERT(finalTokens[finalTokens.Length() - 1] == ')'); 1.1972 + finalTokens.Truncate(finalTokens.Length() - 1); 1.1973 + aResult.Append(value); 1.1974 + 1.1975 + AppendTokens(aResult, valueFirstToken, valueLastToken, 1.1976 + recFirstToken, recLastToken, finalTokens); 1.1977 + 1.1978 + mScanner->StartRecording(); 1.1979 + UngetToken(); 1.1980 + aResultFirstToken = valueFirstToken; 1.1981 + aResultLastToken = valueLastToken; 1.1982 + return true; 1.1983 + } else if (mToken.mSymbol == ')' || 1.1984 + mToken.mSymbol == ']' || 1.1985 + mToken.mSymbol == '}') { 1.1986 + if (stack.IsEmpty() || 1.1987 + stack.LastElement() != mToken.mSymbol) { 1.1988 + // A mismatched closing bracket is invalid. 1.1989 + return false; 1.1990 + } 1.1991 + stack.TruncateLength(stack.Length() - 1); 1.1992 + } else if (mToken.mSymbol == '#') { 1.1993 + type = eCSSTokenSerialization_Symbol_Hash; 1.1994 + } else if (mToken.mSymbol == '@') { 1.1995 + type = eCSSTokenSerialization_Symbol_At; 1.1996 + } else if (mToken.mSymbol == '.' || 1.1997 + mToken.mSymbol == '+') { 1.1998 + type = eCSSTokenSerialization_Symbol_Dot_or_Plus; 1.1999 + } else if (mToken.mSymbol == '-') { 1.2000 + type = eCSSTokenSerialization_Symbol_Minus; 1.2001 + } else if (mToken.mSymbol == '?') { 1.2002 + type = eCSSTokenSerialization_Symbol_Question; 1.2003 + } else if (mToken.mSymbol == '$' || 1.2004 + mToken.mSymbol == '^' || 1.2005 + mToken.mSymbol == '~') { 1.2006 + type = eCSSTokenSerialization_Symbol_Assorted; 1.2007 + } else if (mToken.mSymbol == '=') { 1.2008 + type = eCSSTokenSerialization_Symbol_Equals; 1.2009 + } else if (mToken.mSymbol == '|') { 1.2010 + type = eCSSTokenSerialization_Symbol_Bar; 1.2011 + } else if (mToken.mSymbol == '/') { 1.2012 + type = eCSSTokenSerialization_Symbol_Slash; 1.2013 + } else if (mToken.mSymbol == '*') { 1.2014 + type = eCSSTokenSerialization_Symbol_Asterisk; 1.2015 + } 1.2016 + UPDATE_RECORDING_TOKENS(type); 1.2017 + break; 1.2018 + } 1.2019 + 1.2020 + case eCSSToken_Function: 1.2021 + if (mToken.mIdent.LowerCaseEqualsLiteral("var")) { 1.2022 + // Save the tokens before the "var(" to our resolved value. 1.2023 + nsString recording; 1.2024 + mScanner->StopRecording(recording); 1.2025 + recording.Truncate(lengthBeforeVar); 1.2026 + AppendTokens(value, valueFirstToken, valueLastToken, 1.2027 + recFirstToken, recLastToken, recording); 1.2028 + recFirstToken = eCSSTokenSerialization_Nothing; 1.2029 + recLastToken = eCSSTokenSerialization_Nothing; 1.2030 + 1.2031 + if (!GetToken(true) || 1.2032 + mToken.mType != eCSSToken_Ident || 1.2033 + !nsCSSProps::IsCustomPropertyName(mToken.mIdent)) { 1.2034 + // "var(" must be followed by an identifier, and it must be a 1.2035 + // custom property name. 1.2036 + return false; 1.2037 + } 1.2038 + 1.2039 + // Turn the custom property name into a variable name by removing the 1.2040 + // '--' prefix. 1.2041 + MOZ_ASSERT(Substring(mToken.mIdent, 0, 1.2042 + CSS_CUSTOM_NAME_PREFIX_LENGTH). 1.2043 + EqualsLiteral("--")); 1.2044 + nsDependentString variableName(mToken.mIdent, 1.2045 + CSS_CUSTOM_NAME_PREFIX_LENGTH); 1.2046 + 1.2047 + // Get the value of the identified variable. Note that we 1.2048 + // check if the variable value is the empty string, as that means 1.2049 + // that the variable was invalid at computed value time due to 1.2050 + // unresolveable variable references or cycles. 1.2051 + nsString variableValue; 1.2052 + nsCSSTokenSerializationType varFirstToken, varLastToken; 1.2053 + bool valid = aVariables->Get(variableName, variableValue, 1.2054 + varFirstToken, varLastToken) && 1.2055 + !variableValue.IsEmpty(); 1.2056 + 1.2057 + if (!GetToken(true) || 1.2058 + mToken.IsSymbol(')')) { 1.2059 + mScanner->StartRecording(); 1.2060 + if (!valid) { 1.2061 + // Invalid variable with no fallback. 1.2062 + return false; 1.2063 + } 1.2064 + // Valid variable with no fallback. 1.2065 + AppendTokens(value, valueFirstToken, valueLastToken, 1.2066 + varFirstToken, varLastToken, variableValue); 1.2067 + } else if (mToken.IsSymbol(',')) { 1.2068 + mScanner->StartRecording(); 1.2069 + if (!GetToken(false) || 1.2070 + mToken.IsSymbol(')')) { 1.2071 + // Comma must be followed by at least one fallback token. 1.2072 + return false; 1.2073 + } 1.2074 + UngetToken(); 1.2075 + if (valid) { 1.2076 + // Valid variable with ignored fallback. 1.2077 + mScanner->StopRecording(); 1.2078 + AppendTokens(value, valueFirstToken, valueLastToken, 1.2079 + varFirstToken, varLastToken, variableValue); 1.2080 + bool ok = SkipBalancedContentUntil(')'); 1.2081 + mScanner->StartRecording(); 1.2082 + if (!ok) { 1.2083 + return false; 1.2084 + } 1.2085 + } else { 1.2086 + nsString fallback; 1.2087 + if (!ResolveValueWithVariableReferencesRec(fallback, 1.2088 + varFirstToken, 1.2089 + varLastToken, 1.2090 + aVariables)) { 1.2091 + // Fallback value had invalid tokens or an invalid variable reference 1.2092 + // that itself had no fallback. 1.2093 + return false; 1.2094 + } 1.2095 + AppendTokens(value, valueFirstToken, valueLastToken, 1.2096 + varFirstToken, varLastToken, fallback); 1.2097 + // Now we're either at the pushed back ')' that finished the 1.2098 + // fallback or at EOF. 1.2099 + DebugOnly<bool> gotToken = GetToken(false); 1.2100 + MOZ_ASSERT(!gotToken || mToken.IsSymbol(')')); 1.2101 + } 1.2102 + } else { 1.2103 + // Expected ',' or ')' after the variable name. 1.2104 + mScanner->StartRecording(); 1.2105 + return false; 1.2106 + } 1.2107 + } else { 1.2108 + stack.AppendElement(')'); 1.2109 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Function); 1.2110 + } 1.2111 + break; 1.2112 + 1.2113 + case eCSSToken_Bad_String: 1.2114 + case eCSSToken_Bad_URL: 1.2115 + return false; 1.2116 + 1.2117 + case eCSSToken_Whitespace: 1.2118 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Whitespace); 1.2119 + break; 1.2120 + 1.2121 + case eCSSToken_AtKeyword: 1.2122 + case eCSSToken_Hash: 1.2123 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_AtKeyword_or_Hash); 1.2124 + break; 1.2125 + 1.2126 + case eCSSToken_Number: 1.2127 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Number); 1.2128 + break; 1.2129 + 1.2130 + case eCSSToken_Dimension: 1.2131 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Dimension); 1.2132 + break; 1.2133 + 1.2134 + case eCSSToken_Ident: 1.2135 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Ident); 1.2136 + break; 1.2137 + 1.2138 + case eCSSToken_Percentage: 1.2139 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Percentage); 1.2140 + break; 1.2141 + 1.2142 + case eCSSToken_URange: 1.2143 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_URange); 1.2144 + break; 1.2145 + 1.2146 + case eCSSToken_URL: 1.2147 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_URL_or_BadURL); 1.2148 + break; 1.2149 + 1.2150 + case eCSSToken_HTMLComment: 1.2151 + if (mToken.mIdent[0] == '-') { 1.2152 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_CDC); 1.2153 + } else { 1.2154 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Other); 1.2155 + } 1.2156 + break; 1.2157 + 1.2158 + case eCSSToken_Dashmatch: 1.2159 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_DashMatch); 1.2160 + break; 1.2161 + 1.2162 + case eCSSToken_Containsmatch: 1.2163 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_ContainsMatch); 1.2164 + break; 1.2165 + 1.2166 + default: 1.2167 + NS_NOTREACHED("unexpected token type"); 1.2168 + // fall through 1.2169 + case eCSSToken_ID: 1.2170 + case eCSSToken_String: 1.2171 + case eCSSToken_Includes: 1.2172 + case eCSSToken_Beginsmatch: 1.2173 + case eCSSToken_Endsmatch: 1.2174 + UPDATE_RECORDING_TOKENS(eCSSTokenSerialization_Other); 1.2175 + break; 1.2176 + } 1.2177 + 1.2178 + lengthBeforeVar = mScanner->RecordingLength(); 1.2179 + } 1.2180 + 1.2181 +#undef UPDATE_RECORDING_TOKENS 1.2182 + 1.2183 + aResult.Append(value); 1.2184 + StopRecordingAndAppendTokens(aResult, valueFirstToken, valueLastToken, 1.2185 + recFirstToken, recLastToken, mScanner); 1.2186 + 1.2187 + // Append any implicitly closed brackets. 1.2188 + if (!stack.IsEmpty()) { 1.2189 + do { 1.2190 + aResult.Append(stack.LastElement()); 1.2191 + stack.TruncateLength(stack.Length() - 1); 1.2192 + } while (!stack.IsEmpty()); 1.2193 + valueLastToken = eCSSTokenSerialization_Other; 1.2194 + } 1.2195 + 1.2196 + mScanner->StartRecording(); 1.2197 + aResultFirstToken = valueFirstToken; 1.2198 + aResultLastToken = valueLastToken; 1.2199 + return true; 1.2200 +} 1.2201 + 1.2202 +bool 1.2203 +CSSParserImpl::ResolveValueWithVariableReferences( 1.2204 + const CSSVariableValues* aVariables, 1.2205 + nsString& aResult, 1.2206 + nsCSSTokenSerializationType& aFirstToken, 1.2207 + nsCSSTokenSerializationType& aLastToken) 1.2208 +{ 1.2209 + aResult.Truncate(0); 1.2210 + 1.2211 + // Start recording before we read the first token. 1.2212 + mScanner->StartRecording(); 1.2213 + 1.2214 + if (!GetToken(false)) { 1.2215 + // Value was empty since we reached EOF. 1.2216 + mScanner->StopRecording(); 1.2217 + return false; 1.2218 + } 1.2219 + 1.2220 + UngetToken(); 1.2221 + 1.2222 + nsString value; 1.2223 + nsCSSTokenSerializationType firstToken, lastToken; 1.2224 + bool ok = ResolveValueWithVariableReferencesRec(value, firstToken, lastToken, aVariables) && 1.2225 + !GetToken(true); 1.2226 + 1.2227 + mScanner->StopRecording(); 1.2228 + 1.2229 + if (ok) { 1.2230 + aResult = value; 1.2231 + aFirstToken = firstToken; 1.2232 + aLastToken = lastToken; 1.2233 + } 1.2234 + return ok; 1.2235 +} 1.2236 + 1.2237 +bool 1.2238 +CSSParserImpl::ResolveVariableValue(const nsAString& aPropertyValue, 1.2239 + const CSSVariableValues* aVariables, 1.2240 + nsString& aResult, 1.2241 + nsCSSTokenSerializationType& aFirstToken, 1.2242 + nsCSSTokenSerializationType& aLastToken) 1.2243 +{ 1.2244 + nsCSSScanner scanner(aPropertyValue, 0); 1.2245 + 1.2246 + // At this point, we know that aPropertyValue is syntactically correct 1.2247 + // for a token stream that has variable references. We also won't be 1.2248 + // interpreting any of the stream as we parse it, apart from expanding 1.2249 + // var() references, so we don't need a base URL etc. or any useful 1.2250 + // error reporting. 1.2251 + css::ErrorReporter reporter(scanner, nullptr, nullptr, nullptr); 1.2252 + InitScanner(scanner, reporter, nullptr, nullptr, nullptr); 1.2253 + 1.2254 + bool valid = ResolveValueWithVariableReferences(aVariables, aResult, 1.2255 + aFirstToken, aLastToken); 1.2256 + 1.2257 + ReleaseScanner(); 1.2258 + return valid; 1.2259 +} 1.2260 + 1.2261 +void 1.2262 +CSSParserImpl::ParsePropertyWithVariableReferences( 1.2263 + nsCSSProperty aPropertyID, 1.2264 + nsCSSProperty aShorthandPropertyID, 1.2265 + const nsAString& aValue, 1.2266 + const CSSVariableValues* aVariables, 1.2267 + nsRuleData* aRuleData, 1.2268 + nsIURI* aDocURL, 1.2269 + nsIURI* aBaseURL, 1.2270 + nsIPrincipal* aDocPrincipal, 1.2271 + nsCSSStyleSheet* aSheet, 1.2272 + uint32_t aLineNumber, 1.2273 + uint32_t aLineOffset) 1.2274 +{ 1.2275 + mTempData.AssertInitialState(); 1.2276 + 1.2277 + bool valid; 1.2278 + nsString expandedValue; 1.2279 + 1.2280 + // Resolve any variable references in the property value. 1.2281 + { 1.2282 + nsCSSScanner scanner(aValue, 0); 1.2283 + css::ErrorReporter reporter(scanner, aSheet, mChildLoader, aDocURL); 1.2284 + InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal); 1.2285 + 1.2286 + nsCSSTokenSerializationType firstToken, lastToken; 1.2287 + valid = ResolveValueWithVariableReferences(aVariables, expandedValue, 1.2288 + firstToken, lastToken); 1.2289 + if (!valid) { 1.2290 + NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropertyID)); 1.2291 + REPORT_UNEXPECTED(PEInvalidVariableReference); 1.2292 + REPORT_UNEXPECTED_P(PEValueParsingError, propName); 1.2293 + if (nsCSSProps::IsInherited(aPropertyID)) { 1.2294 + REPORT_UNEXPECTED(PEValueWithVariablesFallbackInherit); 1.2295 + } else { 1.2296 + REPORT_UNEXPECTED(PEValueWithVariablesFallbackInitial); 1.2297 + } 1.2298 + OUTPUT_ERROR_WITH_POSITION(aLineNumber, aLineOffset); 1.2299 + } 1.2300 + ReleaseScanner(); 1.2301 + } 1.2302 + 1.2303 + nsCSSProperty propertyToParse = 1.2304 + aShorthandPropertyID != eCSSProperty_UNKNOWN ? aShorthandPropertyID : 1.2305 + aPropertyID; 1.2306 + 1.2307 + // Parse the property with that resolved value. 1.2308 + if (valid) { 1.2309 + nsCSSScanner scanner(expandedValue, 0); 1.2310 + css::ErrorReporter reporter(scanner, aSheet, mChildLoader, aDocURL); 1.2311 + InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal); 1.2312 + valid = ParseProperty(propertyToParse); 1.2313 + if (valid && GetToken(true)) { 1.2314 + REPORT_UNEXPECTED_TOKEN(PEExpectEndValue); 1.2315 + valid = false; 1.2316 + } 1.2317 + if (!valid) { 1.2318 + NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue( 1.2319 + propertyToParse)); 1.2320 + REPORT_UNEXPECTED_P(PEValueWithVariablesParsingError, propName); 1.2321 + if (nsCSSProps::IsInherited(aPropertyID)) { 1.2322 + REPORT_UNEXPECTED(PEValueWithVariablesFallbackInherit); 1.2323 + } else { 1.2324 + REPORT_UNEXPECTED(PEValueWithVariablesFallbackInitial); 1.2325 + } 1.2326 + OUTPUT_ERROR_WITH_POSITION(aLineNumber, aLineOffset); 1.2327 + } 1.2328 + ReleaseScanner(); 1.2329 + } 1.2330 + 1.2331 + // If the property could not be parsed with the resolved value, then we 1.2332 + // treat it as if the value were 'initial' or 'inherit', depending on whether 1.2333 + // the property is an inherited property. 1.2334 + if (!valid) { 1.2335 + nsCSSValue defaultValue; 1.2336 + if (nsCSSProps::IsInherited(aPropertyID)) { 1.2337 + defaultValue.SetInheritValue(); 1.2338 + } else { 1.2339 + defaultValue.SetInitialValue(); 1.2340 + } 1.2341 + mTempData.AddLonghandProperty(aPropertyID, defaultValue); 1.2342 + } 1.2343 + 1.2344 + // Copy the property value into the rule data. 1.2345 + mTempData.MapRuleInfoInto(aPropertyID, aRuleData); 1.2346 + 1.2347 + mTempData.ClearProperty(propertyToParse); 1.2348 + mTempData.AssertInitialState(); 1.2349 +} 1.2350 + 1.2351 +//---------------------------------------------------------------------- 1.2352 + 1.2353 +bool 1.2354 +CSSParserImpl::GetToken(bool aSkipWS) 1.2355 +{ 1.2356 + if (mHavePushBack) { 1.2357 + mHavePushBack = false; 1.2358 + if (!aSkipWS || mToken.mType != eCSSToken_Whitespace) { 1.2359 + return true; 1.2360 + } 1.2361 + } 1.2362 + return mScanner->Next(mToken, aSkipWS); 1.2363 +} 1.2364 + 1.2365 +void 1.2366 +CSSParserImpl::UngetToken() 1.2367 +{ 1.2368 + NS_PRECONDITION(!mHavePushBack, "double pushback"); 1.2369 + mHavePushBack = true; 1.2370 +} 1.2371 + 1.2372 +bool 1.2373 +CSSParserImpl::GetNextTokenLocation(bool aSkipWS, uint32_t *linenum, uint32_t *colnum) 1.2374 +{ 1.2375 + // Peek at next token so that mScanner updates line and column vals 1.2376 + if (!GetToken(aSkipWS)) { 1.2377 + return false; 1.2378 + } 1.2379 + UngetToken(); 1.2380 + // The scanner uses one-indexing for line numbers but zero-indexing 1.2381 + // for column numbers. 1.2382 + *linenum = mScanner->GetLineNumber(); 1.2383 + *colnum = 1 + mScanner->GetColumnNumber(); 1.2384 + return true; 1.2385 +} 1.2386 + 1.2387 +bool 1.2388 +CSSParserImpl::ExpectSymbol(char16_t aSymbol, 1.2389 + bool aSkipWS) 1.2390 +{ 1.2391 + if (!GetToken(aSkipWS)) { 1.2392 + // CSS2.1 specifies that all "open constructs" are to be closed at 1.2393 + // EOF. It simplifies higher layers if we claim to have found an 1.2394 + // ), ], }, or ; if we encounter EOF while looking for one of them. 1.2395 + // Do still issue a diagnostic, to aid debugging. 1.2396 + if (aSymbol == ')' || aSymbol == ']' || 1.2397 + aSymbol == '}' || aSymbol == ';') { 1.2398 + REPORT_UNEXPECTED_EOF_CHAR(aSymbol); 1.2399 + return true; 1.2400 + } 1.2401 + else 1.2402 + return false; 1.2403 + } 1.2404 + if (mToken.IsSymbol(aSymbol)) { 1.2405 + return true; 1.2406 + } 1.2407 + UngetToken(); 1.2408 + return false; 1.2409 +} 1.2410 + 1.2411 +// Checks to see if we're at the end of a property. If an error occurs during 1.2412 +// the check, does not signal a parse error. 1.2413 +bool 1.2414 +CSSParserImpl::CheckEndProperty() 1.2415 +{ 1.2416 + if (!GetToken(true)) { 1.2417 + return true; // properties may end with eof 1.2418 + } 1.2419 + if ((eCSSToken_Symbol == mToken.mType) && 1.2420 + ((';' == mToken.mSymbol) || 1.2421 + ('!' == mToken.mSymbol) || 1.2422 + ('}' == mToken.mSymbol) || 1.2423 + (')' == mToken.mSymbol))) { 1.2424 + // XXX need to verify that ! is only followed by "important [;|}] 1.2425 + // XXX this requires a multi-token pushback buffer 1.2426 + UngetToken(); 1.2427 + return true; 1.2428 + } 1.2429 + UngetToken(); 1.2430 + return false; 1.2431 +} 1.2432 + 1.2433 +// Checks if we're at the end of a property, raising an error if we're not. 1.2434 +bool 1.2435 +CSSParserImpl::ExpectEndProperty() 1.2436 +{ 1.2437 + if (CheckEndProperty()) 1.2438 + return true; 1.2439 + 1.2440 + // If we're here, we read something incorrect, so we should report it. 1.2441 + REPORT_UNEXPECTED_TOKEN(PEExpectEndValue); 1.2442 + return false; 1.2443 +} 1.2444 + 1.2445 +// Parses the priority suffix on a property, which at present may be 1.2446 +// either '!important' or nothing. 1.2447 +CSSParserImpl::PriorityParsingStatus 1.2448 +CSSParserImpl::ParsePriority() 1.2449 +{ 1.2450 + if (!GetToken(true)) { 1.2451 + return ePriority_None; // properties may end with EOF 1.2452 + } 1.2453 + if (!mToken.IsSymbol('!')) { 1.2454 + UngetToken(); 1.2455 + return ePriority_None; // dunno what it is, but it's not a priority 1.2456 + } 1.2457 + 1.2458 + if (!GetToken(true)) { 1.2459 + // EOF is not ok after ! 1.2460 + REPORT_UNEXPECTED_EOF(PEImportantEOF); 1.2461 + return ePriority_Error; 1.2462 + } 1.2463 + 1.2464 + if (mToken.mType != eCSSToken_Ident || 1.2465 + !mToken.mIdent.LowerCaseEqualsLiteral("important")) { 1.2466 + REPORT_UNEXPECTED_TOKEN(PEExpectedImportant); 1.2467 + UngetToken(); 1.2468 + return ePriority_Error; 1.2469 + } 1.2470 + 1.2471 + return ePriority_Important; 1.2472 +} 1.2473 + 1.2474 +nsSubstring* 1.2475 +CSSParserImpl::NextIdent() 1.2476 +{ 1.2477 + // XXX Error reporting? 1.2478 + if (!GetToken(true)) { 1.2479 + return nullptr; 1.2480 + } 1.2481 + if (eCSSToken_Ident != mToken.mType) { 1.2482 + UngetToken(); 1.2483 + return nullptr; 1.2484 + } 1.2485 + return &mToken.mIdent; 1.2486 +} 1.2487 + 1.2488 +bool 1.2489 +CSSParserImpl::SkipAtRule(bool aInsideBlock) 1.2490 +{ 1.2491 + for (;;) { 1.2492 + if (!GetToken(true)) { 1.2493 + REPORT_UNEXPECTED_EOF(PESkipAtRuleEOF2); 1.2494 + return false; 1.2495 + } 1.2496 + if (eCSSToken_Symbol == mToken.mType) { 1.2497 + char16_t symbol = mToken.mSymbol; 1.2498 + if (symbol == ';') { 1.2499 + break; 1.2500 + } 1.2501 + if (aInsideBlock && symbol == '}') { 1.2502 + // The closing } doesn't belong to us. 1.2503 + UngetToken(); 1.2504 + break; 1.2505 + } 1.2506 + if (symbol == '{') { 1.2507 + SkipUntil('}'); 1.2508 + break; 1.2509 + } else if (symbol == '(') { 1.2510 + SkipUntil(')'); 1.2511 + } else if (symbol == '[') { 1.2512 + SkipUntil(']'); 1.2513 + } 1.2514 + } else if (eCSSToken_Function == mToken.mType || 1.2515 + eCSSToken_Bad_URL == mToken.mType) { 1.2516 + SkipUntil(')'); 1.2517 + } 1.2518 + } 1.2519 + return true; 1.2520 +} 1.2521 + 1.2522 +bool 1.2523 +CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc, 1.2524 + void* aData, 1.2525 + bool aInAtRule) 1.2526 +{ 1.2527 + 1.2528 + nsCSSSection newSection; 1.2529 + bool (CSSParserImpl::*parseFunc)(RuleAppendFunc, void*); 1.2530 + 1.2531 + if ((mSection <= eCSSSection_Charset) && 1.2532 + (mToken.mIdent.LowerCaseEqualsLiteral("charset"))) { 1.2533 + parseFunc = &CSSParserImpl::ParseCharsetRule; 1.2534 + newSection = eCSSSection_Import; // only one charset allowed 1.2535 + 1.2536 + } else if ((mSection <= eCSSSection_Import) && 1.2537 + mToken.mIdent.LowerCaseEqualsLiteral("import")) { 1.2538 + parseFunc = &CSSParserImpl::ParseImportRule; 1.2539 + newSection = eCSSSection_Import; 1.2540 + 1.2541 + } else if ((mSection <= eCSSSection_NameSpace) && 1.2542 + mToken.mIdent.LowerCaseEqualsLiteral("namespace")) { 1.2543 + parseFunc = &CSSParserImpl::ParseNameSpaceRule; 1.2544 + newSection = eCSSSection_NameSpace; 1.2545 + 1.2546 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("media")) { 1.2547 + parseFunc = &CSSParserImpl::ParseMediaRule; 1.2548 + newSection = eCSSSection_General; 1.2549 + 1.2550 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("-moz-document")) { 1.2551 + parseFunc = &CSSParserImpl::ParseMozDocumentRule; 1.2552 + newSection = eCSSSection_General; 1.2553 + 1.2554 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("font-face")) { 1.2555 + parseFunc = &CSSParserImpl::ParseFontFaceRule; 1.2556 + newSection = eCSSSection_General; 1.2557 + 1.2558 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("font-feature-values") && 1.2559 + nsCSSFontFeatureValuesRule::PrefEnabled()) { 1.2560 + parseFunc = &CSSParserImpl::ParseFontFeatureValuesRule; 1.2561 + newSection = eCSSSection_General; 1.2562 + 1.2563 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("page")) { 1.2564 + parseFunc = &CSSParserImpl::ParsePageRule; 1.2565 + newSection = eCSSSection_General; 1.2566 + 1.2567 + } else if ((nsCSSProps::IsEnabled(eCSSPropertyAlias_MozAnimation) && 1.2568 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-keyframes")) || 1.2569 + mToken.mIdent.LowerCaseEqualsLiteral("keyframes")) { 1.2570 + parseFunc = &CSSParserImpl::ParseKeyframesRule; 1.2571 + newSection = eCSSSection_General; 1.2572 + 1.2573 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("supports") && 1.2574 + CSSSupportsRule::PrefEnabled()) { 1.2575 + parseFunc = &CSSParserImpl::ParseSupportsRule; 1.2576 + newSection = eCSSSection_General; 1.2577 + 1.2578 + } else { 1.2579 + if (!NonMozillaVendorIdentifier(mToken.mIdent)) { 1.2580 + REPORT_UNEXPECTED_TOKEN(PEUnknownAtRule); 1.2581 + OUTPUT_ERROR(); 1.2582 + } 1.2583 + // Skip over unsupported at rule, don't advance section 1.2584 + return SkipAtRule(aInAtRule); 1.2585 + } 1.2586 + 1.2587 + // Inside of @-rules, only the rules that can occur anywhere 1.2588 + // are allowed. 1.2589 + bool unnestable = aInAtRule && newSection != eCSSSection_General; 1.2590 + if (unnestable) { 1.2591 + REPORT_UNEXPECTED_TOKEN(PEGroupRuleNestedAtRule); 1.2592 + } 1.2593 + 1.2594 + if (unnestable || !(this->*parseFunc)(aAppendFunc, aData)) { 1.2595 + // Skip over invalid at rule, don't advance section 1.2596 + OUTPUT_ERROR(); 1.2597 + return SkipAtRule(aInAtRule); 1.2598 + } 1.2599 + 1.2600 + // Nested @-rules don't affect the top-level rule chain requirement 1.2601 + if (!aInAtRule) { 1.2602 + mSection = newSection; 1.2603 + } 1.2604 + 1.2605 + return true; 1.2606 +} 1.2607 + 1.2608 +bool 1.2609 +CSSParserImpl::ParseCharsetRule(RuleAppendFunc aAppendFunc, 1.2610 + void* aData) 1.2611 +{ 1.2612 + if (!GetToken(true)) { 1.2613 + REPORT_UNEXPECTED_EOF(PECharsetRuleEOF); 1.2614 + return false; 1.2615 + } 1.2616 + 1.2617 + if (eCSSToken_String != mToken.mType) { 1.2618 + UngetToken(); 1.2619 + REPORT_UNEXPECTED_TOKEN(PECharsetRuleNotString); 1.2620 + return false; 1.2621 + } 1.2622 + 1.2623 + nsAutoString charset = mToken.mIdent; 1.2624 + 1.2625 + if (!ExpectSymbol(';', true)) { 1.2626 + return false; 1.2627 + } 1.2628 + 1.2629 + nsRefPtr<css::CharsetRule> rule = new css::CharsetRule(charset); 1.2630 + (*aAppendFunc)(rule, aData); 1.2631 + 1.2632 + return true; 1.2633 +} 1.2634 + 1.2635 +bool 1.2636 +CSSParserImpl::ParseURLOrString(nsString& aURL) 1.2637 +{ 1.2638 + if (!GetToken(true)) { 1.2639 + return false; 1.2640 + } 1.2641 + if (eCSSToken_String == mToken.mType || eCSSToken_URL == mToken.mType) { 1.2642 + aURL = mToken.mIdent; 1.2643 + return true; 1.2644 + } 1.2645 + UngetToken(); 1.2646 + return false; 1.2647 +} 1.2648 + 1.2649 +bool 1.2650 +CSSParserImpl::ParseMediaQuery(bool aInAtRule, 1.2651 + nsMediaQuery **aQuery, 1.2652 + bool *aHitStop) 1.2653 +{ 1.2654 + *aQuery = nullptr; 1.2655 + *aHitStop = false; 1.2656 + 1.2657 + // "If the comma-separated list is the empty list it is assumed to 1.2658 + // specify the media query 'all'." (css3-mediaqueries, section 1.2659 + // "Media Queries") 1.2660 + if (!GetToken(true)) { 1.2661 + *aHitStop = true; 1.2662 + // expected termination by EOF 1.2663 + if (!aInAtRule) 1.2664 + return true; 1.2665 + 1.2666 + // unexpected termination by EOF 1.2667 + REPORT_UNEXPECTED_EOF(PEGatherMediaEOF); 1.2668 + return true; 1.2669 + } 1.2670 + 1.2671 + if (eCSSToken_Symbol == mToken.mType && aInAtRule && 1.2672 + (mToken.mSymbol == ';' || mToken.mSymbol == '{' || mToken.mSymbol == '}' )) { 1.2673 + *aHitStop = true; 1.2674 + UngetToken(); 1.2675 + return true; 1.2676 + } 1.2677 + UngetToken(); 1.2678 + 1.2679 + nsMediaQuery* query = new nsMediaQuery; 1.2680 + *aQuery = query; 1.2681 + 1.2682 + if (ExpectSymbol('(', true)) { 1.2683 + // we got an expression without a media type 1.2684 + UngetToken(); // so ParseMediaQueryExpression can handle it 1.2685 + query->SetType(nsGkAtoms::all); 1.2686 + query->SetTypeOmitted(); 1.2687 + // Just parse the first expression here. 1.2688 + if (!ParseMediaQueryExpression(query)) { 1.2689 + OUTPUT_ERROR(); 1.2690 + query->SetHadUnknownExpression(); 1.2691 + } 1.2692 + } else { 1.2693 + nsCOMPtr<nsIAtom> mediaType; 1.2694 + bool gotNotOrOnly = false; 1.2695 + for (;;) { 1.2696 + if (!GetToken(true)) { 1.2697 + REPORT_UNEXPECTED_EOF(PEGatherMediaEOF); 1.2698 + return false; 1.2699 + } 1.2700 + if (eCSSToken_Ident != mToken.mType) { 1.2701 + REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotIdent); 1.2702 + UngetToken(); 1.2703 + return false; 1.2704 + } 1.2705 + // case insensitive from CSS - must be lower cased 1.2706 + nsContentUtils::ASCIIToLower(mToken.mIdent); 1.2707 + mediaType = do_GetAtom(mToken.mIdent); 1.2708 + if (!mediaType) { 1.2709 + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); 1.2710 + } 1.2711 + if (!gotNotOrOnly && mediaType == nsGkAtoms::_not) { 1.2712 + gotNotOrOnly = true; 1.2713 + query->SetNegated(); 1.2714 + } else if (!gotNotOrOnly && mediaType == nsGkAtoms::only) { 1.2715 + gotNotOrOnly = true; 1.2716 + query->SetHasOnly(); 1.2717 + } else if (mediaType == nsGkAtoms::_not || 1.2718 + mediaType == nsGkAtoms::only || 1.2719 + mediaType == nsGkAtoms::_and || 1.2720 + mediaType == nsGkAtoms::_or) { 1.2721 + REPORT_UNEXPECTED_TOKEN(PEGatherMediaReservedMediaType); 1.2722 + UngetToken(); 1.2723 + return false; 1.2724 + } else { 1.2725 + // valid media type 1.2726 + break; 1.2727 + } 1.2728 + } 1.2729 + query->SetType(mediaType); 1.2730 + } 1.2731 + 1.2732 + for (;;) { 1.2733 + if (!GetToken(true)) { 1.2734 + *aHitStop = true; 1.2735 + // expected termination by EOF 1.2736 + if (!aInAtRule) 1.2737 + break; 1.2738 + 1.2739 + // unexpected termination by EOF 1.2740 + REPORT_UNEXPECTED_EOF(PEGatherMediaEOF); 1.2741 + break; 1.2742 + } 1.2743 + 1.2744 + if (eCSSToken_Symbol == mToken.mType && aInAtRule && 1.2745 + (mToken.mSymbol == ';' || mToken.mSymbol == '{' || mToken.mSymbol == '}')) { 1.2746 + *aHitStop = true; 1.2747 + UngetToken(); 1.2748 + break; 1.2749 + } 1.2750 + if (eCSSToken_Symbol == mToken.mType && mToken.mSymbol == ',') { 1.2751 + // Done with the expressions for this query 1.2752 + break; 1.2753 + } 1.2754 + if (eCSSToken_Ident != mToken.mType || 1.2755 + !mToken.mIdent.LowerCaseEqualsLiteral("and")) { 1.2756 + REPORT_UNEXPECTED_TOKEN(PEGatherMediaNotComma); 1.2757 + UngetToken(); 1.2758 + return false; 1.2759 + } 1.2760 + if (!ParseMediaQueryExpression(query)) { 1.2761 + OUTPUT_ERROR(); 1.2762 + query->SetHadUnknownExpression(); 1.2763 + } 1.2764 + } 1.2765 + return true; 1.2766 +} 1.2767 + 1.2768 +// Returns false only when there is a low-level error in the scanner 1.2769 +// (out-of-memory). 1.2770 +bool 1.2771 +CSSParserImpl::GatherMedia(nsMediaList* aMedia, 1.2772 + bool aInAtRule) 1.2773 +{ 1.2774 + for (;;) { 1.2775 + nsAutoPtr<nsMediaQuery> query; 1.2776 + bool hitStop; 1.2777 + if (!ParseMediaQuery(aInAtRule, getter_Transfers(query), 1.2778 + &hitStop)) { 1.2779 + NS_ASSERTION(!hitStop, "should return true when hit stop"); 1.2780 + OUTPUT_ERROR(); 1.2781 + if (query) { 1.2782 + query->SetHadUnknownExpression(); 1.2783 + } 1.2784 + if (aInAtRule) { 1.2785 + const char16_t stopChars[] = 1.2786 + { char16_t(','), char16_t('{'), char16_t(';'), char16_t('}'), char16_t(0) }; 1.2787 + SkipUntilOneOf(stopChars); 1.2788 + } else { 1.2789 + SkipUntil(','); 1.2790 + } 1.2791 + // Rely on SkipUntilOneOf leaving mToken around as the last token read. 1.2792 + if (mToken.mType == eCSSToken_Symbol && aInAtRule && 1.2793 + (mToken.mSymbol == '{' || mToken.mSymbol == ';' || mToken.mSymbol == '}')) { 1.2794 + UngetToken(); 1.2795 + hitStop = true; 1.2796 + } 1.2797 + } 1.2798 + if (query) { 1.2799 + aMedia->AppendQuery(query); 1.2800 + } 1.2801 + if (hitStop) { 1.2802 + break; 1.2803 + } 1.2804 + } 1.2805 + return true; 1.2806 +} 1.2807 + 1.2808 +bool 1.2809 +CSSParserImpl::ParseMediaQueryExpression(nsMediaQuery* aQuery) 1.2810 +{ 1.2811 + if (!ExpectSymbol('(', true)) { 1.2812 + REPORT_UNEXPECTED_TOKEN(PEMQExpectedExpressionStart); 1.2813 + return false; 1.2814 + } 1.2815 + if (! GetToken(true)) { 1.2816 + REPORT_UNEXPECTED_EOF(PEMQExpressionEOF); 1.2817 + return false; 1.2818 + } 1.2819 + if (eCSSToken_Ident != mToken.mType) { 1.2820 + REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName); 1.2821 + UngetToken(); 1.2822 + SkipUntil(')'); 1.2823 + return false; 1.2824 + } 1.2825 + 1.2826 + nsMediaExpression *expr = aQuery->NewExpression(); 1.2827 + 1.2828 + // case insensitive from CSS - must be lower cased 1.2829 + nsContentUtils::ASCIIToLower(mToken.mIdent); 1.2830 + const char16_t *featureString; 1.2831 + if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("min-"))) { 1.2832 + expr->mRange = nsMediaExpression::eMin; 1.2833 + featureString = mToken.mIdent.get() + 4; 1.2834 + } else if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("max-"))) { 1.2835 + expr->mRange = nsMediaExpression::eMax; 1.2836 + featureString = mToken.mIdent.get() + 4; 1.2837 + } else { 1.2838 + expr->mRange = nsMediaExpression::eEqual; 1.2839 + featureString = mToken.mIdent.get(); 1.2840 + } 1.2841 + 1.2842 + nsCOMPtr<nsIAtom> mediaFeatureAtom = do_GetAtom(featureString); 1.2843 + if (!mediaFeatureAtom) { 1.2844 + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); 1.2845 + } 1.2846 + const nsMediaFeature *feature = nsMediaFeatures::features; 1.2847 + for (; feature->mName; ++feature) { 1.2848 + if (*(feature->mName) == mediaFeatureAtom) { 1.2849 + break; 1.2850 + } 1.2851 + } 1.2852 + if (!feature->mName || 1.2853 + (expr->mRange != nsMediaExpression::eEqual && 1.2854 + feature->mRangeType != nsMediaFeature::eMinMaxAllowed)) { 1.2855 + REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureName); 1.2856 + SkipUntil(')'); 1.2857 + return false; 1.2858 + } 1.2859 + expr->mFeature = feature; 1.2860 + 1.2861 + if (!GetToken(true) || mToken.IsSymbol(')')) { 1.2862 + // Query expressions for any feature can be given without a value. 1.2863 + // However, min/max prefixes are not allowed. 1.2864 + if (expr->mRange != nsMediaExpression::eEqual) { 1.2865 + REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue); 1.2866 + return false; 1.2867 + } 1.2868 + expr->mValue.Reset(); 1.2869 + return true; 1.2870 + } 1.2871 + 1.2872 + if (!mToken.IsSymbol(':')) { 1.2873 + REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd); 1.2874 + UngetToken(); 1.2875 + SkipUntil(')'); 1.2876 + return false; 1.2877 + } 1.2878 + 1.2879 + bool rv = false; 1.2880 + switch (feature->mValueType) { 1.2881 + case nsMediaFeature::eLength: 1.2882 + rv = ParseNonNegativeVariant(expr->mValue, VARIANT_LENGTH, nullptr); 1.2883 + break; 1.2884 + case nsMediaFeature::eInteger: 1.2885 + case nsMediaFeature::eBoolInteger: 1.2886 + rv = ParseNonNegativeVariant(expr->mValue, VARIANT_INTEGER, nullptr); 1.2887 + // Enforce extra restrictions for eBoolInteger 1.2888 + if (rv && 1.2889 + feature->mValueType == nsMediaFeature::eBoolInteger && 1.2890 + expr->mValue.GetIntValue() > 1) 1.2891 + rv = false; 1.2892 + break; 1.2893 + case nsMediaFeature::eFloat: 1.2894 + rv = ParseNonNegativeVariant(expr->mValue, VARIANT_NUMBER, nullptr); 1.2895 + break; 1.2896 + case nsMediaFeature::eIntRatio: 1.2897 + { 1.2898 + // Two integers separated by '/', with optional whitespace on 1.2899 + // either side of the '/'. 1.2900 + nsRefPtr<nsCSSValue::Array> a = nsCSSValue::Array::Create(2); 1.2901 + expr->mValue.SetArrayValue(a, eCSSUnit_Array); 1.2902 + // We don't bother with ParseNonNegativeVariant since we have to 1.2903 + // check for != 0 as well; no need to worry about the UngetToken 1.2904 + // since we're throwing out up to the next ')' anyway. 1.2905 + rv = ParseVariant(a->Item(0), VARIANT_INTEGER, nullptr) && 1.2906 + a->Item(0).GetIntValue() > 0 && 1.2907 + ExpectSymbol('/', true) && 1.2908 + ParseVariant(a->Item(1), VARIANT_INTEGER, nullptr) && 1.2909 + a->Item(1).GetIntValue() > 0; 1.2910 + } 1.2911 + break; 1.2912 + case nsMediaFeature::eResolution: 1.2913 + rv = GetToken(true); 1.2914 + if (!rv) 1.2915 + break; 1.2916 + rv = mToken.mType == eCSSToken_Dimension && mToken.mNumber > 0.0f; 1.2917 + if (!rv) { 1.2918 + UngetToken(); 1.2919 + break; 1.2920 + } 1.2921 + // No worries about whether unitless zero is allowed, since the 1.2922 + // value must be positive (and we checked that above). 1.2923 + NS_ASSERTION(!mToken.mIdent.IsEmpty(), "unit lied"); 1.2924 + if (mToken.mIdent.LowerCaseEqualsLiteral("dpi")) { 1.2925 + expr->mValue.SetFloatValue(mToken.mNumber, eCSSUnit_Inch); 1.2926 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("dppx")) { 1.2927 + expr->mValue.SetFloatValue(mToken.mNumber, eCSSUnit_Pixel); 1.2928 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("dpcm")) { 1.2929 + expr->mValue.SetFloatValue(mToken.mNumber, eCSSUnit_Centimeter); 1.2930 + } else { 1.2931 + rv = false; 1.2932 + } 1.2933 + break; 1.2934 + case nsMediaFeature::eEnumerated: 1.2935 + rv = ParseVariant(expr->mValue, VARIANT_KEYWORD, 1.2936 + feature->mData.mKeywordTable); 1.2937 + break; 1.2938 + case nsMediaFeature::eIdent: 1.2939 + rv = ParseVariant(expr->mValue, VARIANT_IDENTIFIER, nullptr); 1.2940 + break; 1.2941 + } 1.2942 + if (!rv || !ExpectSymbol(')', true)) { 1.2943 + REPORT_UNEXPECTED(PEMQExpectedFeatureValue); 1.2944 + SkipUntil(')'); 1.2945 + return false; 1.2946 + } 1.2947 + 1.2948 + return true; 1.2949 +} 1.2950 + 1.2951 +// Parse a CSS2 import rule: "@import STRING | URL [medium [, medium]]" 1.2952 +bool 1.2953 +CSSParserImpl::ParseImportRule(RuleAppendFunc aAppendFunc, void* aData) 1.2954 +{ 1.2955 + nsRefPtr<nsMediaList> media = new nsMediaList(); 1.2956 + 1.2957 + nsAutoString url; 1.2958 + if (!ParseURLOrString(url)) { 1.2959 + REPORT_UNEXPECTED_TOKEN(PEImportNotURI); 1.2960 + return false; 1.2961 + } 1.2962 + 1.2963 + if (!ExpectSymbol(';', true)) { 1.2964 + if (!GatherMedia(media, true) || 1.2965 + !ExpectSymbol(';', true)) { 1.2966 + REPORT_UNEXPECTED_TOKEN(PEImportUnexpected); 1.2967 + // don't advance section, simply ignore invalid @import 1.2968 + return false; 1.2969 + } 1.2970 + 1.2971 + // Safe to assert this, since we ensured that there is something 1.2972 + // other than the ';' coming after the @import's url() token. 1.2973 + NS_ASSERTION(media->Length() != 0, "media list must be nonempty"); 1.2974 + } 1.2975 + 1.2976 + ProcessImport(url, media, aAppendFunc, aData); 1.2977 + return true; 1.2978 +} 1.2979 + 1.2980 + 1.2981 +void 1.2982 +CSSParserImpl::ProcessImport(const nsString& aURLSpec, 1.2983 + nsMediaList* aMedia, 1.2984 + RuleAppendFunc aAppendFunc, 1.2985 + void* aData) 1.2986 +{ 1.2987 + nsRefPtr<css::ImportRule> rule = new css::ImportRule(aMedia, aURLSpec); 1.2988 + (*aAppendFunc)(rule, aData); 1.2989 + 1.2990 + // Diagnose bad URIs even if we don't have a child loader. 1.2991 + nsCOMPtr<nsIURI> url; 1.2992 + // Charset will be deduced from mBaseURI, which is more or less correct. 1.2993 + nsresult rv = NS_NewURI(getter_AddRefs(url), aURLSpec, nullptr, mBaseURI); 1.2994 + 1.2995 + if (NS_FAILED(rv)) { 1.2996 + if (rv == NS_ERROR_MALFORMED_URI) { 1.2997 + // import url is bad 1.2998 + REPORT_UNEXPECTED_P(PEImportBadURI, aURLSpec); 1.2999 + OUTPUT_ERROR(); 1.3000 + } 1.3001 + return; 1.3002 + } 1.3003 + 1.3004 + if (mChildLoader) { 1.3005 + mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule); 1.3006 + } 1.3007 +} 1.3008 + 1.3009 +// Parse the {} part of an @media or @-moz-document rule. 1.3010 +bool 1.3011 +CSSParserImpl::ParseGroupRule(css::GroupRule* aRule, 1.3012 + RuleAppendFunc aAppendFunc, 1.3013 + void* aData) 1.3014 +{ 1.3015 + // XXXbz this could use better error reporting throughout the method 1.3016 + if (!ExpectSymbol('{', true)) { 1.3017 + return false; 1.3018 + } 1.3019 + 1.3020 + // push rule on stack, loop over children 1.3021 + PushGroup(aRule); 1.3022 + nsCSSSection holdSection = mSection; 1.3023 + mSection = eCSSSection_General; 1.3024 + 1.3025 + for (;;) { 1.3026 + // Get next non-whitespace token 1.3027 + if (! GetToken(true)) { 1.3028 + REPORT_UNEXPECTED_EOF(PEGroupRuleEOF2); 1.3029 + break; 1.3030 + } 1.3031 + if (mToken.IsSymbol('}')) { // done! 1.3032 + UngetToken(); 1.3033 + break; 1.3034 + } 1.3035 + if (eCSSToken_AtKeyword == mToken.mType) { 1.3036 + // Parse for nested rules 1.3037 + ParseAtRule(aAppendFunc, aData, true); 1.3038 + continue; 1.3039 + } 1.3040 + UngetToken(); 1.3041 + ParseRuleSet(AppendRuleToSheet, this, true); 1.3042 + } 1.3043 + PopGroup(); 1.3044 + 1.3045 + if (!ExpectSymbol('}', true)) { 1.3046 + mSection = holdSection; 1.3047 + return false; 1.3048 + } 1.3049 + (*aAppendFunc)(aRule, aData); 1.3050 + return true; 1.3051 +} 1.3052 + 1.3053 +// Parse a CSS2 media rule: "@media medium [, medium] { ... }" 1.3054 +bool 1.3055 +CSSParserImpl::ParseMediaRule(RuleAppendFunc aAppendFunc, void* aData) 1.3056 +{ 1.3057 + nsRefPtr<nsMediaList> media = new nsMediaList(); 1.3058 + 1.3059 + if (GatherMedia(media, true)) { 1.3060 + // XXXbz this could use better error reporting throughout the method 1.3061 + nsRefPtr<css::MediaRule> rule = new css::MediaRule(); 1.3062 + // Append first, so when we do SetMedia() the rule 1.3063 + // knows what its stylesheet is. 1.3064 + if (ParseGroupRule(rule, aAppendFunc, aData)) { 1.3065 + rule->SetMedia(media); 1.3066 + return true; 1.3067 + } 1.3068 + } 1.3069 + 1.3070 + return false; 1.3071 +} 1.3072 + 1.3073 +// Parse a @-moz-document rule. This is like an @media rule, but instead 1.3074 +// of a medium it has a nonempty list of items where each item is either 1.3075 +// url(), url-prefix(), or domain(). 1.3076 +bool 1.3077 +CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc, void* aData) 1.3078 +{ 1.3079 + css::DocumentRule::URL *urls = nullptr; 1.3080 + css::DocumentRule::URL **next = &urls; 1.3081 + do { 1.3082 + if (!GetToken(true)) { 1.3083 + REPORT_UNEXPECTED_EOF(PEMozDocRuleEOF); 1.3084 + delete urls; 1.3085 + return false; 1.3086 + } 1.3087 + 1.3088 + if (!(eCSSToken_URL == mToken.mType || 1.3089 + (eCSSToken_Function == mToken.mType && 1.3090 + (mToken.mIdent.LowerCaseEqualsLiteral("url-prefix") || 1.3091 + mToken.mIdent.LowerCaseEqualsLiteral("domain") || 1.3092 + mToken.mIdent.LowerCaseEqualsLiteral("regexp"))))) { 1.3093 + REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc2); 1.3094 + UngetToken(); 1.3095 + delete urls; 1.3096 + return false; 1.3097 + } 1.3098 + css::DocumentRule::URL *cur = *next = new css::DocumentRule::URL; 1.3099 + next = &cur->next; 1.3100 + if (mToken.mType == eCSSToken_URL) { 1.3101 + cur->func = css::DocumentRule::eURL; 1.3102 + CopyUTF16toUTF8(mToken.mIdent, cur->url); 1.3103 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("regexp")) { 1.3104 + // regexp() is different from url-prefix() and domain() (but 1.3105 + // probably the way they *should* have been* in that it requires a 1.3106 + // string argument, and doesn't try to behave like url(). 1.3107 + cur->func = css::DocumentRule::eRegExp; 1.3108 + GetToken(true); 1.3109 + // copy before we know it's valid (but before ExpectSymbol changes 1.3110 + // mToken.mIdent) 1.3111 + CopyUTF16toUTF8(mToken.mIdent, cur->url); 1.3112 + if (eCSSToken_String != mToken.mType || !ExpectSymbol(')', true)) { 1.3113 + REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotString); 1.3114 + SkipUntil(')'); 1.3115 + delete urls; 1.3116 + return false; 1.3117 + } 1.3118 + } else { 1.3119 + if (mToken.mIdent.LowerCaseEqualsLiteral("url-prefix")) { 1.3120 + cur->func = css::DocumentRule::eURLPrefix; 1.3121 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("domain")) { 1.3122 + cur->func = css::DocumentRule::eDomain; 1.3123 + } 1.3124 + 1.3125 + NS_ASSERTION(!mHavePushBack, "mustn't have pushback at this point"); 1.3126 + if (!mScanner->NextURL(mToken) || mToken.mType != eCSSToken_URL) { 1.3127 + REPORT_UNEXPECTED_TOKEN(PEMozDocRuleNotURI); 1.3128 + SkipUntil(')'); 1.3129 + delete urls; 1.3130 + return false; 1.3131 + } 1.3132 + 1.3133 + // We could try to make the URL (as long as it's not domain()) 1.3134 + // canonical and absolute with NS_NewURI and GetSpec, but I'm 1.3135 + // inclined to think we shouldn't. 1.3136 + CopyUTF16toUTF8(mToken.mIdent, cur->url); 1.3137 + } 1.3138 + } while (ExpectSymbol(',', true)); 1.3139 + 1.3140 + nsRefPtr<css::DocumentRule> rule = new css::DocumentRule(); 1.3141 + rule->SetURLs(urls); 1.3142 + 1.3143 + return ParseGroupRule(rule, aAppendFunc, aData); 1.3144 +} 1.3145 + 1.3146 +// Parse a CSS3 namespace rule: "@namespace [prefix] STRING | URL;" 1.3147 +bool 1.3148 +CSSParserImpl::ParseNameSpaceRule(RuleAppendFunc aAppendFunc, void* aData) 1.3149 +{ 1.3150 + if (!GetToken(true)) { 1.3151 + REPORT_UNEXPECTED_EOF(PEAtNSPrefixEOF); 1.3152 + return false; 1.3153 + } 1.3154 + 1.3155 + nsAutoString prefix; 1.3156 + nsAutoString url; 1.3157 + 1.3158 + if (eCSSToken_Ident == mToken.mType) { 1.3159 + prefix = mToken.mIdent; 1.3160 + // user-specified identifiers are case-sensitive (bug 416106) 1.3161 + } else { 1.3162 + UngetToken(); 1.3163 + } 1.3164 + 1.3165 + if (!ParseURLOrString(url) || !ExpectSymbol(';', true)) { 1.3166 + if (mHavePushBack) { 1.3167 + REPORT_UNEXPECTED_TOKEN(PEAtNSUnexpected); 1.3168 + } else { 1.3169 + REPORT_UNEXPECTED_EOF(PEAtNSURIEOF); 1.3170 + } 1.3171 + return false; 1.3172 + } 1.3173 + 1.3174 + ProcessNameSpace(prefix, url, aAppendFunc, aData); 1.3175 + return true; 1.3176 +} 1.3177 + 1.3178 +void 1.3179 +CSSParserImpl::ProcessNameSpace(const nsString& aPrefix, 1.3180 + const nsString& aURLSpec, 1.3181 + RuleAppendFunc aAppendFunc, 1.3182 + void* aData) 1.3183 +{ 1.3184 + nsCOMPtr<nsIAtom> prefix; 1.3185 + 1.3186 + if (!aPrefix.IsEmpty()) { 1.3187 + prefix = do_GetAtom(aPrefix); 1.3188 + if (!prefix) { 1.3189 + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); 1.3190 + } 1.3191 + } 1.3192 + 1.3193 + nsRefPtr<css::NameSpaceRule> rule = new css::NameSpaceRule(prefix, aURLSpec); 1.3194 + (*aAppendFunc)(rule, aData); 1.3195 + 1.3196 + // If this was the first namespace rule encountered, it will trigger 1.3197 + // creation of a namespace map. 1.3198 + if (!mNameSpaceMap) { 1.3199 + mNameSpaceMap = mSheet->GetNameSpaceMap(); 1.3200 + } 1.3201 +} 1.3202 + 1.3203 +// font-face-rule: '@font-face' '{' font-description '}' 1.3204 +// font-description: font-descriptor+ 1.3205 +bool 1.3206 +CSSParserImpl::ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aData) 1.3207 +{ 1.3208 + if (!ExpectSymbol('{', true)) { 1.3209 + REPORT_UNEXPECTED_TOKEN(PEBadFontBlockStart); 1.3210 + return false; 1.3211 + } 1.3212 + 1.3213 + nsRefPtr<nsCSSFontFaceRule> rule(new nsCSSFontFaceRule()); 1.3214 + 1.3215 + for (;;) { 1.3216 + if (!GetToken(true)) { 1.3217 + REPORT_UNEXPECTED_EOF(PEFontFaceEOF); 1.3218 + break; 1.3219 + } 1.3220 + if (mToken.IsSymbol('}')) { // done! 1.3221 + UngetToken(); 1.3222 + break; 1.3223 + } 1.3224 + 1.3225 + // ignore extra semicolons 1.3226 + if (mToken.IsSymbol(';')) 1.3227 + continue; 1.3228 + 1.3229 + if (!ParseFontDescriptor(rule)) { 1.3230 + REPORT_UNEXPECTED(PEDeclSkipped); 1.3231 + OUTPUT_ERROR(); 1.3232 + if (!SkipDeclaration(true)) 1.3233 + break; 1.3234 + } 1.3235 + } 1.3236 + if (!ExpectSymbol('}', true)) { 1.3237 + REPORT_UNEXPECTED_TOKEN(PEBadFontBlockEnd); 1.3238 + return false; 1.3239 + } 1.3240 + (*aAppendFunc)(rule, aData); 1.3241 + return true; 1.3242 +} 1.3243 + 1.3244 +// font-descriptor: font-family-desc 1.3245 +// | font-style-desc 1.3246 +// | font-weight-desc 1.3247 +// | font-stretch-desc 1.3248 +// | font-src-desc 1.3249 +// | unicode-range-desc 1.3250 +// 1.3251 +// All font-*-desc productions follow the pattern 1.3252 +// IDENT ':' value ';' 1.3253 +// 1.3254 +// On entry to this function, mToken is the IDENT. 1.3255 + 1.3256 +bool 1.3257 +CSSParserImpl::ParseFontDescriptor(nsCSSFontFaceRule* aRule) 1.3258 +{ 1.3259 + if (eCSSToken_Ident != mToken.mType) { 1.3260 + REPORT_UNEXPECTED_TOKEN(PEFontDescExpected); 1.3261 + return false; 1.3262 + } 1.3263 + 1.3264 + nsString descName = mToken.mIdent; 1.3265 + if (!ExpectSymbol(':', true)) { 1.3266 + REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon); 1.3267 + OUTPUT_ERROR(); 1.3268 + return false; 1.3269 + } 1.3270 + 1.3271 + nsCSSFontDesc descID = nsCSSProps::LookupFontDesc(descName); 1.3272 + nsCSSValue value; 1.3273 + 1.3274 + if (descID == eCSSFontDesc_UNKNOWN) { 1.3275 + if (NonMozillaVendorIdentifier(descName)) { 1.3276 + // silently skip other vendors' extensions 1.3277 + SkipDeclaration(true); 1.3278 + return true; 1.3279 + } else { 1.3280 + REPORT_UNEXPECTED_P(PEUnknownFontDesc, descName); 1.3281 + return false; 1.3282 + } 1.3283 + } 1.3284 + 1.3285 + if (!ParseFontDescriptorValue(descID, value)) { 1.3286 + REPORT_UNEXPECTED_P(PEValueParsingError, descName); 1.3287 + return false; 1.3288 + } 1.3289 + 1.3290 + if (!ExpectEndProperty()) 1.3291 + return false; 1.3292 + 1.3293 + aRule->SetDesc(descID, value); 1.3294 + return true; 1.3295 +} 1.3296 + 1.3297 +// @font-feature-values <font-family># { 1.3298 +// @<feature-type> { 1.3299 +// <feature-ident> : <feature-index>+; 1.3300 +// <feature-ident> : <feature-index>+; 1.3301 +// ... 1.3302 +// } 1.3303 +// ... 1.3304 +// } 1.3305 + 1.3306 +bool 1.3307 +CSSParserImpl::ParseFontFeatureValuesRule(RuleAppendFunc aAppendFunc, 1.3308 + void* aData) 1.3309 +{ 1.3310 + nsRefPtr<nsCSSFontFeatureValuesRule> 1.3311 + valuesRule(new nsCSSFontFeatureValuesRule()); 1.3312 + 1.3313 + // parse family list 1.3314 + nsCSSValue familyValue; 1.3315 + 1.3316 + if (!ParseFamily(familyValue) || 1.3317 + familyValue.GetUnit() != eCSSUnit_Families) 1.3318 + { 1.3319 + REPORT_UNEXPECTED_TOKEN(PEFFVNoFamily); 1.3320 + return false; 1.3321 + } 1.3322 + 1.3323 + // add family to rule 1.3324 + nsAutoString familyList; 1.3325 + bool hasGeneric; 1.3326 + familyValue.GetStringValue(familyList); 1.3327 + valuesRule->SetFamilyList(familyList, hasGeneric); 1.3328 + 1.3329 + // family list has generic ==> parse error 1.3330 + if (hasGeneric) { 1.3331 + REPORT_UNEXPECTED_TOKEN(PEFFVGenericInFamilyList); 1.3332 + return false; 1.3333 + } 1.3334 + 1.3335 + // open brace 1.3336 + if (!ExpectSymbol('{', true)) { 1.3337 + REPORT_UNEXPECTED_TOKEN(PEFFVBlockStart); 1.3338 + return false; 1.3339 + } 1.3340 + 1.3341 + // list of sets of feature values, each set bound to a specific 1.3342 + // feature-type (e.g. swash, annotation) 1.3343 + for (;;) { 1.3344 + if (!GetToken(true)) { 1.3345 + REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF); 1.3346 + break; 1.3347 + } 1.3348 + if (mToken.IsSymbol('}')) { // done! 1.3349 + UngetToken(); 1.3350 + break; 1.3351 + } 1.3352 + 1.3353 + if (!ParseFontFeatureValueSet(valuesRule)) { 1.3354 + if (!SkipAtRule(false)) { 1.3355 + break; 1.3356 + } 1.3357 + } 1.3358 + } 1.3359 + if (!ExpectSymbol('}', true)) { 1.3360 + REPORT_UNEXPECTED_TOKEN(PEFFVUnexpectedBlockEnd); 1.3361 + SkipUntil('}'); 1.3362 + return false; 1.3363 + } 1.3364 + 1.3365 + (*aAppendFunc)(valuesRule, aData); 1.3366 + return true; 1.3367 +} 1.3368 + 1.3369 +#define NUMVALUES_NO_LIMIT 0xFFFF 1.3370 + 1.3371 +// parse a single value set containing name-value pairs for a single feature type 1.3372 +// @<feature-type> { [ <feature-ident> : <feature-index>+ ; ]* } 1.3373 +// Ex: @swash { flowing: 1; delicate: 2; } 1.3374 +bool 1.3375 +CSSParserImpl::ParseFontFeatureValueSet(nsCSSFontFeatureValuesRule 1.3376 + *aFeatureValuesRule) 1.3377 +{ 1.3378 + // -- @keyword (e.g. swash, styleset) 1.3379 + if (eCSSToken_AtKeyword != mToken.mType) { 1.3380 + REPORT_UNEXPECTED_TOKEN(PEFontFeatureValuesNoAt); 1.3381 + OUTPUT_ERROR(); 1.3382 + UngetToken(); 1.3383 + return false; 1.3384 + } 1.3385 + 1.3386 + // which font-specific variant of font-variant-alternates 1.3387 + int32_t whichVariant; 1.3388 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); 1.3389 + if (keyword == eCSSKeyword_UNKNOWN || 1.3390 + !nsCSSProps::FindKeyword(keyword, 1.3391 + nsCSSProps::kFontVariantAlternatesFuncsKTable, 1.3392 + whichVariant)) 1.3393 + { 1.3394 + if (!NonMozillaVendorIdentifier(mToken.mIdent)) { 1.3395 + REPORT_UNEXPECTED_TOKEN(PEFFVUnknownFontVariantPropValue); 1.3396 + OUTPUT_ERROR(); 1.3397 + } 1.3398 + UngetToken(); 1.3399 + return false; 1.3400 + } 1.3401 + 1.3402 + nsAutoString featureType(mToken.mIdent); 1.3403 + 1.3404 + // open brace 1.3405 + if (!ExpectSymbol('{', true)) { 1.3406 + REPORT_UNEXPECTED_TOKEN(PEFFVValueSetStart); 1.3407 + return false; 1.3408 + } 1.3409 + 1.3410 + // styleset and character-variant can be multi-valued, otherwise single value 1.3411 + int32_t limitNumValues; 1.3412 + 1.3413 + switch (keyword) { 1.3414 + case eCSSKeyword_styleset: 1.3415 + limitNumValues = NUMVALUES_NO_LIMIT; 1.3416 + break; 1.3417 + case eCSSKeyword_character_variant: 1.3418 + limitNumValues = 2; 1.3419 + break; 1.3420 + default: 1.3421 + limitNumValues = 1; 1.3422 + break; 1.3423 + } 1.3424 + 1.3425 + // -- ident integer+ [, ident integer+] 1.3426 + nsAutoTArray<gfxFontFeatureValueSet::ValueList, 5> values; 1.3427 + 1.3428 + // list of font-feature-values-declaration's 1.3429 + for (;;) { 1.3430 + nsAutoString valueId; 1.3431 + 1.3432 + if (!GetToken(true)) { 1.3433 + REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF); 1.3434 + break; 1.3435 + } 1.3436 + 1.3437 + // ignore extra semicolons 1.3438 + if (mToken.IsSymbol(';')) { 1.3439 + continue; 1.3440 + } 1.3441 + 1.3442 + // close brace ==> done 1.3443 + if (mToken.IsSymbol('}')) { 1.3444 + break; 1.3445 + } 1.3446 + 1.3447 + // ident 1.3448 + if (eCSSToken_Ident != mToken.mType) { 1.3449 + REPORT_UNEXPECTED_TOKEN(PEFFVExpectedIdent); 1.3450 + if (!SkipDeclaration(true)) { 1.3451 + break; 1.3452 + } 1.3453 + continue; 1.3454 + } 1.3455 + 1.3456 + valueId.Assign(mToken.mIdent); 1.3457 + 1.3458 + // colon 1.3459 + if (!ExpectSymbol(':', true)) { 1.3460 + REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon); 1.3461 + OUTPUT_ERROR(); 1.3462 + if (!SkipDeclaration(true)) { 1.3463 + break; 1.3464 + } 1.3465 + continue; 1.3466 + } 1.3467 + 1.3468 + // value list 1.3469 + nsAutoTArray<uint32_t,4> featureSelectors; 1.3470 + 1.3471 + nsCSSValue intValue; 1.3472 + while (ParseNonNegativeVariant(intValue, VARIANT_INTEGER, nullptr)) { 1.3473 + featureSelectors.AppendElement(uint32_t(intValue.GetIntValue())); 1.3474 + } 1.3475 + 1.3476 + int32_t numValues = featureSelectors.Length(); 1.3477 + 1.3478 + if (numValues == 0) { 1.3479 + REPORT_UNEXPECTED_TOKEN(PEFFVExpectedValue); 1.3480 + OUTPUT_ERROR(); 1.3481 + if (!SkipDeclaration(true)) { 1.3482 + break; 1.3483 + } 1.3484 + continue; 1.3485 + } 1.3486 + 1.3487 + if (numValues > limitNumValues) { 1.3488 + REPORT_UNEXPECTED_P(PEFFVTooManyValues, featureType); 1.3489 + OUTPUT_ERROR(); 1.3490 + if (!SkipDeclaration(true)) { 1.3491 + break; 1.3492 + } 1.3493 + continue; 1.3494 + } 1.3495 + 1.3496 + if (!GetToken(true)) { 1.3497 + REPORT_UNEXPECTED_EOF(PEFFVUnexpectedEOF); 1.3498 + gfxFontFeatureValueSet::ValueList v(valueId, featureSelectors); 1.3499 + values.AppendElement(v); 1.3500 + break; 1.3501 + } 1.3502 + 1.3503 + // ';' or '}' to end definition 1.3504 + if (!mToken.IsSymbol(';') && !mToken.IsSymbol('}')) { 1.3505 + REPORT_UNEXPECTED_TOKEN(PEFFVValueDefinitionTrailing); 1.3506 + OUTPUT_ERROR(); 1.3507 + if (!SkipDeclaration(true)) { 1.3508 + break; 1.3509 + } 1.3510 + continue; 1.3511 + } 1.3512 + 1.3513 + gfxFontFeatureValueSet::ValueList v(valueId, featureSelectors); 1.3514 + values.AppendElement(v); 1.3515 + 1.3516 + if (mToken.IsSymbol('}')) { 1.3517 + break; 1.3518 + } 1.3519 + } 1.3520 + 1.3521 + aFeatureValuesRule->AddValueList(whichVariant, values); 1.3522 + return true; 1.3523 +} 1.3524 + 1.3525 +bool 1.3526 +CSSParserImpl::ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aData) 1.3527 +{ 1.3528 + if (!GetToken(true)) { 1.3529 + REPORT_UNEXPECTED_EOF(PEKeyframeNameEOF); 1.3530 + return false; 1.3531 + } 1.3532 + 1.3533 + if (mToken.mType != eCSSToken_Ident) { 1.3534 + REPORT_UNEXPECTED_TOKEN(PEKeyframeBadName); 1.3535 + UngetToken(); 1.3536 + return false; 1.3537 + } 1.3538 + nsString name(mToken.mIdent); 1.3539 + 1.3540 + if (!ExpectSymbol('{', true)) { 1.3541 + REPORT_UNEXPECTED_TOKEN(PEKeyframeBrace); 1.3542 + return false; 1.3543 + } 1.3544 + 1.3545 + nsRefPtr<nsCSSKeyframesRule> rule = new nsCSSKeyframesRule(name); 1.3546 + 1.3547 + while (!ExpectSymbol('}', true)) { 1.3548 + nsRefPtr<nsCSSKeyframeRule> kid = ParseKeyframeRule(); 1.3549 + if (kid) { 1.3550 + rule->AppendStyleRule(kid); 1.3551 + } else { 1.3552 + OUTPUT_ERROR(); 1.3553 + SkipRuleSet(true); 1.3554 + } 1.3555 + } 1.3556 + 1.3557 + (*aAppendFunc)(rule, aData); 1.3558 + return true; 1.3559 +} 1.3560 + 1.3561 +bool 1.3562 +CSSParserImpl::ParsePageRule(RuleAppendFunc aAppendFunc, void* aData) 1.3563 +{ 1.3564 + // TODO: There can be page selectors after @page such as ":first", ":left". 1.3565 + uint32_t parseFlags = eParseDeclaration_InBraces | 1.3566 + eParseDeclaration_AllowImportant; 1.3567 + 1.3568 + // Forbid viewport units in @page rules. See bug 811391. 1.3569 + NS_ABORT_IF_FALSE(mViewportUnitsEnabled, 1.3570 + "Viewport units should be enabled outside of @page rules."); 1.3571 + mViewportUnitsEnabled = false; 1.3572 + nsAutoPtr<css::Declaration> declaration( 1.3573 + ParseDeclarationBlock(parseFlags, 1.3574 + eCSSContext_Page)); 1.3575 + mViewportUnitsEnabled = true; 1.3576 + 1.3577 + if (!declaration) { 1.3578 + return false; 1.3579 + } 1.3580 + 1.3581 + // Takes ownership of declaration. 1.3582 + nsRefPtr<nsCSSPageRule> rule = new nsCSSPageRule(declaration); 1.3583 + 1.3584 + (*aAppendFunc)(rule, aData); 1.3585 + return true; 1.3586 +} 1.3587 + 1.3588 +already_AddRefed<nsCSSKeyframeRule> 1.3589 +CSSParserImpl::ParseKeyframeRule() 1.3590 +{ 1.3591 + InfallibleTArray<float> selectorList; 1.3592 + if (!ParseKeyframeSelectorList(selectorList)) { 1.3593 + REPORT_UNEXPECTED(PEBadSelectorKeyframeRuleIgnored); 1.3594 + return nullptr; 1.3595 + } 1.3596 + 1.3597 + // Ignore !important in keyframe rules 1.3598 + uint32_t parseFlags = eParseDeclaration_InBraces; 1.3599 + nsAutoPtr<css::Declaration> declaration(ParseDeclarationBlock(parseFlags)); 1.3600 + if (!declaration) { 1.3601 + return nullptr; 1.3602 + } 1.3603 + 1.3604 + // Takes ownership of declaration, and steals contents of selectorList. 1.3605 + nsRefPtr<nsCSSKeyframeRule> rule = 1.3606 + new nsCSSKeyframeRule(selectorList, declaration); 1.3607 + 1.3608 + return rule.forget(); 1.3609 +} 1.3610 + 1.3611 +bool 1.3612 +CSSParserImpl::ParseKeyframeSelectorList(InfallibleTArray<float>& aSelectorList) 1.3613 +{ 1.3614 + for (;;) { 1.3615 + if (!GetToken(true)) { 1.3616 + // The first time through the loop, this means we got an empty 1.3617 + // list. Otherwise, it means we have a trailing comma. 1.3618 + return false; 1.3619 + } 1.3620 + float value; 1.3621 + switch (mToken.mType) { 1.3622 + case eCSSToken_Percentage: 1.3623 + value = mToken.mNumber; 1.3624 + break; 1.3625 + case eCSSToken_Ident: 1.3626 + if (mToken.mIdent.LowerCaseEqualsLiteral("from")) { 1.3627 + value = 0.0f; 1.3628 + break; 1.3629 + } 1.3630 + if (mToken.mIdent.LowerCaseEqualsLiteral("to")) { 1.3631 + value = 1.0f; 1.3632 + break; 1.3633 + } 1.3634 + // fall through 1.3635 + default: 1.3636 + UngetToken(); 1.3637 + // The first time through the loop, this means we got an empty 1.3638 + // list. Otherwise, it means we have a trailing comma. 1.3639 + return false; 1.3640 + } 1.3641 + aSelectorList.AppendElement(value); 1.3642 + if (!ExpectSymbol(',', true)) { 1.3643 + return true; 1.3644 + } 1.3645 + } 1.3646 +} 1.3647 + 1.3648 +// supports_rule 1.3649 +// : "@supports" supports_condition group_rule_body 1.3650 +// ; 1.3651 +bool 1.3652 +CSSParserImpl::ParseSupportsRule(RuleAppendFunc aAppendFunc, void* aProcessData) 1.3653 +{ 1.3654 + bool conditionMet = false; 1.3655 + nsString condition; 1.3656 + 1.3657 + mScanner->StartRecording(); 1.3658 + bool parsed = ParseSupportsCondition(conditionMet); 1.3659 + 1.3660 + if (!parsed) { 1.3661 + mScanner->StopRecording(); 1.3662 + return false; 1.3663 + } 1.3664 + 1.3665 + if (!ExpectSymbol('{', true)) { 1.3666 + REPORT_UNEXPECTED_TOKEN(PESupportsGroupRuleStart); 1.3667 + mScanner->StopRecording(); 1.3668 + return false; 1.3669 + } 1.3670 + 1.3671 + UngetToken(); 1.3672 + mScanner->StopRecording(condition); 1.3673 + 1.3674 + // Remove the "{" that would follow the condition. 1.3675 + if (condition.Length() != 0) { 1.3676 + condition.Truncate(condition.Length() - 1); 1.3677 + } 1.3678 + 1.3679 + // Remove spaces from the start and end of the recorded supports condition. 1.3680 + condition.Trim(" ", true, true, false); 1.3681 + 1.3682 + // Record whether we are in a failing @supports, so that property parse 1.3683 + // errors don't get reported. 1.3684 + nsAutoFailingSupportsRule failing(this, conditionMet); 1.3685 + 1.3686 + nsRefPtr<css::GroupRule> rule = new CSSSupportsRule(conditionMet, condition); 1.3687 + return ParseGroupRule(rule, aAppendFunc, aProcessData); 1.3688 +} 1.3689 + 1.3690 +// supports_condition 1.3691 +// : supports_condition_in_parens supports_condition_terms 1.3692 +// | supports_condition_negation 1.3693 +// ; 1.3694 +bool 1.3695 +CSSParserImpl::ParseSupportsCondition(bool& aConditionMet) 1.3696 +{ 1.3697 + mInSupportsCondition = true; 1.3698 + 1.3699 + if (!GetToken(true)) { 1.3700 + REPORT_UNEXPECTED_EOF(PESupportsConditionStartEOF2); 1.3701 + return false; 1.3702 + } 1.3703 + 1.3704 + UngetToken(); 1.3705 + 1.3706 + mScanner->ClearSeenBadToken(); 1.3707 + 1.3708 + if (mToken.IsSymbol('(') || 1.3709 + mToken.mType == eCSSToken_Function || 1.3710 + mToken.mType == eCSSToken_URL || 1.3711 + mToken.mType == eCSSToken_Bad_URL) { 1.3712 + bool result = ParseSupportsConditionInParens(aConditionMet) && 1.3713 + ParseSupportsConditionTerms(aConditionMet) && 1.3714 + !mScanner->SeenBadToken(); 1.3715 + mInSupportsCondition = false; 1.3716 + return result; 1.3717 + } 1.3718 + 1.3719 + if (mToken.mType == eCSSToken_Ident && 1.3720 + mToken.mIdent.LowerCaseEqualsLiteral("not")) { 1.3721 + bool result = ParseSupportsConditionNegation(aConditionMet) && 1.3722 + !mScanner->SeenBadToken(); 1.3723 + mInSupportsCondition = false; 1.3724 + return result; 1.3725 + } 1.3726 + 1.3727 + REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedStart); 1.3728 + mInSupportsCondition = false; 1.3729 + return false; 1.3730 +} 1.3731 + 1.3732 +// supports_condition_negation 1.3733 +// : 'not' S+ supports_condition_in_parens 1.3734 +// ; 1.3735 +bool 1.3736 +CSSParserImpl::ParseSupportsConditionNegation(bool& aConditionMet) 1.3737 +{ 1.3738 + if (!GetToken(true)) { 1.3739 + REPORT_UNEXPECTED_EOF(PESupportsConditionNotEOF); 1.3740 + return false; 1.3741 + } 1.3742 + 1.3743 + if (mToken.mType != eCSSToken_Ident || 1.3744 + !mToken.mIdent.LowerCaseEqualsLiteral("not")) { 1.3745 + REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedNot); 1.3746 + return false; 1.3747 + } 1.3748 + 1.3749 + if (!RequireWhitespace()) { 1.3750 + REPORT_UNEXPECTED(PESupportsWhitespaceRequired); 1.3751 + return false; 1.3752 + } 1.3753 + 1.3754 + if (ParseSupportsConditionInParens(aConditionMet)) { 1.3755 + aConditionMet = !aConditionMet; 1.3756 + return true; 1.3757 + } 1.3758 + 1.3759 + return false; 1.3760 +} 1.3761 + 1.3762 +// supports_condition_in_parens 1.3763 +// : '(' S* supports_condition_in_parens_inside_parens ')' S* 1.3764 +// | general_enclosed 1.3765 +// ; 1.3766 +bool 1.3767 +CSSParserImpl::ParseSupportsConditionInParens(bool& aConditionMet) 1.3768 +{ 1.3769 + if (!GetToken(true)) { 1.3770 + REPORT_UNEXPECTED_EOF(PESupportsConditionInParensStartEOF); 1.3771 + return false; 1.3772 + } 1.3773 + 1.3774 + if (mToken.mType == eCSSToken_URL) { 1.3775 + aConditionMet = false; 1.3776 + return true; 1.3777 + } 1.3778 + 1.3779 + if (mToken.mType == eCSSToken_Function || 1.3780 + mToken.mType == eCSSToken_Bad_URL) { 1.3781 + if (!SkipUntil(')')) { 1.3782 + REPORT_UNEXPECTED_EOF(PESupportsConditionInParensEOF); 1.3783 + return false; 1.3784 + } 1.3785 + aConditionMet = false; 1.3786 + return true; 1.3787 + } 1.3788 + 1.3789 + if (!mToken.IsSymbol('(')) { 1.3790 + REPORT_UNEXPECTED_TOKEN(PESupportsConditionExpectedOpenParenOrFunction); 1.3791 + UngetToken(); 1.3792 + return false; 1.3793 + } 1.3794 + 1.3795 + if (!ParseSupportsConditionInParensInsideParens(aConditionMet)) { 1.3796 + if (!SkipUntil(')')) { 1.3797 + REPORT_UNEXPECTED_EOF(PESupportsConditionInParensEOF); 1.3798 + return false; 1.3799 + } 1.3800 + aConditionMet = false; 1.3801 + return true; 1.3802 + } 1.3803 + 1.3804 + if (!(ExpectSymbol(')', true))) { 1.3805 + SkipUntil(')'); 1.3806 + aConditionMet = false; 1.3807 + return true; 1.3808 + } 1.3809 + 1.3810 + return true; 1.3811 +} 1.3812 + 1.3813 +// supports_condition_in_parens_inside_parens 1.3814 +// : core_declaration 1.3815 +// | supports_condition_negation 1.3816 +// | supports_condition_in_parens supports_condition_terms 1.3817 +// ; 1.3818 +bool 1.3819 +CSSParserImpl::ParseSupportsConditionInParensInsideParens(bool& aConditionMet) 1.3820 +{ 1.3821 + if (!GetToken(true)) { 1.3822 + return false; 1.3823 + } 1.3824 + 1.3825 + if (mToken.mType == eCSSToken_Ident) { 1.3826 + if (!mToken.mIdent.LowerCaseEqualsLiteral("not")) { 1.3827 + nsAutoString propertyName = mToken.mIdent; 1.3828 + if (!ExpectSymbol(':', true)) { 1.3829 + return false; 1.3830 + } 1.3831 + 1.3832 + nsCSSProperty propID = LookupEnabledProperty(propertyName); 1.3833 + if (propID == eCSSProperty_UNKNOWN) { 1.3834 + if (ExpectSymbol(')', true)) { 1.3835 + UngetToken(); 1.3836 + return false; 1.3837 + } 1.3838 + aConditionMet = false; 1.3839 + SkipUntil(')'); 1.3840 + UngetToken(); 1.3841 + } else if (propID == eCSSPropertyExtra_variable) { 1.3842 + if (ExpectSymbol(')', false)) { 1.3843 + UngetToken(); 1.3844 + return false; 1.3845 + } 1.3846 + CSSVariableDeclarations::Type variableType; 1.3847 + nsString variableValue; 1.3848 + aConditionMet = 1.3849 + ParseVariableDeclaration(&variableType, variableValue) && 1.3850 + ParsePriority() != ePriority_Error; 1.3851 + if (!aConditionMet) { 1.3852 + SkipUntil(')'); 1.3853 + UngetToken(); 1.3854 + } 1.3855 + } else { 1.3856 + if (ExpectSymbol(')', true)) { 1.3857 + UngetToken(); 1.3858 + return false; 1.3859 + } 1.3860 + aConditionMet = ParseProperty(propID) && 1.3861 + ParsePriority() != ePriority_Error; 1.3862 + if (!aConditionMet) { 1.3863 + SkipUntil(')'); 1.3864 + UngetToken(); 1.3865 + } 1.3866 + mTempData.ClearProperty(propID); 1.3867 + mTempData.AssertInitialState(); 1.3868 + } 1.3869 + return true; 1.3870 + } 1.3871 + 1.3872 + UngetToken(); 1.3873 + return ParseSupportsConditionNegation(aConditionMet); 1.3874 + } 1.3875 + 1.3876 + UngetToken(); 1.3877 + return ParseSupportsConditionInParens(aConditionMet) && 1.3878 + ParseSupportsConditionTerms(aConditionMet); 1.3879 +} 1.3880 + 1.3881 +// supports_condition_terms 1.3882 +// : S+ 'and' supports_condition_terms_after_operator('and') 1.3883 +// | S+ 'or' supports_condition_terms_after_operator('or') 1.3884 +// | 1.3885 +// ; 1.3886 +bool 1.3887 +CSSParserImpl::ParseSupportsConditionTerms(bool& aConditionMet) 1.3888 +{ 1.3889 + if (!RequireWhitespace() || !GetToken(false)) { 1.3890 + return true; 1.3891 + } 1.3892 + 1.3893 + if (mToken.mType != eCSSToken_Ident) { 1.3894 + UngetToken(); 1.3895 + return true; 1.3896 + } 1.3897 + 1.3898 + if (mToken.mIdent.LowerCaseEqualsLiteral("and")) { 1.3899 + return ParseSupportsConditionTermsAfterOperator(aConditionMet, eAnd); 1.3900 + } 1.3901 + 1.3902 + if (mToken.mIdent.LowerCaseEqualsLiteral("or")) { 1.3903 + return ParseSupportsConditionTermsAfterOperator(aConditionMet, eOr); 1.3904 + } 1.3905 + 1.3906 + UngetToken(); 1.3907 + return true; 1.3908 +} 1.3909 + 1.3910 +// supports_condition_terms_after_operator(operator) 1.3911 +// : S+ supports_condition_in_parens ( <operator> supports_condition_in_parens )* 1.3912 +// ; 1.3913 +bool 1.3914 +CSSParserImpl::ParseSupportsConditionTermsAfterOperator( 1.3915 + bool& aConditionMet, 1.3916 + CSSParserImpl::SupportsConditionTermOperator aOperator) 1.3917 +{ 1.3918 + if (!RequireWhitespace()) { 1.3919 + REPORT_UNEXPECTED(PESupportsWhitespaceRequired); 1.3920 + return false; 1.3921 + } 1.3922 + 1.3923 + const char* token = aOperator == eAnd ? "and" : "or"; 1.3924 + for (;;) { 1.3925 + bool termConditionMet = false; 1.3926 + if (!ParseSupportsConditionInParens(termConditionMet)) { 1.3927 + return false; 1.3928 + } 1.3929 + aConditionMet = aOperator == eAnd ? aConditionMet && termConditionMet : 1.3930 + aConditionMet || termConditionMet; 1.3931 + 1.3932 + if (!GetToken(true)) { 1.3933 + return true; 1.3934 + } 1.3935 + 1.3936 + if (mToken.mType != eCSSToken_Ident || 1.3937 + !mToken.mIdent.LowerCaseEqualsASCII(token)) { 1.3938 + UngetToken(); 1.3939 + return true; 1.3940 + } 1.3941 + } 1.3942 +} 1.3943 + 1.3944 +bool 1.3945 +CSSParserImpl::SkipUntil(char16_t aStopSymbol) 1.3946 +{ 1.3947 + nsCSSToken* tk = &mToken; 1.3948 + nsAutoTArray<char16_t, 16> stack; 1.3949 + stack.AppendElement(aStopSymbol); 1.3950 + for (;;) { 1.3951 + if (!GetToken(true)) { 1.3952 + return false; 1.3953 + } 1.3954 + if (eCSSToken_Symbol == tk->mType) { 1.3955 + char16_t symbol = tk->mSymbol; 1.3956 + uint32_t stackTopIndex = stack.Length() - 1; 1.3957 + if (symbol == stack.ElementAt(stackTopIndex)) { 1.3958 + stack.RemoveElementAt(stackTopIndex); 1.3959 + if (stackTopIndex == 0) { 1.3960 + return true; 1.3961 + } 1.3962 + 1.3963 + // Just handle out-of-memory by parsing incorrectly. It's 1.3964 + // highly unlikely we're dealing with a legitimate style sheet 1.3965 + // anyway. 1.3966 + } else if ('{' == symbol) { 1.3967 + stack.AppendElement('}'); 1.3968 + } else if ('[' == symbol) { 1.3969 + stack.AppendElement(']'); 1.3970 + } else if ('(' == symbol) { 1.3971 + stack.AppendElement(')'); 1.3972 + } 1.3973 + } else if (eCSSToken_Function == tk->mType || 1.3974 + eCSSToken_Bad_URL == tk->mType) { 1.3975 + stack.AppendElement(')'); 1.3976 + } 1.3977 + } 1.3978 +} 1.3979 + 1.3980 +bool 1.3981 +CSSParserImpl::SkipBalancedContentUntil(char16_t aStopSymbol) 1.3982 +{ 1.3983 + nsCSSToken* tk = &mToken; 1.3984 + nsAutoTArray<char16_t, 16> stack; 1.3985 + stack.AppendElement(aStopSymbol); 1.3986 + for (;;) { 1.3987 + if (!GetToken(true)) { 1.3988 + return true; 1.3989 + } 1.3990 + if (eCSSToken_Symbol == tk->mType) { 1.3991 + char16_t symbol = tk->mSymbol; 1.3992 + uint32_t stackTopIndex = stack.Length() - 1; 1.3993 + if (symbol == stack.ElementAt(stackTopIndex)) { 1.3994 + stack.RemoveElementAt(stackTopIndex); 1.3995 + if (stackTopIndex == 0) { 1.3996 + return true; 1.3997 + } 1.3998 + 1.3999 + // Just handle out-of-memory by parsing incorrectly. It's 1.4000 + // highly unlikely we're dealing with a legitimate style sheet 1.4001 + // anyway. 1.4002 + } else if ('{' == symbol) { 1.4003 + stack.AppendElement('}'); 1.4004 + } else if ('[' == symbol) { 1.4005 + stack.AppendElement(']'); 1.4006 + } else if ('(' == symbol) { 1.4007 + stack.AppendElement(')'); 1.4008 + } else if (')' == symbol || 1.4009 + ']' == symbol || 1.4010 + '}' == symbol) { 1.4011 + UngetToken(); 1.4012 + return false; 1.4013 + } 1.4014 + } else if (eCSSToken_Function == tk->mType || 1.4015 + eCSSToken_Bad_URL == tk->mType) { 1.4016 + stack.AppendElement(')'); 1.4017 + } 1.4018 + } 1.4019 +} 1.4020 + 1.4021 +void 1.4022 +CSSParserImpl::SkipUntilOneOf(const char16_t* aStopSymbolChars) 1.4023 +{ 1.4024 + nsCSSToken* tk = &mToken; 1.4025 + nsDependentString stopSymbolChars(aStopSymbolChars); 1.4026 + for (;;) { 1.4027 + if (!GetToken(true)) { 1.4028 + break; 1.4029 + } 1.4030 + if (eCSSToken_Symbol == tk->mType) { 1.4031 + char16_t symbol = tk->mSymbol; 1.4032 + if (stopSymbolChars.FindChar(symbol) != -1) { 1.4033 + break; 1.4034 + } else if ('{' == symbol) { 1.4035 + SkipUntil('}'); 1.4036 + } else if ('[' == symbol) { 1.4037 + SkipUntil(']'); 1.4038 + } else if ('(' == symbol) { 1.4039 + SkipUntil(')'); 1.4040 + } 1.4041 + } else if (eCSSToken_Function == tk->mType || 1.4042 + eCSSToken_Bad_URL == tk->mType) { 1.4043 + SkipUntil(')'); 1.4044 + } 1.4045 + } 1.4046 +} 1.4047 + 1.4048 +void 1.4049 +CSSParserImpl::SkipUntilAllOf(const StopSymbolCharStack& aStopSymbolChars) 1.4050 +{ 1.4051 + uint32_t i = aStopSymbolChars.Length(); 1.4052 + while (i--) { 1.4053 + SkipUntil(aStopSymbolChars[i]); 1.4054 + } 1.4055 +} 1.4056 + 1.4057 +bool 1.4058 +CSSParserImpl::SkipDeclaration(bool aCheckForBraces) 1.4059 +{ 1.4060 + nsCSSToken* tk = &mToken; 1.4061 + for (;;) { 1.4062 + if (!GetToken(true)) { 1.4063 + if (aCheckForBraces) { 1.4064 + REPORT_UNEXPECTED_EOF(PESkipDeclBraceEOF); 1.4065 + } 1.4066 + return false; 1.4067 + } 1.4068 + if (eCSSToken_Symbol == tk->mType) { 1.4069 + char16_t symbol = tk->mSymbol; 1.4070 + if (';' == symbol) { 1.4071 + break; 1.4072 + } 1.4073 + if (aCheckForBraces) { 1.4074 + if ('}' == symbol) { 1.4075 + UngetToken(); 1.4076 + break; 1.4077 + } 1.4078 + } 1.4079 + if ('{' == symbol) { 1.4080 + SkipUntil('}'); 1.4081 + } else if ('(' == symbol) { 1.4082 + SkipUntil(')'); 1.4083 + } else if ('[' == symbol) { 1.4084 + SkipUntil(']'); 1.4085 + } 1.4086 + } else if (eCSSToken_Function == tk->mType || 1.4087 + eCSSToken_Bad_URL == tk->mType) { 1.4088 + SkipUntil(')'); 1.4089 + } 1.4090 + } 1.4091 + return true; 1.4092 +} 1.4093 + 1.4094 +void 1.4095 +CSSParserImpl::SkipRuleSet(bool aInsideBraces) 1.4096 +{ 1.4097 + nsCSSToken* tk = &mToken; 1.4098 + for (;;) { 1.4099 + if (!GetToken(true)) { 1.4100 + REPORT_UNEXPECTED_EOF(PESkipRSBraceEOF); 1.4101 + break; 1.4102 + } 1.4103 + if (eCSSToken_Symbol == tk->mType) { 1.4104 + char16_t symbol = tk->mSymbol; 1.4105 + if ('}' == symbol && aInsideBraces) { 1.4106 + // leave block closer for higher-level grammar to consume 1.4107 + UngetToken(); 1.4108 + break; 1.4109 + } else if ('{' == symbol) { 1.4110 + SkipUntil('}'); 1.4111 + break; 1.4112 + } else if ('(' == symbol) { 1.4113 + SkipUntil(')'); 1.4114 + } else if ('[' == symbol) { 1.4115 + SkipUntil(']'); 1.4116 + } 1.4117 + } else if (eCSSToken_Function == tk->mType || 1.4118 + eCSSToken_Bad_URL == tk->mType) { 1.4119 + SkipUntil(')'); 1.4120 + } 1.4121 + } 1.4122 +} 1.4123 + 1.4124 +void 1.4125 +CSSParserImpl::PushGroup(css::GroupRule* aRule) 1.4126 +{ 1.4127 + mGroupStack.AppendElement(aRule); 1.4128 +} 1.4129 + 1.4130 +void 1.4131 +CSSParserImpl::PopGroup() 1.4132 +{ 1.4133 + uint32_t count = mGroupStack.Length(); 1.4134 + if (0 < count) { 1.4135 + mGroupStack.RemoveElementAt(count - 1); 1.4136 + } 1.4137 +} 1.4138 + 1.4139 +void 1.4140 +CSSParserImpl::AppendRule(css::Rule* aRule) 1.4141 +{ 1.4142 + uint32_t count = mGroupStack.Length(); 1.4143 + if (0 < count) { 1.4144 + mGroupStack[count - 1]->AppendStyleRule(aRule); 1.4145 + } 1.4146 + else { 1.4147 + mSheet->AppendStyleRule(aRule); 1.4148 + } 1.4149 +} 1.4150 + 1.4151 +bool 1.4152 +CSSParserImpl::ParseRuleSet(RuleAppendFunc aAppendFunc, void* aData, 1.4153 + bool aInsideBraces) 1.4154 +{ 1.4155 + // First get the list of selectors for the rule 1.4156 + nsCSSSelectorList* slist = nullptr; 1.4157 + uint32_t linenum, colnum; 1.4158 + if (!GetNextTokenLocation(true, &linenum, &colnum) || 1.4159 + !ParseSelectorList(slist, char16_t('{'))) { 1.4160 + REPORT_UNEXPECTED(PEBadSelectorRSIgnored); 1.4161 + OUTPUT_ERROR(); 1.4162 + SkipRuleSet(aInsideBraces); 1.4163 + return false; 1.4164 + } 1.4165 + NS_ASSERTION(nullptr != slist, "null selector list"); 1.4166 + CLEAR_ERROR(); 1.4167 + 1.4168 + // Next parse the declaration block 1.4169 + uint32_t parseFlags = eParseDeclaration_InBraces | 1.4170 + eParseDeclaration_AllowImportant; 1.4171 + css::Declaration* declaration = ParseDeclarationBlock(parseFlags); 1.4172 + if (nullptr == declaration) { 1.4173 + delete slist; 1.4174 + return false; 1.4175 + } 1.4176 + 1.4177 +#if 0 1.4178 + slist->Dump(); 1.4179 + fputs("{\n", stdout); 1.4180 + declaration->List(); 1.4181 + fputs("}\n", stdout); 1.4182 +#endif 1.4183 + 1.4184 + // Translate the selector list and declaration block into style data 1.4185 + 1.4186 + nsRefPtr<css::StyleRule> rule = new css::StyleRule(slist, declaration); 1.4187 + rule->SetLineNumberAndColumnNumber(linenum, colnum); 1.4188 + (*aAppendFunc)(rule, aData); 1.4189 + 1.4190 + return true; 1.4191 +} 1.4192 + 1.4193 +bool 1.4194 +CSSParserImpl::ParseSelectorList(nsCSSSelectorList*& aListHead, 1.4195 + char16_t aStopChar) 1.4196 +{ 1.4197 + nsCSSSelectorList* list = nullptr; 1.4198 + if (! ParseSelectorGroup(list)) { 1.4199 + // must have at least one selector group 1.4200 + aListHead = nullptr; 1.4201 + return false; 1.4202 + } 1.4203 + NS_ASSERTION(nullptr != list, "no selector list"); 1.4204 + aListHead = list; 1.4205 + 1.4206 + // After that there must either be a "," or a "{" (the latter if 1.4207 + // StopChar is nonzero) 1.4208 + nsCSSToken* tk = &mToken; 1.4209 + for (;;) { 1.4210 + if (! GetToken(true)) { 1.4211 + if (aStopChar == char16_t(0)) { 1.4212 + return true; 1.4213 + } 1.4214 + 1.4215 + REPORT_UNEXPECTED_EOF(PESelectorListExtraEOF); 1.4216 + break; 1.4217 + } 1.4218 + 1.4219 + if (eCSSToken_Symbol == tk->mType) { 1.4220 + if (',' == tk->mSymbol) { 1.4221 + nsCSSSelectorList* newList = nullptr; 1.4222 + // Another selector group must follow 1.4223 + if (! ParseSelectorGroup(newList)) { 1.4224 + break; 1.4225 + } 1.4226 + // add new list to the end of the selector list 1.4227 + list->mNext = newList; 1.4228 + list = newList; 1.4229 + continue; 1.4230 + } else if (aStopChar == tk->mSymbol && aStopChar != char16_t(0)) { 1.4231 + UngetToken(); 1.4232 + return true; 1.4233 + } 1.4234 + } 1.4235 + REPORT_UNEXPECTED_TOKEN(PESelectorListExtra); 1.4236 + UngetToken(); 1.4237 + break; 1.4238 + } 1.4239 + 1.4240 + delete aListHead; 1.4241 + aListHead = nullptr; 1.4242 + return false; 1.4243 +} 1.4244 + 1.4245 +static bool IsUniversalSelector(const nsCSSSelector& aSelector) 1.4246 +{ 1.4247 + return bool((aSelector.mNameSpace == kNameSpaceID_Unknown) && 1.4248 + (aSelector.mLowercaseTag == nullptr) && 1.4249 + (aSelector.mIDList == nullptr) && 1.4250 + (aSelector.mClassList == nullptr) && 1.4251 + (aSelector.mAttrList == nullptr) && 1.4252 + (aSelector.mNegations == nullptr) && 1.4253 + (aSelector.mPseudoClassList == nullptr)); 1.4254 +} 1.4255 + 1.4256 +bool 1.4257 +CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList) 1.4258 +{ 1.4259 + char16_t combinator = 0; 1.4260 + nsAutoPtr<nsCSSSelectorList> list(new nsCSSSelectorList()); 1.4261 + 1.4262 + for (;;) { 1.4263 + if (!ParseSelector(list, combinator)) { 1.4264 + return false; 1.4265 + } 1.4266 + 1.4267 + // Look for a combinator. 1.4268 + if (!GetToken(false)) { 1.4269 + break; // EOF ok here 1.4270 + } 1.4271 + 1.4272 + combinator = char16_t(0); 1.4273 + if (mToken.mType == eCSSToken_Whitespace) { 1.4274 + if (!GetToken(true)) { 1.4275 + break; // EOF ok here 1.4276 + } 1.4277 + combinator = char16_t(' '); 1.4278 + } 1.4279 + 1.4280 + if (mToken.mType != eCSSToken_Symbol) { 1.4281 + UngetToken(); // not a combinator 1.4282 + } else { 1.4283 + char16_t symbol = mToken.mSymbol; 1.4284 + if (symbol == '+' || symbol == '>' || symbol == '~') { 1.4285 + combinator = mToken.mSymbol; 1.4286 + } else { 1.4287 + UngetToken(); // not a combinator 1.4288 + if (symbol == ',' || symbol == '{' || symbol == ')') { 1.4289 + break; // end of selector group 1.4290 + } 1.4291 + } 1.4292 + } 1.4293 + 1.4294 + if (!combinator) { 1.4295 + REPORT_UNEXPECTED_TOKEN(PESelectorListExtra); 1.4296 + return false; 1.4297 + } 1.4298 + } 1.4299 + 1.4300 + aList = list.forget(); 1.4301 + return true; 1.4302 +} 1.4303 + 1.4304 +#define SEL_MASK_NSPACE 0x01 1.4305 +#define SEL_MASK_ELEM 0x02 1.4306 +#define SEL_MASK_ID 0x04 1.4307 +#define SEL_MASK_CLASS 0x08 1.4308 +#define SEL_MASK_ATTRIB 0x10 1.4309 +#define SEL_MASK_PCLASS 0x20 1.4310 +#define SEL_MASK_PELEM 0x40 1.4311 + 1.4312 +// 1.4313 +// Parses an ID selector #name 1.4314 +// 1.4315 +CSSParserImpl::nsSelectorParsingStatus 1.4316 +CSSParserImpl::ParseIDSelector(int32_t& aDataMask, 1.4317 + nsCSSSelector& aSelector) 1.4318 +{ 1.4319 + NS_ASSERTION(!mToken.mIdent.IsEmpty(), 1.4320 + "Empty mIdent in eCSSToken_ID token?"); 1.4321 + aDataMask |= SEL_MASK_ID; 1.4322 + aSelector.AddID(mToken.mIdent); 1.4323 + return eSelectorParsingStatus_Continue; 1.4324 +} 1.4325 + 1.4326 +// 1.4327 +// Parses a class selector .name 1.4328 +// 1.4329 +CSSParserImpl::nsSelectorParsingStatus 1.4330 +CSSParserImpl::ParseClassSelector(int32_t& aDataMask, 1.4331 + nsCSSSelector& aSelector) 1.4332 +{ 1.4333 + if (! GetToken(false)) { // get ident 1.4334 + REPORT_UNEXPECTED_EOF(PEClassSelEOF); 1.4335 + return eSelectorParsingStatus_Error; 1.4336 + } 1.4337 + if (eCSSToken_Ident != mToken.mType) { // malformed selector 1.4338 + REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent); 1.4339 + UngetToken(); 1.4340 + return eSelectorParsingStatus_Error; 1.4341 + } 1.4342 + aDataMask |= SEL_MASK_CLASS; 1.4343 + 1.4344 + aSelector.AddClass(mToken.mIdent); 1.4345 + 1.4346 + return eSelectorParsingStatus_Continue; 1.4347 +} 1.4348 + 1.4349 +// 1.4350 +// Parse a type element selector or a universal selector 1.4351 +// namespace|type or namespace|* or *|* or * 1.4352 +// 1.4353 +CSSParserImpl::nsSelectorParsingStatus 1.4354 +CSSParserImpl::ParseTypeOrUniversalSelector(int32_t& aDataMask, 1.4355 + nsCSSSelector& aSelector, 1.4356 + bool aIsNegated) 1.4357 +{ 1.4358 + nsAutoString buffer; 1.4359 + if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace 1.4360 + if (ExpectSymbol('|', false)) { // was namespace 1.4361 + aDataMask |= SEL_MASK_NSPACE; 1.4362 + aSelector.SetNameSpace(kNameSpaceID_Unknown); // namespace wildcard 1.4363 + 1.4364 + if (! GetToken(false)) { 1.4365 + REPORT_UNEXPECTED_EOF(PETypeSelEOF); 1.4366 + return eSelectorParsingStatus_Error; 1.4367 + } 1.4368 + if (eCSSToken_Ident == mToken.mType) { // element name 1.4369 + aDataMask |= SEL_MASK_ELEM; 1.4370 + 1.4371 + aSelector.SetTag(mToken.mIdent); 1.4372 + } 1.4373 + else if (mToken.IsSymbol('*')) { // universal selector 1.4374 + aDataMask |= SEL_MASK_ELEM; 1.4375 + // don't set tag 1.4376 + } 1.4377 + else { 1.4378 + REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); 1.4379 + UngetToken(); 1.4380 + return eSelectorParsingStatus_Error; 1.4381 + } 1.4382 + } 1.4383 + else { // was universal element selector 1.4384 + SetDefaultNamespaceOnSelector(aSelector); 1.4385 + aDataMask |= SEL_MASK_ELEM; 1.4386 + // don't set any tag in the selector 1.4387 + } 1.4388 + if (! GetToken(false)) { // premature eof is ok (here!) 1.4389 + return eSelectorParsingStatus_Done; 1.4390 + } 1.4391 + } 1.4392 + else if (eCSSToken_Ident == mToken.mType) { // element name or namespace name 1.4393 + buffer = mToken.mIdent; // hang on to ident 1.4394 + 1.4395 + if (ExpectSymbol('|', false)) { // was namespace 1.4396 + aDataMask |= SEL_MASK_NSPACE; 1.4397 + int32_t nameSpaceID = GetNamespaceIdForPrefix(buffer); 1.4398 + if (nameSpaceID == kNameSpaceID_Unknown) { 1.4399 + return eSelectorParsingStatus_Error; 1.4400 + } 1.4401 + aSelector.SetNameSpace(nameSpaceID); 1.4402 + 1.4403 + if (! GetToken(false)) { 1.4404 + REPORT_UNEXPECTED_EOF(PETypeSelEOF); 1.4405 + return eSelectorParsingStatus_Error; 1.4406 + } 1.4407 + if (eCSSToken_Ident == mToken.mType) { // element name 1.4408 + aDataMask |= SEL_MASK_ELEM; 1.4409 + aSelector.SetTag(mToken.mIdent); 1.4410 + } 1.4411 + else if (mToken.IsSymbol('*')) { // universal selector 1.4412 + aDataMask |= SEL_MASK_ELEM; 1.4413 + // don't set tag 1.4414 + } 1.4415 + else { 1.4416 + REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); 1.4417 + UngetToken(); 1.4418 + return eSelectorParsingStatus_Error; 1.4419 + } 1.4420 + } 1.4421 + else { // was element name 1.4422 + SetDefaultNamespaceOnSelector(aSelector); 1.4423 + aSelector.SetTag(buffer); 1.4424 + 1.4425 + aDataMask |= SEL_MASK_ELEM; 1.4426 + } 1.4427 + if (! GetToken(false)) { // premature eof is ok (here!) 1.4428 + return eSelectorParsingStatus_Done; 1.4429 + } 1.4430 + } 1.4431 + else if (mToken.IsSymbol('|')) { // No namespace 1.4432 + aDataMask |= SEL_MASK_NSPACE; 1.4433 + aSelector.SetNameSpace(kNameSpaceID_None); // explicit NO namespace 1.4434 + 1.4435 + // get mandatory tag 1.4436 + if (! GetToken(false)) { 1.4437 + REPORT_UNEXPECTED_EOF(PETypeSelEOF); 1.4438 + return eSelectorParsingStatus_Error; 1.4439 + } 1.4440 + if (eCSSToken_Ident == mToken.mType) { // element name 1.4441 + aDataMask |= SEL_MASK_ELEM; 1.4442 + aSelector.SetTag(mToken.mIdent); 1.4443 + } 1.4444 + else if (mToken.IsSymbol('*')) { // universal selector 1.4445 + aDataMask |= SEL_MASK_ELEM; 1.4446 + // don't set tag 1.4447 + } 1.4448 + else { 1.4449 + REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); 1.4450 + UngetToken(); 1.4451 + return eSelectorParsingStatus_Error; 1.4452 + } 1.4453 + if (! GetToken(false)) { // premature eof is ok (here!) 1.4454 + return eSelectorParsingStatus_Done; 1.4455 + } 1.4456 + } 1.4457 + else { 1.4458 + SetDefaultNamespaceOnSelector(aSelector); 1.4459 + } 1.4460 + 1.4461 + if (aIsNegated) { 1.4462 + // restore last token read in case of a negated type selector 1.4463 + UngetToken(); 1.4464 + } 1.4465 + return eSelectorParsingStatus_Continue; 1.4466 +} 1.4467 + 1.4468 +// 1.4469 +// Parse attribute selectors [attr], [attr=value], [attr|=value], 1.4470 +// [attr~=value], [attr^=value], [attr$=value] and [attr*=value] 1.4471 +// 1.4472 +CSSParserImpl::nsSelectorParsingStatus 1.4473 +CSSParserImpl::ParseAttributeSelector(int32_t& aDataMask, 1.4474 + nsCSSSelector& aSelector) 1.4475 +{ 1.4476 + if (! GetToken(true)) { // premature EOF 1.4477 + REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); 1.4478 + return eSelectorParsingStatus_Error; 1.4479 + } 1.4480 + 1.4481 + int32_t nameSpaceID = kNameSpaceID_None; 1.4482 + nsAutoString attr; 1.4483 + if (mToken.IsSymbol('*')) { // wildcard namespace 1.4484 + nameSpaceID = kNameSpaceID_Unknown; 1.4485 + if (ExpectSymbol('|', false)) { 1.4486 + if (! GetToken(false)) { // premature EOF 1.4487 + REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); 1.4488 + return eSelectorParsingStatus_Error; 1.4489 + } 1.4490 + if (eCSSToken_Ident == mToken.mType) { // attr name 1.4491 + attr = mToken.mIdent; 1.4492 + } 1.4493 + else { 1.4494 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); 1.4495 + UngetToken(); 1.4496 + return eSelectorParsingStatus_Error; 1.4497 + } 1.4498 + } 1.4499 + else { 1.4500 + REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar); 1.4501 + return eSelectorParsingStatus_Error; 1.4502 + } 1.4503 + } 1.4504 + else if (mToken.IsSymbol('|')) { // NO namespace 1.4505 + if (! GetToken(false)) { // premature EOF 1.4506 + REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); 1.4507 + return eSelectorParsingStatus_Error; 1.4508 + } 1.4509 + if (eCSSToken_Ident == mToken.mType) { // attr name 1.4510 + attr = mToken.mIdent; 1.4511 + } 1.4512 + else { 1.4513 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); 1.4514 + UngetToken(); 1.4515 + return eSelectorParsingStatus_Error; 1.4516 + } 1.4517 + } 1.4518 + else if (eCSSToken_Ident == mToken.mType) { // attr name or namespace 1.4519 + attr = mToken.mIdent; // hang on to it 1.4520 + if (ExpectSymbol('|', false)) { // was a namespace 1.4521 + nameSpaceID = GetNamespaceIdForPrefix(attr); 1.4522 + if (nameSpaceID == kNameSpaceID_Unknown) { 1.4523 + return eSelectorParsingStatus_Error; 1.4524 + } 1.4525 + if (! GetToken(false)) { // premature EOF 1.4526 + REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); 1.4527 + return eSelectorParsingStatus_Error; 1.4528 + } 1.4529 + if (eCSSToken_Ident == mToken.mType) { // attr name 1.4530 + attr = mToken.mIdent; 1.4531 + } 1.4532 + else { 1.4533 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); 1.4534 + UngetToken(); 1.4535 + return eSelectorParsingStatus_Error; 1.4536 + } 1.4537 + } 1.4538 + } 1.4539 + else { // malformed 1.4540 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected); 1.4541 + UngetToken(); 1.4542 + return eSelectorParsingStatus_Error; 1.4543 + } 1.4544 + 1.4545 + if (! GetToken(true)) { // premature EOF 1.4546 + REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF); 1.4547 + return eSelectorParsingStatus_Error; 1.4548 + } 1.4549 + if ((eCSSToken_Symbol == mToken.mType) || 1.4550 + (eCSSToken_Includes == mToken.mType) || 1.4551 + (eCSSToken_Dashmatch == mToken.mType) || 1.4552 + (eCSSToken_Beginsmatch == mToken.mType) || 1.4553 + (eCSSToken_Endsmatch == mToken.mType) || 1.4554 + (eCSSToken_Containsmatch == mToken.mType)) { 1.4555 + uint8_t func; 1.4556 + if (eCSSToken_Includes == mToken.mType) { 1.4557 + func = NS_ATTR_FUNC_INCLUDES; 1.4558 + } 1.4559 + else if (eCSSToken_Dashmatch == mToken.mType) { 1.4560 + func = NS_ATTR_FUNC_DASHMATCH; 1.4561 + } 1.4562 + else if (eCSSToken_Beginsmatch == mToken.mType) { 1.4563 + func = NS_ATTR_FUNC_BEGINSMATCH; 1.4564 + } 1.4565 + else if (eCSSToken_Endsmatch == mToken.mType) { 1.4566 + func = NS_ATTR_FUNC_ENDSMATCH; 1.4567 + } 1.4568 + else if (eCSSToken_Containsmatch == mToken.mType) { 1.4569 + func = NS_ATTR_FUNC_CONTAINSMATCH; 1.4570 + } 1.4571 + else if (']' == mToken.mSymbol) { 1.4572 + aDataMask |= SEL_MASK_ATTRIB; 1.4573 + aSelector.AddAttribute(nameSpaceID, attr); 1.4574 + func = NS_ATTR_FUNC_SET; 1.4575 + } 1.4576 + else if ('=' == mToken.mSymbol) { 1.4577 + func = NS_ATTR_FUNC_EQUALS; 1.4578 + } 1.4579 + else { 1.4580 + REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected); 1.4581 + UngetToken(); // bad function 1.4582 + return eSelectorParsingStatus_Error; 1.4583 + } 1.4584 + if (NS_ATTR_FUNC_SET != func) { // get value 1.4585 + if (! GetToken(true)) { // premature EOF 1.4586 + REPORT_UNEXPECTED_EOF(PEAttSelValueEOF); 1.4587 + return eSelectorParsingStatus_Error; 1.4588 + } 1.4589 + if ((eCSSToken_Ident == mToken.mType) || (eCSSToken_String == mToken.mType)) { 1.4590 + nsAutoString value(mToken.mIdent); 1.4591 + if (! GetToken(true)) { // premature EOF 1.4592 + REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF); 1.4593 + return eSelectorParsingStatus_Error; 1.4594 + } 1.4595 + if (mToken.IsSymbol(']')) { 1.4596 + bool isCaseSensitive = true; 1.4597 + 1.4598 + // For cases when this style sheet is applied to an HTML 1.4599 + // element in an HTML document, and the attribute selector is 1.4600 + // for a non-namespaced attribute, then check to see if it's 1.4601 + // one of the known attributes whose VALUE is 1.4602 + // case-insensitive. 1.4603 + if (nameSpaceID == kNameSpaceID_None) { 1.4604 + static const char* caseInsensitiveHTMLAttribute[] = { 1.4605 + // list based on http://www.w3.org/TR/html4/ 1.4606 + "lang", 1.4607 + "dir", 1.4608 + "http-equiv", 1.4609 + "text", 1.4610 + "link", 1.4611 + "vlink", 1.4612 + "alink", 1.4613 + "compact", 1.4614 + "align", 1.4615 + "frame", 1.4616 + "rules", 1.4617 + "valign", 1.4618 + "scope", 1.4619 + "axis", 1.4620 + "nowrap", 1.4621 + "hreflang", 1.4622 + "rel", 1.4623 + "rev", 1.4624 + "charset", 1.4625 + "codetype", 1.4626 + "declare", 1.4627 + "valuetype", 1.4628 + "shape", 1.4629 + "nohref", 1.4630 + "media", 1.4631 + "bgcolor", 1.4632 + "clear", 1.4633 + "color", 1.4634 + "face", 1.4635 + "noshade", 1.4636 + "noresize", 1.4637 + "scrolling", 1.4638 + "target", 1.4639 + "method", 1.4640 + "enctype", 1.4641 + "accept-charset", 1.4642 + "accept", 1.4643 + "checked", 1.4644 + "multiple", 1.4645 + "selected", 1.4646 + "disabled", 1.4647 + "readonly", 1.4648 + "language", 1.4649 + "defer", 1.4650 + "type", 1.4651 + // additional attributes not in HTML4 1.4652 + "direction", // marquee 1.4653 + nullptr 1.4654 + }; 1.4655 + short i = 0; 1.4656 + const char* htmlAttr; 1.4657 + while ((htmlAttr = caseInsensitiveHTMLAttribute[i++])) { 1.4658 + if (attr.LowerCaseEqualsASCII(htmlAttr)) { 1.4659 + isCaseSensitive = false; 1.4660 + break; 1.4661 + } 1.4662 + } 1.4663 + } 1.4664 + aDataMask |= SEL_MASK_ATTRIB; 1.4665 + aSelector.AddAttribute(nameSpaceID, attr, func, value, isCaseSensitive); 1.4666 + } 1.4667 + else { 1.4668 + REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose); 1.4669 + UngetToken(); 1.4670 + return eSelectorParsingStatus_Error; 1.4671 + } 1.4672 + } 1.4673 + else { 1.4674 + REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue); 1.4675 + UngetToken(); 1.4676 + return eSelectorParsingStatus_Error; 1.4677 + } 1.4678 + } 1.4679 + } 1.4680 + else { 1.4681 + REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected); 1.4682 + UngetToken(); // bad dog, no biscut! 1.4683 + return eSelectorParsingStatus_Error; 1.4684 + } 1.4685 + return eSelectorParsingStatus_Continue; 1.4686 +} 1.4687 + 1.4688 +// 1.4689 +// Parse pseudo-classes and pseudo-elements 1.4690 +// 1.4691 +CSSParserImpl::nsSelectorParsingStatus 1.4692 +CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, 1.4693 + nsCSSSelector& aSelector, 1.4694 + bool aIsNegated, 1.4695 + nsIAtom** aPseudoElement, 1.4696 + nsAtomList** aPseudoElementArgs, 1.4697 + nsCSSPseudoElements::Type* aPseudoElementType) 1.4698 +{ 1.4699 + NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs), 1.4700 + "expected location to store pseudo element"); 1.4701 + NS_ASSERTION(!aIsNegated || (!aPseudoElement && !aPseudoElementArgs), 1.4702 + "negated selectors shouldn't have a place to store " 1.4703 + "pseudo elements"); 1.4704 + if (! GetToken(false)) { // premature eof 1.4705 + REPORT_UNEXPECTED_EOF(PEPseudoSelEOF); 1.4706 + return eSelectorParsingStatus_Error; 1.4707 + } 1.4708 + 1.4709 + // First, find out whether we are parsing a CSS3 pseudo-element 1.4710 + bool parsingPseudoElement = false; 1.4711 + if (mToken.IsSymbol(':')) { 1.4712 + parsingPseudoElement = true; 1.4713 + if (! GetToken(false)) { // premature eof 1.4714 + REPORT_UNEXPECTED_EOF(PEPseudoSelEOF); 1.4715 + return eSelectorParsingStatus_Error; 1.4716 + } 1.4717 + } 1.4718 + 1.4719 + // Do some sanity-checking on the token 1.4720 + if (eCSSToken_Ident != mToken.mType && eCSSToken_Function != mToken.mType) { 1.4721 + // malformed selector 1.4722 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName); 1.4723 + UngetToken(); 1.4724 + return eSelectorParsingStatus_Error; 1.4725 + } 1.4726 + 1.4727 + // OK, now we know we have an mIdent. Atomize it. All the atoms, for 1.4728 + // pseudo-classes as well as pseudo-elements, start with a single ':'. 1.4729 + nsAutoString buffer; 1.4730 + buffer.Append(char16_t(':')); 1.4731 + buffer.Append(mToken.mIdent); 1.4732 + nsContentUtils::ASCIIToLower(buffer); 1.4733 + nsCOMPtr<nsIAtom> pseudo = do_GetAtom(buffer); 1.4734 + if (!pseudo) { 1.4735 + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); 1.4736 + } 1.4737 + 1.4738 + // stash away some info about this pseudo so we only have to get it once. 1.4739 + bool isTreePseudo = false; 1.4740 + nsCSSPseudoElements::Type pseudoElementType = 1.4741 + nsCSSPseudoElements::GetPseudoType(pseudo); 1.4742 + nsCSSPseudoClasses::Type pseudoClassType = 1.4743 + nsCSSPseudoClasses::GetPseudoType(pseudo); 1.4744 + bool pseudoClassIsUserAction = 1.4745 + nsCSSPseudoClasses::IsUserActionPseudoClass(pseudoClassType); 1.4746 + 1.4747 + if (!mUnsafeRulesEnabled && 1.4748 + pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount && 1.4749 + nsCSSPseudoElements::PseudoElementIsChromeOnly(pseudoElementType)) { 1.4750 + // This pseudo-element is not exposed to content. 1.4751 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown); 1.4752 + UngetToken(); 1.4753 + return eSelectorParsingStatus_Error; 1.4754 + } 1.4755 + 1.4756 + // We currently allow :-moz-placeholder and ::-moz-placeholder. We have to 1.4757 + // be a bit stricter regarding the pseudo-element parsing rules. 1.4758 + if (pseudoElementType == nsCSSPseudoElements::ePseudo_mozPlaceholder && 1.4759 + pseudoClassType == nsCSSPseudoClasses::ePseudoClass_mozPlaceholder) { 1.4760 + if (parsingPseudoElement) { 1.4761 + pseudoClassType = nsCSSPseudoClasses::ePseudoClass_NotPseudoClass; 1.4762 + } else { 1.4763 + pseudoElementType = nsCSSPseudoElements::ePseudo_NotPseudoElement; 1.4764 + } 1.4765 + } 1.4766 + 1.4767 +#ifdef MOZ_XUL 1.4768 + isTreePseudo = (pseudoElementType == nsCSSPseudoElements::ePseudo_XULTree); 1.4769 + // If a tree pseudo-element is using the function syntax, it will 1.4770 + // get isTree set here and will pass the check below that only 1.4771 + // allows functions if they are in our list of things allowed to be 1.4772 + // functions. If it is _not_ using the function syntax, isTree will 1.4773 + // be false, and it will still pass that check. So the tree 1.4774 + // pseudo-elements are allowed to be either functions or not, as 1.4775 + // desired. 1.4776 + bool isTree = (eCSSToken_Function == mToken.mType) && isTreePseudo; 1.4777 +#endif 1.4778 + bool isPseudoElement = 1.4779 + (pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount); 1.4780 + // anonymous boxes are only allowed if they're the tree boxes or we have 1.4781 + // enabled unsafe rules 1.4782 + bool isAnonBox = isTreePseudo || 1.4783 + (pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox && 1.4784 + mUnsafeRulesEnabled); 1.4785 + bool isPseudoClass = 1.4786 + (pseudoClassType != nsCSSPseudoClasses::ePseudoClass_NotPseudoClass); 1.4787 + 1.4788 + NS_ASSERTION(!isPseudoClass || 1.4789 + pseudoElementType == nsCSSPseudoElements::ePseudo_NotPseudoElement, 1.4790 + "Why is this atom both a pseudo-class and a pseudo-element?"); 1.4791 + NS_ASSERTION(isPseudoClass + isPseudoElement + isAnonBox <= 1, 1.4792 + "Shouldn't be more than one of these"); 1.4793 + 1.4794 + if (!isPseudoClass && !isPseudoElement && !isAnonBox) { 1.4795 + // Not a pseudo-class, not a pseudo-element.... forget it 1.4796 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown); 1.4797 + UngetToken(); 1.4798 + return eSelectorParsingStatus_Error; 1.4799 + } 1.4800 + 1.4801 + // If it's a function token, it better be on our "ok" list, and if the name 1.4802 + // is that of a function pseudo it better be a function token 1.4803 + if ((eCSSToken_Function == mToken.mType) != 1.4804 + ( 1.4805 +#ifdef MOZ_XUL 1.4806 + isTree || 1.4807 +#endif 1.4808 + nsCSSPseudoClasses::ePseudoClass_notPseudo == pseudoClassType || 1.4809 + nsCSSPseudoClasses::HasStringArg(pseudoClassType) || 1.4810 + nsCSSPseudoClasses::HasNthPairArg(pseudoClassType) || 1.4811 + nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType))) { 1.4812 + // There are no other function pseudos 1.4813 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc); 1.4814 + UngetToken(); 1.4815 + return eSelectorParsingStatus_Error; 1.4816 + } 1.4817 + 1.4818 + // If it starts with "::", it better be a pseudo-element 1.4819 + if (parsingPseudoElement && 1.4820 + !isPseudoElement && 1.4821 + !isAnonBox) { 1.4822 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE); 1.4823 + UngetToken(); 1.4824 + return eSelectorParsingStatus_Error; 1.4825 + } 1.4826 + 1.4827 + if (!parsingPseudoElement && 1.4828 + nsCSSPseudoClasses::ePseudoClass_notPseudo == pseudoClassType) { 1.4829 + if (aIsNegated) { // :not() can't be itself negated 1.4830 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot); 1.4831 + UngetToken(); 1.4832 + return eSelectorParsingStatus_Error; 1.4833 + } 1.4834 + // CSS 3 Negation pseudo-class takes one simple selector as argument 1.4835 + nsSelectorParsingStatus parsingStatus = 1.4836 + ParseNegatedSimpleSelector(aDataMask, aSelector); 1.4837 + if (eSelectorParsingStatus_Continue != parsingStatus) { 1.4838 + return parsingStatus; 1.4839 + } 1.4840 + } 1.4841 + else if (!parsingPseudoElement && isPseudoClass) { 1.4842 + if (aSelector.IsPseudoElement()) { 1.4843 + nsCSSPseudoElements::Type type = aSelector.PseudoType(); 1.4844 + if (!nsCSSPseudoElements::PseudoElementSupportsUserActionState(type)) { 1.4845 + // We only allow user action pseudo-classes on certain pseudo-elements. 1.4846 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelNoUserActionPC); 1.4847 + UngetToken(); 1.4848 + return eSelectorParsingStatus_Error; 1.4849 + } 1.4850 + if (!pseudoClassIsUserAction) { 1.4851 + // CSS 4 Selectors says that pseudo-elements can only be followed by 1.4852 + // a user action pseudo-class. 1.4853 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassNotUserAction); 1.4854 + UngetToken(); 1.4855 + return eSelectorParsingStatus_Error; 1.4856 + } 1.4857 + } 1.4858 + aDataMask |= SEL_MASK_PCLASS; 1.4859 + if (eCSSToken_Function == mToken.mType) { 1.4860 + nsSelectorParsingStatus parsingStatus; 1.4861 + if (nsCSSPseudoClasses::HasStringArg(pseudoClassType)) { 1.4862 + parsingStatus = 1.4863 + ParsePseudoClassWithIdentArg(aSelector, pseudoClassType); 1.4864 + } 1.4865 + else if (nsCSSPseudoClasses::HasNthPairArg(pseudoClassType)) { 1.4866 + parsingStatus = 1.4867 + ParsePseudoClassWithNthPairArg(aSelector, pseudoClassType); 1.4868 + } 1.4869 + else { 1.4870 + NS_ABORT_IF_FALSE(nsCSSPseudoClasses::HasSelectorListArg(pseudoClassType), 1.4871 + "unexpected pseudo with function token"); 1.4872 + parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector, 1.4873 + pseudoClassType); 1.4874 + } 1.4875 + if (eSelectorParsingStatus_Continue != parsingStatus) { 1.4876 + if (eSelectorParsingStatus_Error == parsingStatus) { 1.4877 + SkipUntil(')'); 1.4878 + } 1.4879 + return parsingStatus; 1.4880 + } 1.4881 + } 1.4882 + else { 1.4883 + aSelector.AddPseudoClass(pseudoClassType); 1.4884 + } 1.4885 + } 1.4886 + else if (isPseudoElement || isAnonBox) { 1.4887 + // Pseudo-element. Make some more sanity checks. 1.4888 + 1.4889 + if (aIsNegated) { // pseudo-elements can't be negated 1.4890 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot); 1.4891 + UngetToken(); 1.4892 + return eSelectorParsingStatus_Error; 1.4893 + } 1.4894 + // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed 1.4895 + // to have a single ':' on them. Others (CSS3+ pseudo-elements and 1.4896 + // various -moz-* pseudo-elements) must have |parsingPseudoElement| 1.4897 + // set. 1.4898 + if (!parsingPseudoElement && 1.4899 + !nsCSSPseudoElements::IsCSS2PseudoElement(pseudo) 1.4900 +#ifdef MOZ_XUL 1.4901 + && !isTreePseudo 1.4902 +#endif 1.4903 + ) { 1.4904 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly); 1.4905 + UngetToken(); 1.4906 + return eSelectorParsingStatus_Error; 1.4907 + } 1.4908 + 1.4909 + if (0 == (aDataMask & SEL_MASK_PELEM)) { 1.4910 + aDataMask |= SEL_MASK_PELEM; 1.4911 + NS_ADDREF(*aPseudoElement = pseudo); 1.4912 + *aPseudoElementType = pseudoElementType; 1.4913 + 1.4914 +#ifdef MOZ_XUL 1.4915 + if (isTree) { 1.4916 + // We have encountered a pseudoelement of the form 1.4917 + // -moz-tree-xxxx(a,b,c). We parse (a,b,c) and add each 1.4918 + // item in the list to the pseudoclass list. They will be pulled 1.4919 + // from the list later along with the pseudo-element. 1.4920 + if (!ParseTreePseudoElement(aPseudoElementArgs)) { 1.4921 + return eSelectorParsingStatus_Error; 1.4922 + } 1.4923 + } 1.4924 +#endif 1.4925 + 1.4926 + // Pseudo-elements can only be followed by user action pseudo-classes 1.4927 + // or be the end of the selector. So the next non-whitespace token must 1.4928 + // be ':', '{' or ',' or EOF. 1.4929 + if (!GetToken(true)) { // premature eof is ok (here!) 1.4930 + return eSelectorParsingStatus_Done; 1.4931 + } 1.4932 + if (parsingPseudoElement && mToken.IsSymbol(':')) { 1.4933 + UngetToken(); 1.4934 + return eSelectorParsingStatus_Continue; 1.4935 + } 1.4936 + if ((mToken.IsSymbol('{') || mToken.IsSymbol(','))) { 1.4937 + UngetToken(); 1.4938 + return eSelectorParsingStatus_Done; 1.4939 + } 1.4940 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelEndOrUserActionPC); 1.4941 + UngetToken(); 1.4942 + return eSelectorParsingStatus_Error; 1.4943 + } 1.4944 + else { // multiple pseudo elements, not legal 1.4945 + REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE); 1.4946 + UngetToken(); 1.4947 + return eSelectorParsingStatus_Error; 1.4948 + } 1.4949 + } 1.4950 +#ifdef DEBUG 1.4951 + else { 1.4952 + // We should never end up here. Indeed, if we ended up here, we know (from 1.4953 + // the current if/else cascade) that !isPseudoElement and !isAnonBox. But 1.4954 + // then due to our earlier check we know that isPseudoClass. Since we 1.4955 + // didn't fall into the isPseudoClass case in this cascade, we must have 1.4956 + // parsingPseudoElement. But we've already checked the 1.4957 + // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if 1.4958 + // it's happened. 1.4959 + NS_NOTREACHED("How did this happen?"); 1.4960 + } 1.4961 +#endif 1.4962 + return eSelectorParsingStatus_Continue; 1.4963 +} 1.4964 + 1.4965 +// 1.4966 +// Parse the argument of a negation pseudo-class :not() 1.4967 +// 1.4968 +CSSParserImpl::nsSelectorParsingStatus 1.4969 +CSSParserImpl::ParseNegatedSimpleSelector(int32_t& aDataMask, 1.4970 + nsCSSSelector& aSelector) 1.4971 +{ 1.4972 + if (! GetToken(true)) { // premature eof 1.4973 + REPORT_UNEXPECTED_EOF(PENegationEOF); 1.4974 + return eSelectorParsingStatus_Error; 1.4975 + } 1.4976 + 1.4977 + if (mToken.IsSymbol(')')) { 1.4978 + REPORT_UNEXPECTED_TOKEN(PENegationBadArg); 1.4979 + return eSelectorParsingStatus_Error; 1.4980 + } 1.4981 + 1.4982 + // Create a new nsCSSSelector and add it to the end of 1.4983 + // aSelector.mNegations. 1.4984 + // Given the current parsing rules, every selector in mNegations 1.4985 + // contains only one simple selector (css3 definition) within it. 1.4986 + // This could easily change in future versions of CSS, and the only 1.4987 + // thing we need to change to support that is this parsing code and the 1.4988 + // serialization code for nsCSSSelector. 1.4989 + nsCSSSelector *newSel = new nsCSSSelector(); 1.4990 + nsCSSSelector* negations = &aSelector; 1.4991 + while (negations->mNegations) { 1.4992 + negations = negations->mNegations; 1.4993 + } 1.4994 + negations->mNegations = newSel; 1.4995 + 1.4996 + nsSelectorParsingStatus parsingStatus; 1.4997 + if (eCSSToken_ID == mToken.mType) { // #id 1.4998 + parsingStatus = ParseIDSelector(aDataMask, *newSel); 1.4999 + } 1.5000 + else if (mToken.IsSymbol('.')) { // .class 1.5001 + parsingStatus = ParseClassSelector(aDataMask, *newSel); 1.5002 + } 1.5003 + else if (mToken.IsSymbol(':')) { // :pseudo 1.5004 + parsingStatus = ParsePseudoSelector(aDataMask, *newSel, true, 1.5005 + nullptr, nullptr, nullptr); 1.5006 + } 1.5007 + else if (mToken.IsSymbol('[')) { // [attribute 1.5008 + parsingStatus = ParseAttributeSelector(aDataMask, *newSel); 1.5009 + if (eSelectorParsingStatus_Error == parsingStatus) { 1.5010 + // Skip forward to the matching ']' 1.5011 + SkipUntil(']'); 1.5012 + } 1.5013 + } 1.5014 + else { 1.5015 + // then it should be a type element or universal selector 1.5016 + parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, true); 1.5017 + } 1.5018 + if (eSelectorParsingStatus_Error == parsingStatus) { 1.5019 + REPORT_UNEXPECTED_TOKEN(PENegationBadInner); 1.5020 + SkipUntil(')'); 1.5021 + return parsingStatus; 1.5022 + } 1.5023 + // close the parenthesis 1.5024 + if (!ExpectSymbol(')', true)) { 1.5025 + REPORT_UNEXPECTED_TOKEN(PENegationNoClose); 1.5026 + SkipUntil(')'); 1.5027 + return eSelectorParsingStatus_Error; 1.5028 + } 1.5029 + 1.5030 + NS_ASSERTION(newSel->mNameSpace == kNameSpaceID_Unknown || 1.5031 + (!newSel->mIDList && !newSel->mClassList && 1.5032 + !newSel->mPseudoClassList && !newSel->mAttrList), 1.5033 + "Need to fix the serialization code to deal with this"); 1.5034 + 1.5035 + return eSelectorParsingStatus_Continue; 1.5036 +} 1.5037 + 1.5038 +// 1.5039 +// Parse the argument of a pseudo-class that has an ident arg 1.5040 +// 1.5041 +CSSParserImpl::nsSelectorParsingStatus 1.5042 +CSSParserImpl::ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector, 1.5043 + nsCSSPseudoClasses::Type aType) 1.5044 +{ 1.5045 + if (! GetToken(true)) { // premature eof 1.5046 + REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF); 1.5047 + return eSelectorParsingStatus_Error; 1.5048 + } 1.5049 + // We expect an identifier with a language abbreviation 1.5050 + if (eCSSToken_Ident != mToken.mType) { 1.5051 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent); 1.5052 + UngetToken(); 1.5053 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5054 + } 1.5055 + 1.5056 + // -moz-locale-dir and -moz-dir can only have values of 'ltr' or 'rtl'. 1.5057 + if (aType == nsCSSPseudoClasses::ePseudoClass_mozLocaleDir || 1.5058 + aType == nsCSSPseudoClasses::ePseudoClass_dir) { 1.5059 + nsContentUtils::ASCIIToLower(mToken.mIdent); // case insensitive 1.5060 + if (!mToken.mIdent.EqualsLiteral("ltr") && 1.5061 + !mToken.mIdent.EqualsLiteral("rtl")) { 1.5062 + REPORT_UNEXPECTED_TOKEN(PEBadDirValue); 1.5063 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5064 + } 1.5065 + } 1.5066 + 1.5067 + // Add the pseudo with the language parameter 1.5068 + aSelector.AddPseudoClass(aType, mToken.mIdent.get()); 1.5069 + 1.5070 + // close the parenthesis 1.5071 + if (!ExpectSymbol(')', true)) { 1.5072 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose); 1.5073 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5074 + } 1.5075 + 1.5076 + return eSelectorParsingStatus_Continue; 1.5077 +} 1.5078 + 1.5079 +CSSParserImpl::nsSelectorParsingStatus 1.5080 +CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector, 1.5081 + nsCSSPseudoClasses::Type aType) 1.5082 +{ 1.5083 + int32_t numbers[2] = { 0, 0 }; 1.5084 + int32_t sign[2] = { 1, 1 }; 1.5085 + bool hasSign[2] = { false, false }; 1.5086 + bool lookForB = true; 1.5087 + 1.5088 + // Follow the whitespace rules as proposed in 1.5089 + // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html 1.5090 + 1.5091 + if (! GetToken(true)) { 1.5092 + REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF); 1.5093 + return eSelectorParsingStatus_Error; 1.5094 + } 1.5095 + 1.5096 + if (mToken.IsSymbol('+') || mToken.IsSymbol('-')) { 1.5097 + hasSign[0] = true; 1.5098 + if (mToken.IsSymbol('-')) { 1.5099 + sign[0] = -1; 1.5100 + } 1.5101 + if (! GetToken(false)) { 1.5102 + REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF); 1.5103 + return eSelectorParsingStatus_Error; 1.5104 + } 1.5105 + } 1.5106 + 1.5107 + if (eCSSToken_Ident == mToken.mType || eCSSToken_Dimension == mToken.mType) { 1.5108 + // The CSS tokenization doesn't handle :nth-child() containing - well: 1.5109 + // 2n-1 is a dimension 1.5110 + // n-1 is an identifier 1.5111 + // The easiest way to deal with that is to push everything from the 1.5112 + // minus on back onto the scanner's pushback buffer. 1.5113 + uint32_t truncAt = 0; 1.5114 + if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("n-"))) { 1.5115 + truncAt = 1; 1.5116 + } else if (StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("-n-")) && !hasSign[0]) { 1.5117 + truncAt = 2; 1.5118 + } 1.5119 + if (truncAt != 0) { 1.5120 + mScanner->Backup(mToken.mIdent.Length() - truncAt); 1.5121 + mToken.mIdent.Truncate(truncAt); 1.5122 + } 1.5123 + } 1.5124 + 1.5125 + if (eCSSToken_Ident == mToken.mType) { 1.5126 + if (mToken.mIdent.LowerCaseEqualsLiteral("odd") && !hasSign[0]) { 1.5127 + numbers[0] = 2; 1.5128 + numbers[1] = 1; 1.5129 + lookForB = false; 1.5130 + } 1.5131 + else if (mToken.mIdent.LowerCaseEqualsLiteral("even") && !hasSign[0]) { 1.5132 + numbers[0] = 2; 1.5133 + numbers[1] = 0; 1.5134 + lookForB = false; 1.5135 + } 1.5136 + else if (mToken.mIdent.LowerCaseEqualsLiteral("n")) { 1.5137 + numbers[0] = sign[0]; 1.5138 + } 1.5139 + else if (mToken.mIdent.LowerCaseEqualsLiteral("-n") && !hasSign[0]) { 1.5140 + numbers[0] = -1; 1.5141 + } 1.5142 + else { 1.5143 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth); 1.5144 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5145 + } 1.5146 + } 1.5147 + else if (eCSSToken_Number == mToken.mType) { 1.5148 + if (!mToken.mIntegerValid) { 1.5149 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth); 1.5150 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5151 + } 1.5152 + // for +-an case 1.5153 + if (mToken.mHasSign && hasSign[0]) { 1.5154 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth); 1.5155 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5156 + } 1.5157 + int32_t intValue = mToken.mInteger * sign[0]; 1.5158 + // for -a/**/n case 1.5159 + if (! GetToken(false)) { 1.5160 + numbers[1] = intValue; 1.5161 + lookForB = false; 1.5162 + } 1.5163 + else { 1.5164 + if (eCSSToken_Ident == mToken.mType && mToken.mIdent.LowerCaseEqualsLiteral("n")) { 1.5165 + numbers[0] = intValue; 1.5166 + } 1.5167 + else if (eCSSToken_Ident == mToken.mType && StringBeginsWith(mToken.mIdent, NS_LITERAL_STRING("n-"))) { 1.5168 + numbers[0] = intValue; 1.5169 + mScanner->Backup(mToken.mIdent.Length() - 1); 1.5170 + } 1.5171 + else { 1.5172 + UngetToken(); 1.5173 + numbers[1] = intValue; 1.5174 + lookForB = false; 1.5175 + } 1.5176 + } 1.5177 + } 1.5178 + else if (eCSSToken_Dimension == mToken.mType) { 1.5179 + if (!mToken.mIntegerValid || !mToken.mIdent.LowerCaseEqualsLiteral("n")) { 1.5180 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth); 1.5181 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5182 + } 1.5183 + // for +-an case 1.5184 + if ( mToken.mHasSign && hasSign[0] ) { 1.5185 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth); 1.5186 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5187 + } 1.5188 + numbers[0] = mToken.mInteger * sign[0]; 1.5189 + } 1.5190 + // XXX If it's a ')', is that valid? (as 0n+0) 1.5191 + else { 1.5192 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth); 1.5193 + UngetToken(); 1.5194 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5195 + } 1.5196 + 1.5197 + if (! GetToken(true)) { 1.5198 + REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF); 1.5199 + return eSelectorParsingStatus_Error; 1.5200 + } 1.5201 + if (lookForB && !mToken.IsSymbol(')')) { 1.5202 + // The '+' or '-' sign can optionally be separated by whitespace. 1.5203 + // If it is separated by whitespace from what follows it, it appears 1.5204 + // as a separate token rather than part of the number token. 1.5205 + if (mToken.IsSymbol('+') || mToken.IsSymbol('-')) { 1.5206 + hasSign[1] = true; 1.5207 + if (mToken.IsSymbol('-')) { 1.5208 + sign[1] = -1; 1.5209 + } 1.5210 + if (! GetToken(true)) { 1.5211 + REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF); 1.5212 + return eSelectorParsingStatus_Error; 1.5213 + } 1.5214 + } 1.5215 + if (eCSSToken_Number != mToken.mType || 1.5216 + !mToken.mIntegerValid || mToken.mHasSign == hasSign[1]) { 1.5217 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotNth); 1.5218 + UngetToken(); 1.5219 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5220 + } 1.5221 + numbers[1] = mToken.mInteger * sign[1]; 1.5222 + if (! GetToken(true)) { 1.5223 + REPORT_UNEXPECTED_EOF(PEPseudoClassArgEOF); 1.5224 + return eSelectorParsingStatus_Error; 1.5225 + } 1.5226 + } 1.5227 + if (!mToken.IsSymbol(')')) { 1.5228 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose); 1.5229 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5230 + } 1.5231 + aSelector.AddPseudoClass(aType, numbers); 1.5232 + return eSelectorParsingStatus_Continue; 1.5233 +} 1.5234 + 1.5235 +// 1.5236 +// Parse the argument of a pseudo-class that has a selector list argument. 1.5237 +// Such selector lists cannot contain combinators, but can contain 1.5238 +// anything that goes between a pair of combinators. 1.5239 +// 1.5240 +CSSParserImpl::nsSelectorParsingStatus 1.5241 +CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector, 1.5242 + nsCSSPseudoClasses::Type aType) 1.5243 +{ 1.5244 + nsAutoPtr<nsCSSSelectorList> slist; 1.5245 + if (! ParseSelectorList(*getter_Transfers(slist), char16_t(')'))) { 1.5246 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5247 + } 1.5248 + 1.5249 + // Check that none of the selectors in the list have combinators or 1.5250 + // pseudo-elements. 1.5251 + for (nsCSSSelectorList *l = slist; l; l = l->mNext) { 1.5252 + nsCSSSelector *s = l->mSelectors; 1.5253 + if (s->mNext || s->IsPseudoElement()) { 1.5254 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5255 + } 1.5256 + } 1.5257 + 1.5258 + // Add the pseudo with the selector list parameter 1.5259 + aSelector.AddPseudoClass(aType, slist.forget()); 1.5260 + 1.5261 + // close the parenthesis 1.5262 + if (!ExpectSymbol(')', true)) { 1.5263 + REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose); 1.5264 + return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')') 1.5265 + } 1.5266 + 1.5267 + return eSelectorParsingStatus_Continue; 1.5268 +} 1.5269 + 1.5270 + 1.5271 +/** 1.5272 + * This is the format for selectors: 1.5273 + * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]* 1.5274 + */ 1.5275 +bool 1.5276 +CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, 1.5277 + char16_t aPrevCombinator) 1.5278 +{ 1.5279 + if (! GetToken(true)) { 1.5280 + REPORT_UNEXPECTED_EOF(PESelectorEOF); 1.5281 + return false; 1.5282 + } 1.5283 + 1.5284 + nsCSSSelector* selector = aList->AddSelector(aPrevCombinator); 1.5285 + nsCOMPtr<nsIAtom> pseudoElement; 1.5286 + nsAutoPtr<nsAtomList> pseudoElementArgs; 1.5287 + nsCSSPseudoElements::Type pseudoElementType = 1.5288 + nsCSSPseudoElements::ePseudo_NotPseudoElement; 1.5289 + 1.5290 + int32_t dataMask = 0; 1.5291 + nsSelectorParsingStatus parsingStatus = 1.5292 + ParseTypeOrUniversalSelector(dataMask, *selector, false); 1.5293 + 1.5294 + while (parsingStatus == eSelectorParsingStatus_Continue) { 1.5295 + if (eCSSToken_ID == mToken.mType) { // #id 1.5296 + parsingStatus = ParseIDSelector(dataMask, *selector); 1.5297 + } 1.5298 + else if (mToken.IsSymbol('.')) { // .class 1.5299 + parsingStatus = ParseClassSelector(dataMask, *selector); 1.5300 + } 1.5301 + else if (mToken.IsSymbol(':')) { // :pseudo 1.5302 + parsingStatus = ParsePseudoSelector(dataMask, *selector, false, 1.5303 + getter_AddRefs(pseudoElement), 1.5304 + getter_Transfers(pseudoElementArgs), 1.5305 + &pseudoElementType); 1.5306 + if (pseudoElement && 1.5307 + pseudoElementType != nsCSSPseudoElements::ePseudo_AnonBox) { 1.5308 + // Pseudo-elements other than anonymous boxes are represented with 1.5309 + // a special ':' combinator. 1.5310 + 1.5311 + aList->mWeight += selector->CalcWeight(); 1.5312 + 1.5313 + selector = aList->AddSelector(':'); 1.5314 + 1.5315 + selector->mLowercaseTag.swap(pseudoElement); 1.5316 + selector->mClassList = pseudoElementArgs.forget(); 1.5317 + selector->SetPseudoType(pseudoElementType); 1.5318 + } 1.5319 + } 1.5320 + else if (mToken.IsSymbol('[')) { // [attribute 1.5321 + parsingStatus = ParseAttributeSelector(dataMask, *selector); 1.5322 + if (eSelectorParsingStatus_Error == parsingStatus) { 1.5323 + SkipUntil(']'); 1.5324 + } 1.5325 + } 1.5326 + else { // not a selector token, we're done 1.5327 + parsingStatus = eSelectorParsingStatus_Done; 1.5328 + UngetToken(); 1.5329 + break; 1.5330 + } 1.5331 + 1.5332 + if (parsingStatus != eSelectorParsingStatus_Continue) { 1.5333 + break; 1.5334 + } 1.5335 + 1.5336 + if (! GetToken(false)) { // premature eof is ok (here!) 1.5337 + parsingStatus = eSelectorParsingStatus_Done; 1.5338 + break; 1.5339 + } 1.5340 + } 1.5341 + 1.5342 + if (parsingStatus == eSelectorParsingStatus_Error) { 1.5343 + return false; 1.5344 + } 1.5345 + 1.5346 + if (!dataMask) { 1.5347 + if (selector->mNext) { 1.5348 + REPORT_UNEXPECTED(PESelectorGroupExtraCombinator); 1.5349 + } else { 1.5350 + REPORT_UNEXPECTED(PESelectorGroupNoSelector); 1.5351 + } 1.5352 + return false; 1.5353 + } 1.5354 + 1.5355 + if (pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox) { 1.5356 + // We got an anonymous box pseudo-element; it must be the only 1.5357 + // thing in this selector group. 1.5358 + if (selector->mNext || !IsUniversalSelector(*selector)) { 1.5359 + REPORT_UNEXPECTED(PEAnonBoxNotAlone); 1.5360 + return false; 1.5361 + } 1.5362 + 1.5363 + // Rewrite the current selector as this pseudo-element. 1.5364 + // It does not contribute to selector weight. 1.5365 + selector->mLowercaseTag.swap(pseudoElement); 1.5366 + selector->mClassList = pseudoElementArgs.forget(); 1.5367 + selector->SetPseudoType(pseudoElementType); 1.5368 + return true; 1.5369 + } 1.5370 + 1.5371 + aList->mWeight += selector->CalcWeight(); 1.5372 + 1.5373 + return true; 1.5374 +} 1.5375 + 1.5376 +css::Declaration* 1.5377 +CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags, nsCSSContextType aContext) 1.5378 +{ 1.5379 + bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0; 1.5380 + 1.5381 + if (checkForBraces) { 1.5382 + if (!ExpectSymbol('{', true)) { 1.5383 + REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart); 1.5384 + OUTPUT_ERROR(); 1.5385 + return nullptr; 1.5386 + } 1.5387 + } 1.5388 + css::Declaration* declaration = new css::Declaration(); 1.5389 + mData.AssertInitialState(); 1.5390 + if (declaration) { 1.5391 + for (;;) { 1.5392 + bool changed; 1.5393 + if (!ParseDeclaration(declaration, aFlags, true, &changed, aContext)) { 1.5394 + if (!SkipDeclaration(checkForBraces)) { 1.5395 + break; 1.5396 + } 1.5397 + if (checkForBraces) { 1.5398 + if (ExpectSymbol('}', true)) { 1.5399 + break; 1.5400 + } 1.5401 + } 1.5402 + // Since the skipped declaration didn't end the block we parse 1.5403 + // the next declaration. 1.5404 + } 1.5405 + } 1.5406 + declaration->CompressFrom(&mData); 1.5407 + } 1.5408 + return declaration; 1.5409 +} 1.5410 + 1.5411 +bool 1.5412 +CSSParserImpl::ParseColor(nsCSSValue& aValue) 1.5413 +{ 1.5414 + if (!GetToken(true)) { 1.5415 + REPORT_UNEXPECTED_EOF(PEColorEOF); 1.5416 + return false; 1.5417 + } 1.5418 + 1.5419 + nsCSSToken* tk = &mToken; 1.5420 + nscolor rgba; 1.5421 + switch (tk->mType) { 1.5422 + case eCSSToken_ID: 1.5423 + case eCSSToken_Hash: 1.5424 + // #xxyyzz 1.5425 + if (NS_HexToRGB(tk->mIdent, &rgba)) { 1.5426 + MOZ_ASSERT(tk->mIdent.Length() == 3 || tk->mIdent.Length() == 6, 1.5427 + "unexpected hex color length"); 1.5428 + nsCSSUnit unit = tk->mIdent.Length() == 3 ? 1.5429 + eCSSUnit_ShortHexColor : 1.5430 + eCSSUnit_HexColor; 1.5431 + aValue.SetIntegerColorValue(rgba, unit); 1.5432 + return true; 1.5433 + } 1.5434 + break; 1.5435 + 1.5436 + case eCSSToken_Ident: 1.5437 + if (NS_ColorNameToRGB(tk->mIdent, &rgba)) { 1.5438 + aValue.SetStringValue(tk->mIdent, eCSSUnit_Ident); 1.5439 + return true; 1.5440 + } 1.5441 + else { 1.5442 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(tk->mIdent); 1.5443 + if (eCSSKeyword_UNKNOWN < keyword) { // known keyword 1.5444 + int32_t value; 1.5445 + if (nsCSSProps::FindKeyword(keyword, nsCSSProps::kColorKTable, value)) { 1.5446 + aValue.SetIntValue(value, eCSSUnit_EnumColor); 1.5447 + return true; 1.5448 + } 1.5449 + } 1.5450 + } 1.5451 + break; 1.5452 + case eCSSToken_Function: 1.5453 + if (mToken.mIdent.LowerCaseEqualsLiteral("rgb")) { 1.5454 + // rgb ( component , component , component ) 1.5455 + if (GetToken(true)) { 1.5456 + UngetToken(); 1.5457 + } 1.5458 + if (mToken.mType == eCSSToken_Number) { 1.5459 + uint8_t r, g, b; 1.5460 + if (ParseNumberColorComponent(r, ',') && 1.5461 + ParseNumberColorComponent(g, ',') && 1.5462 + ParseNumberColorComponent(b, ')')) { 1.5463 + aValue.SetIntegerColorValue(NS_RGB(r, g, b), eCSSUnit_RGBColor); 1.5464 + return true; 1.5465 + } 1.5466 + } else { 1.5467 + float r, g, b; 1.5468 + if (ParsePercentageColorComponent(r, ',') && 1.5469 + ParsePercentageColorComponent(g, ',') && 1.5470 + ParsePercentageColorComponent(b, ')')) { 1.5471 + aValue.SetFloatColorValue(r, g, b, 1.0f, 1.5472 + eCSSUnit_PercentageRGBColor); 1.5473 + return true; 1.5474 + } 1.5475 + } 1.5476 + SkipUntil(')'); 1.5477 + return false; 1.5478 + } 1.5479 + else if (mToken.mIdent.LowerCaseEqualsLiteral("rgba")) { 1.5480 + // rgba ( component , component , component , opacity ) 1.5481 + if (GetToken(true)) { 1.5482 + UngetToken(); 1.5483 + } 1.5484 + if (mToken.mType == eCSSToken_Number) { 1.5485 + uint8_t r, g, b, a; 1.5486 + if (ParseNumberColorComponent(r, ',') && 1.5487 + ParseNumberColorComponent(g, ',') && 1.5488 + ParseNumberColorComponent(b, ',') && 1.5489 + ParseColorOpacity(a)) { 1.5490 + aValue.SetIntegerColorValue(NS_RGBA(r, g, b, a), 1.5491 + eCSSUnit_RGBAColor); 1.5492 + return true; 1.5493 + } 1.5494 + } else { 1.5495 + float r, g, b, a; 1.5496 + if (ParsePercentageColorComponent(r, ',') && 1.5497 + ParsePercentageColorComponent(g, ',') && 1.5498 + ParsePercentageColorComponent(b, ',') && 1.5499 + ParseColorOpacity(a)) { 1.5500 + aValue.SetFloatColorValue(r, g, b, a, eCSSUnit_PercentageRGBAColor); 1.5501 + return true; 1.5502 + } 1.5503 + } 1.5504 + SkipUntil(')'); 1.5505 + return false; 1.5506 + } 1.5507 + else if (mToken.mIdent.LowerCaseEqualsLiteral("hsl")) { 1.5508 + // hsl ( hue , saturation , lightness ) 1.5509 + // "hue" is a number, "saturation" and "lightness" are percentages. 1.5510 + float h, s, l; 1.5511 + if (ParseHSLColor(h, s, l, ')')) { 1.5512 + aValue.SetFloatColorValue(h, s, l, 1.0f, eCSSUnit_HSLColor); 1.5513 + return true; 1.5514 + } 1.5515 + SkipUntil(')'); 1.5516 + return false; 1.5517 + } 1.5518 + else if (mToken.mIdent.LowerCaseEqualsLiteral("hsla")) { 1.5519 + // hsla ( hue , saturation , lightness , opacity ) 1.5520 + // "hue" is a number, "saturation" and "lightness" are percentages, 1.5521 + // "opacity" is a number. 1.5522 + float h, s, l, a; 1.5523 + if (ParseHSLColor(h, s, l, ',') && 1.5524 + ParseColorOpacity(a)) { 1.5525 + aValue.SetFloatColorValue(h, s, l, a, eCSSUnit_HSLAColor); 1.5526 + return true; 1.5527 + } 1.5528 + SkipUntil(')'); 1.5529 + return false; 1.5530 + } 1.5531 + break; 1.5532 + default: 1.5533 + break; 1.5534 + } 1.5535 + 1.5536 + // try 'xxyyzz' without '#' prefix for compatibility with IE and Nav4x (bug 23236 and 45804) 1.5537 + if (mHashlessColorQuirk) { 1.5538 + // - If the string starts with 'a-f', the nsCSSScanner builds the 1.5539 + // token as a eCSSToken_Ident and we can parse the string as a 1.5540 + // 'xxyyzz' RGB color. 1.5541 + // - If it only contains '0-9' digits, the token is a 1.5542 + // eCSSToken_Number and it must be converted back to a 6 1.5543 + // characters string to be parsed as a RGB color. 1.5544 + // - If it starts with '0-9' and contains any 'a-f', the token is a 1.5545 + // eCSSToken_Dimension, the mNumber part must be converted back to 1.5546 + // a string and the mIdent part must be appended to that string so 1.5547 + // that the resulting string has 6 characters. 1.5548 + // Note: This is a hack for Nav compatibility. Do not attempt to 1.5549 + // simplify it by hacking into the ncCSSScanner. This would be very 1.5550 + // bad. 1.5551 + nsAutoString str; 1.5552 + char buffer[20]; 1.5553 + switch (tk->mType) { 1.5554 + case eCSSToken_Ident: 1.5555 + str.Assign(tk->mIdent); 1.5556 + break; 1.5557 + 1.5558 + case eCSSToken_Number: 1.5559 + if (tk->mIntegerValid) { 1.5560 + PR_snprintf(buffer, sizeof(buffer), "%06d", tk->mInteger); 1.5561 + str.AssignWithConversion(buffer); 1.5562 + } 1.5563 + break; 1.5564 + 1.5565 + case eCSSToken_Dimension: 1.5566 + if (tk->mIdent.Length() <= 6) { 1.5567 + PR_snprintf(buffer, sizeof(buffer), "%06.0f", tk->mNumber); 1.5568 + nsAutoString temp; 1.5569 + temp.AssignWithConversion(buffer); 1.5570 + temp.Right(str, 6 - tk->mIdent.Length()); 1.5571 + str.Append(tk->mIdent); 1.5572 + } 1.5573 + break; 1.5574 + default: 1.5575 + // There is a whole bunch of cases that are 1.5576 + // not handled by this switch. Ignore them. 1.5577 + break; 1.5578 + } 1.5579 + if (NS_HexToRGB(str, &rgba)) { 1.5580 + aValue.SetIntegerColorValue(rgba, eCSSUnit_HexColor); 1.5581 + return true; 1.5582 + } 1.5583 + } 1.5584 + 1.5585 + // It's not a color 1.5586 + REPORT_UNEXPECTED_TOKEN(PEColorNotColor); 1.5587 + UngetToken(); 1.5588 + return false; 1.5589 +} 1.5590 + 1.5591 +bool 1.5592 +CSSParserImpl::ParseNumberColorComponent(uint8_t& aComponent, char aStop) 1.5593 +{ 1.5594 + if (!GetToken(true)) { 1.5595 + REPORT_UNEXPECTED_EOF(PEColorComponentEOF); 1.5596 + return false; 1.5597 + } 1.5598 + 1.5599 + if (mToken.mType != eCSSToken_Number || !mToken.mIntegerValid) { 1.5600 + REPORT_UNEXPECTED_TOKEN(PEExpectedInt); 1.5601 + UngetToken(); 1.5602 + return false; 1.5603 + } 1.5604 + 1.5605 + float value = mToken.mNumber; 1.5606 + if (value < 0.0f) value = 0.0f; 1.5607 + if (value > 255.0f) value = 255.0f; 1.5608 + 1.5609 + if (ExpectSymbol(aStop, true)) { 1.5610 + aComponent = NSToIntRound(value); 1.5611 + return true; 1.5612 + } 1.5613 + REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm, aStop); 1.5614 + return false; 1.5615 +} 1.5616 + 1.5617 +bool 1.5618 +CSSParserImpl::ParsePercentageColorComponent(float& aComponent, char aStop) 1.5619 +{ 1.5620 + if (!GetToken(true)) { 1.5621 + REPORT_UNEXPECTED_EOF(PEColorComponentEOF); 1.5622 + return false; 1.5623 + } 1.5624 + 1.5625 + if (mToken.mType != eCSSToken_Percentage) { 1.5626 + REPORT_UNEXPECTED_TOKEN(PEExpectedPercent); 1.5627 + UngetToken(); 1.5628 + return false; 1.5629 + } 1.5630 + 1.5631 + float value = mToken.mNumber; 1.5632 + if (value < 0.0f) value = 0.0f; 1.5633 + if (value > 1.0f) value = 1.0f; 1.5634 + 1.5635 + if (ExpectSymbol(aStop, true)) { 1.5636 + aComponent = value; 1.5637 + return true; 1.5638 + } 1.5639 + REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm, aStop); 1.5640 + return false; 1.5641 +} 1.5642 + 1.5643 + 1.5644 +bool 1.5645 +CSSParserImpl::ParseHSLColor(float& aHue, float& aSaturation, float& aLightness, 1.5646 + char aStop) 1.5647 +{ 1.5648 + float h, s, l; 1.5649 + 1.5650 + // Get the hue 1.5651 + if (!GetToken(true)) { 1.5652 + REPORT_UNEXPECTED_EOF(PEColorHueEOF); 1.5653 + return false; 1.5654 + } 1.5655 + if (mToken.mType != eCSSToken_Number) { 1.5656 + REPORT_UNEXPECTED_TOKEN(PEExpectedNumber); 1.5657 + UngetToken(); 1.5658 + return false; 1.5659 + } 1.5660 + h = mToken.mNumber; 1.5661 + h /= 360.0f; 1.5662 + // hue values are wraparound 1.5663 + h = h - floor(h); 1.5664 + 1.5665 + if (!ExpectSymbol(',', true)) { 1.5666 + REPORT_UNEXPECTED_TOKEN(PEExpectedComma); 1.5667 + return false; 1.5668 + } 1.5669 + 1.5670 + // Get the saturation 1.5671 + if (!GetToken(true)) { 1.5672 + REPORT_UNEXPECTED_EOF(PEColorSaturationEOF); 1.5673 + return false; 1.5674 + } 1.5675 + if (mToken.mType != eCSSToken_Percentage) { 1.5676 + REPORT_UNEXPECTED_TOKEN(PEExpectedPercent); 1.5677 + UngetToken(); 1.5678 + return false; 1.5679 + } 1.5680 + s = mToken.mNumber; 1.5681 + if (s < 0.0f) s = 0.0f; 1.5682 + if (s > 1.0f) s = 1.0f; 1.5683 + 1.5684 + if (!ExpectSymbol(',', true)) { 1.5685 + REPORT_UNEXPECTED_TOKEN(PEExpectedComma); 1.5686 + return false; 1.5687 + } 1.5688 + 1.5689 + // Get the lightness 1.5690 + if (!GetToken(true)) { 1.5691 + REPORT_UNEXPECTED_EOF(PEColorLightnessEOF); 1.5692 + return false; 1.5693 + } 1.5694 + if (mToken.mType != eCSSToken_Percentage) { 1.5695 + REPORT_UNEXPECTED_TOKEN(PEExpectedPercent); 1.5696 + UngetToken(); 1.5697 + return false; 1.5698 + } 1.5699 + l = mToken.mNumber; 1.5700 + if (l < 0.0f) l = 0.0f; 1.5701 + if (l > 1.0f) l = 1.0f; 1.5702 + 1.5703 + if (ExpectSymbol(aStop, true)) { 1.5704 + aHue = h; 1.5705 + aSaturation = s; 1.5706 + aLightness = l; 1.5707 + return true; 1.5708 + } 1.5709 + 1.5710 + REPORT_UNEXPECTED_TOKEN_CHAR(PEColorComponentBadTerm, aStop); 1.5711 + return false; 1.5712 +} 1.5713 + 1.5714 + 1.5715 +bool 1.5716 +CSSParserImpl::ParseColorOpacity(uint8_t& aOpacity) 1.5717 +{ 1.5718 + float floatOpacity; 1.5719 + if (!ParseColorOpacity(floatOpacity)) { 1.5720 + return false; 1.5721 + } 1.5722 + 1.5723 + uint8_t value = nsStyleUtil::FloatToColorComponent(floatOpacity); 1.5724 + // Need to compare to something slightly larger 1.5725 + // than 0.5 due to floating point inaccuracies. 1.5726 + NS_ASSERTION(fabs(255.0f*mToken.mNumber - value) <= 0.51f, 1.5727 + "FloatToColorComponent did something weird"); 1.5728 + 1.5729 + aOpacity = value; 1.5730 + return true; 1.5731 +} 1.5732 + 1.5733 +bool 1.5734 +CSSParserImpl::ParseColorOpacity(float& aOpacity) 1.5735 +{ 1.5736 + if (!GetToken(true)) { 1.5737 + REPORT_UNEXPECTED_EOF(PEColorOpacityEOF); 1.5738 + return false; 1.5739 + } 1.5740 + 1.5741 + if (mToken.mType != eCSSToken_Number) { 1.5742 + REPORT_UNEXPECTED_TOKEN(PEExpectedNumber); 1.5743 + UngetToken(); 1.5744 + return false; 1.5745 + } 1.5746 + 1.5747 + if (!ExpectSymbol(')', true)) { 1.5748 + REPORT_UNEXPECTED_TOKEN(PEExpectedCloseParen); 1.5749 + return false; 1.5750 + } 1.5751 + 1.5752 + if (mToken.mNumber < 0.0f) { 1.5753 + mToken.mNumber = 0.0f; 1.5754 + } else if (mToken.mNumber > 1.0f) { 1.5755 + mToken.mNumber = 1.0f; 1.5756 + } 1.5757 + 1.5758 + aOpacity = mToken.mNumber; 1.5759 + return true; 1.5760 +} 1.5761 + 1.5762 +#ifdef MOZ_XUL 1.5763 +bool 1.5764 +CSSParserImpl::ParseTreePseudoElement(nsAtomList **aPseudoElementArgs) 1.5765 +{ 1.5766 + // The argument to a tree pseudo-element is a sequence of identifiers 1.5767 + // that are either space- or comma-separated. (Was the intent to 1.5768 + // allow only comma-separated? That's not what was done.) 1.5769 + nsCSSSelector fakeSelector; // so we can reuse AddPseudoClass 1.5770 + 1.5771 + while (!ExpectSymbol(')', true)) { 1.5772 + if (!GetToken(true)) { 1.5773 + return false; 1.5774 + } 1.5775 + if (eCSSToken_Ident == mToken.mType) { 1.5776 + fakeSelector.AddClass(mToken.mIdent); 1.5777 + } 1.5778 + else if (!mToken.IsSymbol(',')) { 1.5779 + UngetToken(); 1.5780 + SkipUntil(')'); 1.5781 + return false; 1.5782 + } 1.5783 + } 1.5784 + *aPseudoElementArgs = fakeSelector.mClassList; 1.5785 + fakeSelector.mClassList = nullptr; 1.5786 + return true; 1.5787 +} 1.5788 +#endif 1.5789 + 1.5790 +//---------------------------------------------------------------------- 1.5791 + 1.5792 +bool 1.5793 +CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration, 1.5794 + uint32_t aFlags, 1.5795 + bool aMustCallValueAppended, 1.5796 + bool* aChanged, 1.5797 + nsCSSContextType aContext) 1.5798 +{ 1.5799 + NS_PRECONDITION(aContext == eCSSContext_General || 1.5800 + aContext == eCSSContext_Page, 1.5801 + "Must be page or general context"); 1.5802 + 1.5803 + bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0; 1.5804 + 1.5805 + mTempData.AssertInitialState(); 1.5806 + 1.5807 + // Get property name 1.5808 + nsCSSToken* tk = &mToken; 1.5809 + nsAutoString propertyName; 1.5810 + for (;;) { 1.5811 + if (!GetToken(true)) { 1.5812 + if (checkForBraces) { 1.5813 + REPORT_UNEXPECTED_EOF(PEDeclEndEOF); 1.5814 + } 1.5815 + return false; 1.5816 + } 1.5817 + if (eCSSToken_Ident == tk->mType) { 1.5818 + propertyName = tk->mIdent; 1.5819 + // grab the ident before the ExpectSymbol trashes the token 1.5820 + if (!ExpectSymbol(':', true)) { 1.5821 + REPORT_UNEXPECTED_TOKEN(PEParseDeclarationNoColon); 1.5822 + REPORT_UNEXPECTED(PEDeclDropped); 1.5823 + OUTPUT_ERROR(); 1.5824 + return false; 1.5825 + } 1.5826 + break; 1.5827 + } 1.5828 + if (tk->IsSymbol(';')) { 1.5829 + // dangling semicolons are skipped 1.5830 + continue; 1.5831 + } 1.5832 + 1.5833 + if (!tk->IsSymbol('}')) { 1.5834 + REPORT_UNEXPECTED_TOKEN(PEParseDeclarationDeclExpected); 1.5835 + REPORT_UNEXPECTED(PEDeclSkipped); 1.5836 + OUTPUT_ERROR(); 1.5837 + 1.5838 + if (eCSSToken_AtKeyword == tk->mType) { 1.5839 + SkipAtRule(checkForBraces); 1.5840 + return true; // Not a declaration, but don't skip until ';' 1.5841 + } 1.5842 + } 1.5843 + // Not a declaration... 1.5844 + UngetToken(); 1.5845 + return false; 1.5846 + } 1.5847 + 1.5848 + // Don't report property parse errors if we're inside a failing @supports 1.5849 + // rule. 1.5850 + nsAutoSuppressErrors suppressErrors(this, mInFailingSupportsRule); 1.5851 + 1.5852 + // Information about a parsed non-custom property. 1.5853 + nsCSSProperty propID; 1.5854 + 1.5855 + // Information about a parsed custom property. 1.5856 + CSSVariableDeclarations::Type variableType; 1.5857 + nsString variableValue; 1.5858 + 1.5859 + // Check if the property name is a custom property. 1.5860 + bool customProperty = nsLayoutUtils::CSSVariablesEnabled() && 1.5861 + nsCSSProps::IsCustomPropertyName(propertyName) && 1.5862 + aContext == eCSSContext_General; 1.5863 + 1.5864 + if (customProperty) { 1.5865 + if (!ParseVariableDeclaration(&variableType, variableValue)) { 1.5866 + REPORT_UNEXPECTED_P(PEValueParsingError, propertyName); 1.5867 + REPORT_UNEXPECTED(PEDeclDropped); 1.5868 + OUTPUT_ERROR(); 1.5869 + return false; 1.5870 + } 1.5871 + } else { 1.5872 + // Map property name to its ID. 1.5873 + propID = LookupEnabledProperty(propertyName); 1.5874 + if (eCSSProperty_UNKNOWN == propID || 1.5875 + (aContext == eCSSContext_Page && 1.5876 + !nsCSSProps::PropHasFlags(propID, 1.5877 + CSS_PROPERTY_APPLIES_TO_PAGE_RULE))) { // unknown property 1.5878 + if (!NonMozillaVendorIdentifier(propertyName)) { 1.5879 + REPORT_UNEXPECTED_P(PEUnknownProperty, propertyName); 1.5880 + REPORT_UNEXPECTED(PEDeclDropped); 1.5881 + OUTPUT_ERROR(); 1.5882 + } 1.5883 + return false; 1.5884 + } 1.5885 + // Then parse the property. 1.5886 + if (!ParseProperty(propID)) { 1.5887 + // XXX Much better to put stuff in the value parsers instead... 1.5888 + REPORT_UNEXPECTED_P(PEValueParsingError, propertyName); 1.5889 + REPORT_UNEXPECTED(PEDeclDropped); 1.5890 + OUTPUT_ERROR(); 1.5891 + mTempData.ClearProperty(propID); 1.5892 + mTempData.AssertInitialState(); 1.5893 + return false; 1.5894 + } 1.5895 + } 1.5896 + 1.5897 + CLEAR_ERROR(); 1.5898 + 1.5899 + // Look for "!important". 1.5900 + PriorityParsingStatus status; 1.5901 + if ((aFlags & eParseDeclaration_AllowImportant) != 0) { 1.5902 + status = ParsePriority(); 1.5903 + } else { 1.5904 + status = ePriority_None; 1.5905 + } 1.5906 + 1.5907 + // Look for a semicolon or close brace. 1.5908 + if (status != ePriority_Error) { 1.5909 + if (!GetToken(true)) { 1.5910 + // EOF is always ok 1.5911 + } else if (mToken.IsSymbol(';')) { 1.5912 + // semicolon is always ok 1.5913 + } else if (mToken.IsSymbol('}')) { 1.5914 + // brace is ok if checkForBraces, but don't eat it 1.5915 + UngetToken(); 1.5916 + if (!checkForBraces) { 1.5917 + status = ePriority_Error; 1.5918 + } 1.5919 + } else { 1.5920 + UngetToken(); 1.5921 + status = ePriority_Error; 1.5922 + } 1.5923 + } 1.5924 + 1.5925 + if (status == ePriority_Error) { 1.5926 + if (checkForBraces) { 1.5927 + REPORT_UNEXPECTED_TOKEN(PEBadDeclOrRuleEnd2); 1.5928 + } else { 1.5929 + REPORT_UNEXPECTED_TOKEN(PEBadDeclEnd); 1.5930 + } 1.5931 + REPORT_UNEXPECTED(PEDeclDropped); 1.5932 + OUTPUT_ERROR(); 1.5933 + if (!customProperty) { 1.5934 + mTempData.ClearProperty(propID); 1.5935 + } 1.5936 + mTempData.AssertInitialState(); 1.5937 + return false; 1.5938 + } 1.5939 + 1.5940 + if (customProperty) { 1.5941 + MOZ_ASSERT(Substring(propertyName, 0, 1.5942 + CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--")); 1.5943 + // remove '--' 1.5944 + nsDependentString varName(propertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH); 1.5945 + aDeclaration->AddVariableDeclaration(varName, variableType, variableValue, 1.5946 + status == ePriority_Important, false); 1.5947 + } else { 1.5948 + *aChanged |= mData.TransferFromBlock(mTempData, propID, 1.5949 + status == ePriority_Important, 1.5950 + false, aMustCallValueAppended, 1.5951 + aDeclaration); 1.5952 + } 1.5953 + 1.5954 + return true; 1.5955 +} 1.5956 + 1.5957 +static const nsCSSProperty kBorderTopIDs[] = { 1.5958 + eCSSProperty_border_top_width, 1.5959 + eCSSProperty_border_top_style, 1.5960 + eCSSProperty_border_top_color 1.5961 +}; 1.5962 +static const nsCSSProperty kBorderRightIDs[] = { 1.5963 + eCSSProperty_border_right_width_value, 1.5964 + eCSSProperty_border_right_style_value, 1.5965 + eCSSProperty_border_right_color_value, 1.5966 + eCSSProperty_border_right_width, 1.5967 + eCSSProperty_border_right_style, 1.5968 + eCSSProperty_border_right_color 1.5969 +}; 1.5970 +static const nsCSSProperty kBorderBottomIDs[] = { 1.5971 + eCSSProperty_border_bottom_width, 1.5972 + eCSSProperty_border_bottom_style, 1.5973 + eCSSProperty_border_bottom_color 1.5974 +}; 1.5975 +static const nsCSSProperty kBorderLeftIDs[] = { 1.5976 + eCSSProperty_border_left_width_value, 1.5977 + eCSSProperty_border_left_style_value, 1.5978 + eCSSProperty_border_left_color_value, 1.5979 + eCSSProperty_border_left_width, 1.5980 + eCSSProperty_border_left_style, 1.5981 + eCSSProperty_border_left_color 1.5982 +}; 1.5983 +static const nsCSSProperty kBorderStartIDs[] = { 1.5984 + eCSSProperty_border_start_width_value, 1.5985 + eCSSProperty_border_start_style_value, 1.5986 + eCSSProperty_border_start_color_value, 1.5987 + eCSSProperty_border_start_width, 1.5988 + eCSSProperty_border_start_style, 1.5989 + eCSSProperty_border_start_color 1.5990 +}; 1.5991 +static const nsCSSProperty kBorderEndIDs[] = { 1.5992 + eCSSProperty_border_end_width_value, 1.5993 + eCSSProperty_border_end_style_value, 1.5994 + eCSSProperty_border_end_color_value, 1.5995 + eCSSProperty_border_end_width, 1.5996 + eCSSProperty_border_end_style, 1.5997 + eCSSProperty_border_end_color 1.5998 +}; 1.5999 +static const nsCSSProperty kColumnRuleIDs[] = { 1.6000 + eCSSProperty__moz_column_rule_width, 1.6001 + eCSSProperty__moz_column_rule_style, 1.6002 + eCSSProperty__moz_column_rule_color 1.6003 +}; 1.6004 + 1.6005 +bool 1.6006 +CSSParserImpl::ParseEnum(nsCSSValue& aValue, 1.6007 + const KTableValue aKeywordTable[]) 1.6008 +{ 1.6009 + nsSubstring* ident = NextIdent(); 1.6010 + if (nullptr == ident) { 1.6011 + return false; 1.6012 + } 1.6013 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(*ident); 1.6014 + if (eCSSKeyword_UNKNOWN < keyword) { 1.6015 + int32_t value; 1.6016 + if (nsCSSProps::FindKeyword(keyword, aKeywordTable, value)) { 1.6017 + aValue.SetIntValue(value, eCSSUnit_Enumerated); 1.6018 + return true; 1.6019 + } 1.6020 + } 1.6021 + 1.6022 + // Put the unknown identifier back and return 1.6023 + UngetToken(); 1.6024 + return false; 1.6025 +} 1.6026 + 1.6027 + 1.6028 +struct UnitInfo { 1.6029 + char name[6]; // needs to be long enough for the longest unit, with 1.6030 + // terminating null. 1.6031 + uint32_t length; 1.6032 + nsCSSUnit unit; 1.6033 + int32_t type; 1.6034 +}; 1.6035 + 1.6036 +#define STR_WITH_LEN(_str) \ 1.6037 + _str, sizeof(_str) - 1 1.6038 + 1.6039 +const UnitInfo UnitData[] = { 1.6040 + { STR_WITH_LEN("px"), eCSSUnit_Pixel, VARIANT_LENGTH }, 1.6041 + { STR_WITH_LEN("em"), eCSSUnit_EM, VARIANT_LENGTH }, 1.6042 + { STR_WITH_LEN("ex"), eCSSUnit_XHeight, VARIANT_LENGTH }, 1.6043 + { STR_WITH_LEN("pt"), eCSSUnit_Point, VARIANT_LENGTH }, 1.6044 + { STR_WITH_LEN("in"), eCSSUnit_Inch, VARIANT_LENGTH }, 1.6045 + { STR_WITH_LEN("cm"), eCSSUnit_Centimeter, VARIANT_LENGTH }, 1.6046 + { STR_WITH_LEN("ch"), eCSSUnit_Char, VARIANT_LENGTH }, 1.6047 + { STR_WITH_LEN("rem"), eCSSUnit_RootEM, VARIANT_LENGTH }, 1.6048 + { STR_WITH_LEN("mm"), eCSSUnit_Millimeter, VARIANT_LENGTH }, 1.6049 + { STR_WITH_LEN("mozmm"), eCSSUnit_PhysicalMillimeter, VARIANT_LENGTH }, 1.6050 + { STR_WITH_LEN("vw"), eCSSUnit_ViewportWidth, VARIANT_LENGTH }, 1.6051 + { STR_WITH_LEN("vh"), eCSSUnit_ViewportHeight, VARIANT_LENGTH }, 1.6052 + { STR_WITH_LEN("vmin"), eCSSUnit_ViewportMin, VARIANT_LENGTH }, 1.6053 + { STR_WITH_LEN("vmax"), eCSSUnit_ViewportMax, VARIANT_LENGTH }, 1.6054 + { STR_WITH_LEN("pc"), eCSSUnit_Pica, VARIANT_LENGTH }, 1.6055 + { STR_WITH_LEN("deg"), eCSSUnit_Degree, VARIANT_ANGLE }, 1.6056 + { STR_WITH_LEN("grad"), eCSSUnit_Grad, VARIANT_ANGLE }, 1.6057 + { STR_WITH_LEN("rad"), eCSSUnit_Radian, VARIANT_ANGLE }, 1.6058 + { STR_WITH_LEN("turn"), eCSSUnit_Turn, VARIANT_ANGLE }, 1.6059 + { STR_WITH_LEN("hz"), eCSSUnit_Hertz, VARIANT_FREQUENCY }, 1.6060 + { STR_WITH_LEN("khz"), eCSSUnit_Kilohertz, VARIANT_FREQUENCY }, 1.6061 + { STR_WITH_LEN("s"), eCSSUnit_Seconds, VARIANT_TIME }, 1.6062 + { STR_WITH_LEN("ms"), eCSSUnit_Milliseconds, VARIANT_TIME } 1.6063 +}; 1.6064 + 1.6065 +#undef STR_WITH_LEN 1.6066 + 1.6067 +bool 1.6068 +CSSParserImpl::TranslateDimension(nsCSSValue& aValue, 1.6069 + int32_t aVariantMask, 1.6070 + float aNumber, 1.6071 + const nsString& aUnit) 1.6072 +{ 1.6073 + nsCSSUnit units; 1.6074 + int32_t type = 0; 1.6075 + if (!aUnit.IsEmpty()) { 1.6076 + uint32_t i; 1.6077 + for (i = 0; i < ArrayLength(UnitData); ++i) { 1.6078 + if (aUnit.LowerCaseEqualsASCII(UnitData[i].name, 1.6079 + UnitData[i].length)) { 1.6080 + units = UnitData[i].unit; 1.6081 + type = UnitData[i].type; 1.6082 + break; 1.6083 + } 1.6084 + } 1.6085 + 1.6086 + if (i == ArrayLength(UnitData)) { 1.6087 + // Unknown unit 1.6088 + return false; 1.6089 + } 1.6090 + 1.6091 + if (!mViewportUnitsEnabled && 1.6092 + (eCSSUnit_ViewportWidth == units || 1.6093 + eCSSUnit_ViewportHeight == units || 1.6094 + eCSSUnit_ViewportMin == units || 1.6095 + eCSSUnit_ViewportMax == units)) { 1.6096 + // Viewport units aren't allowed right now, probably because we're 1.6097 + // inside an @page declaration. Fail. 1.6098 + return false; 1.6099 + } 1.6100 + } else { 1.6101 + // Must be a zero number... 1.6102 + NS_ASSERTION(0 == aNumber, "numbers without units must be 0"); 1.6103 + if ((VARIANT_LENGTH & aVariantMask) != 0) { 1.6104 + units = eCSSUnit_Pixel; 1.6105 + type = VARIANT_LENGTH; 1.6106 + } 1.6107 + else if ((VARIANT_ANGLE & aVariantMask) != 0) { 1.6108 + NS_ASSERTION(aVariantMask & VARIANT_ZERO_ANGLE, 1.6109 + "must have allowed zero angle"); 1.6110 + units = eCSSUnit_Degree; 1.6111 + type = VARIANT_ANGLE; 1.6112 + } 1.6113 + else { 1.6114 + NS_ERROR("Variant mask does not include dimension; why were we called?"); 1.6115 + return false; 1.6116 + } 1.6117 + } 1.6118 + if ((type & aVariantMask) != 0) { 1.6119 + aValue.SetFloatValue(aNumber, units); 1.6120 + return true; 1.6121 + } 1.6122 + return false; 1.6123 +} 1.6124 + 1.6125 +// Note that this does include VARIANT_CALC, which is numeric. This is 1.6126 +// because calc() parsing, as proposed, drops range restrictions inside 1.6127 +// the calc() expression and clamps the result of the calculation to the 1.6128 +// range. 1.6129 +#define VARIANT_ALL_NONNUMERIC \ 1.6130 + VARIANT_KEYWORD | \ 1.6131 + VARIANT_COLOR | \ 1.6132 + VARIANT_URL | \ 1.6133 + VARIANT_STRING | \ 1.6134 + VARIANT_COUNTER | \ 1.6135 + VARIANT_ATTR | \ 1.6136 + VARIANT_IDENTIFIER | \ 1.6137 + VARIANT_IDENTIFIER_NO_INHERIT | \ 1.6138 + VARIANT_AUTO | \ 1.6139 + VARIANT_INHERIT | \ 1.6140 + VARIANT_NONE | \ 1.6141 + VARIANT_NORMAL | \ 1.6142 + VARIANT_SYSFONT | \ 1.6143 + VARIANT_GRADIENT | \ 1.6144 + VARIANT_TIMING_FUNCTION | \ 1.6145 + VARIANT_ALL | \ 1.6146 + VARIANT_CALC | \ 1.6147 + VARIANT_OPENTYPE_SVG_KEYWORD 1.6148 + 1.6149 +// Note that callers passing VARIANT_CALC in aVariantMask will get 1.6150 +// full-range parsing inside the calc() expression, and the code that 1.6151 +// computes the calc will be required to clamp the resulting value to an 1.6152 +// appropriate range. 1.6153 +bool 1.6154 +CSSParserImpl::ParseNonNegativeVariant(nsCSSValue& aValue, 1.6155 + int32_t aVariantMask, 1.6156 + const KTableValue aKeywordTable[]) 1.6157 +{ 1.6158 + // The variant mask must only contain non-numeric variants or the ones 1.6159 + // that we specifically handle. 1.6160 + NS_ABORT_IF_FALSE((aVariantMask & ~(VARIANT_ALL_NONNUMERIC | 1.6161 + VARIANT_NUMBER | 1.6162 + VARIANT_LENGTH | 1.6163 + VARIANT_PERCENT | 1.6164 + VARIANT_INTEGER)) == 0, 1.6165 + "need to update code below to handle additional variants"); 1.6166 + 1.6167 + if (ParseVariant(aValue, aVariantMask, aKeywordTable)) { 1.6168 + if (eCSSUnit_Number == aValue.GetUnit() || 1.6169 + aValue.IsLengthUnit()){ 1.6170 + if (aValue.GetFloatValue() < 0) { 1.6171 + UngetToken(); 1.6172 + return false; 1.6173 + } 1.6174 + } 1.6175 + else if (aValue.GetUnit() == eCSSUnit_Percent) { 1.6176 + if (aValue.GetPercentValue() < 0) { 1.6177 + UngetToken(); 1.6178 + return false; 1.6179 + } 1.6180 + } else if (aValue.GetUnit() == eCSSUnit_Integer) { 1.6181 + if (aValue.GetIntValue() < 0) { 1.6182 + UngetToken(); 1.6183 + return false; 1.6184 + } 1.6185 + } 1.6186 + return true; 1.6187 + } 1.6188 + return false; 1.6189 +} 1.6190 + 1.6191 +// Note that callers passing VARIANT_CALC in aVariantMask will get 1.6192 +// full-range parsing inside the calc() expression, and the code that 1.6193 +// computes the calc will be required to clamp the resulting value to an 1.6194 +// appropriate range. 1.6195 +bool 1.6196 +CSSParserImpl::ParseOneOrLargerVariant(nsCSSValue& aValue, 1.6197 + int32_t aVariantMask, 1.6198 + const KTableValue aKeywordTable[]) 1.6199 +{ 1.6200 + // The variant mask must only contain non-numeric variants or the ones 1.6201 + // that we specifically handle. 1.6202 + NS_ABORT_IF_FALSE((aVariantMask & ~(VARIANT_ALL_NONNUMERIC | 1.6203 + VARIANT_NUMBER | 1.6204 + VARIANT_INTEGER)) == 0, 1.6205 + "need to update code below to handle additional variants"); 1.6206 + 1.6207 + if (ParseVariant(aValue, aVariantMask, aKeywordTable)) { 1.6208 + if (aValue.GetUnit() == eCSSUnit_Integer) { 1.6209 + if (aValue.GetIntValue() < 1) { 1.6210 + UngetToken(); 1.6211 + return false; 1.6212 + } 1.6213 + } else if (eCSSUnit_Number == aValue.GetUnit()) { 1.6214 + if (aValue.GetFloatValue() < 1.0f) { 1.6215 + UngetToken(); 1.6216 + return false; 1.6217 + } 1.6218 + } 1.6219 + return true; 1.6220 + } 1.6221 + return false; 1.6222 +} 1.6223 + 1.6224 +// Assigns to aValue iff it returns true. 1.6225 +bool 1.6226 +CSSParserImpl::ParseVariant(nsCSSValue& aValue, 1.6227 + int32_t aVariantMask, 1.6228 + const KTableValue aKeywordTable[]) 1.6229 +{ 1.6230 + NS_ASSERTION(!(mHashlessColorQuirk && (aVariantMask & VARIANT_COLOR)) || 1.6231 + !(aVariantMask & VARIANT_NUMBER), 1.6232 + "can't distinguish colors from numbers"); 1.6233 + NS_ASSERTION(!(mHashlessColorQuirk && (aVariantMask & VARIANT_COLOR)) || 1.6234 + !(mUnitlessLengthQuirk && (aVariantMask & VARIANT_LENGTH)), 1.6235 + "can't distinguish colors from lengths"); 1.6236 + NS_ASSERTION(!(mUnitlessLengthQuirk && (aVariantMask & VARIANT_LENGTH)) || 1.6237 + !(aVariantMask & VARIANT_NUMBER), 1.6238 + "can't distinguish lengths from numbers"); 1.6239 + NS_ABORT_IF_FALSE(!(aVariantMask & VARIANT_IDENTIFIER) || 1.6240 + !(aVariantMask & VARIANT_IDENTIFIER_NO_INHERIT), 1.6241 + "must not set both VARIANT_IDENTIFIER and " 1.6242 + "VARIANT_IDENTIFIER_NO_INHERIT"); 1.6243 + 1.6244 + if (!GetToken(true)) { 1.6245 + return false; 1.6246 + } 1.6247 + nsCSSToken* tk = &mToken; 1.6248 + if (((aVariantMask & (VARIANT_AHK | VARIANT_NORMAL | VARIANT_NONE | VARIANT_ALL)) != 0) && 1.6249 + (eCSSToken_Ident == tk->mType)) { 1.6250 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(tk->mIdent); 1.6251 + if (eCSSKeyword_UNKNOWN < keyword) { // known keyword 1.6252 + if ((aVariantMask & VARIANT_AUTO) != 0) { 1.6253 + if (eCSSKeyword_auto == keyword) { 1.6254 + aValue.SetAutoValue(); 1.6255 + return true; 1.6256 + } 1.6257 + } 1.6258 + if ((aVariantMask & VARIANT_INHERIT) != 0) { 1.6259 + // XXX Should we check IsParsingCompoundProperty, or do all 1.6260 + // callers handle it? (Not all callers set it, though, since 1.6261 + // they want the quirks that are disabled by setting it.) 1.6262 + 1.6263 + // IMPORTANT: If new keywords are added here, 1.6264 + // they probably need to be added in ParseCustomIdent as well. 1.6265 + if (eCSSKeyword_inherit == keyword) { 1.6266 + aValue.SetInheritValue(); 1.6267 + return true; 1.6268 + } 1.6269 + else if (eCSSKeyword_initial == keyword) { 1.6270 + aValue.SetInitialValue(); 1.6271 + return true; 1.6272 + } 1.6273 + else if (eCSSKeyword_unset == keyword && 1.6274 + nsLayoutUtils::UnsetValueEnabled()) { 1.6275 + aValue.SetUnsetValue(); 1.6276 + return true; 1.6277 + } 1.6278 + } 1.6279 + if ((aVariantMask & VARIANT_NONE) != 0) { 1.6280 + if (eCSSKeyword_none == keyword) { 1.6281 + aValue.SetNoneValue(); 1.6282 + return true; 1.6283 + } 1.6284 + } 1.6285 + if ((aVariantMask & VARIANT_ALL) != 0) { 1.6286 + if (eCSSKeyword_all == keyword) { 1.6287 + aValue.SetAllValue(); 1.6288 + return true; 1.6289 + } 1.6290 + } 1.6291 + if ((aVariantMask & VARIANT_NORMAL) != 0) { 1.6292 + if (eCSSKeyword_normal == keyword) { 1.6293 + aValue.SetNormalValue(); 1.6294 + return true; 1.6295 + } 1.6296 + } 1.6297 + if ((aVariantMask & VARIANT_SYSFONT) != 0) { 1.6298 + if (eCSSKeyword__moz_use_system_font == keyword && 1.6299 + !IsParsingCompoundProperty()) { 1.6300 + aValue.SetSystemFontValue(); 1.6301 + return true; 1.6302 + } 1.6303 + } 1.6304 + if ((aVariantMask & VARIANT_OPENTYPE_SVG_KEYWORD) != 0) { 1.6305 + static bool sOpentypeSVGEnabled; 1.6306 + static bool sOpentypeSVGEnabledCached = false; 1.6307 + if (!sOpentypeSVGEnabledCached) { 1.6308 + sOpentypeSVGEnabledCached = true; 1.6309 + Preferences::AddBoolVarCache(&sOpentypeSVGEnabled, 1.6310 + "gfx.font_rendering.opentype_svg.enabled"); 1.6311 + } 1.6312 + if (sOpentypeSVGEnabled) { 1.6313 + aVariantMask |= VARIANT_KEYWORD; 1.6314 + } 1.6315 + } 1.6316 + if ((aVariantMask & VARIANT_KEYWORD) != 0) { 1.6317 + int32_t value; 1.6318 + if (nsCSSProps::FindKeyword(keyword, aKeywordTable, value)) { 1.6319 + aValue.SetIntValue(value, eCSSUnit_Enumerated); 1.6320 + return true; 1.6321 + } 1.6322 + } 1.6323 + } 1.6324 + } 1.6325 + // Check VARIANT_NUMBER and VARIANT_INTEGER before VARIANT_LENGTH or 1.6326 + // VARIANT_ZERO_ANGLE. 1.6327 + if (((aVariantMask & VARIANT_NUMBER) != 0) && 1.6328 + (eCSSToken_Number == tk->mType)) { 1.6329 + aValue.SetFloatValue(tk->mNumber, eCSSUnit_Number); 1.6330 + return true; 1.6331 + } 1.6332 + if (((aVariantMask & VARIANT_INTEGER) != 0) && 1.6333 + (eCSSToken_Number == tk->mType) && tk->mIntegerValid) { 1.6334 + aValue.SetIntValue(tk->mInteger, eCSSUnit_Integer); 1.6335 + return true; 1.6336 + } 1.6337 + if (((aVariantMask & (VARIANT_LENGTH | VARIANT_ANGLE | 1.6338 + VARIANT_FREQUENCY | VARIANT_TIME)) != 0 && 1.6339 + eCSSToken_Dimension == tk->mType) || 1.6340 + ((aVariantMask & (VARIANT_LENGTH | VARIANT_ZERO_ANGLE)) != 0 && 1.6341 + eCSSToken_Number == tk->mType && 1.6342 + tk->mNumber == 0.0f)) { 1.6343 + if (((aVariantMask & VARIANT_POSITIVE_DIMENSION) != 0 && 1.6344 + tk->mNumber <= 0.0) || 1.6345 + ((aVariantMask & VARIANT_NONNEGATIVE_DIMENSION) != 0 && 1.6346 + tk->mNumber < 0.0)) { 1.6347 + UngetToken(); 1.6348 + return false; 1.6349 + } 1.6350 + if (TranslateDimension(aValue, aVariantMask, tk->mNumber, tk->mIdent)) { 1.6351 + return true; 1.6352 + } 1.6353 + // Put the token back; we didn't parse it, so we shouldn't consume it 1.6354 + UngetToken(); 1.6355 + return false; 1.6356 + } 1.6357 + if (((aVariantMask & VARIANT_PERCENT) != 0) && 1.6358 + (eCSSToken_Percentage == tk->mType)) { 1.6359 + aValue.SetPercentValue(tk->mNumber); 1.6360 + return true; 1.6361 + } 1.6362 + if (mUnitlessLengthQuirk) { // NONSTANDARD: Nav interprets unitless numbers as px 1.6363 + if (((aVariantMask & VARIANT_LENGTH) != 0) && 1.6364 + (eCSSToken_Number == tk->mType)) { 1.6365 + aValue.SetFloatValue(tk->mNumber, eCSSUnit_Pixel); 1.6366 + return true; 1.6367 + } 1.6368 + } 1.6369 + 1.6370 + if (IsSVGMode() && !IsParsingCompoundProperty()) { 1.6371 + // STANDARD: SVG Spec states that lengths and coordinates can be unitless 1.6372 + // in which case they default to user-units (1 px = 1 user unit) 1.6373 + if (((aVariantMask & VARIANT_LENGTH) != 0) && 1.6374 + (eCSSToken_Number == tk->mType)) { 1.6375 + aValue.SetFloatValue(tk->mNumber, eCSSUnit_Pixel); 1.6376 + return true; 1.6377 + } 1.6378 + } 1.6379 + 1.6380 + if (((aVariantMask & VARIANT_URL) != 0) && 1.6381 + eCSSToken_URL == tk->mType) { 1.6382 + SetValueToURL(aValue, tk->mIdent); 1.6383 + return true; 1.6384 + } 1.6385 + if ((aVariantMask & VARIANT_GRADIENT) != 0 && 1.6386 + eCSSToken_Function == tk->mType) { 1.6387 + // a generated gradient 1.6388 + nsDependentString tmp(tk->mIdent, 0); 1.6389 + bool isLegacy = false; 1.6390 + if (StringBeginsWith(tmp, NS_LITERAL_STRING("-moz-"))) { 1.6391 + tmp.Rebind(tmp, 5); 1.6392 + isLegacy = true; 1.6393 + } 1.6394 + bool isRepeating = false; 1.6395 + if (StringBeginsWith(tmp, NS_LITERAL_STRING("repeating-"))) { 1.6396 + tmp.Rebind(tmp, 10); 1.6397 + isRepeating = true; 1.6398 + } 1.6399 + 1.6400 + if (tmp.LowerCaseEqualsLiteral("linear-gradient")) { 1.6401 + return ParseLinearGradient(aValue, isRepeating, isLegacy); 1.6402 + } 1.6403 + if (tmp.LowerCaseEqualsLiteral("radial-gradient")) { 1.6404 + return ParseRadialGradient(aValue, isRepeating, isLegacy); 1.6405 + } 1.6406 + } 1.6407 + if ((aVariantMask & VARIANT_IMAGE_RECT) != 0 && 1.6408 + eCSSToken_Function == tk->mType && 1.6409 + tk->mIdent.LowerCaseEqualsLiteral("-moz-image-rect")) { 1.6410 + return ParseImageRect(aValue); 1.6411 + } 1.6412 + if ((aVariantMask & VARIANT_ELEMENT) != 0 && 1.6413 + eCSSToken_Function == tk->mType && 1.6414 + tk->mIdent.LowerCaseEqualsLiteral("-moz-element")) { 1.6415 + return ParseElement(aValue); 1.6416 + } 1.6417 + if ((aVariantMask & VARIANT_COLOR) != 0) { 1.6418 + if (mHashlessColorQuirk || // NONSTANDARD: Nav interprets 'xxyyzz' values even without '#' prefix 1.6419 + (eCSSToken_ID == tk->mType) || 1.6420 + (eCSSToken_Hash == tk->mType) || 1.6421 + (eCSSToken_Ident == tk->mType) || 1.6422 + ((eCSSToken_Function == tk->mType) && 1.6423 + (tk->mIdent.LowerCaseEqualsLiteral("rgb") || 1.6424 + tk->mIdent.LowerCaseEqualsLiteral("hsl") || 1.6425 + tk->mIdent.LowerCaseEqualsLiteral("rgba") || 1.6426 + tk->mIdent.LowerCaseEqualsLiteral("hsla")))) 1.6427 + { 1.6428 + // Put token back so that parse color can get it 1.6429 + UngetToken(); 1.6430 + if (ParseColor(aValue)) { 1.6431 + return true; 1.6432 + } 1.6433 + return false; 1.6434 + } 1.6435 + } 1.6436 + if (((aVariantMask & VARIANT_STRING) != 0) && 1.6437 + (eCSSToken_String == tk->mType)) { 1.6438 + nsAutoString buffer; 1.6439 + buffer.Append(tk->mIdent); 1.6440 + aValue.SetStringValue(buffer, eCSSUnit_String); 1.6441 + return true; 1.6442 + } 1.6443 + if (((aVariantMask & 1.6444 + (VARIANT_IDENTIFIER | VARIANT_IDENTIFIER_NO_INHERIT)) != 0) && 1.6445 + (eCSSToken_Ident == tk->mType) && 1.6446 + ((aVariantMask & VARIANT_IDENTIFIER) != 0 || 1.6447 + !(tk->mIdent.LowerCaseEqualsLiteral("inherit") || 1.6448 + tk->mIdent.LowerCaseEqualsLiteral("initial") || 1.6449 + (tk->mIdent.LowerCaseEqualsLiteral("unset") && 1.6450 + nsLayoutUtils::UnsetValueEnabled())))) { 1.6451 + aValue.SetStringValue(tk->mIdent, eCSSUnit_Ident); 1.6452 + return true; 1.6453 + } 1.6454 + if (((aVariantMask & VARIANT_COUNTER) != 0) && 1.6455 + (eCSSToken_Function == tk->mType) && 1.6456 + (tk->mIdent.LowerCaseEqualsLiteral("counter") || 1.6457 + tk->mIdent.LowerCaseEqualsLiteral("counters"))) { 1.6458 + return ParseCounter(aValue); 1.6459 + } 1.6460 + if (((aVariantMask & VARIANT_ATTR) != 0) && 1.6461 + (eCSSToken_Function == tk->mType) && 1.6462 + tk->mIdent.LowerCaseEqualsLiteral("attr")) { 1.6463 + if (!ParseAttr(aValue)) { 1.6464 + SkipUntil(')'); 1.6465 + return false; 1.6466 + } 1.6467 + return true; 1.6468 + } 1.6469 + if (((aVariantMask & VARIANT_TIMING_FUNCTION) != 0) && 1.6470 + (eCSSToken_Function == tk->mType)) { 1.6471 + if (tk->mIdent.LowerCaseEqualsLiteral("cubic-bezier")) { 1.6472 + if (!ParseTransitionTimingFunctionValues(aValue)) { 1.6473 + SkipUntil(')'); 1.6474 + return false; 1.6475 + } 1.6476 + return true; 1.6477 + } 1.6478 + if (tk->mIdent.LowerCaseEqualsLiteral("steps")) { 1.6479 + if (!ParseTransitionStepTimingFunctionValues(aValue)) { 1.6480 + SkipUntil(')'); 1.6481 + return false; 1.6482 + } 1.6483 + return true; 1.6484 + } 1.6485 + } 1.6486 + if ((aVariantMask & VARIANT_CALC) && 1.6487 + (eCSSToken_Function == tk->mType) && 1.6488 + (tk->mIdent.LowerCaseEqualsLiteral("calc") || 1.6489 + tk->mIdent.LowerCaseEqualsLiteral("-moz-calc"))) { 1.6490 + // calc() currently allows only lengths and percents inside it. 1.6491 + return ParseCalc(aValue, aVariantMask & VARIANT_LP); 1.6492 + } 1.6493 + 1.6494 + UngetToken(); 1.6495 + return false; 1.6496 +} 1.6497 + 1.6498 +bool 1.6499 +CSSParserImpl::ParseCustomIdent(nsCSSValue& aValue, 1.6500 + const nsAutoString& aIdentValue, 1.6501 + const nsCSSKeyword aExcludedKeywords[], 1.6502 + const nsCSSProps::KTableValue aPropertyKTable[]) 1.6503 +{ 1.6504 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aIdentValue); 1.6505 + if (keyword == eCSSKeyword_UNKNOWN) { 1.6506 + // Fast path for identifiers that are not known CSS keywords: 1.6507 + aValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident); 1.6508 + return true; 1.6509 + } 1.6510 + if (keyword == eCSSKeyword_inherit || 1.6511 + keyword == eCSSKeyword_initial || 1.6512 + keyword == eCSSKeyword_unset || 1.6513 + keyword == eCSSKeyword_default || 1.6514 + (aPropertyKTable && 1.6515 + nsCSSProps::FindIndexOfKeyword(keyword, aPropertyKTable) >= 0)) { 1.6516 + return false; 1.6517 + } 1.6518 + if (aExcludedKeywords) { 1.6519 + for (uint32_t i = 0;; i++) { 1.6520 + nsCSSKeyword excludedKeyword = aExcludedKeywords[i]; 1.6521 + if (excludedKeyword == eCSSKeyword_UNKNOWN) { 1.6522 + break; 1.6523 + } 1.6524 + if (excludedKeyword == keyword) { 1.6525 + return false; 1.6526 + } 1.6527 + } 1.6528 + } 1.6529 + aValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident); 1.6530 + return true; 1.6531 +} 1.6532 + 1.6533 +bool 1.6534 +CSSParserImpl::ParseCounter(nsCSSValue& aValue) 1.6535 +{ 1.6536 + nsCSSUnit unit = (mToken.mIdent.LowerCaseEqualsLiteral("counter") ? 1.6537 + eCSSUnit_Counter : eCSSUnit_Counters); 1.6538 + 1.6539 + // A non-iterative for loop to break out when an error occurs. 1.6540 + for (;;) { 1.6541 + if (!GetToken(true)) { 1.6542 + break; 1.6543 + } 1.6544 + if (eCSSToken_Ident != mToken.mType) { 1.6545 + UngetToken(); 1.6546 + break; 1.6547 + } 1.6548 + 1.6549 + nsRefPtr<nsCSSValue::Array> val = 1.6550 + nsCSSValue::Array::Create(unit == eCSSUnit_Counter ? 2 : 3); 1.6551 + 1.6552 + val->Item(0).SetStringValue(mToken.mIdent, eCSSUnit_Ident); 1.6553 + 1.6554 + if (eCSSUnit_Counters == unit) { 1.6555 + // must have a comma and then a separator string 1.6556 + if (!ExpectSymbol(',', true) || !GetToken(true)) { 1.6557 + break; 1.6558 + } 1.6559 + if (eCSSToken_String != mToken.mType) { 1.6560 + UngetToken(); 1.6561 + break; 1.6562 + } 1.6563 + val->Item(1).SetStringValue(mToken.mIdent, eCSSUnit_String); 1.6564 + } 1.6565 + 1.6566 + // get optional type 1.6567 + int32_t type = NS_STYLE_LIST_STYLE_DECIMAL; 1.6568 + if (ExpectSymbol(',', true)) { 1.6569 + if (!GetToken(true)) { 1.6570 + break; 1.6571 + } 1.6572 + nsCSSKeyword keyword; 1.6573 + if (eCSSToken_Ident != mToken.mType || 1.6574 + (keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent)) == 1.6575 + eCSSKeyword_UNKNOWN || 1.6576 + !nsCSSProps::FindKeyword(keyword, nsCSSProps::kListStyleKTable, 1.6577 + type)) { 1.6578 + UngetToken(); 1.6579 + break; 1.6580 + } 1.6581 + } 1.6582 + 1.6583 + int32_t typeItem = eCSSUnit_Counters == unit ? 2 : 1; 1.6584 + val->Item(typeItem).SetIntValue(type, eCSSUnit_Enumerated); 1.6585 + 1.6586 + if (!ExpectSymbol(')', true)) { 1.6587 + break; 1.6588 + } 1.6589 + 1.6590 + aValue.SetArrayValue(val, unit); 1.6591 + return true; 1.6592 + } 1.6593 + 1.6594 + SkipUntil(')'); 1.6595 + return false; 1.6596 +} 1.6597 + 1.6598 +bool 1.6599 +CSSParserImpl::ParseAttr(nsCSSValue& aValue) 1.6600 +{ 1.6601 + if (!GetToken(true)) { 1.6602 + return false; 1.6603 + } 1.6604 + 1.6605 + nsAutoString attr; 1.6606 + if (eCSSToken_Ident == mToken.mType) { // attr name or namespace 1.6607 + nsAutoString holdIdent(mToken.mIdent); 1.6608 + if (ExpectSymbol('|', false)) { // namespace 1.6609 + int32_t nameSpaceID = GetNamespaceIdForPrefix(holdIdent); 1.6610 + if (nameSpaceID == kNameSpaceID_Unknown) { 1.6611 + return false; 1.6612 + } 1.6613 + attr.AppendInt(nameSpaceID, 10); 1.6614 + attr.Append(char16_t('|')); 1.6615 + if (! GetToken(false)) { 1.6616 + REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); 1.6617 + return false; 1.6618 + } 1.6619 + if (eCSSToken_Ident == mToken.mType) { 1.6620 + attr.Append(mToken.mIdent); 1.6621 + } 1.6622 + else { 1.6623 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); 1.6624 + UngetToken(); 1.6625 + return false; 1.6626 + } 1.6627 + } 1.6628 + else { // no namespace 1.6629 + attr = holdIdent; 1.6630 + } 1.6631 + } 1.6632 + else if (mToken.IsSymbol('*')) { // namespace wildcard 1.6633 + // Wildcard namespace makes no sense here and is not allowed 1.6634 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); 1.6635 + UngetToken(); 1.6636 + return false; 1.6637 + } 1.6638 + else if (mToken.IsSymbol('|')) { // explicit NO namespace 1.6639 + if (! GetToken(false)) { 1.6640 + REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); 1.6641 + return false; 1.6642 + } 1.6643 + if (eCSSToken_Ident == mToken.mType) { 1.6644 + attr.Append(mToken.mIdent); 1.6645 + } 1.6646 + else { 1.6647 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); 1.6648 + UngetToken(); 1.6649 + return false; 1.6650 + } 1.6651 + } 1.6652 + else { 1.6653 + REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected); 1.6654 + UngetToken(); 1.6655 + return false; 1.6656 + } 1.6657 + if (!ExpectSymbol(')', true)) { 1.6658 + return false; 1.6659 + } 1.6660 + aValue.SetStringValue(attr, eCSSUnit_Attr); 1.6661 + return true; 1.6662 +} 1.6663 + 1.6664 +bool 1.6665 +CSSParserImpl::SetValueToURL(nsCSSValue& aValue, const nsString& aURL) 1.6666 +{ 1.6667 + if (!mSheetPrincipal) { 1.6668 + NS_NOTREACHED("Codepaths that expect to parse URLs MUST pass in an " 1.6669 + "origin principal"); 1.6670 + return false; 1.6671 + } 1.6672 + 1.6673 + nsRefPtr<nsStringBuffer> buffer(nsCSSValue::BufferFromString(aURL)); 1.6674 + 1.6675 + // Note: urlVal retains its own reference to |buffer|. 1.6676 + mozilla::css::URLValue *urlVal = 1.6677 + new mozilla::css::URLValue(buffer, mBaseURI, mSheetURI, mSheetPrincipal); 1.6678 + aValue.SetURLValue(urlVal); 1.6679 + return true; 1.6680 +} 1.6681 + 1.6682 +/** 1.6683 + * Parse the image-orientation property, which has the grammar: 1.6684 + * <angle> flip? | flip | from-image 1.6685 + */ 1.6686 +bool 1.6687 +CSSParserImpl::ParseImageOrientation(nsCSSValue& aValue) 1.6688 +{ 1.6689 + if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) { 1.6690 + // 'inherit', 'initial' and 'unset' must be alone 1.6691 + return true; 1.6692 + } 1.6693 + 1.6694 + // Check for an angle with optional 'flip'. 1.6695 + nsCSSValue angle; 1.6696 + if (ParseVariant(angle, VARIANT_ANGLE, nullptr)) { 1.6697 + nsCSSValue flip; 1.6698 + 1.6699 + if (ParseVariant(flip, VARIANT_KEYWORD, nsCSSProps::kImageOrientationFlipKTable)) { 1.6700 + nsRefPtr<nsCSSValue::Array> array = nsCSSValue::Array::Create(2); 1.6701 + array->Item(0) = angle; 1.6702 + array->Item(1) = flip; 1.6703 + aValue.SetArrayValue(array, eCSSUnit_Array); 1.6704 + } else { 1.6705 + aValue = angle; 1.6706 + } 1.6707 + 1.6708 + return true; 1.6709 + } 1.6710 + 1.6711 + // The remaining possibilities (bare 'flip' and 'from-image') are both 1.6712 + // keywords, so we can handle them at the same time. 1.6713 + nsCSSValue keyword; 1.6714 + if (ParseVariant(keyword, VARIANT_KEYWORD, nsCSSProps::kImageOrientationKTable)) { 1.6715 + aValue = keyword; 1.6716 + return true; 1.6717 + } 1.6718 + 1.6719 + // All possibilities failed. 1.6720 + return false; 1.6721 +} 1.6722 + 1.6723 +/** 1.6724 + * Parse the arguments of -moz-image-rect() function. 1.6725 + * -moz-image-rect(<uri>, <top>, <right>, <bottom>, <left>) 1.6726 + */ 1.6727 +bool 1.6728 +CSSParserImpl::ParseImageRect(nsCSSValue& aImage) 1.6729 +{ 1.6730 + // A non-iterative for loop to break out when an error occurs. 1.6731 + for (;;) { 1.6732 + nsCSSValue newFunction; 1.6733 + static const uint32_t kNumArgs = 5; 1.6734 + nsCSSValue::Array* func = 1.6735 + newFunction.InitFunction(eCSSKeyword__moz_image_rect, kNumArgs); 1.6736 + 1.6737 + // func->Item(0) is reserved for the function name. 1.6738 + nsCSSValue& url = func->Item(1); 1.6739 + nsCSSValue& top = func->Item(2); 1.6740 + nsCSSValue& right = func->Item(3); 1.6741 + nsCSSValue& bottom = func->Item(4); 1.6742 + nsCSSValue& left = func->Item(5); 1.6743 + 1.6744 + nsAutoString urlString; 1.6745 + if (!ParseURLOrString(urlString) || 1.6746 + !SetValueToURL(url, urlString) || 1.6747 + !ExpectSymbol(',', true)) { 1.6748 + break; 1.6749 + } 1.6750 + 1.6751 + static const int32_t VARIANT_SIDE = VARIANT_NUMBER | VARIANT_PERCENT; 1.6752 + if (!ParseNonNegativeVariant(top, VARIANT_SIDE, nullptr) || 1.6753 + !ExpectSymbol(',', true) || 1.6754 + !ParseNonNegativeVariant(right, VARIANT_SIDE, nullptr) || 1.6755 + !ExpectSymbol(',', true) || 1.6756 + !ParseNonNegativeVariant(bottom, VARIANT_SIDE, nullptr) || 1.6757 + !ExpectSymbol(',', true) || 1.6758 + !ParseNonNegativeVariant(left, VARIANT_SIDE, nullptr) || 1.6759 + !ExpectSymbol(')', true)) 1.6760 + break; 1.6761 + 1.6762 + aImage = newFunction; 1.6763 + return true; 1.6764 + } 1.6765 + 1.6766 + SkipUntil(')'); 1.6767 + return false; 1.6768 +} 1.6769 + 1.6770 +// <element>: -moz-element(# <element_id> ) 1.6771 +bool 1.6772 +CSSParserImpl::ParseElement(nsCSSValue& aValue) 1.6773 +{ 1.6774 + // A non-iterative for loop to break out when an error occurs. 1.6775 + for (;;) { 1.6776 + if (!GetToken(true)) 1.6777 + break; 1.6778 + 1.6779 + if (mToken.mType == eCSSToken_ID) { 1.6780 + aValue.SetStringValue(mToken.mIdent, eCSSUnit_Element); 1.6781 + } else { 1.6782 + UngetToken(); 1.6783 + break; 1.6784 + } 1.6785 + 1.6786 + if (!ExpectSymbol(')', true)) 1.6787 + break; 1.6788 + 1.6789 + return true; 1.6790 + } 1.6791 + 1.6792 + // If we detect a syntax error, we must match the opening parenthesis of the 1.6793 + // function with the closing parenthesis and skip all the tokens in between. 1.6794 + SkipUntil(')'); 1.6795 + return false; 1.6796 +} 1.6797 + 1.6798 +// flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] 1.6799 +bool 1.6800 +CSSParserImpl::ParseFlex() 1.6801 +{ 1.6802 + // First check for inherit / initial / unset 1.6803 + nsCSSValue tmpVal; 1.6804 + if (ParseVariant(tmpVal, VARIANT_INHERIT, nullptr)) { 1.6805 + AppendValue(eCSSProperty_flex_grow, tmpVal); 1.6806 + AppendValue(eCSSProperty_flex_shrink, tmpVal); 1.6807 + AppendValue(eCSSProperty_flex_basis, tmpVal); 1.6808 + return true; 1.6809 + } 1.6810 + 1.6811 + // Next, check for 'none' == '0 0 auto' 1.6812 + if (ParseVariant(tmpVal, VARIANT_NONE, nullptr)) { 1.6813 + AppendValue(eCSSProperty_flex_grow, nsCSSValue(0.0f, eCSSUnit_Number)); 1.6814 + AppendValue(eCSSProperty_flex_shrink, nsCSSValue(0.0f, eCSSUnit_Number)); 1.6815 + AppendValue(eCSSProperty_flex_basis, nsCSSValue(eCSSUnit_Auto)); 1.6816 + return true; 1.6817 + } 1.6818 + 1.6819 + // OK, try parsing our value as individual per-subproperty components: 1.6820 + // [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] 1.6821 + 1.6822 + // Each subproperty has a default value that it takes when it's omitted in a 1.6823 + // "flex" shorthand value. These default values are *only* for the shorthand 1.6824 + // syntax -- they're distinct from the subproperties' own initial values. We 1.6825 + // start with each subproperty at its default, as if we had "flex: 1 1 0%". 1.6826 + nsCSSValue flexGrow(1.0f, eCSSUnit_Number); 1.6827 + nsCSSValue flexShrink(1.0f, eCSSUnit_Number); 1.6828 + nsCSSValue flexBasis(0.0f, eCSSUnit_Percent); 1.6829 + 1.6830 + // OVERVIEW OF PARSING STRATEGY: 1.6831 + // ============================= 1.6832 + // a) Parse the first component as either flex-basis or flex-grow. 1.6833 + // b) If it wasn't flex-grow, parse the _next_ component as flex-grow. 1.6834 + // c) Now we've just parsed flex-grow -- so try parsing the next thing as 1.6835 + // flex-shrink. 1.6836 + // d) Finally: If we didn't get flex-basis at the beginning, try to parse 1.6837 + // it now, at the end. 1.6838 + // 1.6839 + // More details in each section below. 1.6840 + 1.6841 + uint32_t flexBasisVariantMask = 1.6842 + (nsCSSProps::ParserVariant(eCSSProperty_flex_basis) & ~(VARIANT_INHERIT)); 1.6843 + 1.6844 + // (a) Parse first component. It can be either be a 'flex-basis' value or a 1.6845 + // 'flex-grow' value, so we use the flex-basis-specific variant mask, along 1.6846 + // with VARIANT_NUMBER to accept 'flex-grow' values. 1.6847 + // 1.6848 + // NOTE: if we encounter unitless 0 here, we *must* interpret it as a 1.6849 + // 'flex-grow' value (a number), *not* as a 'flex-basis' value (a length). 1.6850 + // Conveniently, that's the behavior this combined variant-mask gives us -- 1.6851 + // it'll treat unitless 0 as a number. The flexbox spec requires this: 1.6852 + // "a unitless zero that is not already preceded by two flex factors must be 1.6853 + // interpreted as a flex factor. 1.6854 + if (!ParseNonNegativeVariant(tmpVal, flexBasisVariantMask | VARIANT_NUMBER, 1.6855 + nsCSSProps::kWidthKTable)) { 1.6856 + // First component was not a valid flex-basis or flex-grow value. Fail. 1.6857 + return false; 1.6858 + } 1.6859 + 1.6860 + // Record what we just parsed as either flex-basis or flex-grow: 1.6861 + bool wasFirstComponentFlexBasis = (tmpVal.GetUnit() != eCSSUnit_Number); 1.6862 + (wasFirstComponentFlexBasis ? flexBasis : flexGrow) = tmpVal; 1.6863 + 1.6864 + // (b) If we didn't get flex-grow yet, parse _next_ component as flex-grow. 1.6865 + bool doneParsing = false; 1.6866 + if (wasFirstComponentFlexBasis) { 1.6867 + if (ParseNonNegativeVariant(tmpVal, VARIANT_NUMBER, nullptr)) { 1.6868 + flexGrow = tmpVal; 1.6869 + } else { 1.6870 + // Failed to parse anything after our flex-basis -- that's fine. We can 1.6871 + // skip the remaining parsing. 1.6872 + doneParsing = true; 1.6873 + } 1.6874 + } 1.6875 + 1.6876 + if (!doneParsing) { 1.6877 + // (c) OK -- the last thing we parsed was flex-grow, so look for a 1.6878 + // flex-shrink in the next position. 1.6879 + if (ParseNonNegativeVariant(tmpVal, VARIANT_NUMBER, nullptr)) { 1.6880 + flexShrink = tmpVal; 1.6881 + } 1.6882 + 1.6883 + // d) Finally: If we didn't get flex-basis at the beginning, try to parse 1.6884 + // it now, at the end. 1.6885 + // 1.6886 + // NOTE: If we encounter unitless 0 in this final position, we'll parse it 1.6887 + // as a 'flex-basis' value. That's OK, because we know it must have 1.6888 + // been "preceded by 2 flex factors" (justification below), which gets us 1.6889 + // out of the spec's requirement of otherwise having to treat unitless 0 1.6890 + // as a flex factor. 1.6891 + // 1.6892 + // JUSTIFICATION: How do we know that a unitless 0 here must have been 1.6893 + // preceded by 2 flex factors? Well, suppose we had a unitless 0 that 1.6894 + // was preceded by only 1 flex factor. Then, we would have already 1.6895 + // accepted this unitless 0 as the 'flex-shrink' value, up above (since 1.6896 + // it's a valid flex-shrink value), and we'd have moved on to the next 1.6897 + // token (if any). And of course, if we instead had a unitless 0 preceded 1.6898 + // by *no* flex factors (if it were the first token), we would've already 1.6899 + // parsed it in our very first call to ParseNonNegativeVariant(). So, any 1.6900 + // unitless 0 encountered here *must* have been preceded by 2 flex factors. 1.6901 + if (!wasFirstComponentFlexBasis && 1.6902 + ParseNonNegativeVariant(tmpVal, flexBasisVariantMask, 1.6903 + nsCSSProps::kWidthKTable)) { 1.6904 + flexBasis = tmpVal; 1.6905 + } 1.6906 + } 1.6907 + 1.6908 + AppendValue(eCSSProperty_flex_grow, flexGrow); 1.6909 + AppendValue(eCSSProperty_flex_shrink, flexShrink); 1.6910 + AppendValue(eCSSProperty_flex_basis, flexBasis); 1.6911 + 1.6912 + return true; 1.6913 +} 1.6914 + 1.6915 +// flex-flow: <flex-direction> || <flex-wrap> 1.6916 +bool 1.6917 +CSSParserImpl::ParseFlexFlow() 1.6918 +{ 1.6919 + static const nsCSSProperty kFlexFlowSubprops[] = { 1.6920 + eCSSProperty_flex_direction, 1.6921 + eCSSProperty_flex_wrap 1.6922 + }; 1.6923 + const size_t numProps = MOZ_ARRAY_LENGTH(kFlexFlowSubprops); 1.6924 + nsCSSValue values[numProps]; 1.6925 + 1.6926 + int32_t found = ParseChoice(values, kFlexFlowSubprops, numProps); 1.6927 + 1.6928 + // Bail if we didn't successfully parse anything 1.6929 + if (found < 1) { 1.6930 + return false; 1.6931 + } 1.6932 + 1.6933 + // If either property didn't get an explicit value, use its initial value. 1.6934 + if ((found & 1) == 0) { 1.6935 + values[0].SetIntValue(NS_STYLE_FLEX_DIRECTION_ROW, eCSSUnit_Enumerated); 1.6936 + } 1.6937 + if ((found & 2) == 0) { 1.6938 + values[1].SetIntValue(NS_STYLE_FLEX_WRAP_NOWRAP, eCSSUnit_Enumerated); 1.6939 + } 1.6940 + 1.6941 + // Store these values and declare success! 1.6942 + for (size_t i = 0; i < numProps; i++) { 1.6943 + AppendValue(kFlexFlowSubprops[i], values[i]); 1.6944 + } 1.6945 + return true; 1.6946 +} 1.6947 + 1.6948 +bool 1.6949 +CSSParserImpl::ParseGridAutoFlow() 1.6950 +{ 1.6951 + nsCSSValue value; 1.6952 + if (ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.6953 + AppendValue(eCSSProperty_grid_auto_flow, value); 1.6954 + return true; 1.6955 + } 1.6956 + 1.6957 + static const int32_t mask[] = { 1.6958 + NS_STYLE_GRID_AUTO_FLOW_COLUMN | NS_STYLE_GRID_AUTO_FLOW_ROW, 1.6959 + MASK_END_VALUE 1.6960 + }; 1.6961 + if (!ParseBitmaskValues(value, nsCSSProps::kGridAutoFlowKTable, mask)) { 1.6962 + return false; 1.6963 + } 1.6964 + int32_t bitField = value.GetIntValue(); 1.6965 + 1.6966 + // Requires one of these 1.6967 + if (!(bitField & NS_STYLE_GRID_AUTO_FLOW_NONE || 1.6968 + bitField & NS_STYLE_GRID_AUTO_FLOW_COLUMN || 1.6969 + bitField & NS_STYLE_GRID_AUTO_FLOW_ROW)) { 1.6970 + return false; 1.6971 + } 1.6972 + 1.6973 + // 'none' is only valid if it occurs alone: 1.6974 + if (bitField & NS_STYLE_GRID_AUTO_FLOW_NONE && 1.6975 + bitField != NS_STYLE_GRID_AUTO_FLOW_NONE) { 1.6976 + return false; 1.6977 + } 1.6978 + 1.6979 + AppendValue(eCSSProperty_grid_auto_flow, value); 1.6980 + return true; 1.6981 +} 1.6982 + 1.6983 +CSSParseResult 1.6984 +CSSParserImpl::ParseGridLineNames(nsCSSValue& aValue) 1.6985 +{ 1.6986 + if (!ExpectSymbol('(', true)) { 1.6987 + return CSSParseResult::NotFound; 1.6988 + } 1.6989 + if (!GetToken(true) || mToken.IsSymbol(')')) { 1.6990 + return CSSParseResult::Ok; 1.6991 + } 1.6992 + // 'return' so far leaves aValue untouched, to represent an empty list. 1.6993 + 1.6994 + nsCSSValueList* item; 1.6995 + if (aValue.GetUnit() == eCSSUnit_List) { 1.6996 + // Find the end of an existing list. 1.6997 + // The grid-template shorthand uses this, at most once for a given list. 1.6998 + 1.6999 + // NOTE: we could avoid this traversal by somehow keeping around 1.7000 + // a pointer to the last item from the previous call. 1.7001 + // It's not yet clear if this is worth the additional code complexity. 1.7002 + item = aValue.GetListValue(); 1.7003 + while (item->mNext) { 1.7004 + item = item->mNext; 1.7005 + } 1.7006 + item->mNext = new nsCSSValueList; 1.7007 + item = item->mNext; 1.7008 + } else { 1.7009 + MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Null, "Unexpected unit"); 1.7010 + item = aValue.SetListValue(); 1.7011 + } 1.7012 + for (;;) { 1.7013 + if (!(eCSSToken_Ident == mToken.mType && 1.7014 + ParseCustomIdent(item->mValue, mToken.mIdent))) { 1.7015 + UngetToken(); 1.7016 + SkipUntil(')'); 1.7017 + return CSSParseResult::Error; 1.7018 + } 1.7019 + if (!GetToken(true) || mToken.IsSymbol(')')) { 1.7020 + return CSSParseResult::Ok; 1.7021 + } 1.7022 + item->mNext = new nsCSSValueList; 1.7023 + item = item->mNext; 1.7024 + } 1.7025 +} 1.7026 + 1.7027 +// Assuming the 'repeat(' function token has already been consumed, 1.7028 +// parse the rest of repeat(<positive-integer>, <line-names>+) 1.7029 +// Append to the linked list whose end is given by |aTailPtr|, 1.7030 +// and updated |aTailPtr| to point to the new end of the list. 1.7031 +bool 1.7032 +CSSParserImpl::ParseGridLineNameListRepeat(nsCSSValueList** aTailPtr) 1.7033 +{ 1.7034 + if (!(GetToken(true) && 1.7035 + mToken.mType == eCSSToken_Number && 1.7036 + mToken.mIntegerValid && 1.7037 + mToken.mInteger > 0)) { 1.7038 + SkipUntil(')'); 1.7039 + return false; 1.7040 + } 1.7041 + int32_t repetitions = std::min(mToken.mInteger, 1.7042 + GRID_TEMPLATE_MAX_REPETITIONS); 1.7043 + if (!ExpectSymbol(',', true)) { 1.7044 + SkipUntil(')'); 1.7045 + return false; 1.7046 + } 1.7047 + 1.7048 + // Parse at least one <line-names> 1.7049 + nsCSSValueList* tail = *aTailPtr; 1.7050 + do { 1.7051 + tail->mNext = new nsCSSValueList; 1.7052 + tail = tail->mNext; 1.7053 + if (ParseGridLineNames(tail->mValue) != CSSParseResult::Ok) { 1.7054 + SkipUntil(')'); 1.7055 + return false; 1.7056 + } 1.7057 + } while (!ExpectSymbol(')', true)); 1.7058 + nsCSSValueList* firstRepeatedItem = (*aTailPtr)->mNext; 1.7059 + nsCSSValueList* lastRepeatedItem = tail; 1.7060 + 1.7061 + // Our repeated items are already in the target list once, 1.7062 + // so they need to be repeated |repetitions - 1| more times. 1.7063 + MOZ_ASSERT(repetitions > 0, "Expected positive repetitions"); 1.7064 + while (--repetitions) { 1.7065 + nsCSSValueList* repeatedItem = firstRepeatedItem; 1.7066 + for (;;) { 1.7067 + tail->mNext = new nsCSSValueList; 1.7068 + tail = tail->mNext; 1.7069 + tail->mValue = repeatedItem->mValue; 1.7070 + if (repeatedItem == lastRepeatedItem) { 1.7071 + break; 1.7072 + } 1.7073 + repeatedItem = repeatedItem->mNext; 1.7074 + } 1.7075 + } 1.7076 + *aTailPtr = tail; 1.7077 + return true; 1.7078 +} 1.7079 + 1.7080 +// Assuming a 'subgrid' keyword was already consumed, parse <line-name-list>? 1.7081 +bool 1.7082 +CSSParserImpl::ParseOptionalLineNameListAfterSubgrid(nsCSSValue& aValue) 1.7083 +{ 1.7084 + nsCSSValueList* item = aValue.SetListValue(); 1.7085 + // This marker distinguishes the value from a <track-list>. 1.7086 + item->mValue.SetIntValue(NS_STYLE_GRID_TEMPLATE_SUBGRID, 1.7087 + eCSSUnit_Enumerated); 1.7088 + for (;;) { 1.7089 + // First try to parse repeat(<positive-integer>, <line-names>+) 1.7090 + if (!GetToken(true)) { 1.7091 + return true; 1.7092 + } 1.7093 + if (mToken.mType == eCSSToken_Function && 1.7094 + mToken.mIdent.LowerCaseEqualsLiteral("repeat")) { 1.7095 + if (!ParseGridLineNameListRepeat(&item)) { 1.7096 + return false; 1.7097 + } 1.7098 + } else { 1.7099 + UngetToken(); 1.7100 + 1.7101 + // This was not a repeat() function. Try to parse <line-names>. 1.7102 + nsCSSValue lineNames; 1.7103 + CSSParseResult result = ParseGridLineNames(lineNames); 1.7104 + if (result == CSSParseResult::NotFound) { 1.7105 + return true; 1.7106 + } 1.7107 + if (result == CSSParseResult::Error) { 1.7108 + return false; 1.7109 + } 1.7110 + item->mNext = new nsCSSValueList; 1.7111 + item = item->mNext; 1.7112 + item->mValue = lineNames; 1.7113 + } 1.7114 + } 1.7115 +} 1.7116 + 1.7117 +// Parse a <track-breadth> 1.7118 +bool 1.7119 +CSSParserImpl::ParseGridTrackBreadth(nsCSSValue& aValue) 1.7120 +{ 1.7121 + if (ParseNonNegativeVariant(aValue, 1.7122 + VARIANT_LPCALC | VARIANT_KEYWORD, 1.7123 + nsCSSProps::kGridTrackBreadthKTable)) { 1.7124 + return true; 1.7125 + } 1.7126 + 1.7127 + // Attempt to parse <flex> (a dimension with the "fr" unit) 1.7128 + if (!GetToken(true)) { 1.7129 + return false; 1.7130 + } 1.7131 + if (!(eCSSToken_Dimension == mToken.mType && 1.7132 + mToken.mIdent.LowerCaseEqualsLiteral("fr") && 1.7133 + mToken.mNumber >= 0)) { 1.7134 + UngetToken(); 1.7135 + return false; 1.7136 + } 1.7137 + aValue.SetFloatValue(mToken.mNumber, eCSSUnit_FlexFraction); 1.7138 + return true; 1.7139 +} 1.7140 + 1.7141 +// Parse a <track-size> 1.7142 +CSSParseResult 1.7143 +CSSParserImpl::ParseGridTrackSize(nsCSSValue& aValue) 1.7144 +{ 1.7145 + // Attempt to parse 'auto' or a single <track-breadth> 1.7146 + if (ParseGridTrackBreadth(aValue) || 1.7147 + ParseVariant(aValue, VARIANT_AUTO, nullptr)) { 1.7148 + return CSSParseResult::Ok; 1.7149 + } 1.7150 + 1.7151 + // Attempt to parse a minmax() function 1.7152 + if (!GetToken(true)) { 1.7153 + return CSSParseResult::NotFound; 1.7154 + } 1.7155 + if (!(eCSSToken_Function == mToken.mType && 1.7156 + mToken.mIdent.LowerCaseEqualsLiteral("minmax"))) { 1.7157 + UngetToken(); 1.7158 + return CSSParseResult::NotFound; 1.7159 + } 1.7160 + nsCSSValue::Array* func = aValue.InitFunction(eCSSKeyword_minmax, 2); 1.7161 + if (ParseGridTrackBreadth(func->Item(1)) && 1.7162 + ExpectSymbol(',', true) && 1.7163 + ParseGridTrackBreadth(func->Item(2)) && 1.7164 + ExpectSymbol(')', true)) { 1.7165 + return CSSParseResult::Ok; 1.7166 + } 1.7167 + SkipUntil(')'); 1.7168 + return CSSParseResult::Error; 1.7169 +} 1.7170 + 1.7171 +bool 1.7172 +CSSParserImpl::ParseGridAutoColumnsRows(nsCSSProperty aPropID) 1.7173 +{ 1.7174 + nsCSSValue value; 1.7175 + if (ParseVariant(value, VARIANT_INHERIT, nullptr) || 1.7176 + ParseGridTrackSize(value) == CSSParseResult::Ok) { 1.7177 + AppendValue(aPropID, value); 1.7178 + return true; 1.7179 + } 1.7180 + return false; 1.7181 +} 1.7182 + 1.7183 +bool 1.7184 +CSSParserImpl::ParseGridTrackListWithFirstLineNames(nsCSSValue& aValue, 1.7185 + const nsCSSValue& aFirstLineNames) 1.7186 +{ 1.7187 + nsCSSValueList* firstLineNamesItem = aValue.SetListValue(); 1.7188 + firstLineNamesItem->mValue = aFirstLineNames; 1.7189 + 1.7190 + // This function is trying to parse <track-list>, which is 1.7191 + // [ <line-names>? [ <track-size> | <repeat()> ] ]+ <line-names>? 1.7192 + // and we're already past the first "<line-names>?". 1.7193 + // 1.7194 + // Each iteration of the following loop attempts to parse either a 1.7195 + // repeat() or a <track-size> expression, and then an (optional) 1.7196 + // <line-names> expression. 1.7197 + // 1.7198 + // The only successful exit point from this loop is the ::NotFound 1.7199 + // case after ParseGridTrackSize(); i.e. we'll greedily parse 1.7200 + // repeat()/<track-size> until we can't find one. 1.7201 + nsCSSValueList* item = firstLineNamesItem; 1.7202 + for (;;) { 1.7203 + // First try to parse repeat() 1.7204 + if (!GetToken(true)) { 1.7205 + break; 1.7206 + } 1.7207 + if (mToken.mType == eCSSToken_Function && 1.7208 + mToken.mIdent.LowerCaseEqualsLiteral("repeat")) { 1.7209 + if (!ParseGridTrackListRepeat(&item)) { 1.7210 + return false; 1.7211 + } 1.7212 + } else { 1.7213 + UngetToken(); 1.7214 + 1.7215 + // This was not a repeat() function. Try to parse <track-size>. 1.7216 + nsCSSValue trackSize; 1.7217 + CSSParseResult result = ParseGridTrackSize(trackSize); 1.7218 + if (result == CSSParseResult::Error) { 1.7219 + return false; 1.7220 + } 1.7221 + if (result == CSSParseResult::NotFound) { 1.7222 + // What we've parsed so far is a valid <track-list> 1.7223 + // (modulo the "at least one <track-size>" check below.) 1.7224 + // Stop here. 1.7225 + break; 1.7226 + } 1.7227 + item->mNext = new nsCSSValueList; 1.7228 + item = item->mNext; 1.7229 + item->mValue = trackSize; 1.7230 + 1.7231 + item->mNext = new nsCSSValueList; 1.7232 + item = item->mNext; 1.7233 + } 1.7234 + if (ParseGridLineNames(item->mValue) == CSSParseResult::Error) { 1.7235 + return false; 1.7236 + } 1.7237 + } 1.7238 + 1.7239 + // Require at least one <track-size>. 1.7240 + if (item == firstLineNamesItem) { 1.7241 + return false; 1.7242 + } 1.7243 + 1.7244 + MOZ_ASSERT(aValue.GetListValue() && 1.7245 + aValue.GetListValue()->mNext && 1.7246 + aValue.GetListValue()->mNext->mNext, 1.7247 + "<track-list> should have a minimum length of 3"); 1.7248 + return true; 1.7249 +} 1.7250 + 1.7251 +// Takes ownership of |aSecond| 1.7252 +static void 1.7253 +ConcatLineNames(nsCSSValue& aFirst, nsCSSValue& aSecond) 1.7254 +{ 1.7255 + if (aSecond.GetUnit() == eCSSUnit_Null) { 1.7256 + // Nothing to do. 1.7257 + return; 1.7258 + } 1.7259 + if (aFirst.GetUnit() == eCSSUnit_Null) { 1.7260 + // Empty or omitted <line-names>. Replace it. 1.7261 + aFirst = aSecond; 1.7262 + return; 1.7263 + } 1.7264 + 1.7265 + // Join the two <line-names> lists. 1.7266 + nsCSSValueList* source = aSecond.GetListValue(); 1.7267 + nsCSSValueList* target = aFirst.GetListValue(); 1.7268 + // Find the end: 1.7269 + while (target->mNext) { 1.7270 + target = target->mNext; 1.7271 + } 1.7272 + // Copy the first name. We can't take ownership of it 1.7273 + // as it'll be destroyed when |aSecond| goes out of scope. 1.7274 + target->mNext = new nsCSSValueList; 1.7275 + target = target->mNext; 1.7276 + target->mValue = source->mValue; 1.7277 + // Move the rest of the linked list. 1.7278 + target->mNext = source->mNext; 1.7279 + source->mNext = nullptr; 1.7280 +} 1.7281 + 1.7282 +// Assuming the 'repeat(' function token has already been consumed, 1.7283 +// parse the rest of 1.7284 +// repeat( <positive-integer> , 1.7285 +// [ <line-names>? <track-size> ]+ <line-names>? ) 1.7286 +// Append to the linked list whose end is given by |aTailPtr|, 1.7287 +// and updated |aTailPtr| to point to the new end of the list. 1.7288 +bool 1.7289 +CSSParserImpl::ParseGridTrackListRepeat(nsCSSValueList** aTailPtr) 1.7290 +{ 1.7291 + if (!(GetToken(true) && 1.7292 + mToken.mType == eCSSToken_Number && 1.7293 + mToken.mIntegerValid && 1.7294 + mToken.mInteger > 0)) { 1.7295 + SkipUntil(')'); 1.7296 + return false; 1.7297 + } 1.7298 + int32_t repetitions = std::min(mToken.mInteger, 1.7299 + GRID_TEMPLATE_MAX_REPETITIONS); 1.7300 + if (!ExpectSymbol(',', true)) { 1.7301 + SkipUntil(')'); 1.7302 + return false; 1.7303 + } 1.7304 + 1.7305 + // Parse [ <line-names>? <track-size> ]+ <line-names>? 1.7306 + // but keep the first and last <line-names> separate 1.7307 + // because they'll need to be joined. 1.7308 + // http://dev.w3.org/csswg/css-grid/#repeat-notation 1.7309 + nsCSSValue firstLineNames; 1.7310 + nsCSSValue trackSize; 1.7311 + nsCSSValue lastLineNames; 1.7312 + // Optional 1.7313 + if (ParseGridLineNames(firstLineNames) == CSSParseResult::Error) { 1.7314 + SkipUntil(')'); 1.7315 + return false; 1.7316 + } 1.7317 + // Required 1.7318 + if (ParseGridTrackSize(trackSize) != CSSParseResult::Ok) { 1.7319 + SkipUntil(')'); 1.7320 + return false; 1.7321 + } 1.7322 + // Use nsAutoPtr to free the list in case of early return. 1.7323 + nsAutoPtr<nsCSSValueList> firstTrackSizeItemAuto(new nsCSSValueList); 1.7324 + firstTrackSizeItemAuto->mValue = trackSize; 1.7325 + 1.7326 + nsCSSValueList* item = firstTrackSizeItemAuto; 1.7327 + for (;;) { 1.7328 + // Optional 1.7329 + if (ParseGridLineNames(lastLineNames) == CSSParseResult::Error) { 1.7330 + SkipUntil(')'); 1.7331 + return false; 1.7332 + } 1.7333 + 1.7334 + if (ExpectSymbol(')', true)) { 1.7335 + break; 1.7336 + } 1.7337 + 1.7338 + // Required 1.7339 + if (ParseGridTrackSize(trackSize) != CSSParseResult::Ok) { 1.7340 + SkipUntil(')'); 1.7341 + return false; 1.7342 + } 1.7343 + 1.7344 + item->mNext = new nsCSSValueList; 1.7345 + item = item->mNext; 1.7346 + item->mValue = lastLineNames; 1.7347 + // Do not append to this list at the next iteration. 1.7348 + lastLineNames.Reset(); 1.7349 + 1.7350 + item->mNext = new nsCSSValueList; 1.7351 + item = item->mNext; 1.7352 + item->mValue = trackSize; 1.7353 + } 1.7354 + nsCSSValueList* lastTrackSizeItem = item; 1.7355 + 1.7356 + // [ <line-names>? <track-size> ]+ <line-names>? is now parsed into: 1.7357 + // * firstLineNames: the first <line-names> 1.7358 + // * a linked list of odd length >= 1, from firstTrackSizeItem 1.7359 + // (the first <track-size>) to lastTrackSizeItem (the last), 1.7360 + // with the <line-names> sublists in between 1.7361 + // * lastLineNames: the last <line-names> 1.7362 + 1.7363 + 1.7364 + // Join the last and first <line-names> (in that order.) 1.7365 + // For example, repeat(3, (a) 100px (b) 200px (c)) results in 1.7366 + // (a) 100px (b) 200px (c a) 100px (b) 200px (c a) 100px (b) 200px (c) 1.7367 + // This is (c a). 1.7368 + // Make deep copies: the originals will be moved. 1.7369 + nsCSSValue joinerLineNames; 1.7370 + { 1.7371 + nsCSSValueList* target = nullptr; 1.7372 + if (lastLineNames.GetUnit() != eCSSUnit_Null) { 1.7373 + target = joinerLineNames.SetListValue(); 1.7374 + nsCSSValueList* source = lastLineNames.GetListValue(); 1.7375 + for (;;) { 1.7376 + target->mValue = source->mValue; 1.7377 + source = source->mNext; 1.7378 + if (!source) { 1.7379 + break; 1.7380 + } 1.7381 + target->mNext = new nsCSSValueList; 1.7382 + target = target->mNext; 1.7383 + } 1.7384 + } 1.7385 + 1.7386 + if (firstLineNames.GetUnit() != eCSSUnit_Null) { 1.7387 + if (target) { 1.7388 + target->mNext = new nsCSSValueList; 1.7389 + target = target->mNext; 1.7390 + } else { 1.7391 + target = joinerLineNames.SetListValue(); 1.7392 + } 1.7393 + nsCSSValueList* source = firstLineNames.GetListValue(); 1.7394 + for (;;) { 1.7395 + target->mValue = source->mValue; 1.7396 + source = source->mNext; 1.7397 + if (!source) { 1.7398 + break; 1.7399 + } 1.7400 + target->mNext = new nsCSSValueList; 1.7401 + target = target->mNext; 1.7402 + } 1.7403 + } 1.7404 + } 1.7405 + 1.7406 + // Join our first <line-names> with the one before repeat(). 1.7407 + // (a) repeat(1, (b) 20px) expands to (a b) 20px 1.7408 + nsCSSValueList* previousItemBeforeRepeat = *aTailPtr; 1.7409 + ConcatLineNames(previousItemBeforeRepeat->mValue, firstLineNames); 1.7410 + 1.7411 + // Move our linked list 1.7412 + // (first to last <track-size>, with the <line-names> sublists in between). 1.7413 + // This is the first repetition. 1.7414 + NS_ASSERTION(previousItemBeforeRepeat->mNext == nullptr, 1.7415 + "Expected the end of a linked list"); 1.7416 + previousItemBeforeRepeat->mNext = firstTrackSizeItemAuto.forget(); 1.7417 + nsCSSValueList* firstTrackSizeItem = previousItemBeforeRepeat->mNext; 1.7418 + nsCSSValueList* tail = lastTrackSizeItem; 1.7419 + 1.7420 + // Repeat |repetitions - 1| more times: 1.7421 + // * the joiner <line-names> 1.7422 + // * the linked list 1.7423 + // (first to last <track-size>, with the <line-names> sublists in between) 1.7424 + MOZ_ASSERT(repetitions > 0, "Expected positive repetitions"); 1.7425 + while (--repetitions) { 1.7426 + tail->mNext = new nsCSSValueList; 1.7427 + tail = tail->mNext; 1.7428 + tail->mValue = joinerLineNames; 1.7429 + 1.7430 + nsCSSValueList* repeatedItem = firstTrackSizeItem; 1.7431 + for (;;) { 1.7432 + tail->mNext = new nsCSSValueList; 1.7433 + tail = tail->mNext; 1.7434 + tail->mValue = repeatedItem->mValue; 1.7435 + if (repeatedItem == lastTrackSizeItem) { 1.7436 + break; 1.7437 + } 1.7438 + repeatedItem = repeatedItem->mNext; 1.7439 + } 1.7440 + } 1.7441 + 1.7442 + // Finally, move our last <line-names>. 1.7443 + // Any <line-names> immediately after repeat() will append to it. 1.7444 + tail->mNext = new nsCSSValueList; 1.7445 + tail = tail->mNext; 1.7446 + tail->mValue = lastLineNames; 1.7447 + 1.7448 + *aTailPtr = tail; 1.7449 + return true; 1.7450 +} 1.7451 + 1.7452 +bool 1.7453 +CSSParserImpl::ParseGridTemplateColumnsRows(nsCSSProperty aPropID) 1.7454 +{ 1.7455 + nsCSSValue value; 1.7456 + if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.7457 + AppendValue(aPropID, value); 1.7458 + return true; 1.7459 + } 1.7460 + 1.7461 + nsSubstring* ident = NextIdent(); 1.7462 + if (ident) { 1.7463 + if (ident->LowerCaseEqualsLiteral("subgrid")) { 1.7464 + if (!ParseOptionalLineNameListAfterSubgrid(value)) { 1.7465 + return false; 1.7466 + } 1.7467 + AppendValue(aPropID, value); 1.7468 + return true; 1.7469 + } 1.7470 + UngetToken(); 1.7471 + } 1.7472 + 1.7473 + nsCSSValue firstLineNames; 1.7474 + if (ParseGridLineNames(firstLineNames) == CSSParseResult::Error || 1.7475 + !ParseGridTrackListWithFirstLineNames(value, firstLineNames)) { 1.7476 + return false; 1.7477 + } 1.7478 + AppendValue(aPropID, value); 1.7479 + return true; 1.7480 +} 1.7481 + 1.7482 +bool 1.7483 +CSSParserImpl::ParseGridTemplateAreasLine(const nsAutoString& aInput, 1.7484 + css::GridTemplateAreasValue* aAreas, 1.7485 + nsDataHashtable<nsStringHashKey, uint32_t>& aAreaIndices) 1.7486 +{ 1.7487 + aAreas->mTemplates.AppendElement(mToken.mIdent); 1.7488 + 1.7489 + nsCSSGridTemplateAreaScanner scanner(aInput); 1.7490 + nsCSSGridTemplateAreaToken token; 1.7491 + css::GridNamedArea* currentArea = nullptr; 1.7492 + uint32_t row = aAreas->NRows(); 1.7493 + uint32_t column; 1.7494 + for (column = 1; scanner.Next(token); column++) { 1.7495 + if (token.isTrash) { 1.7496 + return false; 1.7497 + } 1.7498 + if (currentArea) { 1.7499 + if (token.mName == currentArea->mName) { 1.7500 + if (currentArea->mRowStart == row) { 1.7501 + // Next column in the first row of this named area. 1.7502 + currentArea->mColumnEnd++; 1.7503 + } 1.7504 + continue; 1.7505 + } 1.7506 + // We're exiting |currentArea|, so currentArea is ending at |column|. 1.7507 + // Make sure that this is consistent with currentArea on previous rows: 1.7508 + if (currentArea->mColumnEnd != column) { 1.7509 + NS_ASSERTION(currentArea->mRowStart != row, 1.7510 + "Inconsistent column end for the first row of a named area."); 1.7511 + // Not a rectangle 1.7512 + return false; 1.7513 + } 1.7514 + currentArea = nullptr; 1.7515 + } 1.7516 + if (!token.mName.IsEmpty()) { 1.7517 + // Named cell that doesn't have a cell with the same name on its left. 1.7518 + 1.7519 + // Check if this is the continuation of an existing named area: 1.7520 + uint32_t index; 1.7521 + if (aAreaIndices.Get(token.mName, &index)) { 1.7522 + MOZ_ASSERT(index < aAreas->mNamedAreas.Length(), 1.7523 + "Invalid aAreaIndices hash table"); 1.7524 + currentArea = &aAreas->mNamedAreas[index]; 1.7525 + if (currentArea->mColumnStart != column || 1.7526 + currentArea->mRowEnd != row) { 1.7527 + // Existing named area, but not forming a rectangle 1.7528 + return false; 1.7529 + } 1.7530 + // Next row of an existing named area 1.7531 + currentArea->mRowEnd++; 1.7532 + } else { 1.7533 + // New named area 1.7534 + aAreaIndices.Put(token.mName, aAreas->mNamedAreas.Length()); 1.7535 + currentArea = aAreas->mNamedAreas.AppendElement(); 1.7536 + currentArea->mName = token.mName; 1.7537 + // For column or row N (starting at 1), 1.7538 + // the start line is N, the end line is N + 1 1.7539 + currentArea->mColumnStart = column; 1.7540 + currentArea->mColumnEnd = column + 1; 1.7541 + currentArea->mRowStart = row; 1.7542 + currentArea->mRowEnd = row + 1; 1.7543 + } 1.7544 + } 1.7545 + } 1.7546 + if (currentArea && currentArea->mColumnEnd != column) { 1.7547 + NS_ASSERTION(currentArea->mRowStart != row, 1.7548 + "Inconsistent column end for the first row of a named area."); 1.7549 + // Not a rectangle 1.7550 + return false; 1.7551 + } 1.7552 + 1.7553 + // On the first row, set the number of columns 1.7554 + // that grid-template-areas contributes to the explicit grid. 1.7555 + // On other rows, check that the number of columns is consistent 1.7556 + // between rows. 1.7557 + if (row == 1) { 1.7558 + aAreas->mNColumns = column; 1.7559 + } else if (aAreas->mNColumns != column) { 1.7560 + return false; 1.7561 + } 1.7562 + return true; 1.7563 +} 1.7564 + 1.7565 +bool 1.7566 +CSSParserImpl::ParseGridTemplateAreas() 1.7567 +{ 1.7568 + nsCSSValue value; 1.7569 + if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.7570 + AppendValue(eCSSProperty_grid_template_areas, value); 1.7571 + return true; 1.7572 + } 1.7573 + 1.7574 + nsRefPtr<css::GridTemplateAreasValue> areas = 1.7575 + new css::GridTemplateAreasValue(); 1.7576 + nsDataHashtable<nsStringHashKey, uint32_t> areaIndices; 1.7577 + for (;;) { 1.7578 + if (!GetToken(true)) { 1.7579 + break; 1.7580 + } 1.7581 + if (eCSSToken_String != mToken.mType) { 1.7582 + UngetToken(); 1.7583 + break; 1.7584 + } 1.7585 + if (!ParseGridTemplateAreasLine(mToken.mIdent, areas, areaIndices)) { 1.7586 + return false; 1.7587 + } 1.7588 + } 1.7589 + 1.7590 + if (areas->NRows() == 0) { 1.7591 + return false; 1.7592 + } 1.7593 + 1.7594 + AppendValue(eCSSProperty_grid_template_areas, nsCSSValue(areas)); 1.7595 + return true; 1.7596 +} 1.7597 + 1.7598 +bool 1.7599 +CSSParserImpl::ParseGridTemplate() 1.7600 +{ 1.7601 + // none | 1.7602 + // subgrid | 1.7603 + // <'grid-template-columns'> / <'grid-template-rows'> | 1.7604 + // [ <track-list> / ]? [ <line-names>? <string> <track-size>? <line-names>? ]+ 1.7605 + nsCSSValue value; 1.7606 + if (ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.7607 + AppendValue(eCSSProperty_grid_template_areas, value); 1.7608 + AppendValue(eCSSProperty_grid_template_columns, value); 1.7609 + AppendValue(eCSSProperty_grid_template_rows, value); 1.7610 + return true; 1.7611 + } 1.7612 + 1.7613 + // TODO (bug 983175): add parsing for 'subgrid' by itself 1.7614 + 1.7615 + // 'none' can appear either by itself, 1.7616 + // or as the beginning of <'grid-template-columns'> / <'grid-template-rows'> 1.7617 + if (ParseVariant(value, VARIANT_NONE, nullptr)) { 1.7618 + AppendValue(eCSSProperty_grid_template_columns, value); 1.7619 + if (ExpectSymbol('/', true)) { 1.7620 + return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ false); 1.7621 + } 1.7622 + AppendValue(eCSSProperty_grid_template_areas, value); 1.7623 + AppendValue(eCSSProperty_grid_template_rows, value); 1.7624 + return true; 1.7625 + } 1.7626 + 1.7627 + // 'subgrid' can appear either by itself, 1.7628 + // or as the beginning of <'grid-template-columns'> / <'grid-template-rows'> 1.7629 + nsSubstring* ident = NextIdent(); 1.7630 + if (ident) { 1.7631 + if (ident->LowerCaseEqualsLiteral("subgrid")) { 1.7632 + if (!ParseOptionalLineNameListAfterSubgrid(value)) { 1.7633 + return false; 1.7634 + } 1.7635 + AppendValue(eCSSProperty_grid_template_columns, value); 1.7636 + if (ExpectSymbol('/', true)) { 1.7637 + return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ false); 1.7638 + } 1.7639 + if (value.GetListValue()->mNext) { 1.7640 + // Non-empty <line-name-list> after 'subgrid'. 1.7641 + // This is only valid as part of <'grid-template-columns'>, 1.7642 + // which must be followed by a slash. 1.7643 + return false; 1.7644 + } 1.7645 + // 'subgrid' by itself sets both grid-template-columns 1.7646 + // and grid-template-rows. 1.7647 + AppendValue(eCSSProperty_grid_template_rows, value); 1.7648 + value.SetNoneValue(); 1.7649 + AppendValue(eCSSProperty_grid_template_areas, value); 1.7650 + return true; 1.7651 + } 1.7652 + UngetToken(); 1.7653 + } 1.7654 + 1.7655 + // [ <line-names>? ] here is ambiguous: 1.7656 + // it can be either the start of a <track-list>, 1.7657 + // or the start of [ <line-names>? <string> <track-size>? <line-names>? ]+ 1.7658 + nsCSSValue firstLineNames; 1.7659 + if (ParseGridLineNames(firstLineNames) == CSSParseResult::Error || 1.7660 + !GetToken(true)) { 1.7661 + return false; 1.7662 + } 1.7663 + if (mToken.mType == eCSSToken_String) { 1.7664 + // [ <track-list> / ]? was omitted 1.7665 + // Parse [ <line-names>? <string> <track-size>? <line-names>? ]+ 1.7666 + value.SetNoneValue(); 1.7667 + AppendValue(eCSSProperty_grid_template_columns, value); 1.7668 + return ParseGridTemplateAfterString(firstLineNames); 1.7669 + } 1.7670 + UngetToken(); 1.7671 + 1.7672 + if (!(ParseGridTrackListWithFirstLineNames(value, firstLineNames) && 1.7673 + ExpectSymbol('/', true))) { 1.7674 + return false; 1.7675 + } 1.7676 + AppendValue(eCSSProperty_grid_template_columns, value); 1.7677 + return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ true); 1.7678 +} 1.7679 + 1.7680 +// Helper for parsing the 'grid-template' shorthand 1.7681 +// 1.7682 +// NOTE: This parses the portion after the slash, for *one* of the 1.7683 +// following types of expressions: 1.7684 +// - <'grid-template-columns'> / <'grid-template-rows'> 1.7685 +// - <track-list> / [ <line-names>? <string> <track-size>? <line-names>? ]+ 1.7686 +// 1.7687 +// We don't know which type of expression we've got until we've parsed the 1.7688 +// second half, since the pre-slash part is ambiguous. The various return 1.7689 +// clauses below are labeled with the type of expression they're completing. 1.7690 +bool 1.7691 +CSSParserImpl::ParseGridTemplateAfterSlash(bool aColumnsIsTrackList) 1.7692 +{ 1.7693 + nsCSSValue rowsValue; 1.7694 + if (ParseVariant(rowsValue, VARIANT_NONE, nullptr)) { 1.7695 + // <'grid-template-columns'> / <'grid-template-rows'> 1.7696 + AppendValue(eCSSProperty_grid_template_rows, rowsValue); 1.7697 + nsCSSValue areasValue(eCSSUnit_None); // implied 1.7698 + AppendValue(eCSSProperty_grid_template_areas, areasValue); 1.7699 + return true; 1.7700 + } 1.7701 + 1.7702 + nsSubstring* ident = NextIdent(); 1.7703 + if (ident) { 1.7704 + if (ident->LowerCaseEqualsLiteral("subgrid")) { 1.7705 + if (!ParseOptionalLineNameListAfterSubgrid(rowsValue)) { 1.7706 + return false; 1.7707 + } 1.7708 + // <'grid-template-columns'> / <'grid-template-rows'> 1.7709 + AppendValue(eCSSProperty_grid_template_rows, rowsValue); 1.7710 + nsCSSValue areasValue(eCSSUnit_None); // implied 1.7711 + AppendValue(eCSSProperty_grid_template_areas, areasValue); 1.7712 + return true; 1.7713 + } 1.7714 + UngetToken(); 1.7715 + } 1.7716 + 1.7717 + nsCSSValue firstLineNames; 1.7718 + if (ParseGridLineNames(firstLineNames) == CSSParseResult::Error || 1.7719 + !GetToken(true)) { 1.7720 + return false; 1.7721 + } 1.7722 + if (aColumnsIsTrackList && mToken.mType == eCSSToken_String) { 1.7723 + // [ <track-list> / ]? [ <line-names>? <string> <track-size>? <line-names>? ]+ 1.7724 + return ParseGridTemplateAfterString(firstLineNames); 1.7725 + } 1.7726 + UngetToken(); 1.7727 + 1.7728 + if (!ParseGridTrackListWithFirstLineNames(rowsValue, firstLineNames)) { 1.7729 + return false; 1.7730 + } 1.7731 + 1.7732 + // <'grid-template-columns'> / <'grid-template-rows'> 1.7733 + AppendValue(eCSSProperty_grid_template_rows, rowsValue); 1.7734 + nsCSSValue areasValue(eCSSUnit_None); // implied 1.7735 + AppendValue(eCSSProperty_grid_template_areas, areasValue); 1.7736 + return true; 1.7737 +} 1.7738 + 1.7739 +// Helper for parsing the 'grid-template' shorthand: 1.7740 +// Parse [ <line-names>? <string> <track-size>? <line-names>? ]+ 1.7741 +// with a <line-names>? already consumed, stored in |aFirstLineNames|, 1.7742 +// and the current token a <string> 1.7743 +bool 1.7744 +CSSParserImpl::ParseGridTemplateAfterString(const nsCSSValue& aFirstLineNames) 1.7745 +{ 1.7746 + MOZ_ASSERT(mToken.mType == eCSSToken_String, 1.7747 + "ParseGridTemplateAfterString called with a non-string token"); 1.7748 + 1.7749 + nsCSSValue rowsValue; 1.7750 + nsRefPtr<css::GridTemplateAreasValue> areas = 1.7751 + new css::GridTemplateAreasValue(); 1.7752 + nsDataHashtable<nsStringHashKey, uint32_t> areaIndices; 1.7753 + nsCSSValueList* rowsItem = rowsValue.SetListValue(); 1.7754 + rowsItem->mValue = aFirstLineNames; 1.7755 + 1.7756 + for (;;) { 1.7757 + if (!ParseGridTemplateAreasLine(mToken.mIdent, areas, areaIndices)) { 1.7758 + return false; 1.7759 + } 1.7760 + 1.7761 + rowsItem->mNext = new nsCSSValueList; 1.7762 + rowsItem = rowsItem->mNext; 1.7763 + CSSParseResult result = ParseGridTrackSize(rowsItem->mValue); 1.7764 + if (result == CSSParseResult::Error) { 1.7765 + return false; 1.7766 + } 1.7767 + if (result == CSSParseResult::NotFound) { 1.7768 + rowsItem->mValue.SetAutoValue(); 1.7769 + } 1.7770 + 1.7771 + rowsItem->mNext = new nsCSSValueList; 1.7772 + rowsItem = rowsItem->mNext; 1.7773 + result = ParseGridLineNames(rowsItem->mValue); 1.7774 + if (result == CSSParseResult::Error) { 1.7775 + return false; 1.7776 + } 1.7777 + if (result == CSSParseResult::Ok) { 1.7778 + // Append to the same list as the previous call to ParseGridLineNames. 1.7779 + result = ParseGridLineNames(rowsItem->mValue); 1.7780 + if (result == CSSParseResult::Error) { 1.7781 + return false; 1.7782 + } 1.7783 + if (result == CSSParseResult::Ok) { 1.7784 + // Parsed <line-name> twice. 1.7785 + // The property value can not end here, we expect a string next. 1.7786 + if (!GetToken(true)) { 1.7787 + return false; 1.7788 + } 1.7789 + if (eCSSToken_String != mToken.mType) { 1.7790 + UngetToken(); 1.7791 + return false; 1.7792 + } 1.7793 + continue; 1.7794 + } 1.7795 + } 1.7796 + 1.7797 + // Did not find a <line-names>. 1.7798 + // Next, we expect either a string or the end of the property value. 1.7799 + if (!GetToken(true)) { 1.7800 + break; 1.7801 + } 1.7802 + if (eCSSToken_String != mToken.mType) { 1.7803 + UngetToken(); 1.7804 + break; 1.7805 + } 1.7806 + } 1.7807 + 1.7808 + AppendValue(eCSSProperty_grid_template_areas, nsCSSValue(areas)); 1.7809 + AppendValue(eCSSProperty_grid_template_rows, rowsValue); 1.7810 + return true; 1.7811 +} 1.7812 + 1.7813 +// <'grid-template'> | 1.7814 +// [ <'grid-auto-flow'> [ <'grid-auto-columns'> [ / <'grid-auto-rows'> ]? ]? ] 1.7815 +bool 1.7816 +CSSParserImpl::ParseGrid() 1.7817 +{ 1.7818 + nsCSSValue value; 1.7819 + if (ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.7820 + for (const nsCSSProperty* subprops = 1.7821 + nsCSSProps::SubpropertyEntryFor(eCSSProperty_grid); 1.7822 + *subprops != eCSSProperty_UNKNOWN; ++subprops) { 1.7823 + AppendValue(*subprops, value); 1.7824 + } 1.7825 + return true; 1.7826 + } 1.7827 + 1.7828 + // 'none' at the beginning could be a <'grid-auto-flow'> 1.7829 + // (which also covers 'none' by itself) 1.7830 + // or a <'grid-template-columns'> (as part of <'grid-template'>) 1.7831 + if (ParseVariant(value, VARIANT_NONE, nullptr)) { 1.7832 + if (ExpectSymbol('/', true)) { 1.7833 + AppendValue(eCSSProperty_grid_template_columns, value); 1.7834 + 1.7835 + // Set grid-auto-* subproperties to their initial values. 1.7836 + value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_NONE, eCSSUnit_Enumerated); 1.7837 + AppendValue(eCSSProperty_grid_auto_flow, value); 1.7838 + value.SetAutoValue(); 1.7839 + AppendValue(eCSSProperty_grid_auto_columns, value); 1.7840 + AppendValue(eCSSProperty_grid_auto_rows, value); 1.7841 + 1.7842 + return ParseGridTemplateAfterSlash(/* aColumnsIsTrackList = */ false); 1.7843 + } 1.7844 + value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_NONE, eCSSUnit_Enumerated); 1.7845 + AppendValue(eCSSProperty_grid_auto_flow, value); 1.7846 + return ParseGridShorthandAutoProps(); 1.7847 + } 1.7848 + 1.7849 + // An empty value is always invalid. 1.7850 + if (!GetToken(true)) { 1.7851 + return false; 1.7852 + } 1.7853 + 1.7854 + // If the value starts with a 'dense', 'column' or 'row' keyword, 1.7855 + // it can only start with a <'grid-auto-flow'> 1.7856 + if (mToken.mType == eCSSToken_Ident) { 1.7857 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); 1.7858 + if (keyword == eCSSKeyword_dense || 1.7859 + keyword == eCSSKeyword_column || 1.7860 + keyword == eCSSKeyword_row) { 1.7861 + UngetToken(); 1.7862 + return ParseGridAutoFlow() && ParseGridShorthandAutoProps(); 1.7863 + } 1.7864 + } 1.7865 + UngetToken(); 1.7866 + 1.7867 + // Set other subproperties to their initial values 1.7868 + // and parse <'grid-template'>. 1.7869 + value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_NONE, eCSSUnit_Enumerated); 1.7870 + AppendValue(eCSSProperty_grid_auto_flow, value); 1.7871 + value.SetAutoValue(); 1.7872 + AppendValue(eCSSProperty_grid_auto_columns, value); 1.7873 + AppendValue(eCSSProperty_grid_auto_rows, value); 1.7874 + return ParseGridTemplate(); 1.7875 +} 1.7876 + 1.7877 +// Parse [ <'grid-auto-columns'> [ / <'grid-auto-rows'> ]? ]? 1.7878 +// for the 'grid' shorthand. 1.7879 +// Assumes that <'grid-auto-flow'> was already parsed by the caller. 1.7880 +bool 1.7881 +CSSParserImpl::ParseGridShorthandAutoProps() 1.7882 +{ 1.7883 + nsCSSValue autoColumnsValue; 1.7884 + nsCSSValue autoRowsValue; 1.7885 + CSSParseResult result = ParseGridTrackSize(autoColumnsValue); 1.7886 + if (result == CSSParseResult::Error) { 1.7887 + return false; 1.7888 + } 1.7889 + if (result == CSSParseResult::NotFound) { 1.7890 + autoColumnsValue.SetAutoValue(); 1.7891 + autoRowsValue.SetAutoValue(); 1.7892 + } else { 1.7893 + if (!ExpectSymbol('/', true)) { 1.7894 + autoRowsValue.SetAutoValue(); 1.7895 + } else if (ParseGridTrackSize(autoRowsValue) != CSSParseResult::Ok) { 1.7896 + return false; 1.7897 + } 1.7898 + } 1.7899 + AppendValue(eCSSProperty_grid_auto_columns, autoColumnsValue); 1.7900 + AppendValue(eCSSProperty_grid_auto_rows, autoRowsValue); 1.7901 + nsCSSValue templateValue(eCSSUnit_None); // Initial values 1.7902 + AppendValue(eCSSProperty_grid_template_areas, templateValue); 1.7903 + AppendValue(eCSSProperty_grid_template_columns, templateValue); 1.7904 + AppendValue(eCSSProperty_grid_template_rows, templateValue); 1.7905 + return true; 1.7906 +} 1.7907 + 1.7908 +// Parse a <grid-line>. 1.7909 +// If successful, set aValue to eCSSUnit_Auto, 1.7910 +// or a eCSSUnit_List containing, in that order: 1.7911 +// 1.7912 +// * An optional eCSSUnit_Enumerated marking a "span" keyword. 1.7913 +// * An optional eCSSUnit_Integer 1.7914 +// * An optional eCSSUnit_Ident 1.7915 +// 1.7916 +// At least one of eCSSUnit_Integer or eCSSUnit_Ident is present. 1.7917 +bool 1.7918 +CSSParserImpl::ParseGridLine(nsCSSValue& aValue) 1.7919 +{ 1.7920 + // <grid-line> = 1.7921 + // auto | 1.7922 + // <custom-ident> | 1.7923 + // [ <integer> && <custom-ident>? ] | 1.7924 + // [ span && [ <integer> || <custom-ident> ] ] 1.7925 + // 1.7926 + // Syntactically, this simplifies to: 1.7927 + // 1.7928 + // <grid-line> = 1.7929 + // auto | 1.7930 + // [ span? && [ <integer> || <custom-ident> ] ] 1.7931 + 1.7932 + if (ParseVariant(aValue, VARIANT_AUTO, nullptr)) { 1.7933 + return true; 1.7934 + } 1.7935 + 1.7936 + static const nsCSSKeyword kGridLineKeywords[] = { 1.7937 + eCSSKeyword_span, 1.7938 + eCSSKeyword_UNKNOWN // End-of-array marker 1.7939 + }; 1.7940 + bool hasSpan = false; 1.7941 + bool hasInteger = false; 1.7942 + bool hasIdent = false; 1.7943 + int32_t integer; 1.7944 + nsCSSValue ident; 1.7945 + 1.7946 + if (!GetToken(true)) { 1.7947 + return false; 1.7948 + } 1.7949 + if (mToken.mType == eCSSToken_Ident && 1.7950 + mToken.mIdent.LowerCaseEqualsLiteral("span")) { 1.7951 + hasSpan = true; 1.7952 + if (!GetToken(true)) { 1.7953 + return false; 1.7954 + } 1.7955 + } 1.7956 + 1.7957 + do { 1.7958 + if (!hasIdent && 1.7959 + mToken.mType == eCSSToken_Ident && 1.7960 + ParseCustomIdent(ident, mToken.mIdent, kGridLineKeywords)) { 1.7961 + hasIdent = true; 1.7962 + } else if (!hasInteger && 1.7963 + mToken.mType == eCSSToken_Number && 1.7964 + mToken.mIntegerValid && 1.7965 + mToken.mInteger != 0) { 1.7966 + hasInteger = true; 1.7967 + integer = mToken.mInteger; 1.7968 + } else { 1.7969 + UngetToken(); 1.7970 + break; 1.7971 + } 1.7972 + } while (!(hasInteger && hasIdent) && GetToken(true)); 1.7973 + 1.7974 + // Require at least one of <integer> or <custom-ident> 1.7975 + if (!(hasInteger || hasIdent)) { 1.7976 + return false; 1.7977 + } 1.7978 + 1.7979 + if (!hasSpan && GetToken(true)) { 1.7980 + if (mToken.mType == eCSSToken_Ident && 1.7981 + mToken.mIdent.LowerCaseEqualsLiteral("span")) { 1.7982 + hasSpan = true; 1.7983 + } else { 1.7984 + UngetToken(); 1.7985 + } 1.7986 + } 1.7987 + 1.7988 + nsCSSValueList* item = aValue.SetListValue(); 1.7989 + if (hasSpan) { 1.7990 + // Given "span", a negative <integer> is invalid. 1.7991 + if (hasInteger && integer < 0) { 1.7992 + return false; 1.7993 + } 1.7994 + // '1' here is a dummy value. 1.7995 + // The mere presence of eCSSUnit_Enumerated indicates a "span" keyword. 1.7996 + item->mValue.SetIntValue(1, eCSSUnit_Enumerated); 1.7997 + item->mNext = new nsCSSValueList; 1.7998 + item = item->mNext; 1.7999 + } 1.8000 + if (hasInteger) { 1.8001 + item->mValue.SetIntValue(integer, eCSSUnit_Integer); 1.8002 + if (hasIdent) { 1.8003 + item->mNext = new nsCSSValueList; 1.8004 + item = item->mNext; 1.8005 + } 1.8006 + } 1.8007 + if (hasIdent) { 1.8008 + item->mValue = ident; 1.8009 + } 1.8010 + return true; 1.8011 +} 1.8012 + 1.8013 +bool 1.8014 +CSSParserImpl::ParseGridAutoPosition() 1.8015 +{ 1.8016 + nsCSSValue value; 1.8017 + if (ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.8018 + AppendValue(eCSSProperty_grid_auto_position, value); 1.8019 + return true; 1.8020 + } 1.8021 + nsCSSValue columnStartValue; 1.8022 + nsCSSValue rowStartValue; 1.8023 + if (ParseGridLine(columnStartValue) && 1.8024 + ExpectSymbol('/', true) && 1.8025 + ParseGridLine(rowStartValue)) { 1.8026 + value.SetPairValue(columnStartValue, rowStartValue); 1.8027 + AppendValue(eCSSProperty_grid_auto_position, value); 1.8028 + return true; 1.8029 + } 1.8030 + return false; 1.8031 +} 1.8032 + 1.8033 +bool 1.8034 +CSSParserImpl::ParseGridColumnRowStartEnd(nsCSSProperty aPropID) 1.8035 +{ 1.8036 + nsCSSValue value; 1.8037 + if (ParseVariant(value, VARIANT_INHERIT, nullptr) || 1.8038 + ParseGridLine(value)) { 1.8039 + AppendValue(aPropID, value); 1.8040 + return true; 1.8041 + } 1.8042 + return false; 1.8043 +} 1.8044 + 1.8045 +// If |aFallback| is a List containing a single Ident, set |aValue| to that. 1.8046 +// Otherwise, set |aValue| to Auto. 1.8047 +// Used with |aFallback| from ParseGridLine() 1.8048 +static void 1.8049 +HandleGridLineFallback(const nsCSSValue& aFallback, nsCSSValue& aValue) 1.8050 +{ 1.8051 + if (aFallback.GetUnit() == eCSSUnit_List && 1.8052 + aFallback.GetListValue()->mValue.GetUnit() == eCSSUnit_Ident && 1.8053 + !aFallback.GetListValue()->mNext) { 1.8054 + aValue = aFallback; 1.8055 + } else { 1.8056 + aValue.SetAutoValue(); 1.8057 + } 1.8058 +} 1.8059 + 1.8060 +bool 1.8061 +CSSParserImpl::ParseGridColumnRow(nsCSSProperty aStartPropID, 1.8062 + nsCSSProperty aEndPropID) 1.8063 +{ 1.8064 + nsCSSValue value; 1.8065 + nsCSSValue secondValue; 1.8066 + if (ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.8067 + AppendValue(aStartPropID, value); 1.8068 + AppendValue(aEndPropID, value); 1.8069 + return true; 1.8070 + } 1.8071 + 1.8072 + if (!ParseGridLine(value)) { 1.8073 + return false; 1.8074 + } 1.8075 + if (GetToken(true)) { 1.8076 + if (mToken.IsSymbol('/')) { 1.8077 + if (ParseGridLine(secondValue)) { 1.8078 + AppendValue(aStartPropID, value); 1.8079 + AppendValue(aEndPropID, secondValue); 1.8080 + return true; 1.8081 + } else { 1.8082 + return false; 1.8083 + } 1.8084 + } 1.8085 + UngetToken(); 1.8086 + } 1.8087 + 1.8088 + // A single <custom-ident> is repeated to both properties, 1.8089 + // anything else sets the grid-{column,row}-end property to 'auto'. 1.8090 + HandleGridLineFallback(value, secondValue); 1.8091 + 1.8092 + AppendValue(aStartPropID, value); 1.8093 + AppendValue(aEndPropID, secondValue); 1.8094 + return true; 1.8095 +} 1.8096 + 1.8097 +bool 1.8098 +CSSParserImpl::ParseGridArea() 1.8099 +{ 1.8100 + nsCSSValue values[4]; 1.8101 + if (ParseVariant(values[0], VARIANT_INHERIT, nullptr)) { 1.8102 + AppendValue(eCSSProperty_grid_row_start, values[0]); 1.8103 + AppendValue(eCSSProperty_grid_column_start, values[0]); 1.8104 + AppendValue(eCSSProperty_grid_row_end, values[0]); 1.8105 + AppendValue(eCSSProperty_grid_column_end, values[0]); 1.8106 + return true; 1.8107 + } 1.8108 + 1.8109 + int32_t i = 0; 1.8110 + for (;;) { 1.8111 + if (!ParseGridLine(values[i])) { 1.8112 + return false; 1.8113 + } 1.8114 + if (++i == 4 || !GetToken(true)) { 1.8115 + break; 1.8116 + } 1.8117 + if (!mToken.IsSymbol('/')) { 1.8118 + UngetToken(); 1.8119 + break; 1.8120 + } 1.8121 + } 1.8122 + 1.8123 + MOZ_ASSERT(i >= 1, "should have parsed at least one grid-line (or returned)"); 1.8124 + if (i < 2) { 1.8125 + HandleGridLineFallback(values[0], values[1]); 1.8126 + } 1.8127 + if (i < 3) { 1.8128 + HandleGridLineFallback(values[0], values[2]); 1.8129 + } 1.8130 + if (i < 4) { 1.8131 + HandleGridLineFallback(values[1], values[3]); 1.8132 + } 1.8133 + 1.8134 + AppendValue(eCSSProperty_grid_row_start, values[0]); 1.8135 + AppendValue(eCSSProperty_grid_column_start, values[1]); 1.8136 + AppendValue(eCSSProperty_grid_row_end, values[2]); 1.8137 + AppendValue(eCSSProperty_grid_column_end, values[3]); 1.8138 + return true; 1.8139 +} 1.8140 + 1.8141 +// <color-stop> : <color> [ <percentage> | <length> ]? 1.8142 +bool 1.8143 +CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient) 1.8144 +{ 1.8145 + nsCSSValueGradientStop* stop = aGradient->mStops.AppendElement(); 1.8146 + if (!ParseVariant(stop->mColor, VARIANT_COLOR, nullptr)) { 1.8147 + return false; 1.8148 + } 1.8149 + 1.8150 + // Stop positions do not have to fall between the starting-point and 1.8151 + // ending-point, so we don't use ParseNonNegativeVariant. 1.8152 + if (!ParseVariant(stop->mLocation, VARIANT_LP | VARIANT_CALC, nullptr)) { 1.8153 + stop->mLocation.SetNoneValue(); 1.8154 + } 1.8155 + return true; 1.8156 +} 1.8157 + 1.8158 +// <gradient> 1.8159 +// : linear-gradient( <linear-gradient-line>? <color-stops> ')' 1.8160 +// | radial-gradient( <radial-gradient-line>? <color-stops> ')' 1.8161 +// 1.8162 +// <linear-gradient-line> : [ to [left | right] || [top | bottom] ] , 1.8163 +// | <legacy-gradient-line> 1.8164 +// <radial-gradient-line> : [ <shape> || <size> ] [ at <position> ]? , 1.8165 +// | [ at <position> ] , 1.8166 +// | <legacy-gradient-line>? <legacy-shape-size>? 1.8167 +// <shape> : circle | ellipse 1.8168 +// <size> : closest-side | closest-corner | farthest-side | farthest-corner 1.8169 +// | <length> | [<length> | <percentage>]{2} 1.8170 +// 1.8171 +// <legacy-gradient-line> : [ <position> || <angle>] , 1.8172 +// 1.8173 +// <legacy-shape-size> : [ <shape> || <legacy-size> ] , 1.8174 +// <legacy-size> : closest-side | closest-corner | farthest-side 1.8175 +// | farthest-corner | contain | cover 1.8176 +// 1.8177 +// <color-stops> : <color-stop> , <color-stop> [, <color-stop>]* 1.8178 +bool 1.8179 +CSSParserImpl::ParseLinearGradient(nsCSSValue& aValue, bool aIsRepeating, 1.8180 + bool aIsLegacy) 1.8181 +{ 1.8182 + nsRefPtr<nsCSSValueGradient> cssGradient 1.8183 + = new nsCSSValueGradient(false, aIsRepeating); 1.8184 + 1.8185 + if (!GetToken(true)) { 1.8186 + return false; 1.8187 + } 1.8188 + 1.8189 + if (mToken.mType == eCSSToken_Ident && 1.8190 + mToken.mIdent.LowerCaseEqualsLiteral("to")) { 1.8191 + 1.8192 + // "to" syntax doesn't allow explicit "center" 1.8193 + if (!ParseBoxPositionValues(cssGradient->mBgPos, false, false)) { 1.8194 + SkipUntil(')'); 1.8195 + return false; 1.8196 + } 1.8197 + 1.8198 + // [ to [left | right] || [top | bottom] ] , 1.8199 + const nsCSSValue& xValue = cssGradient->mBgPos.mXValue; 1.8200 + const nsCSSValue& yValue = cssGradient->mBgPos.mYValue; 1.8201 + if (xValue.GetUnit() != eCSSUnit_Enumerated || 1.8202 + !(xValue.GetIntValue() & (NS_STYLE_BG_POSITION_LEFT | 1.8203 + NS_STYLE_BG_POSITION_CENTER | 1.8204 + NS_STYLE_BG_POSITION_RIGHT)) || 1.8205 + yValue.GetUnit() != eCSSUnit_Enumerated || 1.8206 + !(yValue.GetIntValue() & (NS_STYLE_BG_POSITION_TOP | 1.8207 + NS_STYLE_BG_POSITION_CENTER | 1.8208 + NS_STYLE_BG_POSITION_BOTTOM))) { 1.8209 + SkipUntil(')'); 1.8210 + return false; 1.8211 + } 1.8212 + 1.8213 + if (!ExpectSymbol(',', true)) { 1.8214 + SkipUntil(')'); 1.8215 + return false; 1.8216 + } 1.8217 + 1.8218 + return ParseGradientColorStops(cssGradient, aValue); 1.8219 + } 1.8220 + 1.8221 + if (!aIsLegacy) { 1.8222 + UngetToken(); 1.8223 + 1.8224 + // <angle> , 1.8225 + if (ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr) && 1.8226 + !ExpectSymbol(',', true)) { 1.8227 + SkipUntil(')'); 1.8228 + return false; 1.8229 + } 1.8230 + 1.8231 + return ParseGradientColorStops(cssGradient, aValue); 1.8232 + } 1.8233 + 1.8234 + nsCSSTokenType ty = mToken.mType; 1.8235 + nsString id = mToken.mIdent; 1.8236 + UngetToken(); 1.8237 + 1.8238 + // <legacy-gradient-line> 1.8239 + bool haveGradientLine = IsLegacyGradientLine(ty, id); 1.8240 + if (haveGradientLine) { 1.8241 + cssGradient->mIsLegacySyntax = true; 1.8242 + bool haveAngle = 1.8243 + ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr); 1.8244 + 1.8245 + // if we got an angle, we might now have a comma, ending the gradient-line 1.8246 + if (!haveAngle || !ExpectSymbol(',', true)) { 1.8247 + if (!ParseBoxPositionValues(cssGradient->mBgPos, false)) { 1.8248 + SkipUntil(')'); 1.8249 + return false; 1.8250 + } 1.8251 + 1.8252 + if (!ExpectSymbol(',', true) && 1.8253 + // if we didn't already get an angle, we might have one now, 1.8254 + // otherwise it's an error 1.8255 + (haveAngle || 1.8256 + !ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr) || 1.8257 + // now we better have a comma 1.8258 + !ExpectSymbol(',', true))) { 1.8259 + SkipUntil(')'); 1.8260 + return false; 1.8261 + } 1.8262 + } 1.8263 + } 1.8264 + 1.8265 + return ParseGradientColorStops(cssGradient, aValue); 1.8266 +} 1.8267 + 1.8268 +bool 1.8269 +CSSParserImpl::ParseRadialGradient(nsCSSValue& aValue, bool aIsRepeating, 1.8270 + bool aIsLegacy) 1.8271 +{ 1.8272 + nsRefPtr<nsCSSValueGradient> cssGradient 1.8273 + = new nsCSSValueGradient(true, aIsRepeating); 1.8274 + 1.8275 + // [ <shape> || <size> ] 1.8276 + bool haveShape = 1.8277 + ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD, 1.8278 + nsCSSProps::kRadialGradientShapeKTable); 1.8279 + 1.8280 + bool haveSize = ParseVariant(cssGradient->GetRadialSize(), VARIANT_KEYWORD, 1.8281 + aIsLegacy ? 1.8282 + nsCSSProps::kRadialGradientLegacySizeKTable : 1.8283 + nsCSSProps::kRadialGradientSizeKTable); 1.8284 + if (haveSize) { 1.8285 + if (!haveShape) { 1.8286 + // <size> <shape> 1.8287 + haveShape = ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD, 1.8288 + nsCSSProps::kRadialGradientShapeKTable); 1.8289 + } 1.8290 + } else if (!aIsLegacy) { 1.8291 + // Save RadialShape before parsing RadiusX because RadialShape and 1.8292 + // RadiusX share the storage. 1.8293 + int32_t shape = 1.8294 + cssGradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated ? 1.8295 + cssGradient->GetRadialShape().GetIntValue() : -1; 1.8296 + // <length> | [<length> | <percentage>]{2} 1.8297 + cssGradient->mIsExplicitSize = true; 1.8298 + haveSize = 1.8299 + ParseNonNegativeVariant(cssGradient->GetRadiusX(), VARIANT_LP, nullptr); 1.8300 + if (!haveSize) { 1.8301 + // It was not an explicit size after all. 1.8302 + // Note that ParseNonNegativeVariant may have put something 1.8303 + // invalid into our storage, but only in the case where it was 1.8304 + // rejected only for being negative. Since this means the token 1.8305 + // was a length or a percentage, we know it's not valid syntax 1.8306 + // (which must be a comma, the 'at' keyword, or a color), so we 1.8307 + // know this value will be dropped. This means it doesn't matter 1.8308 + // that we have something invalid in our storage. 1.8309 + cssGradient->mIsExplicitSize = false; 1.8310 + } else { 1.8311 + // vertical extent is optional 1.8312 + bool haveYSize = 1.8313 + ParseNonNegativeVariant(cssGradient->GetRadiusY(), VARIANT_LP, nullptr); 1.8314 + if (!haveShape) { 1.8315 + nsCSSValue shapeValue; 1.8316 + haveShape = ParseVariant(shapeValue, VARIANT_KEYWORD, 1.8317 + nsCSSProps::kRadialGradientShapeKTable); 1.8318 + if (haveShape) { 1.8319 + shape = shapeValue.GetIntValue(); 1.8320 + } 1.8321 + } 1.8322 + if (haveYSize 1.8323 + ? shape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR 1.8324 + : cssGradient->GetRadiusX().GetUnit() == eCSSUnit_Percent || 1.8325 + shape == NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL) { 1.8326 + SkipUntil(')'); 1.8327 + return false; 1.8328 + } 1.8329 + } 1.8330 + } 1.8331 + 1.8332 + if ((haveShape || haveSize) && ExpectSymbol(',', true)) { 1.8333 + // [ <shape> || <size> ] , 1.8334 + return ParseGradientColorStops(cssGradient, aValue); 1.8335 + } 1.8336 + 1.8337 + if (!GetToken(true)) { 1.8338 + return false; 1.8339 + } 1.8340 + 1.8341 + if (!aIsLegacy) { 1.8342 + if (mToken.mType == eCSSToken_Ident && 1.8343 + mToken.mIdent.LowerCaseEqualsLiteral("at")) { 1.8344 + // [ <shape> || <size> ]? at <position> , 1.8345 + if (!ParseBoxPositionValues(cssGradient->mBgPos, false) || 1.8346 + !ExpectSymbol(',', true)) { 1.8347 + SkipUntil(')'); 1.8348 + return false; 1.8349 + } 1.8350 + 1.8351 + return ParseGradientColorStops(cssGradient, aValue); 1.8352 + } 1.8353 + 1.8354 + // <color-stops> only 1.8355 + UngetToken(); 1.8356 + return ParseGradientColorStops(cssGradient, aValue); 1.8357 + } 1.8358 + MOZ_ASSERT(!cssGradient->mIsExplicitSize); 1.8359 + 1.8360 + nsCSSTokenType ty = mToken.mType; 1.8361 + nsString id = mToken.mIdent; 1.8362 + UngetToken(); 1.8363 + 1.8364 + // <legacy-gradient-line> 1.8365 + bool haveGradientLine = false; 1.8366 + // if we already encountered a shape or size, 1.8367 + // we can not have a gradient-line in legacy syntax 1.8368 + if (!haveShape && !haveSize) { 1.8369 + haveGradientLine = IsLegacyGradientLine(ty, id); 1.8370 + } 1.8371 + if (haveGradientLine) { 1.8372 + bool haveAngle = 1.8373 + ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr); 1.8374 + 1.8375 + // if we got an angle, we might now have a comma, ending the gradient-line 1.8376 + if (!haveAngle || !ExpectSymbol(',', true)) { 1.8377 + if (!ParseBoxPositionValues(cssGradient->mBgPos, false)) { 1.8378 + SkipUntil(')'); 1.8379 + return false; 1.8380 + } 1.8381 + 1.8382 + if (!ExpectSymbol(',', true) && 1.8383 + // if we didn't already get an angle, we might have one now, 1.8384 + // otherwise it's an error 1.8385 + (haveAngle || 1.8386 + !ParseVariant(cssGradient->mAngle, VARIANT_ANGLE, nullptr) || 1.8387 + // now we better have a comma 1.8388 + !ExpectSymbol(',', true))) { 1.8389 + SkipUntil(')'); 1.8390 + return false; 1.8391 + } 1.8392 + } 1.8393 + 1.8394 + if (cssGradient->mAngle.GetUnit() != eCSSUnit_None) { 1.8395 + cssGradient->mIsLegacySyntax = true; 1.8396 + } 1.8397 + } 1.8398 + 1.8399 + // radial gradients might have a shape and size here for legacy syntax 1.8400 + if (!haveShape && !haveSize) { 1.8401 + haveShape = 1.8402 + ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD, 1.8403 + nsCSSProps::kRadialGradientShapeKTable); 1.8404 + haveSize = 1.8405 + ParseVariant(cssGradient->GetRadialSize(), VARIANT_KEYWORD, 1.8406 + nsCSSProps::kRadialGradientLegacySizeKTable); 1.8407 + 1.8408 + // could be in either order 1.8409 + if (!haveShape) { 1.8410 + haveShape = 1.8411 + ParseVariant(cssGradient->GetRadialShape(), VARIANT_KEYWORD, 1.8412 + nsCSSProps::kRadialGradientShapeKTable); 1.8413 + } 1.8414 + } 1.8415 + 1.8416 + if ((haveShape || haveSize) && !ExpectSymbol(',', true)) { 1.8417 + SkipUntil(')'); 1.8418 + return false; 1.8419 + } 1.8420 + 1.8421 + return ParseGradientColorStops(cssGradient, aValue); 1.8422 +} 1.8423 + 1.8424 +bool 1.8425 +CSSParserImpl::IsLegacyGradientLine(const nsCSSTokenType& aType, 1.8426 + const nsString& aId) 1.8427 +{ 1.8428 + // N.B. ParseBoxPositionValues is not guaranteed to put back 1.8429 + // everything it scanned if it fails, so we must only call it 1.8430 + // if there is no alternative to consuming a <box-position>. 1.8431 + // ParseVariant, as used here, will either succeed and consume 1.8432 + // a single token, or fail and consume none, so we can be more 1.8433 + // cavalier about calling it. 1.8434 + 1.8435 + bool haveGradientLine = false; 1.8436 + switch (aType) { 1.8437 + case eCSSToken_Percentage: 1.8438 + case eCSSToken_Number: 1.8439 + case eCSSToken_Dimension: 1.8440 + haveGradientLine = true; 1.8441 + break; 1.8442 + 1.8443 + case eCSSToken_Function: 1.8444 + if (aId.LowerCaseEqualsLiteral("calc") || 1.8445 + aId.LowerCaseEqualsLiteral("-moz-calc")) { 1.8446 + haveGradientLine = true; 1.8447 + break; 1.8448 + } 1.8449 + // fall through 1.8450 + case eCSSToken_ID: 1.8451 + case eCSSToken_Hash: 1.8452 + // this is a color 1.8453 + break; 1.8454 + 1.8455 + case eCSSToken_Ident: { 1.8456 + // This is only a gradient line if it's a box position keyword. 1.8457 + nsCSSKeyword kw = nsCSSKeywords::LookupKeyword(aId); 1.8458 + int32_t junk; 1.8459 + if (kw != eCSSKeyword_UNKNOWN && 1.8460 + nsCSSProps::FindKeyword(kw, nsCSSProps::kBackgroundPositionKTable, 1.8461 + junk)) { 1.8462 + haveGradientLine = true; 1.8463 + } 1.8464 + break; 1.8465 + } 1.8466 + 1.8467 + default: 1.8468 + // error 1.8469 + break; 1.8470 + } 1.8471 + 1.8472 + return haveGradientLine; 1.8473 +} 1.8474 + 1.8475 +bool 1.8476 +CSSParserImpl::ParseGradientColorStops(nsCSSValueGradient* aGradient, 1.8477 + nsCSSValue& aValue) 1.8478 +{ 1.8479 + // At least two color stops are required 1.8480 + if (!ParseColorStop(aGradient) || 1.8481 + !ExpectSymbol(',', true) || 1.8482 + !ParseColorStop(aGradient)) { 1.8483 + SkipUntil(')'); 1.8484 + return false; 1.8485 + } 1.8486 + 1.8487 + // Additional color stops 1.8488 + while (ExpectSymbol(',', true)) { 1.8489 + if (!ParseColorStop(aGradient)) { 1.8490 + SkipUntil(')'); 1.8491 + return false; 1.8492 + } 1.8493 + } 1.8494 + 1.8495 + if (!ExpectSymbol(')', true)) { 1.8496 + SkipUntil(')'); 1.8497 + return false; 1.8498 + } 1.8499 + 1.8500 + aValue.SetGradientValue(aGradient); 1.8501 + return true; 1.8502 +} 1.8503 + 1.8504 +int32_t 1.8505 +CSSParserImpl::ParseChoice(nsCSSValue aValues[], 1.8506 + const nsCSSProperty aPropIDs[], int32_t aNumIDs) 1.8507 +{ 1.8508 + int32_t found = 0; 1.8509 + nsAutoParseCompoundProperty compound(this); 1.8510 + 1.8511 + int32_t loop; 1.8512 + for (loop = 0; loop < aNumIDs; loop++) { 1.8513 + // Try each property parser in order 1.8514 + int32_t hadFound = found; 1.8515 + int32_t index; 1.8516 + for (index = 0; index < aNumIDs; index++) { 1.8517 + int32_t bit = 1 << index; 1.8518 + if ((found & bit) == 0) { 1.8519 + if (ParseSingleValueProperty(aValues[index], aPropIDs[index])) { 1.8520 + found |= bit; 1.8521 + // It's more efficient to break since it will reset |hadFound| 1.8522 + // to |found|. Furthermore, ParseListStyle depends on our going 1.8523 + // through the properties in order for each value.. 1.8524 + break; 1.8525 + } 1.8526 + } 1.8527 + } 1.8528 + if (found == hadFound) { // found nothing new 1.8529 + break; 1.8530 + } 1.8531 + } 1.8532 + if (0 < found) { 1.8533 + if (1 == found) { // only first property 1.8534 + if (eCSSUnit_Inherit == aValues[0].GetUnit()) { // one inherit, all inherit 1.8535 + for (loop = 1; loop < aNumIDs; loop++) { 1.8536 + aValues[loop].SetInheritValue(); 1.8537 + } 1.8538 + found = ((1 << aNumIDs) - 1); 1.8539 + } 1.8540 + else if (eCSSUnit_Initial == aValues[0].GetUnit()) { // one initial, all initial 1.8541 + for (loop = 1; loop < aNumIDs; loop++) { 1.8542 + aValues[loop].SetInitialValue(); 1.8543 + } 1.8544 + found = ((1 << aNumIDs) - 1); 1.8545 + } 1.8546 + else if (eCSSUnit_Unset == aValues[0].GetUnit()) { // one unset, all unset 1.8547 + for (loop = 1; loop < aNumIDs; loop++) { 1.8548 + aValues[loop].SetUnsetValue(); 1.8549 + } 1.8550 + found = ((1 << aNumIDs) - 1); 1.8551 + } 1.8552 + } 1.8553 + else { // more than one value, verify no inherits, initials or unsets 1.8554 + for (loop = 0; loop < aNumIDs; loop++) { 1.8555 + if (eCSSUnit_Inherit == aValues[loop].GetUnit()) { 1.8556 + found = -1; 1.8557 + break; 1.8558 + } 1.8559 + else if (eCSSUnit_Initial == aValues[loop].GetUnit()) { 1.8560 + found = -1; 1.8561 + break; 1.8562 + } 1.8563 + else if (eCSSUnit_Unset == aValues[loop].GetUnit()) { 1.8564 + found = -1; 1.8565 + break; 1.8566 + } 1.8567 + } 1.8568 + } 1.8569 + } 1.8570 + return found; 1.8571 +} 1.8572 + 1.8573 +void 1.8574 +CSSParserImpl::AppendValue(nsCSSProperty aPropID, const nsCSSValue& aValue) 1.8575 +{ 1.8576 + mTempData.AddLonghandProperty(aPropID, aValue); 1.8577 +} 1.8578 + 1.8579 +/** 1.8580 + * Parse a "box" property. Box properties have 1 to 4 values. When less 1.8581 + * than 4 values are provided a standard mapping is used to replicate 1.8582 + * existing values. 1.8583 + */ 1.8584 +bool 1.8585 +CSSParserImpl::ParseBoxProperties(const nsCSSProperty aPropIDs[]) 1.8586 +{ 1.8587 + // Get up to four values for the property 1.8588 + int32_t count = 0; 1.8589 + nsCSSRect result; 1.8590 + NS_FOR_CSS_SIDES (index) { 1.8591 + if (! ParseSingleValueProperty(result.*(nsCSSRect::sides[index]), 1.8592 + aPropIDs[index])) { 1.8593 + break; 1.8594 + } 1.8595 + count++; 1.8596 + } 1.8597 + if (count == 0) { 1.8598 + return false; 1.8599 + } 1.8600 + 1.8601 + if (1 < count) { // verify no more than single inherit, initial or unset 1.8602 + NS_FOR_CSS_SIDES (index) { 1.8603 + nsCSSUnit unit = (result.*(nsCSSRect::sides[index])).GetUnit(); 1.8604 + if (eCSSUnit_Inherit == unit || 1.8605 + eCSSUnit_Initial == unit || 1.8606 + eCSSUnit_Unset == unit) { 1.8607 + return false; 1.8608 + } 1.8609 + } 1.8610 + } 1.8611 + 1.8612 + // Provide missing values by replicating some of the values found 1.8613 + switch (count) { 1.8614 + case 1: // Make right == top 1.8615 + result.mRight = result.mTop; 1.8616 + case 2: // Make bottom == top 1.8617 + result.mBottom = result.mTop; 1.8618 + case 3: // Make left == right 1.8619 + result.mLeft = result.mRight; 1.8620 + } 1.8621 + 1.8622 + NS_FOR_CSS_SIDES (index) { 1.8623 + AppendValue(aPropIDs[index], result.*(nsCSSRect::sides[index])); 1.8624 + } 1.8625 + return true; 1.8626 +} 1.8627 + 1.8628 +// Similar to ParseBoxProperties, except there is only one property 1.8629 +// with the result as its value, not four. Requires values be nonnegative. 1.8630 +bool 1.8631 +CSSParserImpl::ParseGroupedBoxProperty(int32_t aVariantMask, 1.8632 + /** outparam */ nsCSSValue& aValue) 1.8633 +{ 1.8634 + nsCSSRect& result = aValue.SetRectValue(); 1.8635 + 1.8636 + int32_t count = 0; 1.8637 + NS_FOR_CSS_SIDES (index) { 1.8638 + if (!ParseNonNegativeVariant(result.*(nsCSSRect::sides[index]), 1.8639 + aVariantMask, nullptr)) { 1.8640 + break; 1.8641 + } 1.8642 + count++; 1.8643 + } 1.8644 + 1.8645 + if (count == 0) { 1.8646 + return false; 1.8647 + } 1.8648 + 1.8649 + // Provide missing values by replicating some of the values found 1.8650 + switch (count) { 1.8651 + case 1: // Make right == top 1.8652 + result.mRight = result.mTop; 1.8653 + case 2: // Make bottom == top 1.8654 + result.mBottom = result.mTop; 1.8655 + case 3: // Make left == right 1.8656 + result.mLeft = result.mRight; 1.8657 + } 1.8658 + 1.8659 + return true; 1.8660 +} 1.8661 + 1.8662 +bool 1.8663 +CSSParserImpl::ParseDirectionalBoxProperty(nsCSSProperty aProperty, 1.8664 + int32_t aSourceType) 1.8665 +{ 1.8666 + const nsCSSProperty* subprops = nsCSSProps::SubpropertyEntryFor(aProperty); 1.8667 + NS_ASSERTION(subprops[3] == eCSSProperty_UNKNOWN, 1.8668 + "not box property with physical vs. logical cascading"); 1.8669 + nsCSSValue value; 1.8670 + if (!ParseSingleValueProperty(value, subprops[0])) { 1.8671 + return false; 1.8672 + } 1.8673 + 1.8674 + AppendValue(subprops[0], value); 1.8675 + nsCSSValue typeVal(aSourceType, eCSSUnit_Enumerated); 1.8676 + AppendValue(subprops[1], typeVal); 1.8677 + AppendValue(subprops[2], typeVal); 1.8678 + return true; 1.8679 +} 1.8680 + 1.8681 +bool 1.8682 +CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID) 1.8683 +{ 1.8684 + nsCSSValue dimenX, dimenY; 1.8685 + // required first value 1.8686 + if (! ParseNonNegativeVariant(dimenX, VARIANT_HLP | VARIANT_CALC, nullptr)) 1.8687 + return false; 1.8688 + 1.8689 + // optional second value (forbidden if first value is inherit/initial/unset) 1.8690 + if (dimenX.GetUnit() != eCSSUnit_Inherit && 1.8691 + dimenX.GetUnit() != eCSSUnit_Initial && 1.8692 + dimenX.GetUnit() != eCSSUnit_Unset) { 1.8693 + ParseNonNegativeVariant(dimenY, VARIANT_LP | VARIANT_CALC, nullptr); 1.8694 + } 1.8695 + 1.8696 + if (dimenX == dimenY || dimenY.GetUnit() == eCSSUnit_Null) { 1.8697 + AppendValue(aPropID, dimenX); 1.8698 + } else { 1.8699 + nsCSSValue value; 1.8700 + value.SetPairValue(dimenX, dimenY); 1.8701 + AppendValue(aPropID, value); 1.8702 + } 1.8703 + return true; 1.8704 +} 1.8705 + 1.8706 +bool 1.8707 +CSSParserImpl::ParseBoxCornerRadii(const nsCSSProperty aPropIDs[]) 1.8708 +{ 1.8709 + // Rectangles are used as scratch storage. 1.8710 + // top => top-left, right => top-right, 1.8711 + // bottom => bottom-right, left => bottom-left. 1.8712 + nsCSSRect dimenX, dimenY; 1.8713 + int32_t countX = 0, countY = 0; 1.8714 + 1.8715 + NS_FOR_CSS_SIDES (side) { 1.8716 + if (! ParseNonNegativeVariant(dimenX.*nsCSSRect::sides[side], 1.8717 + (side > 0 ? 0 : VARIANT_INHERIT) | 1.8718 + VARIANT_LP | VARIANT_CALC, 1.8719 + nullptr)) 1.8720 + break; 1.8721 + countX++; 1.8722 + } 1.8723 + if (countX == 0) 1.8724 + return false; 1.8725 + 1.8726 + if (ExpectSymbol('/', true)) { 1.8727 + NS_FOR_CSS_SIDES (side) { 1.8728 + if (! ParseNonNegativeVariant(dimenY.*nsCSSRect::sides[side], 1.8729 + VARIANT_LP | VARIANT_CALC, nullptr)) 1.8730 + break; 1.8731 + countY++; 1.8732 + } 1.8733 + if (countY == 0) 1.8734 + return false; 1.8735 + } 1.8736 + 1.8737 + // if 'initial', 'inherit' or 'unset' was used, it must be the only value 1.8738 + if (countX > 1 || countY > 0) { 1.8739 + nsCSSUnit unit = dimenX.mTop.GetUnit(); 1.8740 + if (eCSSUnit_Inherit == unit || 1.8741 + eCSSUnit_Initial == unit || 1.8742 + eCSSUnit_Unset == unit) 1.8743 + return false; 1.8744 + } 1.8745 + 1.8746 + // if we have no Y-values, use the X-values 1.8747 + if (countY == 0) { 1.8748 + dimenY = dimenX; 1.8749 + countY = countX; 1.8750 + } 1.8751 + 1.8752 + // Provide missing values by replicating some of the values found 1.8753 + switch (countX) { 1.8754 + case 1: dimenX.mRight = dimenX.mTop; // top-right same as top-left, and 1.8755 + case 2: dimenX.mBottom = dimenX.mTop; // bottom-right same as top-left, and 1.8756 + case 3: dimenX.mLeft = dimenX.mRight; // bottom-left same as top-right 1.8757 + } 1.8758 + 1.8759 + switch (countY) { 1.8760 + case 1: dimenY.mRight = dimenY.mTop; // top-right same as top-left, and 1.8761 + case 2: dimenY.mBottom = dimenY.mTop; // bottom-right same as top-left, and 1.8762 + case 3: dimenY.mLeft = dimenY.mRight; // bottom-left same as top-right 1.8763 + } 1.8764 + 1.8765 + NS_FOR_CSS_SIDES(side) { 1.8766 + nsCSSValue& x = dimenX.*nsCSSRect::sides[side]; 1.8767 + nsCSSValue& y = dimenY.*nsCSSRect::sides[side]; 1.8768 + 1.8769 + if (x == y) { 1.8770 + AppendValue(aPropIDs[side], x); 1.8771 + } else { 1.8772 + nsCSSValue pair; 1.8773 + pair.SetPairValue(x, y); 1.8774 + AppendValue(aPropIDs[side], pair); 1.8775 + } 1.8776 + } 1.8777 + return true; 1.8778 +} 1.8779 + 1.8780 +// These must be in CSS order (top,right,bottom,left) for indexing to work 1.8781 +static const nsCSSProperty kBorderStyleIDs[] = { 1.8782 + eCSSProperty_border_top_style, 1.8783 + eCSSProperty_border_right_style_value, 1.8784 + eCSSProperty_border_bottom_style, 1.8785 + eCSSProperty_border_left_style_value 1.8786 +}; 1.8787 +static const nsCSSProperty kBorderWidthIDs[] = { 1.8788 + eCSSProperty_border_top_width, 1.8789 + eCSSProperty_border_right_width_value, 1.8790 + eCSSProperty_border_bottom_width, 1.8791 + eCSSProperty_border_left_width_value 1.8792 +}; 1.8793 +static const nsCSSProperty kBorderColorIDs[] = { 1.8794 + eCSSProperty_border_top_color, 1.8795 + eCSSProperty_border_right_color_value, 1.8796 + eCSSProperty_border_bottom_color, 1.8797 + eCSSProperty_border_left_color_value 1.8798 +}; 1.8799 +static const nsCSSProperty kBorderRadiusIDs[] = { 1.8800 + eCSSProperty_border_top_left_radius, 1.8801 + eCSSProperty_border_top_right_radius, 1.8802 + eCSSProperty_border_bottom_right_radius, 1.8803 + eCSSProperty_border_bottom_left_radius 1.8804 +}; 1.8805 +static const nsCSSProperty kOutlineRadiusIDs[] = { 1.8806 + eCSSProperty__moz_outline_radius_topLeft, 1.8807 + eCSSProperty__moz_outline_radius_topRight, 1.8808 + eCSSProperty__moz_outline_radius_bottomRight, 1.8809 + eCSSProperty__moz_outline_radius_bottomLeft 1.8810 +}; 1.8811 + 1.8812 +void 1.8813 +CSSParserImpl::SaveInputState(CSSParserInputState& aState) 1.8814 +{ 1.8815 + aState.mToken = mToken; 1.8816 + aState.mHavePushBack = mHavePushBack; 1.8817 + mScanner->SavePosition(aState.mPosition); 1.8818 +} 1.8819 + 1.8820 +void 1.8821 +CSSParserImpl::RestoreSavedInputState(const CSSParserInputState& aState) 1.8822 +{ 1.8823 + mToken = aState.mToken; 1.8824 + mHavePushBack = aState.mHavePushBack; 1.8825 + mScanner->RestoreSavedPosition(aState.mPosition); 1.8826 +} 1.8827 + 1.8828 +bool 1.8829 +CSSParserImpl::ParseProperty(nsCSSProperty aPropID) 1.8830 +{ 1.8831 + // Can't use AutoRestore<bool> because it's a bitfield. 1.8832 + NS_ABORT_IF_FALSE(!mHashlessColorQuirk, 1.8833 + "hashless color quirk should not be set"); 1.8834 + NS_ABORT_IF_FALSE(!mUnitlessLengthQuirk, 1.8835 + "unitless length quirk should not be set"); 1.8836 + 1.8837 + if (mNavQuirkMode) { 1.8838 + mHashlessColorQuirk = 1.8839 + nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_HASHLESS_COLOR_QUIRK); 1.8840 + mUnitlessLengthQuirk = 1.8841 + nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_UNITLESS_LENGTH_QUIRK); 1.8842 + } 1.8843 + 1.8844 + // Save the current input state so that we can restore it later if we 1.8845 + // have to re-parse the property value as a variable-reference-containing 1.8846 + // token stream. 1.8847 + CSSParserInputState stateBeforeProperty; 1.8848 + SaveInputState(stateBeforeProperty); 1.8849 + mScanner->ClearSeenVariableReference(); 1.8850 + 1.8851 + NS_ASSERTION(aPropID < eCSSProperty_COUNT, "index out of range"); 1.8852 + bool allowVariables = true; 1.8853 + bool result; 1.8854 + switch (nsCSSProps::PropertyParseType(aPropID)) { 1.8855 + case CSS_PROPERTY_PARSE_INACCESSIBLE: { 1.8856 + // The user can't use these 1.8857 + REPORT_UNEXPECTED(PEInaccessibleProperty2); 1.8858 + allowVariables = false; 1.8859 + result = false; 1.8860 + break; 1.8861 + } 1.8862 + case CSS_PROPERTY_PARSE_FUNCTION: { 1.8863 + result = ParsePropertyByFunction(aPropID); 1.8864 + break; 1.8865 + } 1.8866 + case CSS_PROPERTY_PARSE_VALUE: { 1.8867 + result = false; 1.8868 + nsCSSValue value; 1.8869 + if (ParseSingleValueProperty(value, aPropID)) { 1.8870 + AppendValue(aPropID, value); 1.8871 + result = true; 1.8872 + } 1.8873 + // XXX Report errors? 1.8874 + break; 1.8875 + } 1.8876 + case CSS_PROPERTY_PARSE_VALUE_LIST: { 1.8877 + result = ParseValueList(aPropID); 1.8878 + break; 1.8879 + } 1.8880 + default: { 1.8881 + result = false; 1.8882 + allowVariables = false; 1.8883 + NS_ABORT_IF_FALSE(false, 1.8884 + "Property's flags field in nsCSSPropList.h is missing " 1.8885 + "one of the CSS_PROPERTY_PARSE_* constants"); 1.8886 + break; 1.8887 + } 1.8888 + } 1.8889 + 1.8890 + if (result) { 1.8891 + // We need to call ExpectEndProperty() to decide whether to reparse 1.8892 + // with variables. This is needed because the property parsing may 1.8893 + // have stopped upon finding a variable (e.g., 'margin: 1px var(a)') 1.8894 + // in a way that future variable substitutions will be valid, or 1.8895 + // because it parsed everything that's possible but we still want to 1.8896 + // act as though the property contains variables even though we know 1.8897 + // the substitution will never work (e.g., for 'margin: 1px 2px 3px 1.8898 + // 4px 5px var(a)'). 1.8899 + // 1.8900 + // It would be nice to find a better solution here 1.8901 + // (and for the SkipUntilOneOf below), though, that doesn't depend 1.8902 + // on using what we don't accept for doing parsing correctly. 1.8903 + if (!ExpectEndProperty()) { 1.8904 + result = false; 1.8905 + } 1.8906 + } 1.8907 + 1.8908 + bool seenVariable = mScanner->SeenVariableReference() || 1.8909 + (stateBeforeProperty.mHavePushBack && 1.8910 + stateBeforeProperty.mToken.mType == eCSSToken_Function && 1.8911 + stateBeforeProperty.mToken.mIdent.LowerCaseEqualsLiteral("var")); 1.8912 + bool parseAsTokenStream; 1.8913 + 1.8914 + if (!result && allowVariables) { 1.8915 + parseAsTokenStream = true; 1.8916 + if (!seenVariable) { 1.8917 + // We might have stopped parsing the property before its end and before 1.8918 + // finding a variable reference. Keep checking until the end of the 1.8919 + // property. 1.8920 + CSSParserInputState stateAtError; 1.8921 + SaveInputState(stateAtError); 1.8922 + 1.8923 + const char16_t stopChars[] = { ';', '!', '}', ')', 0 }; 1.8924 + SkipUntilOneOf(stopChars); 1.8925 + UngetToken(); 1.8926 + parseAsTokenStream = mScanner->SeenVariableReference(); 1.8927 + 1.8928 + if (!parseAsTokenStream) { 1.8929 + // If we parsed to the end of the propery and didn't find any variable 1.8930 + // references, then the real position we want to report the error at 1.8931 + // is |stateAtError|. 1.8932 + RestoreSavedInputState(stateAtError); 1.8933 + } 1.8934 + } 1.8935 + } else { 1.8936 + parseAsTokenStream = false; 1.8937 + } 1.8938 + 1.8939 + if (parseAsTokenStream) { 1.8940 + // Go back to the start of the property value and parse it to make sure 1.8941 + // its variable references are syntactically valid and is otherwise 1.8942 + // balanced. 1.8943 + RestoreSavedInputState(stateBeforeProperty); 1.8944 + 1.8945 + if (!mInSupportsCondition) { 1.8946 + mScanner->StartRecording(); 1.8947 + } 1.8948 + 1.8949 + CSSVariableDeclarations::Type type; 1.8950 + bool dropBackslash; 1.8951 + nsString impliedCharacters; 1.8952 + nsCSSValue value; 1.8953 + if (ParseValueWithVariables(&type, &dropBackslash, impliedCharacters, 1.8954 + nullptr, nullptr)) { 1.8955 + MOZ_ASSERT(type == CSSVariableDeclarations::eTokenStream, 1.8956 + "a non-custom property reparsed since it contained variable " 1.8957 + "references should not have been 'initial' or 'inherit'"); 1.8958 + 1.8959 + nsString propertyValue; 1.8960 + 1.8961 + if (!mInSupportsCondition) { 1.8962 + // If we are in an @supports condition, we don't need to store the 1.8963 + // actual token stream on the nsCSSValue. 1.8964 + mScanner->StopRecording(propertyValue); 1.8965 + if (dropBackslash) { 1.8966 + MOZ_ASSERT(!propertyValue.IsEmpty() && 1.8967 + propertyValue[propertyValue.Length() - 1] == '\\'); 1.8968 + propertyValue.Truncate(propertyValue.Length() - 1); 1.8969 + } 1.8970 + propertyValue.Append(impliedCharacters); 1.8971 + } 1.8972 + 1.8973 + if (mHavePushBack) { 1.8974 + // If we came to the end of a property value that had a variable 1.8975 + // reference and a token was pushed back, then it would have been 1.8976 + // ended by '!', ')', ';', ']' or '}'. We should remove it from the 1.8977 + // recorded property value. 1.8978 + MOZ_ASSERT(mToken.IsSymbol('!') || 1.8979 + mToken.IsSymbol(')') || 1.8980 + mToken.IsSymbol(';') || 1.8981 + mToken.IsSymbol(']') || 1.8982 + mToken.IsSymbol('}')); 1.8983 + if (!mInSupportsCondition) { 1.8984 + MOZ_ASSERT(!propertyValue.IsEmpty()); 1.8985 + MOZ_ASSERT(propertyValue[propertyValue.Length() - 1] == 1.8986 + mToken.mSymbol); 1.8987 + propertyValue.Truncate(propertyValue.Length() - 1); 1.8988 + } 1.8989 + } 1.8990 + 1.8991 + if (!mInSupportsCondition) { 1.8992 + if (nsCSSProps::IsShorthand(aPropID)) { 1.8993 + // If this is a shorthand property, we store the token stream on each 1.8994 + // of its corresponding longhand properties. 1.8995 + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID) { 1.8996 + nsCSSValueTokenStream* tokenStream = new nsCSSValueTokenStream; 1.8997 + tokenStream->mPropertyID = *p; 1.8998 + tokenStream->mShorthandPropertyID = aPropID; 1.8999 + tokenStream->mTokenStream = propertyValue; 1.9000 + tokenStream->mBaseURI = mBaseURI; 1.9001 + tokenStream->mSheetURI = mSheetURI; 1.9002 + tokenStream->mSheetPrincipal = mSheetPrincipal; 1.9003 + tokenStream->mSheet = mSheet; 1.9004 + tokenStream->mLineNumber = stateBeforeProperty.mPosition.LineNumber(); 1.9005 + tokenStream->mLineOffset = stateBeforeProperty.mPosition.LineOffset(); 1.9006 + value.SetTokenStreamValue(tokenStream); 1.9007 + AppendValue(*p, value); 1.9008 + } 1.9009 + } else { 1.9010 + nsCSSValueTokenStream* tokenStream = new nsCSSValueTokenStream; 1.9011 + tokenStream->mPropertyID = aPropID; 1.9012 + tokenStream->mTokenStream = propertyValue; 1.9013 + tokenStream->mBaseURI = mBaseURI; 1.9014 + tokenStream->mSheetURI = mSheetURI; 1.9015 + tokenStream->mSheetPrincipal = mSheetPrincipal; 1.9016 + tokenStream->mSheet = mSheet; 1.9017 + tokenStream->mLineNumber = stateBeforeProperty.mPosition.LineNumber(); 1.9018 + tokenStream->mLineOffset = stateBeforeProperty.mPosition.LineOffset(); 1.9019 + value.SetTokenStreamValue(tokenStream); 1.9020 + AppendValue(aPropID, value); 1.9021 + } 1.9022 + } 1.9023 + result = true; 1.9024 + } else { 1.9025 + if (!mInSupportsCondition) { 1.9026 + mScanner->StopRecording(); 1.9027 + } 1.9028 + } 1.9029 + } 1.9030 + 1.9031 + if (mNavQuirkMode) { 1.9032 + mHashlessColorQuirk = false; 1.9033 + mUnitlessLengthQuirk = false; 1.9034 + } 1.9035 + 1.9036 + return result; 1.9037 +} 1.9038 + 1.9039 +bool 1.9040 +CSSParserImpl::ParsePropertyByFunction(nsCSSProperty aPropID) 1.9041 +{ 1.9042 + switch (aPropID) { // handle shorthand or multiple properties 1.9043 + case eCSSProperty_background: 1.9044 + return ParseBackground(); 1.9045 + case eCSSProperty_background_repeat: 1.9046 + return ParseBackgroundRepeat(); 1.9047 + case eCSSProperty_background_position: 1.9048 + return ParseBackgroundPosition(); 1.9049 + case eCSSProperty_background_size: 1.9050 + return ParseBackgroundSize(); 1.9051 + case eCSSProperty_border: 1.9052 + return ParseBorderSide(kBorderTopIDs, true); 1.9053 + case eCSSProperty_border_color: 1.9054 + return ParseBorderColor(); 1.9055 + case eCSSProperty_border_spacing: 1.9056 + return ParseBorderSpacing(); 1.9057 + case eCSSProperty_border_style: 1.9058 + return ParseBorderStyle(); 1.9059 + case eCSSProperty_border_bottom: 1.9060 + return ParseBorderSide(kBorderBottomIDs, false); 1.9061 + case eCSSProperty_border_end: 1.9062 + return ParseDirectionalBorderSide(kBorderEndIDs, 1.9063 + NS_BOXPROP_SOURCE_LOGICAL); 1.9064 + case eCSSProperty_border_left: 1.9065 + return ParseDirectionalBorderSide(kBorderLeftIDs, 1.9066 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9067 + case eCSSProperty_border_right: 1.9068 + return ParseDirectionalBorderSide(kBorderRightIDs, 1.9069 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9070 + case eCSSProperty_border_start: 1.9071 + return ParseDirectionalBorderSide(kBorderStartIDs, 1.9072 + NS_BOXPROP_SOURCE_LOGICAL); 1.9073 + case eCSSProperty_border_top: 1.9074 + return ParseBorderSide(kBorderTopIDs, false); 1.9075 + case eCSSProperty_border_bottom_colors: 1.9076 + case eCSSProperty_border_left_colors: 1.9077 + case eCSSProperty_border_right_colors: 1.9078 + case eCSSProperty_border_top_colors: 1.9079 + return ParseBorderColors(aPropID); 1.9080 + case eCSSProperty_border_image_slice: 1.9081 + return ParseBorderImageSlice(true, nullptr); 1.9082 + case eCSSProperty_border_image_width: 1.9083 + return ParseBorderImageWidth(true); 1.9084 + case eCSSProperty_border_image_outset: 1.9085 + return ParseBorderImageOutset(true); 1.9086 + case eCSSProperty_border_image_repeat: 1.9087 + return ParseBorderImageRepeat(true); 1.9088 + case eCSSProperty_border_image: 1.9089 + return ParseBorderImage(); 1.9090 + case eCSSProperty_border_width: 1.9091 + return ParseBorderWidth(); 1.9092 + case eCSSProperty_border_end_color: 1.9093 + return ParseDirectionalBoxProperty(eCSSProperty_border_end_color, 1.9094 + NS_BOXPROP_SOURCE_LOGICAL); 1.9095 + case eCSSProperty_border_left_color: 1.9096 + return ParseDirectionalBoxProperty(eCSSProperty_border_left_color, 1.9097 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9098 + case eCSSProperty_border_right_color: 1.9099 + return ParseDirectionalBoxProperty(eCSSProperty_border_right_color, 1.9100 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9101 + case eCSSProperty_border_start_color: 1.9102 + return ParseDirectionalBoxProperty(eCSSProperty_border_start_color, 1.9103 + NS_BOXPROP_SOURCE_LOGICAL); 1.9104 + case eCSSProperty_border_end_width: 1.9105 + return ParseDirectionalBoxProperty(eCSSProperty_border_end_width, 1.9106 + NS_BOXPROP_SOURCE_LOGICAL); 1.9107 + case eCSSProperty_border_left_width: 1.9108 + return ParseDirectionalBoxProperty(eCSSProperty_border_left_width, 1.9109 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9110 + case eCSSProperty_border_right_width: 1.9111 + return ParseDirectionalBoxProperty(eCSSProperty_border_right_width, 1.9112 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9113 + case eCSSProperty_border_start_width: 1.9114 + return ParseDirectionalBoxProperty(eCSSProperty_border_start_width, 1.9115 + NS_BOXPROP_SOURCE_LOGICAL); 1.9116 + case eCSSProperty_border_end_style: 1.9117 + return ParseDirectionalBoxProperty(eCSSProperty_border_end_style, 1.9118 + NS_BOXPROP_SOURCE_LOGICAL); 1.9119 + case eCSSProperty_border_left_style: 1.9120 + return ParseDirectionalBoxProperty(eCSSProperty_border_left_style, 1.9121 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9122 + case eCSSProperty_border_right_style: 1.9123 + return ParseDirectionalBoxProperty(eCSSProperty_border_right_style, 1.9124 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9125 + case eCSSProperty_border_start_style: 1.9126 + return ParseDirectionalBoxProperty(eCSSProperty_border_start_style, 1.9127 + NS_BOXPROP_SOURCE_LOGICAL); 1.9128 + case eCSSProperty_border_radius: 1.9129 + return ParseBoxCornerRadii(kBorderRadiusIDs); 1.9130 + case eCSSProperty__moz_outline_radius: 1.9131 + return ParseBoxCornerRadii(kOutlineRadiusIDs); 1.9132 + 1.9133 + case eCSSProperty_border_top_left_radius: 1.9134 + case eCSSProperty_border_top_right_radius: 1.9135 + case eCSSProperty_border_bottom_right_radius: 1.9136 + case eCSSProperty_border_bottom_left_radius: 1.9137 + case eCSSProperty__moz_outline_radius_topLeft: 1.9138 + case eCSSProperty__moz_outline_radius_topRight: 1.9139 + case eCSSProperty__moz_outline_radius_bottomRight: 1.9140 + case eCSSProperty__moz_outline_radius_bottomLeft: 1.9141 + return ParseBoxCornerRadius(aPropID); 1.9142 + 1.9143 + case eCSSProperty_box_shadow: 1.9144 + case eCSSProperty_text_shadow: 1.9145 + return ParseShadowList(aPropID); 1.9146 + 1.9147 + case eCSSProperty_clip: 1.9148 + return ParseRect(eCSSProperty_clip); 1.9149 + case eCSSProperty__moz_columns: 1.9150 + return ParseColumns(); 1.9151 + case eCSSProperty__moz_column_rule: 1.9152 + return ParseBorderSide(kColumnRuleIDs, false); 1.9153 + case eCSSProperty_content: 1.9154 + return ParseContent(); 1.9155 + case eCSSProperty_counter_increment: 1.9156 + case eCSSProperty_counter_reset: 1.9157 + return ParseCounterData(aPropID); 1.9158 + case eCSSProperty_cursor: 1.9159 + return ParseCursor(); 1.9160 + case eCSSProperty_filter: 1.9161 + return ParseFilter(); 1.9162 + case eCSSProperty_flex: 1.9163 + return ParseFlex(); 1.9164 + case eCSSProperty_flex_flow: 1.9165 + return ParseFlexFlow(); 1.9166 + case eCSSProperty_font: 1.9167 + return ParseFont(); 1.9168 + case eCSSProperty_grid_auto_flow: 1.9169 + return ParseGridAutoFlow(); 1.9170 + case eCSSProperty_grid_auto_columns: 1.9171 + case eCSSProperty_grid_auto_rows: 1.9172 + return ParseGridAutoColumnsRows(aPropID); 1.9173 + case eCSSProperty_grid_template_areas: 1.9174 + return ParseGridTemplateAreas(); 1.9175 + case eCSSProperty_grid_template_columns: 1.9176 + case eCSSProperty_grid_template_rows: 1.9177 + return ParseGridTemplateColumnsRows(aPropID); 1.9178 + case eCSSProperty_grid_template: 1.9179 + return ParseGridTemplate(); 1.9180 + case eCSSProperty_grid: 1.9181 + return ParseGrid(); 1.9182 + case eCSSProperty_grid_auto_position: 1.9183 + return ParseGridAutoPosition(); 1.9184 + case eCSSProperty_grid_column_start: 1.9185 + case eCSSProperty_grid_column_end: 1.9186 + case eCSSProperty_grid_row_start: 1.9187 + case eCSSProperty_grid_row_end: 1.9188 + return ParseGridColumnRowStartEnd(aPropID); 1.9189 + case eCSSProperty_grid_column: 1.9190 + return ParseGridColumnRow(eCSSProperty_grid_column_start, 1.9191 + eCSSProperty_grid_column_end); 1.9192 + case eCSSProperty_grid_row: 1.9193 + return ParseGridColumnRow(eCSSProperty_grid_row_start, 1.9194 + eCSSProperty_grid_row_end); 1.9195 + case eCSSProperty_grid_area: 1.9196 + return ParseGridArea(); 1.9197 + case eCSSProperty_image_region: 1.9198 + return ParseRect(eCSSProperty_image_region); 1.9199 + case eCSSProperty_list_style: 1.9200 + return ParseListStyle(); 1.9201 + case eCSSProperty_margin: 1.9202 + return ParseMargin(); 1.9203 + case eCSSProperty_margin_end: 1.9204 + return ParseDirectionalBoxProperty(eCSSProperty_margin_end, 1.9205 + NS_BOXPROP_SOURCE_LOGICAL); 1.9206 + case eCSSProperty_margin_left: 1.9207 + return ParseDirectionalBoxProperty(eCSSProperty_margin_left, 1.9208 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9209 + case eCSSProperty_margin_right: 1.9210 + return ParseDirectionalBoxProperty(eCSSProperty_margin_right, 1.9211 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9212 + case eCSSProperty_margin_start: 1.9213 + return ParseDirectionalBoxProperty(eCSSProperty_margin_start, 1.9214 + NS_BOXPROP_SOURCE_LOGICAL); 1.9215 + case eCSSProperty_outline: 1.9216 + return ParseOutline(); 1.9217 + case eCSSProperty_overflow: 1.9218 + return ParseOverflow(); 1.9219 + case eCSSProperty_padding: 1.9220 + return ParsePadding(); 1.9221 + case eCSSProperty_padding_end: 1.9222 + return ParseDirectionalBoxProperty(eCSSProperty_padding_end, 1.9223 + NS_BOXPROP_SOURCE_LOGICAL); 1.9224 + case eCSSProperty_padding_left: 1.9225 + return ParseDirectionalBoxProperty(eCSSProperty_padding_left, 1.9226 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9227 + case eCSSProperty_padding_right: 1.9228 + return ParseDirectionalBoxProperty(eCSSProperty_padding_right, 1.9229 + NS_BOXPROP_SOURCE_PHYSICAL); 1.9230 + case eCSSProperty_padding_start: 1.9231 + return ParseDirectionalBoxProperty(eCSSProperty_padding_start, 1.9232 + NS_BOXPROP_SOURCE_LOGICAL); 1.9233 + case eCSSProperty_quotes: 1.9234 + return ParseQuotes(); 1.9235 + case eCSSProperty_size: 1.9236 + return ParseSize(); 1.9237 + case eCSSProperty_text_decoration: 1.9238 + return ParseTextDecoration(); 1.9239 + case eCSSProperty_will_change: 1.9240 + return ParseWillChange(); 1.9241 + case eCSSProperty_transform: 1.9242 + return ParseTransform(false); 1.9243 + case eCSSProperty__moz_transform: 1.9244 + return ParseTransform(true); 1.9245 + case eCSSProperty_transform_origin: 1.9246 + return ParseTransformOrigin(false); 1.9247 + case eCSSProperty_perspective_origin: 1.9248 + return ParseTransformOrigin(true); 1.9249 + case eCSSProperty_transition: 1.9250 + return ParseTransition(); 1.9251 + case eCSSProperty_animation: 1.9252 + return ParseAnimation(); 1.9253 + case eCSSProperty_transition_property: 1.9254 + return ParseTransitionProperty(); 1.9255 + case eCSSProperty_fill: 1.9256 + case eCSSProperty_stroke: 1.9257 + return ParsePaint(aPropID); 1.9258 + case eCSSProperty_stroke_dasharray: 1.9259 + return ParseDasharray(); 1.9260 + case eCSSProperty_marker: 1.9261 + return ParseMarker(); 1.9262 + case eCSSProperty_paint_order: 1.9263 + return ParsePaintOrder(); 1.9264 + case eCSSProperty_all: 1.9265 + return ParseAll(); 1.9266 + default: 1.9267 + NS_ABORT_IF_FALSE(false, "should not be called"); 1.9268 + return false; 1.9269 + } 1.9270 +} 1.9271 + 1.9272 +// Bits used in determining which background position info we have 1.9273 +#define BG_CENTER NS_STYLE_BG_POSITION_CENTER 1.9274 +#define BG_TOP NS_STYLE_BG_POSITION_TOP 1.9275 +#define BG_BOTTOM NS_STYLE_BG_POSITION_BOTTOM 1.9276 +#define BG_LEFT NS_STYLE_BG_POSITION_LEFT 1.9277 +#define BG_RIGHT NS_STYLE_BG_POSITION_RIGHT 1.9278 +#define BG_CTB (BG_CENTER | BG_TOP | BG_BOTTOM) 1.9279 +#define BG_TB (BG_TOP | BG_BOTTOM) 1.9280 +#define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT) 1.9281 +#define BG_LR (BG_LEFT | BG_RIGHT) 1.9282 + 1.9283 +bool 1.9284 +CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue, 1.9285 + nsCSSProperty aPropID) 1.9286 +{ 1.9287 + if (aPropID == eCSSPropertyExtra_x_none_value) { 1.9288 + return ParseVariant(aValue, VARIANT_NONE | VARIANT_INHERIT, nullptr); 1.9289 + } 1.9290 + 1.9291 + if (aPropID == eCSSPropertyExtra_x_auto_value) { 1.9292 + return ParseVariant(aValue, VARIANT_AUTO | VARIANT_INHERIT, nullptr); 1.9293 + } 1.9294 + 1.9295 + if (aPropID < 0 || aPropID >= eCSSProperty_COUNT_no_shorthands) { 1.9296 + NS_ABORT_IF_FALSE(false, "not a single value property"); 1.9297 + return false; 1.9298 + } 1.9299 + 1.9300 + if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_VALUE_PARSER_FUNCTION)) { 1.9301 + switch (aPropID) { 1.9302 + case eCSSProperty_font_family: 1.9303 + return ParseFamily(aValue); 1.9304 + case eCSSProperty_font_synthesis: 1.9305 + return ParseFontSynthesis(aValue); 1.9306 + case eCSSProperty_font_variant_alternates: 1.9307 + return ParseFontVariantAlternates(aValue); 1.9308 + case eCSSProperty_font_variant_east_asian: 1.9309 + return ParseFontVariantEastAsian(aValue); 1.9310 + case eCSSProperty_font_variant_ligatures: 1.9311 + return ParseFontVariantLigatures(aValue); 1.9312 + case eCSSProperty_font_variant_numeric: 1.9313 + return ParseFontVariantNumeric(aValue); 1.9314 + case eCSSProperty_font_feature_settings: 1.9315 + return ParseFontFeatureSettings(aValue); 1.9316 + case eCSSProperty_font_weight: 1.9317 + return ParseFontWeight(aValue); 1.9318 + case eCSSProperty_image_orientation: 1.9319 + return ParseImageOrientation(aValue); 1.9320 + case eCSSProperty_marks: 1.9321 + return ParseMarks(aValue); 1.9322 + case eCSSProperty_text_align: 1.9323 + return ParseTextAlign(aValue); 1.9324 + case eCSSProperty_text_align_last: 1.9325 + return ParseTextAlignLast(aValue); 1.9326 + case eCSSProperty_text_decoration_line: 1.9327 + return ParseTextDecorationLine(aValue); 1.9328 + case eCSSProperty_text_combine_upright: 1.9329 + return ParseTextCombineUpright(aValue); 1.9330 + case eCSSProperty_text_overflow: 1.9331 + return ParseTextOverflow(aValue); 1.9332 + case eCSSProperty_touch_action: 1.9333 + return ParseTouchAction(aValue); 1.9334 + default: 1.9335 + NS_ABORT_IF_FALSE(false, "should not reach here"); 1.9336 + return false; 1.9337 + } 1.9338 + } 1.9339 + 1.9340 + uint32_t variant = nsCSSProps::ParserVariant(aPropID); 1.9341 + if (variant == 0) { 1.9342 + NS_ABORT_IF_FALSE(false, "not a single value property"); 1.9343 + return false; 1.9344 + } 1.9345 + 1.9346 + // We only allow 'script-level' when unsafe rules are enabled, because 1.9347 + // otherwise it could interfere with rulenode optimizations if used in 1.9348 + // a non-MathML-enabled document. We also only allow math-display when 1.9349 + // unsafe rules are enabled. 1.9350 + if (!mUnsafeRulesEnabled && 1.9351 + (aPropID == eCSSProperty_script_level || 1.9352 + aPropID == eCSSProperty_math_display)) 1.9353 + return false; 1.9354 + 1.9355 + const KTableValue *kwtable = nsCSSProps::kKeywordTableTable[aPropID]; 1.9356 + switch (nsCSSProps::ValueRestrictions(aPropID)) { 1.9357 + default: 1.9358 + NS_ABORT_IF_FALSE(false, "should not be reached"); 1.9359 + case 0: 1.9360 + return ParseVariant(aValue, variant, kwtable); 1.9361 + case CSS_PROPERTY_VALUE_NONNEGATIVE: 1.9362 + return ParseNonNegativeVariant(aValue, variant, kwtable); 1.9363 + case CSS_PROPERTY_VALUE_AT_LEAST_ONE: 1.9364 + return ParseOneOrLargerVariant(aValue, variant, kwtable); 1.9365 + } 1.9366 +} 1.9367 + 1.9368 +// nsFont::EnumerateFamilies callback for ParseFontDescriptorValue 1.9369 +struct MOZ_STACK_CLASS ExtractFirstFamilyData { 1.9370 + nsAutoString mFamilyName; 1.9371 + bool mGood; 1.9372 + ExtractFirstFamilyData() : mFamilyName(), mGood(false) {} 1.9373 +}; 1.9374 + 1.9375 +static bool 1.9376 +ExtractFirstFamily(const nsString& aFamily, 1.9377 + bool aGeneric, 1.9378 + void* aData) 1.9379 +{ 1.9380 + ExtractFirstFamilyData* realData = (ExtractFirstFamilyData*) aData; 1.9381 + if (aGeneric || realData->mFamilyName.Length() > 0) { 1.9382 + realData->mGood = false; 1.9383 + return false; 1.9384 + } 1.9385 + realData->mFamilyName.Assign(aFamily); 1.9386 + realData->mGood = true; 1.9387 + return true; 1.9388 +} 1.9389 + 1.9390 +// font-descriptor: descriptor ':' value ';' 1.9391 +// caller has advanced mToken to point at the descriptor 1.9392 +bool 1.9393 +CSSParserImpl::ParseFontDescriptorValue(nsCSSFontDesc aDescID, 1.9394 + nsCSSValue& aValue) 1.9395 +{ 1.9396 + switch (aDescID) { 1.9397 + // These four are similar to the properties of the same name, 1.9398 + // possibly with more restrictions on the values they can take. 1.9399 + case eCSSFontDesc_Family: { 1.9400 + if (!ParseFamily(aValue) || 1.9401 + aValue.GetUnit() != eCSSUnit_Families) 1.9402 + return false; 1.9403 + 1.9404 + // the style parameters to the nsFont constructor are ignored, 1.9405 + // because it's only being used to call EnumerateFamilies 1.9406 + nsAutoString valueStr; 1.9407 + aValue.GetStringValue(valueStr); 1.9408 + nsFont font(valueStr, 0, 0, 0, 0, 0, 0); 1.9409 + ExtractFirstFamilyData dat; 1.9410 + 1.9411 + font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat); 1.9412 + if (!dat.mGood) 1.9413 + return false; 1.9414 + 1.9415 + aValue.SetStringValue(dat.mFamilyName, eCSSUnit_String); 1.9416 + return true; 1.9417 + } 1.9418 + 1.9419 + case eCSSFontDesc_Style: 1.9420 + // property is VARIANT_HMK|VARIANT_SYSFONT 1.9421 + return ParseVariant(aValue, VARIANT_KEYWORD | VARIANT_NORMAL, 1.9422 + nsCSSProps::kFontStyleKTable); 1.9423 + 1.9424 + case eCSSFontDesc_Weight: 1.9425 + return (ParseFontWeight(aValue) && 1.9426 + aValue.GetUnit() != eCSSUnit_Inherit && 1.9427 + aValue.GetUnit() != eCSSUnit_Initial && 1.9428 + aValue.GetUnit() != eCSSUnit_Unset && 1.9429 + (aValue.GetUnit() != eCSSUnit_Enumerated || 1.9430 + (aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_BOLDER && 1.9431 + aValue.GetIntValue() != NS_STYLE_FONT_WEIGHT_LIGHTER))); 1.9432 + 1.9433 + case eCSSFontDesc_Stretch: 1.9434 + // property is VARIANT_HK|VARIANT_SYSFONT 1.9435 + return ParseVariant(aValue, VARIANT_KEYWORD, 1.9436 + nsCSSProps::kFontStretchKTable); 1.9437 + 1.9438 + // These two are unique to @font-face and have their own special grammar. 1.9439 + case eCSSFontDesc_Src: 1.9440 + return ParseFontSrc(aValue); 1.9441 + 1.9442 + case eCSSFontDesc_UnicodeRange: 1.9443 + return ParseFontRanges(aValue); 1.9444 + 1.9445 + case eCSSFontDesc_FontFeatureSettings: 1.9446 + return ParseFontFeatureSettings(aValue); 1.9447 + 1.9448 + case eCSSFontDesc_FontLanguageOverride: 1.9449 + return ParseVariant(aValue, VARIANT_NORMAL | VARIANT_STRING, nullptr); 1.9450 + 1.9451 + case eCSSFontDesc_UNKNOWN: 1.9452 + case eCSSFontDesc_COUNT: 1.9453 + NS_NOTREACHED("bad nsCSSFontDesc code"); 1.9454 + } 1.9455 + // explicitly do NOT have a default case to let the compiler 1.9456 + // help find missing descriptors 1.9457 + return false; 1.9458 +} 1.9459 + 1.9460 +void 1.9461 +CSSParserImpl::InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties) 1.9462 +{ 1.9463 + nsCSSValue physical(NS_BOXPROP_SOURCE_PHYSICAL, eCSSUnit_Enumerated); 1.9464 + for (const nsCSSProperty *prop = aSourceProperties; 1.9465 + *prop != eCSSProperty_UNKNOWN; ++prop) { 1.9466 + AppendValue(*prop, physical); 1.9467 + } 1.9468 +} 1.9469 + 1.9470 +static nsCSSValue 1.9471 +BoxPositionMaskToCSSValue(int32_t aMask, bool isX) 1.9472 +{ 1.9473 + int32_t val = NS_STYLE_BG_POSITION_CENTER; 1.9474 + if (isX) { 1.9475 + if (aMask & BG_LEFT) { 1.9476 + val = NS_STYLE_BG_POSITION_LEFT; 1.9477 + } 1.9478 + else if (aMask & BG_RIGHT) { 1.9479 + val = NS_STYLE_BG_POSITION_RIGHT; 1.9480 + } 1.9481 + } 1.9482 + else { 1.9483 + if (aMask & BG_TOP) { 1.9484 + val = NS_STYLE_BG_POSITION_TOP; 1.9485 + } 1.9486 + else if (aMask & BG_BOTTOM) { 1.9487 + val = NS_STYLE_BG_POSITION_BOTTOM; 1.9488 + } 1.9489 + } 1.9490 + 1.9491 + return nsCSSValue(val, eCSSUnit_Enumerated); 1.9492 +} 1.9493 + 1.9494 +bool 1.9495 +CSSParserImpl::ParseBackground() 1.9496 +{ 1.9497 + nsAutoParseCompoundProperty compound(this); 1.9498 + 1.9499 + // background-color can only be set once, so it's not a list. 1.9500 + nsCSSValue color; 1.9501 + 1.9502 + // Check first for inherit/initial/unset. 1.9503 + if (ParseVariant(color, VARIANT_INHERIT, nullptr)) { 1.9504 + // must be alone 1.9505 + for (const nsCSSProperty* subprops = 1.9506 + nsCSSProps::SubpropertyEntryFor(eCSSProperty_background); 1.9507 + *subprops != eCSSProperty_UNKNOWN; ++subprops) { 1.9508 + AppendValue(*subprops, color); 1.9509 + } 1.9510 + return true; 1.9511 + } 1.9512 + 1.9513 + nsCSSValue image, repeat, attachment, clip, origin, position, size; 1.9514 + BackgroundParseState state(color, image.SetListValue(), 1.9515 + repeat.SetPairListValue(), 1.9516 + attachment.SetListValue(), clip.SetListValue(), 1.9517 + origin.SetListValue(), position.SetListValue(), 1.9518 + size.SetPairListValue()); 1.9519 + 1.9520 + for (;;) { 1.9521 + if (!ParseBackgroundItem(state)) { 1.9522 + return false; 1.9523 + } 1.9524 + // If we saw a color, this must be the last item. 1.9525 + if (color.GetUnit() != eCSSUnit_Null) { 1.9526 + break; 1.9527 + } 1.9528 + // If there's a comma, expect another item. 1.9529 + if (!ExpectSymbol(',', true)) { 1.9530 + break; 1.9531 + } 1.9532 + // Chain another entry on all the lists. 1.9533 + state.mImage->mNext = new nsCSSValueList; 1.9534 + state.mImage = state.mImage->mNext; 1.9535 + state.mRepeat->mNext = new nsCSSValuePairList; 1.9536 + state.mRepeat = state.mRepeat->mNext; 1.9537 + state.mAttachment->mNext = new nsCSSValueList; 1.9538 + state.mAttachment = state.mAttachment->mNext; 1.9539 + state.mClip->mNext = new nsCSSValueList; 1.9540 + state.mClip = state.mClip->mNext; 1.9541 + state.mOrigin->mNext = new nsCSSValueList; 1.9542 + state.mOrigin = state.mOrigin->mNext; 1.9543 + state.mPosition->mNext = new nsCSSValueList; 1.9544 + state.mPosition = state.mPosition->mNext; 1.9545 + state.mSize->mNext = new nsCSSValuePairList; 1.9546 + state.mSize = state.mSize->mNext; 1.9547 + } 1.9548 + 1.9549 + // If we get to this point without seeing a color, provide a default. 1.9550 + if (color.GetUnit() == eCSSUnit_Null) { 1.9551 + color.SetIntegerColorValue(NS_RGBA(0,0,0,0), eCSSUnit_RGBAColor); 1.9552 + } 1.9553 + 1.9554 + AppendValue(eCSSProperty_background_image, image); 1.9555 + AppendValue(eCSSProperty_background_repeat, repeat); 1.9556 + AppendValue(eCSSProperty_background_attachment, attachment); 1.9557 + AppendValue(eCSSProperty_background_clip, clip); 1.9558 + AppendValue(eCSSProperty_background_origin, origin); 1.9559 + AppendValue(eCSSProperty_background_position, position); 1.9560 + AppendValue(eCSSProperty_background_size, size); 1.9561 + AppendValue(eCSSProperty_background_color, color); 1.9562 + return true; 1.9563 +} 1.9564 + 1.9565 +// Parse one item of the background shorthand property. 1.9566 +bool 1.9567 +CSSParserImpl::ParseBackgroundItem(CSSParserImpl::BackgroundParseState& aState) 1.9568 + 1.9569 +{ 1.9570 + // Fill in the values that the shorthand will set if we don't find 1.9571 + // other values. 1.9572 + aState.mImage->mValue.SetNoneValue(); 1.9573 + aState.mRepeat->mXValue.SetIntValue(NS_STYLE_BG_REPEAT_REPEAT, 1.9574 + eCSSUnit_Enumerated); 1.9575 + aState.mRepeat->mYValue.Reset(); 1.9576 + aState.mAttachment->mValue.SetIntValue(NS_STYLE_BG_ATTACHMENT_SCROLL, 1.9577 + eCSSUnit_Enumerated); 1.9578 + aState.mClip->mValue.SetIntValue(NS_STYLE_BG_CLIP_BORDER, 1.9579 + eCSSUnit_Enumerated); 1.9580 + aState.mOrigin->mValue.SetIntValue(NS_STYLE_BG_ORIGIN_PADDING, 1.9581 + eCSSUnit_Enumerated); 1.9582 + nsRefPtr<nsCSSValue::Array> positionArr = nsCSSValue::Array::Create(4); 1.9583 + aState.mPosition->mValue.SetArrayValue(positionArr, eCSSUnit_Array); 1.9584 + positionArr->Item(1).SetPercentValue(0.0f); 1.9585 + positionArr->Item(3).SetPercentValue(0.0f); 1.9586 + aState.mSize->mXValue.SetAutoValue(); 1.9587 + aState.mSize->mYValue.SetAutoValue(); 1.9588 + 1.9589 + bool haveColor = false, 1.9590 + haveImage = false, 1.9591 + haveRepeat = false, 1.9592 + haveAttach = false, 1.9593 + havePositionAndSize = false, 1.9594 + haveOrigin = false, 1.9595 + haveSomething = false; 1.9596 + 1.9597 + while (GetToken(true)) { 1.9598 + nsCSSTokenType tt = mToken.mType; 1.9599 + UngetToken(); // ...but we'll still cheat and use mToken 1.9600 + if (tt == eCSSToken_Symbol) { 1.9601 + // ExpectEndProperty only looks for symbols, and nothing else will 1.9602 + // show up as one. 1.9603 + break; 1.9604 + } 1.9605 + 1.9606 + if (tt == eCSSToken_Ident) { 1.9607 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); 1.9608 + int32_t dummy; 1.9609 + if (keyword == eCSSKeyword_inherit || 1.9610 + keyword == eCSSKeyword_initial || 1.9611 + keyword == eCSSKeyword_unset) { 1.9612 + return false; 1.9613 + } else if (keyword == eCSSKeyword_none) { 1.9614 + if (haveImage) 1.9615 + return false; 1.9616 + haveImage = true; 1.9617 + if (!ParseSingleValueProperty(aState.mImage->mValue, 1.9618 + eCSSProperty_background_image)) { 1.9619 + NS_NOTREACHED("should be able to parse"); 1.9620 + return false; 1.9621 + } 1.9622 + } else if (nsCSSProps::FindKeyword(keyword, 1.9623 + nsCSSProps::kBackgroundAttachmentKTable, dummy)) { 1.9624 + if (haveAttach) 1.9625 + return false; 1.9626 + haveAttach = true; 1.9627 + if (!ParseSingleValueProperty(aState.mAttachment->mValue, 1.9628 + eCSSProperty_background_attachment)) { 1.9629 + NS_NOTREACHED("should be able to parse"); 1.9630 + return false; 1.9631 + } 1.9632 + } else if (nsCSSProps::FindKeyword(keyword, 1.9633 + nsCSSProps::kBackgroundRepeatKTable, dummy)) { 1.9634 + if (haveRepeat) 1.9635 + return false; 1.9636 + haveRepeat = true; 1.9637 + nsCSSValuePair scratch; 1.9638 + if (!ParseBackgroundRepeatValues(scratch)) { 1.9639 + NS_NOTREACHED("should be able to parse"); 1.9640 + return false; 1.9641 + } 1.9642 + aState.mRepeat->mXValue = scratch.mXValue; 1.9643 + aState.mRepeat->mYValue = scratch.mYValue; 1.9644 + } else if (nsCSSProps::FindKeyword(keyword, 1.9645 + nsCSSProps::kBackgroundPositionKTable, dummy)) { 1.9646 + if (havePositionAndSize) 1.9647 + return false; 1.9648 + havePositionAndSize = true; 1.9649 + if (!ParseBackgroundPositionValues(aState.mPosition->mValue, false)) { 1.9650 + return false; 1.9651 + } 1.9652 + if (ExpectSymbol('/', true)) { 1.9653 + nsCSSValuePair scratch; 1.9654 + if (!ParseBackgroundSizeValues(scratch)) { 1.9655 + return false; 1.9656 + } 1.9657 + aState.mSize->mXValue = scratch.mXValue; 1.9658 + aState.mSize->mYValue = scratch.mYValue; 1.9659 + } 1.9660 + } else if (nsCSSProps::FindKeyword(keyword, 1.9661 + nsCSSProps::kBackgroundOriginKTable, dummy)) { 1.9662 + if (haveOrigin) 1.9663 + return false; 1.9664 + haveOrigin = true; 1.9665 + if (!ParseSingleValueProperty(aState.mOrigin->mValue, 1.9666 + eCSSProperty_background_origin)) { 1.9667 + NS_NOTREACHED("should be able to parse"); 1.9668 + return false; 1.9669 + } 1.9670 + 1.9671 + // The spec allows a second box value (for background-clip), 1.9672 + // immediately following the first one (for background-origin). 1.9673 + 1.9674 + // 'background-clip' and 'background-origin' use the same keyword table 1.9675 + MOZ_ASSERT(nsCSSProps::kKeywordTableTable[ 1.9676 + eCSSProperty_background_origin] == 1.9677 + nsCSSProps::kBackgroundOriginKTable); 1.9678 + MOZ_ASSERT(nsCSSProps::kKeywordTableTable[ 1.9679 + eCSSProperty_background_clip] == 1.9680 + nsCSSProps::kBackgroundOriginKTable); 1.9681 + static_assert(NS_STYLE_BG_CLIP_BORDER == 1.9682 + NS_STYLE_BG_ORIGIN_BORDER && 1.9683 + NS_STYLE_BG_CLIP_PADDING == 1.9684 + NS_STYLE_BG_ORIGIN_PADDING && 1.9685 + NS_STYLE_BG_CLIP_CONTENT == 1.9686 + NS_STYLE_BG_ORIGIN_CONTENT, 1.9687 + "bg-clip and bg-origin style constants must agree"); 1.9688 + 1.9689 + if (!ParseSingleValueProperty(aState.mClip->mValue, 1.9690 + eCSSProperty_background_clip)) { 1.9691 + // When exactly one <box> value is set, it is used for both 1.9692 + // 'background-origin' and 'background-clip'. 1.9693 + // See assertions above showing these values are compatible. 1.9694 + aState.mClip->mValue = aState.mOrigin->mValue; 1.9695 + } 1.9696 + } else { 1.9697 + if (haveColor) 1.9698 + return false; 1.9699 + haveColor = true; 1.9700 + if (!ParseSingleValueProperty(aState.mColor, 1.9701 + eCSSProperty_background_color)) { 1.9702 + return false; 1.9703 + } 1.9704 + } 1.9705 + } else if (tt == eCSSToken_URL || 1.9706 + (tt == eCSSToken_Function && 1.9707 + (mToken.mIdent.LowerCaseEqualsLiteral("linear-gradient") || 1.9708 + mToken.mIdent.LowerCaseEqualsLiteral("radial-gradient") || 1.9709 + mToken.mIdent.LowerCaseEqualsLiteral("repeating-linear-gradient") || 1.9710 + mToken.mIdent.LowerCaseEqualsLiteral("repeating-radial-gradient") || 1.9711 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-linear-gradient") || 1.9712 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-radial-gradient") || 1.9713 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-linear-gradient") || 1.9714 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") || 1.9715 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-image-rect") || 1.9716 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-element")))) { 1.9717 + if (haveImage) 1.9718 + return false; 1.9719 + haveImage = true; 1.9720 + if (!ParseSingleValueProperty(aState.mImage->mValue, 1.9721 + eCSSProperty_background_image)) { 1.9722 + return false; 1.9723 + } 1.9724 + } else if (tt == eCSSToken_Dimension || 1.9725 + tt == eCSSToken_Number || 1.9726 + tt == eCSSToken_Percentage || 1.9727 + (tt == eCSSToken_Function && 1.9728 + (mToken.mIdent.LowerCaseEqualsLiteral("calc") || 1.9729 + mToken.mIdent.LowerCaseEqualsLiteral("-moz-calc")))) { 1.9730 + if (havePositionAndSize) 1.9731 + return false; 1.9732 + havePositionAndSize = true; 1.9733 + if (!ParseBackgroundPositionValues(aState.mPosition->mValue, false)) { 1.9734 + return false; 1.9735 + } 1.9736 + if (ExpectSymbol('/', true)) { 1.9737 + nsCSSValuePair scratch; 1.9738 + if (!ParseBackgroundSizeValues(scratch)) { 1.9739 + return false; 1.9740 + } 1.9741 + aState.mSize->mXValue = scratch.mXValue; 1.9742 + aState.mSize->mYValue = scratch.mYValue; 1.9743 + } 1.9744 + } else { 1.9745 + if (haveColor) 1.9746 + return false; 1.9747 + haveColor = true; 1.9748 + // Note: This parses 'inherit', 'initial' and 'unset', but 1.9749 + // we've already checked for them, so it's ok. 1.9750 + if (!ParseSingleValueProperty(aState.mColor, 1.9751 + eCSSProperty_background_color)) { 1.9752 + return false; 1.9753 + } 1.9754 + } 1.9755 + haveSomething = true; 1.9756 + } 1.9757 + 1.9758 + return haveSomething; 1.9759 +} 1.9760 + 1.9761 +// This function is very similar to ParseBackgroundPosition and 1.9762 +// ParseBackgroundSize. 1.9763 +bool 1.9764 +CSSParserImpl::ParseValueList(nsCSSProperty aPropID) 1.9765 +{ 1.9766 + // aPropID is a single value prop-id 1.9767 + nsCSSValue value; 1.9768 + // 'initial', 'inherit' and 'unset' stand alone, no list permitted. 1.9769 + if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.9770 + nsCSSValueList* item = value.SetListValue(); 1.9771 + for (;;) { 1.9772 + if (!ParseSingleValueProperty(item->mValue, aPropID)) { 1.9773 + return false; 1.9774 + } 1.9775 + if (!ExpectSymbol(',', true)) { 1.9776 + break; 1.9777 + } 1.9778 + item->mNext = new nsCSSValueList; 1.9779 + item = item->mNext; 1.9780 + } 1.9781 + } 1.9782 + AppendValue(aPropID, value); 1.9783 + return true; 1.9784 +} 1.9785 + 1.9786 +bool 1.9787 +CSSParserImpl::ParseBackgroundRepeat() 1.9788 +{ 1.9789 + nsCSSValue value; 1.9790 + // 'initial', 'inherit' and 'unset' stand alone, no list permitted. 1.9791 + if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.9792 + nsCSSValuePair valuePair; 1.9793 + if (!ParseBackgroundRepeatValues(valuePair)) { 1.9794 + return false; 1.9795 + } 1.9796 + nsCSSValuePairList* item = value.SetPairListValue(); 1.9797 + for (;;) { 1.9798 + item->mXValue = valuePair.mXValue; 1.9799 + item->mYValue = valuePair.mYValue; 1.9800 + if (!ExpectSymbol(',', true)) { 1.9801 + break; 1.9802 + } 1.9803 + if (!ParseBackgroundRepeatValues(valuePair)) { 1.9804 + return false; 1.9805 + } 1.9806 + item->mNext = new nsCSSValuePairList; 1.9807 + item = item->mNext; 1.9808 + } 1.9809 + } 1.9810 + 1.9811 + AppendValue(eCSSProperty_background_repeat, value); 1.9812 + return true; 1.9813 +} 1.9814 + 1.9815 +bool 1.9816 +CSSParserImpl::ParseBackgroundRepeatValues(nsCSSValuePair& aValue) 1.9817 +{ 1.9818 + nsCSSValue& xValue = aValue.mXValue; 1.9819 + nsCSSValue& yValue = aValue.mYValue; 1.9820 + 1.9821 + if (ParseEnum(xValue, nsCSSProps::kBackgroundRepeatKTable)) { 1.9822 + int32_t value = xValue.GetIntValue(); 1.9823 + // For single values set yValue as eCSSUnit_Null. 1.9824 + if (value == NS_STYLE_BG_REPEAT_REPEAT_X || 1.9825 + value == NS_STYLE_BG_REPEAT_REPEAT_Y || 1.9826 + !ParseEnum(yValue, nsCSSProps::kBackgroundRepeatPartKTable)) { 1.9827 + // the caller will fail cases like "repeat-x no-repeat" 1.9828 + // by expecting a list separator or an end property. 1.9829 + yValue.Reset(); 1.9830 + } 1.9831 + return true; 1.9832 + } 1.9833 + 1.9834 + return false; 1.9835 +} 1.9836 + 1.9837 +// This function is very similar to ParseBackgroundList and ParseBackgroundSize. 1.9838 +bool 1.9839 +CSSParserImpl::ParseBackgroundPosition() 1.9840 +{ 1.9841 + nsCSSValue value; 1.9842 + // 'initial', 'inherit' and 'unset' stand alone, no list permitted. 1.9843 + if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.9844 + nsCSSValue itemValue; 1.9845 + if (!ParseBackgroundPositionValues(itemValue, false)) { 1.9846 + return false; 1.9847 + } 1.9848 + nsCSSValueList* item = value.SetListValue(); 1.9849 + for (;;) { 1.9850 + item->mValue = itemValue; 1.9851 + if (!ExpectSymbol(',', true)) { 1.9852 + break; 1.9853 + } 1.9854 + if (!ParseBackgroundPositionValues(itemValue, false)) { 1.9855 + return false; 1.9856 + } 1.9857 + item->mNext = new nsCSSValueList; 1.9858 + item = item->mNext; 1.9859 + } 1.9860 + } 1.9861 + AppendValue(eCSSProperty_background_position, value); 1.9862 + return true; 1.9863 +} 1.9864 + 1.9865 +/** 1.9866 + * BoxPositionMaskToCSSValue and ParseBoxPositionValues are used 1.9867 + * for parsing the CSS 2.1 background-position syntax (which has at 1.9868 + * most two values). (Compare to the css3-background syntax which 1.9869 + * takes up to four values.) Some current CSS specifications that 1.9870 + * use background-position-like syntax still use this old syntax. 1.9871 + ** 1.9872 + * Parses two values that correspond to positions in a box. These can be 1.9873 + * values corresponding to percentages of the box, raw offsets, or keywords 1.9874 + * like "top," "left center," etc. 1.9875 + * 1.9876 + * @param aOut The nsCSSValuePair in which to place the result. 1.9877 + * @param aAcceptsInherit If true, 'inherit', 'initial' and 'unset' are 1.9878 + * legal values 1.9879 + * @param aAllowExplicitCenter If true, 'center' is a legal value 1.9880 + * @return Whether or not the operation succeeded. 1.9881 + */ 1.9882 +bool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut, 1.9883 + bool aAcceptsInherit, 1.9884 + bool aAllowExplicitCenter) 1.9885 +{ 1.9886 + // First try a percentage or a length value 1.9887 + nsCSSValue &xValue = aOut.mXValue, 1.9888 + &yValue = aOut.mYValue; 1.9889 + int32_t variantMask = 1.9890 + (aAcceptsInherit ? VARIANT_INHERIT : 0) | VARIANT_LP | VARIANT_CALC; 1.9891 + if (ParseVariant(xValue, variantMask, nullptr)) { 1.9892 + if (eCSSUnit_Inherit == xValue.GetUnit() || 1.9893 + eCSSUnit_Initial == xValue.GetUnit() || 1.9894 + eCSSUnit_Unset == xValue.GetUnit()) { // both are inherit, initial or unset 1.9895 + yValue = xValue; 1.9896 + return true; 1.9897 + } 1.9898 + // We have one percentage/length/calc. Get the optional second 1.9899 + // percentage/length/calc/keyword. 1.9900 + if (ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nullptr)) { 1.9901 + // We have two numbers 1.9902 + return true; 1.9903 + } 1.9904 + 1.9905 + if (ParseEnum(yValue, nsCSSProps::kBackgroundPositionKTable)) { 1.9906 + int32_t yVal = yValue.GetIntValue(); 1.9907 + if (!(yVal & BG_CTB)) { 1.9908 + // The second keyword can only be 'center', 'top', or 'bottom' 1.9909 + return false; 1.9910 + } 1.9911 + yValue = BoxPositionMaskToCSSValue(yVal, false); 1.9912 + return true; 1.9913 + } 1.9914 + 1.9915 + // If only one percentage or length value is given, it sets the 1.9916 + // horizontal position only, and the vertical position will be 50%. 1.9917 + yValue.SetPercentValue(0.5f); 1.9918 + return true; 1.9919 + } 1.9920 + 1.9921 + // Now try keywords. We do this manually to allow for the first 1.9922 + // appearance of "center" to apply to the either the x or y 1.9923 + // position (it's ambiguous so we have to disambiguate). Each 1.9924 + // allowed keyword value is assigned it's own bit. We don't allow 1.9925 + // any duplicate keywords other than center. We try to get two 1.9926 + // keywords but it's okay if there is only one. 1.9927 + int32_t mask = 0; 1.9928 + if (ParseEnum(xValue, nsCSSProps::kBackgroundPositionKTable)) { 1.9929 + int32_t bit = xValue.GetIntValue(); 1.9930 + mask |= bit; 1.9931 + if (ParseEnum(xValue, nsCSSProps::kBackgroundPositionKTable)) { 1.9932 + bit = xValue.GetIntValue(); 1.9933 + if (mask & (bit & ~BG_CENTER)) { 1.9934 + // Only the 'center' keyword can be duplicated. 1.9935 + return false; 1.9936 + } 1.9937 + mask |= bit; 1.9938 + } 1.9939 + else { 1.9940 + // Only one keyword. See if we have a length, percentage, or calc. 1.9941 + if (ParseVariant(yValue, VARIANT_LP | VARIANT_CALC, nullptr)) { 1.9942 + if (!(mask & BG_CLR)) { 1.9943 + // The first keyword can only be 'center', 'left', or 'right' 1.9944 + return false; 1.9945 + } 1.9946 + 1.9947 + xValue = BoxPositionMaskToCSSValue(mask, true); 1.9948 + return true; 1.9949 + } 1.9950 + } 1.9951 + } 1.9952 + 1.9953 + // Check for bad input. Bad input consists of no matching keywords, 1.9954 + // or pairs of x keywords or pairs of y keywords. 1.9955 + if ((mask == 0) || (mask == (BG_TOP | BG_BOTTOM)) || 1.9956 + (mask == (BG_LEFT | BG_RIGHT)) || 1.9957 + (!aAllowExplicitCenter && (mask & BG_CENTER))) { 1.9958 + return false; 1.9959 + } 1.9960 + 1.9961 + // Create style values 1.9962 + xValue = BoxPositionMaskToCSSValue(mask, true); 1.9963 + yValue = BoxPositionMaskToCSSValue(mask, false); 1.9964 + return true; 1.9965 +} 1.9966 + 1.9967 +bool CSSParserImpl::ParseBackgroundPositionValues(nsCSSValue& aOut, 1.9968 + bool aAcceptsInherit) 1.9969 +{ 1.9970 + // css3-background allows positions to be defined as offsets 1.9971 + // from an edge. There can be 2 keywords and 2 offsets given. These 1.9972 + // four 'values' are stored in an array in the following order: 1.9973 + // [keyword offset keyword offset]. If a keyword or offset isn't 1.9974 + // parsed the value of the corresponding array element is set 1.9975 + // to eCSSUnit_Null by a call to nsCSSValue::Reset(). 1.9976 + if (aAcceptsInherit && ParseVariant(aOut, VARIANT_INHERIT, nullptr)) { 1.9977 + return true; 1.9978 + } 1.9979 + 1.9980 + nsRefPtr<nsCSSValue::Array> value = nsCSSValue::Array::Create(4); 1.9981 + aOut.SetArrayValue(value, eCSSUnit_Array); 1.9982 + 1.9983 + // The following clarifies organisation of the array. 1.9984 + nsCSSValue &xEdge = value->Item(0), 1.9985 + &xOffset = value->Item(1), 1.9986 + &yEdge = value->Item(2), 1.9987 + &yOffset = value->Item(3); 1.9988 + 1.9989 + // Parse all the values into the array. 1.9990 + uint32_t valueCount = 0; 1.9991 + for (int32_t i = 0; i < 4; i++) { 1.9992 + if (!ParseVariant(value->Item(i), VARIANT_LPCALC | VARIANT_KEYWORD, 1.9993 + nsCSSProps::kBackgroundPositionKTable)) { 1.9994 + break; 1.9995 + } 1.9996 + ++valueCount; 1.9997 + } 1.9998 + 1.9999 + switch (valueCount) { 1.10000 + case 4: 1.10001 + // "If three or four values are given, then each <percentage> or <length> 1.10002 + // represents an offset and must be preceded by a keyword, which specifies 1.10003 + // from which edge the offset is given." 1.10004 + if (eCSSUnit_Enumerated != xEdge.GetUnit() || 1.10005 + BG_CENTER == xEdge.GetIntValue() || 1.10006 + eCSSUnit_Enumerated == xOffset.GetUnit() || 1.10007 + eCSSUnit_Enumerated != yEdge.GetUnit() || 1.10008 + BG_CENTER == yEdge.GetIntValue() || 1.10009 + eCSSUnit_Enumerated == yOffset.GetUnit()) { 1.10010 + return false; 1.10011 + } 1.10012 + break; 1.10013 + case 3: 1.10014 + // "If three or four values are given, then each <percentage> or<length> 1.10015 + // represents an offset and must be preceded by a keyword, which specifies 1.10016 + // from which edge the offset is given." ... "If three values are given, 1.10017 + // the missing offset is assumed to be zero." 1.10018 + if (eCSSUnit_Enumerated != value->Item(1).GetUnit()) { 1.10019 + // keyword offset keyword 1.10020 + // Second value is non-keyword, thus first value must be a non-center 1.10021 + // keyword. 1.10022 + if (eCSSUnit_Enumerated != value->Item(0).GetUnit() || 1.10023 + BG_CENTER == value->Item(0).GetIntValue()) { 1.10024 + return false; 1.10025 + } 1.10026 + 1.10027 + // Remaining value must be a keyword. 1.10028 + if (eCSSUnit_Enumerated != value->Item(2).GetUnit()) { 1.10029 + return false; 1.10030 + } 1.10031 + 1.10032 + yOffset.Reset(); // Everything else is in the correct position. 1.10033 + } else if (eCSSUnit_Enumerated != value->Item(2).GetUnit()) { 1.10034 + // keyword keyword offset 1.10035 + // Third value is non-keyword, thus second value must be non-center 1.10036 + // keyword. 1.10037 + if (BG_CENTER == value->Item(1).GetIntValue()) { 1.10038 + return false; 1.10039 + } 1.10040 + 1.10041 + // Remaining value must be a keyword. 1.10042 + if (eCSSUnit_Enumerated != value->Item(0).GetUnit()) { 1.10043 + return false; 1.10044 + } 1.10045 + 1.10046 + // Move the values to the correct position in the array. 1.10047 + value->Item(3) = value->Item(2); // yOffset 1.10048 + value->Item(2) = value->Item(1); // yEdge 1.10049 + value->Item(1).Reset(); // xOffset 1.10050 + } else { 1.10051 + return false; 1.10052 + } 1.10053 + break; 1.10054 + case 2: 1.10055 + // "If two values are given and at least one value is not a keyword, then 1.10056 + // the first value represents the horizontal position (or offset) and the 1.10057 + // second represents the vertical position (or offset)" 1.10058 + if (eCSSUnit_Enumerated == value->Item(0).GetUnit()) { 1.10059 + if (eCSSUnit_Enumerated == value->Item(1).GetUnit()) { 1.10060 + // keyword keyword 1.10061 + value->Item(2) = value->Item(1); // move yEdge to correct position 1.10062 + xOffset.Reset(); 1.10063 + yOffset.Reset(); 1.10064 + } else { 1.10065 + // keyword offset 1.10066 + // First value must represent horizontal position. 1.10067 + if ((BG_TOP | BG_BOTTOM) & value->Item(0).GetIntValue()) { 1.10068 + return false; 1.10069 + } 1.10070 + value->Item(3) = value->Item(1); // move yOffset to correct position 1.10071 + xOffset.Reset(); 1.10072 + yEdge.Reset(); 1.10073 + } 1.10074 + } else { 1.10075 + if (eCSSUnit_Enumerated == value->Item(1).GetUnit()) { 1.10076 + // offset keyword 1.10077 + // Second value must represent vertical position. 1.10078 + if ((BG_LEFT | BG_RIGHT) & value->Item(1).GetIntValue()) { 1.10079 + return false; 1.10080 + } 1.10081 + value->Item(2) = value->Item(1); // move yEdge to correct position 1.10082 + value->Item(1) = value->Item(0); // move xOffset to correct position 1.10083 + xEdge.Reset(); 1.10084 + yOffset.Reset(); 1.10085 + } else { 1.10086 + // offset offset 1.10087 + value->Item(3) = value->Item(1); // move yOffset to correct position 1.10088 + value->Item(1) = value->Item(0); // move xOffset to correct position 1.10089 + xEdge.Reset(); 1.10090 + yEdge.Reset(); 1.10091 + } 1.10092 + } 1.10093 + break; 1.10094 + case 1: 1.10095 + // "If only one value is specified, the second value is assumed to be 1.10096 + // center." 1.10097 + if (eCSSUnit_Enumerated == value->Item(0).GetUnit()) { 1.10098 + xOffset.Reset(); 1.10099 + } else { 1.10100 + value->Item(1) = value->Item(0); // move xOffset to correct position 1.10101 + xEdge.Reset(); 1.10102 + } 1.10103 + yEdge.SetIntValue(NS_STYLE_BG_POSITION_CENTER, eCSSUnit_Enumerated); 1.10104 + yOffset.Reset(); 1.10105 + break; 1.10106 + default: 1.10107 + return false; 1.10108 + } 1.10109 + 1.10110 + // For compatibility with CSS2.1 code the edges can be unspecified. 1.10111 + // Unspecified edges are recorded as nullptr. 1.10112 + NS_ASSERTION((eCSSUnit_Enumerated == xEdge.GetUnit() || 1.10113 + eCSSUnit_Null == xEdge.GetUnit()) && 1.10114 + (eCSSUnit_Enumerated == yEdge.GetUnit() || 1.10115 + eCSSUnit_Null == yEdge.GetUnit()) && 1.10116 + eCSSUnit_Enumerated != xOffset.GetUnit() && 1.10117 + eCSSUnit_Enumerated != yOffset.GetUnit(), 1.10118 + "Unexpected units"); 1.10119 + 1.10120 + // Keywords in first and second pairs can not both be vertical or 1.10121 + // horizontal keywords. (eg. left right, bottom top). Additionally, 1.10122 + // non-center keyword can not be duplicated (eg. left left). 1.10123 + int32_t xEdgeEnum = 1.10124 + xEdge.GetUnit() == eCSSUnit_Enumerated ? xEdge.GetIntValue() : 0; 1.10125 + int32_t yEdgeEnum = 1.10126 + yEdge.GetUnit() == eCSSUnit_Enumerated ? yEdge.GetIntValue() : 0; 1.10127 + if ((xEdgeEnum | yEdgeEnum) == (BG_LEFT | BG_RIGHT) || 1.10128 + (xEdgeEnum | yEdgeEnum) == (BG_TOP | BG_BOTTOM) || 1.10129 + (xEdgeEnum & yEdgeEnum & ~BG_CENTER)) { 1.10130 + return false; 1.10131 + } 1.10132 + 1.10133 + // The values could be in an order that is different than expected. 1.10134 + // eg. x contains vertical information, y contains horizontal information. 1.10135 + // Swap if incorrect order. 1.10136 + if (xEdgeEnum & (BG_TOP | BG_BOTTOM) || 1.10137 + yEdgeEnum & (BG_LEFT | BG_RIGHT)) { 1.10138 + nsCSSValue swapEdge = xEdge; 1.10139 + nsCSSValue swapOffset = xOffset; 1.10140 + xEdge = yEdge; 1.10141 + xOffset = yOffset; 1.10142 + yEdge = swapEdge; 1.10143 + yOffset = swapOffset; 1.10144 + } 1.10145 + 1.10146 + return true; 1.10147 +} 1.10148 + 1.10149 +// This function is very similar to ParseBackgroundList and 1.10150 +// ParseBackgroundPosition. 1.10151 +bool 1.10152 +CSSParserImpl::ParseBackgroundSize() 1.10153 +{ 1.10154 + nsCSSValue value; 1.10155 + // 'initial', 'inherit' and 'unset' stand alone, no list permitted. 1.10156 + if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.10157 + nsCSSValuePair valuePair; 1.10158 + if (!ParseBackgroundSizeValues(valuePair)) { 1.10159 + return false; 1.10160 + } 1.10161 + nsCSSValuePairList* item = value.SetPairListValue(); 1.10162 + for (;;) { 1.10163 + item->mXValue = valuePair.mXValue; 1.10164 + item->mYValue = valuePair.mYValue; 1.10165 + if (!ExpectSymbol(',', true)) { 1.10166 + break; 1.10167 + } 1.10168 + if (!ParseBackgroundSizeValues(valuePair)) { 1.10169 + return false; 1.10170 + } 1.10171 + item->mNext = new nsCSSValuePairList; 1.10172 + item = item->mNext; 1.10173 + } 1.10174 + } 1.10175 + AppendValue(eCSSProperty_background_size, value); 1.10176 + return true; 1.10177 +} 1.10178 + 1.10179 +/** 1.10180 + * Parses two values that correspond to lengths for the background-size 1.10181 + * property. These can be one or two lengths (or the 'auto' keyword) or 1.10182 + * percentages corresponding to the element's dimensions or the single keywords 1.10183 + * 'contain' or 'cover'. 'initial', 'inherit' and 'unset' must be handled by 1.10184 + * the caller if desired. 1.10185 + * 1.10186 + * @param aOut The nsCSSValuePair in which to place the result. 1.10187 + * @return Whether or not the operation succeeded. 1.10188 + */ 1.10189 +#define BG_SIZE_VARIANT (VARIANT_LP | VARIANT_AUTO | VARIANT_CALC) 1.10190 +bool CSSParserImpl::ParseBackgroundSizeValues(nsCSSValuePair &aOut) 1.10191 +{ 1.10192 + // First try a percentage or a length value 1.10193 + nsCSSValue &xValue = aOut.mXValue, 1.10194 + &yValue = aOut.mYValue; 1.10195 + if (ParseNonNegativeVariant(xValue, BG_SIZE_VARIANT, nullptr)) { 1.10196 + // We have one percentage/length/calc/auto. Get the optional second 1.10197 + // percentage/length/calc/keyword. 1.10198 + if (ParseNonNegativeVariant(yValue, BG_SIZE_VARIANT, nullptr)) { 1.10199 + // We have a second percentage/length/calc/auto. 1.10200 + return true; 1.10201 + } 1.10202 + 1.10203 + // If only one percentage or length value is given, it sets the 1.10204 + // horizontal size only, and the vertical size will be as if by 'auto'. 1.10205 + yValue.SetAutoValue(); 1.10206 + return true; 1.10207 + } 1.10208 + 1.10209 + // Now address 'contain' and 'cover'. 1.10210 + if (!ParseEnum(xValue, nsCSSProps::kBackgroundSizeKTable)) 1.10211 + return false; 1.10212 + yValue.Reset(); 1.10213 + return true; 1.10214 +} 1.10215 +#undef BG_SIZE_VARIANT 1.10216 + 1.10217 +bool 1.10218 +CSSParserImpl::ParseBorderColor() 1.10219 +{ 1.10220 + static const nsCSSProperty kBorderColorSources[] = { 1.10221 + eCSSProperty_border_left_color_ltr_source, 1.10222 + eCSSProperty_border_left_color_rtl_source, 1.10223 + eCSSProperty_border_right_color_ltr_source, 1.10224 + eCSSProperty_border_right_color_rtl_source, 1.10225 + eCSSProperty_UNKNOWN 1.10226 + }; 1.10227 + 1.10228 + // do this now, in case 4 values weren't specified 1.10229 + InitBoxPropsAsPhysical(kBorderColorSources); 1.10230 + return ParseBoxProperties(kBorderColorIDs); 1.10231 +} 1.10232 + 1.10233 +void 1.10234 +CSSParserImpl::SetBorderImageInitialValues() 1.10235 +{ 1.10236 + // border-image-source: none 1.10237 + nsCSSValue source; 1.10238 + source.SetNoneValue(); 1.10239 + AppendValue(eCSSProperty_border_image_source, source); 1.10240 + 1.10241 + // border-image-slice: 100% 1.10242 + nsCSSValue sliceBoxValue; 1.10243 + nsCSSRect& sliceBox = sliceBoxValue.SetRectValue(); 1.10244 + sliceBox.SetAllSidesTo(nsCSSValue(1.0f, eCSSUnit_Percent)); 1.10245 + nsCSSValue slice; 1.10246 + nsCSSValueList* sliceList = slice.SetListValue(); 1.10247 + sliceList->mValue = sliceBoxValue; 1.10248 + AppendValue(eCSSProperty_border_image_slice, slice); 1.10249 + 1.10250 + // border-image-width: 1 1.10251 + nsCSSValue width; 1.10252 + nsCSSRect& widthBox = width.SetRectValue(); 1.10253 + widthBox.SetAllSidesTo(nsCSSValue(1.0f, eCSSUnit_Number)); 1.10254 + AppendValue(eCSSProperty_border_image_width, width); 1.10255 + 1.10256 + // border-image-outset: 0 1.10257 + nsCSSValue outset; 1.10258 + nsCSSRect& outsetBox = outset.SetRectValue(); 1.10259 + outsetBox.SetAllSidesTo(nsCSSValue(0.0f, eCSSUnit_Number)); 1.10260 + AppendValue(eCSSProperty_border_image_outset, outset); 1.10261 + 1.10262 + // border-image-repeat: repeat 1.10263 + nsCSSValue repeat; 1.10264 + nsCSSValuePair repeatPair; 1.10265 + repeatPair.SetBothValuesTo(nsCSSValue(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH, 1.10266 + eCSSUnit_Enumerated)); 1.10267 + repeat.SetPairValue(&repeatPair); 1.10268 + AppendValue(eCSSProperty_border_image_repeat, repeat); 1.10269 +} 1.10270 + 1.10271 +bool 1.10272 +CSSParserImpl::ParseBorderImageSlice(bool aAcceptsInherit, 1.10273 + bool* aConsumedTokens) 1.10274 +{ 1.10275 + // border-image-slice: initial | [<number>|<percentage>]{1,4} && fill? 1.10276 + nsCSSValue value; 1.10277 + 1.10278 + if (aConsumedTokens) { 1.10279 + *aConsumedTokens = true; 1.10280 + } 1.10281 + 1.10282 + if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.10283 + // Keywords "inherit", "initial" and "unset" can not be mixed, so we 1.10284 + // are done. 1.10285 + AppendValue(eCSSProperty_border_image_slice, value); 1.10286 + return true; 1.10287 + } 1.10288 + 1.10289 + // Try parsing "fill" value. 1.10290 + nsCSSValue imageSliceFillValue; 1.10291 + bool hasFill = ParseEnum(imageSliceFillValue, 1.10292 + nsCSSProps::kBorderImageSliceKTable); 1.10293 + 1.10294 + // Parse the box dimensions. 1.10295 + nsCSSValue imageSliceBoxValue; 1.10296 + if (!ParseGroupedBoxProperty(VARIANT_PN, imageSliceBoxValue)) { 1.10297 + if (!hasFill && aConsumedTokens) { 1.10298 + *aConsumedTokens = false; 1.10299 + } 1.10300 + 1.10301 + return false; 1.10302 + } 1.10303 + 1.10304 + // Try parsing "fill" keyword again if the first time failed because keyword 1.10305 + // and slice dimensions can be in any order. 1.10306 + if (!hasFill) { 1.10307 + hasFill = ParseEnum(imageSliceFillValue, 1.10308 + nsCSSProps::kBorderImageSliceKTable); 1.10309 + } 1.10310 + 1.10311 + nsCSSValueList* borderImageSlice = value.SetListValue(); 1.10312 + // Put the box value into the list. 1.10313 + borderImageSlice->mValue = imageSliceBoxValue; 1.10314 + 1.10315 + if (hasFill) { 1.10316 + // Put the "fill" value into the list. 1.10317 + borderImageSlice->mNext = new nsCSSValueList; 1.10318 + borderImageSlice->mNext->mValue = imageSliceFillValue; 1.10319 + } 1.10320 + 1.10321 + AppendValue(eCSSProperty_border_image_slice, value); 1.10322 + return true; 1.10323 +} 1.10324 + 1.10325 +bool 1.10326 +CSSParserImpl::ParseBorderImageWidth(bool aAcceptsInherit) 1.10327 +{ 1.10328 + // border-image-width: initial | [<length>|<number>|<percentage>|auto]{1,4} 1.10329 + nsCSSValue value; 1.10330 + 1.10331 + if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.10332 + // Keywords "inherit", "initial" and "unset" can not be mixed, so we 1.10333 + // are done. 1.10334 + AppendValue(eCSSProperty_border_image_width, value); 1.10335 + return true; 1.10336 + } 1.10337 + 1.10338 + // Parse the box dimensions. 1.10339 + if (!ParseGroupedBoxProperty(VARIANT_ALPN, value)) { 1.10340 + return false; 1.10341 + } 1.10342 + 1.10343 + AppendValue(eCSSProperty_border_image_width, value); 1.10344 + return true; 1.10345 +} 1.10346 + 1.10347 +bool 1.10348 +CSSParserImpl::ParseBorderImageOutset(bool aAcceptsInherit) 1.10349 +{ 1.10350 + // border-image-outset: initial | [<length>|<number>]{1,4} 1.10351 + nsCSSValue value; 1.10352 + 1.10353 + if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.10354 + // Keywords "inherit", "initial" and "unset" can not be mixed, so we 1.10355 + // are done. 1.10356 + AppendValue(eCSSProperty_border_image_outset, value); 1.10357 + return true; 1.10358 + } 1.10359 + 1.10360 + // Parse the box dimensions. 1.10361 + if (!ParseGroupedBoxProperty(VARIANT_LN, value)) { 1.10362 + return false; 1.10363 + } 1.10364 + 1.10365 + AppendValue(eCSSProperty_border_image_outset, value); 1.10366 + return true; 1.10367 +} 1.10368 + 1.10369 +bool 1.10370 +CSSParserImpl::ParseBorderImageRepeat(bool aAcceptsInherit) 1.10371 +{ 1.10372 + nsCSSValue value; 1.10373 + if (aAcceptsInherit && ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.10374 + // Keywords "inherit", "initial" and "unset" can not be mixed, so we 1.10375 + // are done. 1.10376 + AppendValue(eCSSProperty_border_image_repeat, value); 1.10377 + return true; 1.10378 + } 1.10379 + 1.10380 + nsCSSValuePair result; 1.10381 + if (!ParseEnum(result.mXValue, nsCSSProps::kBorderImageRepeatKTable)) { 1.10382 + return false; 1.10383 + } 1.10384 + 1.10385 + // optional second keyword, defaults to first 1.10386 + if (!ParseEnum(result.mYValue, nsCSSProps::kBorderImageRepeatKTable)) { 1.10387 + result.mYValue = result.mXValue; 1.10388 + } 1.10389 + 1.10390 + value.SetPairValue(&result); 1.10391 + AppendValue(eCSSProperty_border_image_repeat, value); 1.10392 + return true; 1.10393 +} 1.10394 + 1.10395 +bool 1.10396 +CSSParserImpl::ParseBorderImage() 1.10397 +{ 1.10398 + nsAutoParseCompoundProperty compound(this); 1.10399 + 1.10400 + // border-image: inherit | initial | 1.10401 + // <border-image-source> || 1.10402 + // <border-image-slice> 1.10403 + // [ / <border-image-width> | 1.10404 + // / <border-image-width>? / <border-image-outset> ]? || 1.10405 + // <border-image-repeat> 1.10406 + 1.10407 + nsCSSValue value; 1.10408 + if (ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.10409 + AppendValue(eCSSProperty_border_image_source, value); 1.10410 + AppendValue(eCSSProperty_border_image_slice, value); 1.10411 + AppendValue(eCSSProperty_border_image_width, value); 1.10412 + AppendValue(eCSSProperty_border_image_outset, value); 1.10413 + AppendValue(eCSSProperty_border_image_repeat, value); 1.10414 + // Keywords "inherit", "initial" and "unset" can't be mixed, so we are done. 1.10415 + return true; 1.10416 + } 1.10417 + 1.10418 + // No empty property. 1.10419 + if (CheckEndProperty()) { 1.10420 + return false; 1.10421 + } 1.10422 + 1.10423 + // Shorthand properties are required to set everything they can. 1.10424 + SetBorderImageInitialValues(); 1.10425 + 1.10426 + bool foundSource = false; 1.10427 + bool foundSliceWidthOutset = false; 1.10428 + bool foundRepeat = false; 1.10429 + 1.10430 + // This loop is used to handle the parsing of border-image properties which 1.10431 + // can appear in any order. 1.10432 + nsCSSValue imageSourceValue; 1.10433 + while (!CheckEndProperty()) { 1.10434 + // <border-image-source> 1.10435 + if (!foundSource && ParseVariant(imageSourceValue, VARIANT_IMAGE, nullptr)) { 1.10436 + AppendValue(eCSSProperty_border_image_source, imageSourceValue); 1.10437 + foundSource = true; 1.10438 + continue; 1.10439 + } 1.10440 + 1.10441 + // <border-image-slice> 1.10442 + // ParseBorderImageSlice is weird. It may consume tokens and then return 1.10443 + // false, because it parses a property with two required components that 1.10444 + // can appear in either order. Since the tokens that were consumed cannot 1.10445 + // parse as anything else we care about, this isn't a problem. 1.10446 + if (!foundSliceWidthOutset) { 1.10447 + bool sliceConsumedTokens = false; 1.10448 + if (ParseBorderImageSlice(false, &sliceConsumedTokens)) { 1.10449 + foundSliceWidthOutset = true; 1.10450 + 1.10451 + // [ / <border-image-width>? 1.10452 + if (ExpectSymbol('/', true)) { 1.10453 + bool foundBorderImageWidth = ParseBorderImageWidth(false); 1.10454 + 1.10455 + // [ / <border-image-outset> 1.10456 + if (ExpectSymbol('/', true)) { 1.10457 + if (!ParseBorderImageOutset(false)) { 1.10458 + return false; 1.10459 + } 1.10460 + } else if (!foundBorderImageWidth) { 1.10461 + // If this part has an trailing slash, the whole declaration is 1.10462 + // invalid. 1.10463 + return false; 1.10464 + } 1.10465 + } 1.10466 + 1.10467 + continue; 1.10468 + } else { 1.10469 + // If we consumed some tokens for <border-image-slice> but did not 1.10470 + // successfully parse it, we have an error. 1.10471 + if (sliceConsumedTokens) { 1.10472 + return false; 1.10473 + } 1.10474 + } 1.10475 + } 1.10476 + 1.10477 + // <border-image-repeat> 1.10478 + if (!foundRepeat && ParseBorderImageRepeat(false)) { 1.10479 + foundRepeat = true; 1.10480 + continue; 1.10481 + } 1.10482 + 1.10483 + return false; 1.10484 + } 1.10485 + 1.10486 + return true; 1.10487 +} 1.10488 + 1.10489 +bool 1.10490 +CSSParserImpl::ParseBorderSpacing() 1.10491 +{ 1.10492 + nsCSSValue xValue, yValue; 1.10493 + if (!ParseNonNegativeVariant(xValue, VARIANT_HL | VARIANT_CALC, nullptr)) { 1.10494 + return false; 1.10495 + } 1.10496 + 1.10497 + // If we have one length, get the optional second length. 1.10498 + // set the second value equal to the first. 1.10499 + if (xValue.IsLengthUnit() || xValue.IsCalcUnit()) { 1.10500 + ParseNonNegativeVariant(yValue, VARIANT_LENGTH | VARIANT_CALC, nullptr); 1.10501 + } 1.10502 + 1.10503 + if (yValue == xValue || yValue.GetUnit() == eCSSUnit_Null) { 1.10504 + AppendValue(eCSSProperty_border_spacing, xValue); 1.10505 + } else { 1.10506 + nsCSSValue pair; 1.10507 + pair.SetPairValue(xValue, yValue); 1.10508 + AppendValue(eCSSProperty_border_spacing, pair); 1.10509 + } 1.10510 + return true; 1.10511 +} 1.10512 + 1.10513 +bool 1.10514 +CSSParserImpl::ParseBorderSide(const nsCSSProperty aPropIDs[], 1.10515 + bool aSetAllSides) 1.10516 +{ 1.10517 + const int32_t numProps = 3; 1.10518 + nsCSSValue values[numProps]; 1.10519 + 1.10520 + int32_t found = ParseChoice(values, aPropIDs, numProps); 1.10521 + if (found < 1) { 1.10522 + return false; 1.10523 + } 1.10524 + 1.10525 + if ((found & 1) == 0) { // Provide default border-width 1.10526 + values[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated); 1.10527 + } 1.10528 + if ((found & 2) == 0) { // Provide default border-style 1.10529 + values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated); 1.10530 + } 1.10531 + if ((found & 4) == 0) { // text color will be used 1.10532 + values[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated); 1.10533 + } 1.10534 + 1.10535 + if (aSetAllSides) { 1.10536 + static const nsCSSProperty kBorderSources[] = { 1.10537 + eCSSProperty_border_left_color_ltr_source, 1.10538 + eCSSProperty_border_left_color_rtl_source, 1.10539 + eCSSProperty_border_right_color_ltr_source, 1.10540 + eCSSProperty_border_right_color_rtl_source, 1.10541 + eCSSProperty_border_left_style_ltr_source, 1.10542 + eCSSProperty_border_left_style_rtl_source, 1.10543 + eCSSProperty_border_right_style_ltr_source, 1.10544 + eCSSProperty_border_right_style_rtl_source, 1.10545 + eCSSProperty_border_left_width_ltr_source, 1.10546 + eCSSProperty_border_left_width_rtl_source, 1.10547 + eCSSProperty_border_right_width_ltr_source, 1.10548 + eCSSProperty_border_right_width_rtl_source, 1.10549 + eCSSProperty_UNKNOWN 1.10550 + }; 1.10551 + 1.10552 + InitBoxPropsAsPhysical(kBorderSources); 1.10553 + 1.10554 + // Parsing "border" shorthand; set all four sides to the same thing 1.10555 + for (int32_t index = 0; index < 4; index++) { 1.10556 + NS_ASSERTION(numProps == 3, "This code needs updating"); 1.10557 + AppendValue(kBorderWidthIDs[index], values[0]); 1.10558 + AppendValue(kBorderStyleIDs[index], values[1]); 1.10559 + AppendValue(kBorderColorIDs[index], values[2]); 1.10560 + } 1.10561 + 1.10562 + static const nsCSSProperty kBorderColorsProps[] = { 1.10563 + eCSSProperty_border_top_colors, 1.10564 + eCSSProperty_border_right_colors, 1.10565 + eCSSProperty_border_bottom_colors, 1.10566 + eCSSProperty_border_left_colors 1.10567 + }; 1.10568 + 1.10569 + // Set the other properties that the border shorthand sets to their 1.10570 + // initial values. 1.10571 + nsCSSValue extraValue; 1.10572 + switch (values[0].GetUnit()) { 1.10573 + case eCSSUnit_Inherit: 1.10574 + case eCSSUnit_Initial: 1.10575 + case eCSSUnit_Unset: 1.10576 + extraValue = values[0]; 1.10577 + // Set value of border-image properties to initial/inherit/unset 1.10578 + AppendValue(eCSSProperty_border_image_source, extraValue); 1.10579 + AppendValue(eCSSProperty_border_image_slice, extraValue); 1.10580 + AppendValue(eCSSProperty_border_image_width, extraValue); 1.10581 + AppendValue(eCSSProperty_border_image_outset, extraValue); 1.10582 + AppendValue(eCSSProperty_border_image_repeat, extraValue); 1.10583 + break; 1.10584 + default: 1.10585 + extraValue.SetNoneValue(); 1.10586 + SetBorderImageInitialValues(); 1.10587 + break; 1.10588 + } 1.10589 + NS_FOR_CSS_SIDES(side) { 1.10590 + AppendValue(kBorderColorsProps[side], extraValue); 1.10591 + } 1.10592 + } 1.10593 + else { 1.10594 + // Just set our one side 1.10595 + for (int32_t index = 0; index < numProps; index++) { 1.10596 + AppendValue(aPropIDs[index], values[index]); 1.10597 + } 1.10598 + } 1.10599 + return true; 1.10600 +} 1.10601 + 1.10602 +bool 1.10603 +CSSParserImpl::ParseDirectionalBorderSide(const nsCSSProperty aPropIDs[], 1.10604 + int32_t aSourceType) 1.10605 +{ 1.10606 + const int32_t numProps = 3; 1.10607 + nsCSSValue values[numProps]; 1.10608 + 1.10609 + int32_t found = ParseChoice(values, aPropIDs, numProps); 1.10610 + if (found < 1) { 1.10611 + return false; 1.10612 + } 1.10613 + 1.10614 + if ((found & 1) == 0) { // Provide default border-width 1.10615 + values[0].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated); 1.10616 + } 1.10617 + if ((found & 2) == 0) { // Provide default border-style 1.10618 + values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated); 1.10619 + } 1.10620 + if ((found & 4) == 0) { // text color will be used 1.10621 + values[2].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated); 1.10622 + } 1.10623 + for (int32_t index = 0; index < numProps; index++) { 1.10624 + const nsCSSProperty* subprops = 1.10625 + nsCSSProps::SubpropertyEntryFor(aPropIDs[index + numProps]); 1.10626 + NS_ASSERTION(subprops[3] == eCSSProperty_UNKNOWN, 1.10627 + "not box property with physical vs. logical cascading"); 1.10628 + AppendValue(subprops[0], values[index]); 1.10629 + nsCSSValue typeVal(aSourceType, eCSSUnit_Enumerated); 1.10630 + AppendValue(subprops[1], typeVal); 1.10631 + AppendValue(subprops[2], typeVal); 1.10632 + } 1.10633 + return true; 1.10634 +} 1.10635 + 1.10636 +bool 1.10637 +CSSParserImpl::ParseBorderStyle() 1.10638 +{ 1.10639 + static const nsCSSProperty kBorderStyleSources[] = { 1.10640 + eCSSProperty_border_left_style_ltr_source, 1.10641 + eCSSProperty_border_left_style_rtl_source, 1.10642 + eCSSProperty_border_right_style_ltr_source, 1.10643 + eCSSProperty_border_right_style_rtl_source, 1.10644 + eCSSProperty_UNKNOWN 1.10645 + }; 1.10646 + 1.10647 + // do this now, in case 4 values weren't specified 1.10648 + InitBoxPropsAsPhysical(kBorderStyleSources); 1.10649 + return ParseBoxProperties(kBorderStyleIDs); 1.10650 +} 1.10651 + 1.10652 +bool 1.10653 +CSSParserImpl::ParseBorderWidth() 1.10654 +{ 1.10655 + static const nsCSSProperty kBorderWidthSources[] = { 1.10656 + eCSSProperty_border_left_width_ltr_source, 1.10657 + eCSSProperty_border_left_width_rtl_source, 1.10658 + eCSSProperty_border_right_width_ltr_source, 1.10659 + eCSSProperty_border_right_width_rtl_source, 1.10660 + eCSSProperty_UNKNOWN 1.10661 + }; 1.10662 + 1.10663 + // do this now, in case 4 values weren't specified 1.10664 + InitBoxPropsAsPhysical(kBorderWidthSources); 1.10665 + return ParseBoxProperties(kBorderWidthIDs); 1.10666 +} 1.10667 + 1.10668 +bool 1.10669 +CSSParserImpl::ParseBorderColors(nsCSSProperty aProperty) 1.10670 +{ 1.10671 + nsCSSValue value; 1.10672 + // 'inherit', 'initial', 'unset' and 'none' are only allowed on their own 1.10673 + if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.10674 + nsCSSValueList *cur = value.SetListValue(); 1.10675 + for (;;) { 1.10676 + if (!ParseVariant(cur->mValue, VARIANT_COLOR | VARIANT_KEYWORD, 1.10677 + nsCSSProps::kBorderColorKTable)) { 1.10678 + return false; 1.10679 + } 1.10680 + if (CheckEndProperty()) { 1.10681 + break; 1.10682 + } 1.10683 + cur->mNext = new nsCSSValueList; 1.10684 + cur = cur->mNext; 1.10685 + } 1.10686 + } 1.10687 + AppendValue(aProperty, value); 1.10688 + return true; 1.10689 +} 1.10690 + 1.10691 +// Parse the top level of a calc() expression. 1.10692 +bool 1.10693 +CSSParserImpl::ParseCalc(nsCSSValue &aValue, int32_t aVariantMask) 1.10694 +{ 1.10695 + // Parsing calc expressions requires, in a number of cases, looking 1.10696 + // for a token that is *either* a value of the property or a number. 1.10697 + // This can be done without lookahead when we assume that the property 1.10698 + // values cannot themselves be numbers. 1.10699 + NS_ASSERTION(!(aVariantMask & VARIANT_NUMBER), "unexpected variant mask"); 1.10700 + NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask"); 1.10701 + 1.10702 + bool oldUnitlessLengthQuirk = mUnitlessLengthQuirk; 1.10703 + mUnitlessLengthQuirk = false; 1.10704 + 1.10705 + // One-iteration loop so we can break to the error-handling case. 1.10706 + do { 1.10707 + // The toplevel of a calc() is always an nsCSSValue::Array of length 1. 1.10708 + nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1); 1.10709 + 1.10710 + if (!ParseCalcAdditiveExpression(arr->Item(0), aVariantMask)) 1.10711 + break; 1.10712 + 1.10713 + if (!ExpectSymbol(')', true)) 1.10714 + break; 1.10715 + 1.10716 + aValue.SetArrayValue(arr, eCSSUnit_Calc); 1.10717 + mUnitlessLengthQuirk = oldUnitlessLengthQuirk; 1.10718 + return true; 1.10719 + } while (false); 1.10720 + 1.10721 + SkipUntil(')'); 1.10722 + mUnitlessLengthQuirk = oldUnitlessLengthQuirk; 1.10723 + return false; 1.10724 +} 1.10725 + 1.10726 +// We optimize away the <value-expression> production given that 1.10727 +// ParseVariant consumes initial whitespace and we call 1.10728 +// ExpectSymbol(')') with true for aSkipWS. 1.10729 +// * If aVariantMask is VARIANT_NUMBER, this function parses the 1.10730 +// <number-additive-expression> production. 1.10731 +// * If aVariantMask does not contain VARIANT_NUMBER, this function 1.10732 +// parses the <value-additive-expression> production. 1.10733 +// * Otherwise (VARIANT_NUMBER and other bits) this function parses 1.10734 +// whichever one of the productions matches ***and modifies 1.10735 +// aVariantMask*** to reflect which one it has parsed by either 1.10736 +// removing VARIANT_NUMBER or removing all other bits. 1.10737 +// It does so iteratively, but builds the correct recursive 1.10738 +// data structure. 1.10739 +bool 1.10740 +CSSParserImpl::ParseCalcAdditiveExpression(nsCSSValue& aValue, 1.10741 + int32_t& aVariantMask) 1.10742 +{ 1.10743 + NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask"); 1.10744 + nsCSSValue *storage = &aValue; 1.10745 + for (;;) { 1.10746 + bool haveWS; 1.10747 + if (!ParseCalcMultiplicativeExpression(*storage, aVariantMask, &haveWS)) 1.10748 + return false; 1.10749 + 1.10750 + if (!haveWS || !GetToken(false)) 1.10751 + return true; 1.10752 + nsCSSUnit unit; 1.10753 + if (mToken.IsSymbol('+')) { 1.10754 + unit = eCSSUnit_Calc_Plus; 1.10755 + } else if (mToken.IsSymbol('-')) { 1.10756 + unit = eCSSUnit_Calc_Minus; 1.10757 + } else { 1.10758 + UngetToken(); 1.10759 + return true; 1.10760 + } 1.10761 + if (!RequireWhitespace()) 1.10762 + return false; 1.10763 + 1.10764 + nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(2); 1.10765 + arr->Item(0) = aValue; 1.10766 + storage = &arr->Item(1); 1.10767 + aValue.SetArrayValue(arr, unit); 1.10768 + } 1.10769 +} 1.10770 + 1.10771 +struct ReduceNumberCalcOps : public mozilla::css::BasicFloatCalcOps, 1.10772 + public mozilla::css::CSSValueInputCalcOps 1.10773 +{ 1.10774 + result_type ComputeLeafValue(const nsCSSValue& aValue) 1.10775 + { 1.10776 + NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit"); 1.10777 + return aValue.GetFloatValue(); 1.10778 + } 1.10779 + 1.10780 + float ComputeNumber(const nsCSSValue& aValue) 1.10781 + { 1.10782 + return mozilla::css::ComputeCalc(aValue, *this); 1.10783 + } 1.10784 +}; 1.10785 + 1.10786 +// * If aVariantMask is VARIANT_NUMBER, this function parses the 1.10787 +// <number-multiplicative-expression> production. 1.10788 +// * If aVariantMask does not contain VARIANT_NUMBER, this function 1.10789 +// parses the <value-multiplicative-expression> production. 1.10790 +// * Otherwise (VARIANT_NUMBER and other bits) this function parses 1.10791 +// whichever one of the productions matches ***and modifies 1.10792 +// aVariantMask*** to reflect which one it has parsed by either 1.10793 +// removing VARIANT_NUMBER or removing all other bits. 1.10794 +// It does so iteratively, but builds the correct recursive data 1.10795 +// structure. 1.10796 +// This function always consumes *trailing* whitespace when it returns 1.10797 +// true; whether there was any such whitespace is returned in the 1.10798 +// aHadFinalWS parameter. 1.10799 +bool 1.10800 +CSSParserImpl::ParseCalcMultiplicativeExpression(nsCSSValue& aValue, 1.10801 + int32_t& aVariantMask, 1.10802 + bool *aHadFinalWS) 1.10803 +{ 1.10804 + NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask"); 1.10805 + bool gotValue = false; // already got the part with the unit 1.10806 + bool afterDivision = false; 1.10807 + 1.10808 + nsCSSValue *storage = &aValue; 1.10809 + for (;;) { 1.10810 + int32_t variantMask; 1.10811 + if (afterDivision || gotValue) { 1.10812 + variantMask = VARIANT_NUMBER; 1.10813 + } else { 1.10814 + variantMask = aVariantMask | VARIANT_NUMBER; 1.10815 + } 1.10816 + if (!ParseCalcTerm(*storage, variantMask)) 1.10817 + return false; 1.10818 + NS_ABORT_IF_FALSE(variantMask != 0, 1.10819 + "ParseCalcTerm did not set variantMask appropriately"); 1.10820 + NS_ABORT_IF_FALSE(!(variantMask & VARIANT_NUMBER) || 1.10821 + !(variantMask & ~int32_t(VARIANT_NUMBER)), 1.10822 + "ParseCalcTerm did not set variantMask appropriately"); 1.10823 + 1.10824 + if (variantMask & VARIANT_NUMBER) { 1.10825 + // Simplify the value immediately so we can check for division by 1.10826 + // zero. 1.10827 + ReduceNumberCalcOps ops; 1.10828 + float number = mozilla::css::ComputeCalc(*storage, ops); 1.10829 + if (number == 0.0 && afterDivision) 1.10830 + return false; 1.10831 + storage->SetFloatValue(number, eCSSUnit_Number); 1.10832 + } else { 1.10833 + gotValue = true; 1.10834 + 1.10835 + if (storage != &aValue) { 1.10836 + // Simplify any numbers in the Times_L position (which are 1.10837 + // not simplified by the check above). 1.10838 + NS_ABORT_IF_FALSE(storage == &aValue.GetArrayValue()->Item(1), 1.10839 + "unexpected relationship to current storage"); 1.10840 + nsCSSValue &leftValue = aValue.GetArrayValue()->Item(0); 1.10841 + ReduceNumberCalcOps ops; 1.10842 + float number = mozilla::css::ComputeCalc(leftValue, ops); 1.10843 + leftValue.SetFloatValue(number, eCSSUnit_Number); 1.10844 + } 1.10845 + } 1.10846 + 1.10847 + bool hadWS = RequireWhitespace(); 1.10848 + if (!GetToken(false)) { 1.10849 + *aHadFinalWS = hadWS; 1.10850 + break; 1.10851 + } 1.10852 + nsCSSUnit unit; 1.10853 + if (mToken.IsSymbol('*')) { 1.10854 + unit = gotValue ? eCSSUnit_Calc_Times_R : eCSSUnit_Calc_Times_L; 1.10855 + afterDivision = false; 1.10856 + } else if (mToken.IsSymbol('/')) { 1.10857 + unit = eCSSUnit_Calc_Divided; 1.10858 + afterDivision = true; 1.10859 + } else { 1.10860 + UngetToken(); 1.10861 + *aHadFinalWS = hadWS; 1.10862 + break; 1.10863 + } 1.10864 + 1.10865 + nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(2); 1.10866 + arr->Item(0) = aValue; 1.10867 + storage = &arr->Item(1); 1.10868 + aValue.SetArrayValue(arr, unit); 1.10869 + } 1.10870 + 1.10871 + // Adjust aVariantMask (see comments above function) to reflect which 1.10872 + // option we took. 1.10873 + if (aVariantMask & VARIANT_NUMBER) { 1.10874 + if (gotValue) { 1.10875 + aVariantMask &= ~int32_t(VARIANT_NUMBER); 1.10876 + } else { 1.10877 + aVariantMask = VARIANT_NUMBER; 1.10878 + } 1.10879 + } else { 1.10880 + if (!gotValue) { 1.10881 + // We had to find a value, but we didn't. 1.10882 + return false; 1.10883 + } 1.10884 + } 1.10885 + 1.10886 + return true; 1.10887 +} 1.10888 + 1.10889 +// * If aVariantMask is VARIANT_NUMBER, this function parses the 1.10890 +// <number-term> production. 1.10891 +// * If aVariantMask does not contain VARIANT_NUMBER, this function 1.10892 +// parses the <value-term> production. 1.10893 +// * Otherwise (VARIANT_NUMBER and other bits) this function parses 1.10894 +// whichever one of the productions matches ***and modifies 1.10895 +// aVariantMask*** to reflect which one it has parsed by either 1.10896 +// removing VARIANT_NUMBER or removing all other bits. 1.10897 +bool 1.10898 +CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, int32_t& aVariantMask) 1.10899 +{ 1.10900 + NS_ABORT_IF_FALSE(aVariantMask != 0, "unexpected variant mask"); 1.10901 + if (!GetToken(true)) 1.10902 + return false; 1.10903 + // Either an additive expression in parentheses... 1.10904 + if (mToken.IsSymbol('(')) { 1.10905 + if (!ParseCalcAdditiveExpression(aValue, aVariantMask) || 1.10906 + !ExpectSymbol(')', true)) { 1.10907 + SkipUntil(')'); 1.10908 + return false; 1.10909 + } 1.10910 + return true; 1.10911 + } 1.10912 + // ... or just a value 1.10913 + UngetToken(); 1.10914 + // Always pass VARIANT_NUMBER to ParseVariant so that unitless zero 1.10915 + // always gets picked up 1.10916 + if (!ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nullptr)) { 1.10917 + return false; 1.10918 + } 1.10919 + // ...and do the VARIANT_NUMBER check ourselves. 1.10920 + if (!(aVariantMask & VARIANT_NUMBER) && aValue.GetUnit() == eCSSUnit_Number) { 1.10921 + return false; 1.10922 + } 1.10923 + // If we did the value parsing, we need to adjust aVariantMask to 1.10924 + // reflect which option we took (see above). 1.10925 + if (aVariantMask & VARIANT_NUMBER) { 1.10926 + if (aValue.GetUnit() == eCSSUnit_Number) { 1.10927 + aVariantMask = VARIANT_NUMBER; 1.10928 + } else { 1.10929 + aVariantMask &= ~int32_t(VARIANT_NUMBER); 1.10930 + } 1.10931 + } 1.10932 + return true; 1.10933 +} 1.10934 + 1.10935 +// This function consumes all consecutive whitespace and returns whether 1.10936 +// there was any. 1.10937 +bool 1.10938 +CSSParserImpl::RequireWhitespace() 1.10939 +{ 1.10940 + if (!GetToken(false)) 1.10941 + return false; 1.10942 + if (mToken.mType != eCSSToken_Whitespace) { 1.10943 + UngetToken(); 1.10944 + return false; 1.10945 + } 1.10946 + // Skip any additional whitespace tokens. 1.10947 + if (GetToken(true)) { 1.10948 + UngetToken(); 1.10949 + } 1.10950 + return true; 1.10951 +} 1.10952 + 1.10953 +bool 1.10954 +CSSParserImpl::ParseRect(nsCSSProperty aPropID) 1.10955 +{ 1.10956 + nsCSSValue val; 1.10957 + if (ParseVariant(val, VARIANT_INHERIT | VARIANT_AUTO, nullptr)) { 1.10958 + AppendValue(aPropID, val); 1.10959 + return true; 1.10960 + } 1.10961 + 1.10962 + if (! GetToken(true)) { 1.10963 + return false; 1.10964 + } 1.10965 + 1.10966 + if (mToken.mType == eCSSToken_Function && 1.10967 + mToken.mIdent.LowerCaseEqualsLiteral("rect")) { 1.10968 + nsCSSRect& rect = val.SetRectValue(); 1.10969 + bool useCommas; 1.10970 + NS_FOR_CSS_SIDES(side) { 1.10971 + if (! ParseVariant(rect.*(nsCSSRect::sides[side]), 1.10972 + VARIANT_AL, nullptr)) { 1.10973 + return false; 1.10974 + } 1.10975 + if (side == 0) { 1.10976 + useCommas = ExpectSymbol(',', true); 1.10977 + } else if (useCommas && side < 3) { 1.10978 + // Skip optional commas between elements, but only if the first 1.10979 + // separator was a comma. 1.10980 + if (!ExpectSymbol(',', true)) { 1.10981 + return false; 1.10982 + } 1.10983 + } 1.10984 + } 1.10985 + if (!ExpectSymbol(')', true)) { 1.10986 + return false; 1.10987 + } 1.10988 + } else { 1.10989 + UngetToken(); 1.10990 + return false; 1.10991 + } 1.10992 + 1.10993 + AppendValue(aPropID, val); 1.10994 + return true; 1.10995 +} 1.10996 + 1.10997 +bool 1.10998 +CSSParserImpl::ParseColumns() 1.10999 +{ 1.11000 + // We use a similar "fake value" hack to ParseListStyle, because 1.11001 + // "auto" is acceptable for both column-count and column-width. 1.11002 + // If the fake "auto" value is found, and one of the real values isn't, 1.11003 + // that means the fake auto value is meant for the real value we didn't 1.11004 + // find. 1.11005 + static const nsCSSProperty columnIDs[] = { 1.11006 + eCSSPropertyExtra_x_auto_value, 1.11007 + eCSSProperty__moz_column_count, 1.11008 + eCSSProperty__moz_column_width 1.11009 + }; 1.11010 + const int32_t numProps = MOZ_ARRAY_LENGTH(columnIDs); 1.11011 + 1.11012 + nsCSSValue values[numProps]; 1.11013 + int32_t found = ParseChoice(values, columnIDs, numProps); 1.11014 + if (found < 1) { 1.11015 + return false; 1.11016 + } 1.11017 + if ((found & (1|2|4)) == (1|2|4) && 1.11018 + values[0].GetUnit() == eCSSUnit_Auto) { 1.11019 + // We filled all 3 values, which is invalid 1.11020 + return false; 1.11021 + } 1.11022 + 1.11023 + if ((found & 2) == 0) { 1.11024 + // Provide auto column-count 1.11025 + values[1].SetAutoValue(); 1.11026 + } 1.11027 + if ((found & 4) == 0) { 1.11028 + // Provide auto column-width 1.11029 + values[2].SetAutoValue(); 1.11030 + } 1.11031 + 1.11032 + // Start at index 1 to skip the fake auto value. 1.11033 + for (int32_t index = 1; index < numProps; index++) { 1.11034 + AppendValue(columnIDs[index], values[index]); 1.11035 + } 1.11036 + return true; 1.11037 +} 1.11038 + 1.11039 +#define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \ 1.11040 + VARIANT_KEYWORD) 1.11041 +bool 1.11042 +CSSParserImpl::ParseContent() 1.11043 +{ 1.11044 + // We need to divide the 'content' keywords into two classes for 1.11045 + // ParseVariant's sake, so we can't just use nsCSSProps::kContentKTable. 1.11046 + static const KTableValue kContentListKWs[] = { 1.11047 + eCSSKeyword_open_quote, NS_STYLE_CONTENT_OPEN_QUOTE, 1.11048 + eCSSKeyword_close_quote, NS_STYLE_CONTENT_CLOSE_QUOTE, 1.11049 + eCSSKeyword_no_open_quote, NS_STYLE_CONTENT_NO_OPEN_QUOTE, 1.11050 + eCSSKeyword_no_close_quote, NS_STYLE_CONTENT_NO_CLOSE_QUOTE, 1.11051 + eCSSKeyword_UNKNOWN,-1 1.11052 + }; 1.11053 + 1.11054 + static const KTableValue kContentSolitaryKWs[] = { 1.11055 + eCSSKeyword__moz_alt_content, NS_STYLE_CONTENT_ALT_CONTENT, 1.11056 + eCSSKeyword_UNKNOWN,-1 1.11057 + }; 1.11058 + 1.11059 + // Verify that these two lists add up to the size of 1.11060 + // nsCSSProps::kContentKTable. 1.11061 + NS_ABORT_IF_FALSE(nsCSSProps::kContentKTable[ 1.11062 + ArrayLength(kContentListKWs) + 1.11063 + ArrayLength(kContentSolitaryKWs) - 4] == 1.11064 + eCSSKeyword_UNKNOWN && 1.11065 + nsCSSProps::kContentKTable[ 1.11066 + ArrayLength(kContentListKWs) + 1.11067 + ArrayLength(kContentSolitaryKWs) - 3] == -1, 1.11068 + "content keyword tables out of sync"); 1.11069 + 1.11070 + nsCSSValue value; 1.11071 + // 'inherit', 'initial', 'unset', 'normal', 'none', and 'alt-content' must 1.11072 + // be alone 1.11073 + if (!ParseVariant(value, VARIANT_HMK | VARIANT_NONE, 1.11074 + kContentSolitaryKWs)) { 1.11075 + nsCSSValueList* cur = value.SetListValue(); 1.11076 + for (;;) { 1.11077 + if (!ParseVariant(cur->mValue, VARIANT_CONTENT, kContentListKWs)) { 1.11078 + return false; 1.11079 + } 1.11080 + if (CheckEndProperty()) { 1.11081 + break; 1.11082 + } 1.11083 + cur->mNext = new nsCSSValueList; 1.11084 + cur = cur->mNext; 1.11085 + } 1.11086 + } 1.11087 + AppendValue(eCSSProperty_content, value); 1.11088 + return true; 1.11089 +} 1.11090 + 1.11091 +bool 1.11092 +CSSParserImpl::ParseCounterData(nsCSSProperty aPropID) 1.11093 +{ 1.11094 + static const nsCSSKeyword kCounterDataKTable[] = { 1.11095 + eCSSKeyword_none, 1.11096 + eCSSKeyword_UNKNOWN 1.11097 + }; 1.11098 + nsCSSValue value; 1.11099 + if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.11100 + if (!GetToken(true)) { 1.11101 + return false; 1.11102 + } 1.11103 + if (mToken.mType != eCSSToken_Ident) { 1.11104 + UngetToken(); 1.11105 + return false; 1.11106 + } 1.11107 + 1.11108 + nsCSSValuePairList *cur = value.SetPairListValue(); 1.11109 + for (;;) { 1.11110 + if (!ParseCustomIdent(cur->mXValue, mToken.mIdent, kCounterDataKTable)) { 1.11111 + return false; 1.11112 + } 1.11113 + if (!GetToken(true)) { 1.11114 + break; 1.11115 + } 1.11116 + if (mToken.mType == eCSSToken_Number && mToken.mIntegerValid) { 1.11117 + cur->mYValue.SetIntValue(mToken.mInteger, eCSSUnit_Integer); 1.11118 + } else { 1.11119 + UngetToken(); 1.11120 + } 1.11121 + if (!GetToken(true)) { 1.11122 + break; 1.11123 + } 1.11124 + if (mToken.mType != eCSSToken_Ident) { 1.11125 + UngetToken(); 1.11126 + break; 1.11127 + } 1.11128 + cur->mNext = new nsCSSValuePairList; 1.11129 + cur = cur->mNext; 1.11130 + } 1.11131 + } 1.11132 + AppendValue(aPropID, value); 1.11133 + return true; 1.11134 +} 1.11135 + 1.11136 +bool 1.11137 +CSSParserImpl::ParseCursor() 1.11138 +{ 1.11139 + nsCSSValue value; 1.11140 + // 'inherit', 'initial' and 'unset' must be alone 1.11141 + if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.11142 + nsCSSValueList* cur = value.SetListValue(); 1.11143 + for (;;) { 1.11144 + if (!ParseVariant(cur->mValue, VARIANT_UK, nsCSSProps::kCursorKTable)) { 1.11145 + return false; 1.11146 + } 1.11147 + if (cur->mValue.GetUnit() != eCSSUnit_URL) { // keyword must be last 1.11148 + break; 1.11149 + } 1.11150 + 1.11151 + // We have a URL, so make a value array with three values. 1.11152 + nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(3); 1.11153 + val->Item(0) = cur->mValue; 1.11154 + 1.11155 + // Parse optional x and y position of cursor hotspot (css3-ui). 1.11156 + if (ParseVariant(val->Item(1), VARIANT_NUMBER, nullptr)) { 1.11157 + // If we have one number, we must have two. 1.11158 + if (!ParseVariant(val->Item(2), VARIANT_NUMBER, nullptr)) { 1.11159 + return false; 1.11160 + } 1.11161 + } 1.11162 + cur->mValue.SetArrayValue(val, eCSSUnit_Array); 1.11163 + 1.11164 + if (!ExpectSymbol(',', true)) { // url must not be last 1.11165 + return false; 1.11166 + } 1.11167 + cur->mNext = new nsCSSValueList; 1.11168 + cur = cur->mNext; 1.11169 + } 1.11170 + } 1.11171 + AppendValue(eCSSProperty_cursor, value); 1.11172 + return true; 1.11173 +} 1.11174 + 1.11175 + 1.11176 +bool 1.11177 +CSSParserImpl::ParseFont() 1.11178 +{ 1.11179 + static const nsCSSProperty fontIDs[] = { 1.11180 + eCSSProperty_font_style, 1.11181 + eCSSProperty_font_variant, 1.11182 + eCSSProperty_font_weight 1.11183 + }; 1.11184 + 1.11185 + // font-variant-alternates enabled ==> layout.css.font-features.enabled is true 1.11186 + bool featuresEnabled = 1.11187 + nsCSSProps::IsEnabled(eCSSProperty_font_variant_alternates); 1.11188 + nsCSSValue family; 1.11189 + if (ParseVariant(family, VARIANT_HK, nsCSSProps::kFontKTable)) { 1.11190 + if (eCSSUnit_Inherit == family.GetUnit() || 1.11191 + eCSSUnit_Initial == family.GetUnit() || 1.11192 + eCSSUnit_Unset == family.GetUnit()) { 1.11193 + AppendValue(eCSSProperty__x_system_font, nsCSSValue(eCSSUnit_None)); 1.11194 + AppendValue(eCSSProperty_font_family, family); 1.11195 + AppendValue(eCSSProperty_font_style, family); 1.11196 + AppendValue(eCSSProperty_font_variant, family); 1.11197 + AppendValue(eCSSProperty_font_weight, family); 1.11198 + AppendValue(eCSSProperty_font_size, family); 1.11199 + AppendValue(eCSSProperty_line_height, family); 1.11200 + AppendValue(eCSSProperty_font_stretch, family); 1.11201 + AppendValue(eCSSProperty_font_size_adjust, family); 1.11202 + AppendValue(eCSSProperty_font_feature_settings, family); 1.11203 + AppendValue(eCSSProperty_font_language_override, family); 1.11204 + if (featuresEnabled) { 1.11205 + AppendValue(eCSSProperty_font_kerning, family); 1.11206 + AppendValue(eCSSProperty_font_synthesis, family); 1.11207 + AppendValue(eCSSProperty_font_variant_alternates, family); 1.11208 + AppendValue(eCSSProperty_font_variant_caps, family); 1.11209 + AppendValue(eCSSProperty_font_variant_east_asian, family); 1.11210 + AppendValue(eCSSProperty_font_variant_ligatures, family); 1.11211 + AppendValue(eCSSProperty_font_variant_numeric, family); 1.11212 + AppendValue(eCSSProperty_font_variant_position, family); 1.11213 + } 1.11214 + } 1.11215 + else { 1.11216 + AppendValue(eCSSProperty__x_system_font, family); 1.11217 + nsCSSValue systemFont(eCSSUnit_System_Font); 1.11218 + AppendValue(eCSSProperty_font_family, systemFont); 1.11219 + AppendValue(eCSSProperty_font_style, systemFont); 1.11220 + AppendValue(eCSSProperty_font_variant, systemFont); 1.11221 + AppendValue(eCSSProperty_font_weight, systemFont); 1.11222 + AppendValue(eCSSProperty_font_size, systemFont); 1.11223 + AppendValue(eCSSProperty_line_height, systemFont); 1.11224 + AppendValue(eCSSProperty_font_stretch, systemFont); 1.11225 + AppendValue(eCSSProperty_font_size_adjust, systemFont); 1.11226 + AppendValue(eCSSProperty_font_feature_settings, systemFont); 1.11227 + AppendValue(eCSSProperty_font_language_override, systemFont); 1.11228 + if (featuresEnabled) { 1.11229 + AppendValue(eCSSProperty_font_kerning, systemFont); 1.11230 + AppendValue(eCSSProperty_font_synthesis, systemFont); 1.11231 + AppendValue(eCSSProperty_font_variant_alternates, systemFont); 1.11232 + AppendValue(eCSSProperty_font_variant_caps, systemFont); 1.11233 + AppendValue(eCSSProperty_font_variant_east_asian, systemFont); 1.11234 + AppendValue(eCSSProperty_font_variant_ligatures, systemFont); 1.11235 + AppendValue(eCSSProperty_font_variant_numeric, systemFont); 1.11236 + AppendValue(eCSSProperty_font_variant_position, systemFont); 1.11237 + } 1.11238 + } 1.11239 + return true; 1.11240 + } 1.11241 + 1.11242 + // Get optional font-style, font-variant and font-weight (in any order) 1.11243 + const int32_t numProps = 3; 1.11244 + nsCSSValue values[numProps]; 1.11245 + int32_t found = ParseChoice(values, fontIDs, numProps); 1.11246 + if (found < 0 || 1.11247 + eCSSUnit_Inherit == values[0].GetUnit() || 1.11248 + eCSSUnit_Initial == values[0].GetUnit() || 1.11249 + eCSSUnit_Unset == values[0].GetUnit()) { // illegal data 1.11250 + return false; 1.11251 + } 1.11252 + if ((found & 1) == 0) { 1.11253 + // Provide default font-style 1.11254 + values[0].SetIntValue(NS_FONT_STYLE_NORMAL, eCSSUnit_Enumerated); 1.11255 + } 1.11256 + if ((found & 2) == 0) { 1.11257 + // Provide default font-variant 1.11258 + values[1].SetIntValue(NS_FONT_VARIANT_NORMAL, eCSSUnit_Enumerated); 1.11259 + } 1.11260 + if ((found & 4) == 0) { 1.11261 + // Provide default font-weight 1.11262 + values[2].SetIntValue(NS_FONT_WEIGHT_NORMAL, eCSSUnit_Enumerated); 1.11263 + } 1.11264 + 1.11265 + // Get mandatory font-size 1.11266 + nsCSSValue size; 1.11267 + if (! ParseNonNegativeVariant(size, VARIANT_KEYWORD | VARIANT_LP, 1.11268 + nsCSSProps::kFontSizeKTable)) { 1.11269 + return false; 1.11270 + } 1.11271 + 1.11272 + // Get optional "/" line-height 1.11273 + nsCSSValue lineHeight; 1.11274 + if (ExpectSymbol('/', true)) { 1.11275 + if (! ParseNonNegativeVariant(lineHeight, 1.11276 + VARIANT_NUMBER | VARIANT_LP | VARIANT_NORMAL, 1.11277 + nullptr)) { 1.11278 + return false; 1.11279 + } 1.11280 + } 1.11281 + else { 1.11282 + lineHeight.SetNormalValue(); 1.11283 + } 1.11284 + 1.11285 + // Get final mandatory font-family 1.11286 + nsAutoParseCompoundProperty compound(this); 1.11287 + if (ParseFamily(family)) { 1.11288 + if (eCSSUnit_Inherit != family.GetUnit() && 1.11289 + eCSSUnit_Initial != family.GetUnit() && 1.11290 + eCSSUnit_Unset != family.GetUnit()) { 1.11291 + AppendValue(eCSSProperty__x_system_font, nsCSSValue(eCSSUnit_None)); 1.11292 + AppendValue(eCSSProperty_font_family, family); 1.11293 + AppendValue(eCSSProperty_font_style, values[0]); 1.11294 + AppendValue(eCSSProperty_font_variant, values[1]); 1.11295 + AppendValue(eCSSProperty_font_weight, values[2]); 1.11296 + AppendValue(eCSSProperty_font_size, size); 1.11297 + AppendValue(eCSSProperty_line_height, lineHeight); 1.11298 + AppendValue(eCSSProperty_font_stretch, 1.11299 + nsCSSValue(NS_FONT_STRETCH_NORMAL, eCSSUnit_Enumerated)); 1.11300 + AppendValue(eCSSProperty_font_size_adjust, nsCSSValue(eCSSUnit_None)); 1.11301 + AppendValue(eCSSProperty_font_feature_settings, nsCSSValue(eCSSUnit_Normal)); 1.11302 + AppendValue(eCSSProperty_font_language_override, nsCSSValue(eCSSUnit_Normal)); 1.11303 + if (featuresEnabled) { 1.11304 + AppendValue(eCSSProperty_font_kerning, 1.11305 + nsCSSValue(NS_FONT_KERNING_AUTO, eCSSUnit_Enumerated)); 1.11306 + AppendValue(eCSSProperty_font_synthesis, 1.11307 + nsCSSValue(NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE, 1.11308 + eCSSUnit_Enumerated)); 1.11309 + AppendValue(eCSSProperty_font_variant_alternates, 1.11310 + nsCSSValue(eCSSUnit_Normal)); 1.11311 + AppendValue(eCSSProperty_font_variant_caps, nsCSSValue(eCSSUnit_Normal)); 1.11312 + AppendValue(eCSSProperty_font_variant_east_asian, 1.11313 + nsCSSValue(eCSSUnit_Normal)); 1.11314 + AppendValue(eCSSProperty_font_variant_ligatures, 1.11315 + nsCSSValue(eCSSUnit_Normal)); 1.11316 + AppendValue(eCSSProperty_font_variant_numeric, 1.11317 + nsCSSValue(eCSSUnit_Normal)); 1.11318 + AppendValue(eCSSProperty_font_variant_position, 1.11319 + nsCSSValue(eCSSUnit_Normal)); 1.11320 + } 1.11321 + return true; 1.11322 + } 1.11323 + } 1.11324 + return false; 1.11325 +} 1.11326 + 1.11327 +bool 1.11328 +CSSParserImpl::ParseFontSynthesis(nsCSSValue& aValue) 1.11329 +{ 1.11330 + if (!ParseVariant(aValue, VARIANT_HK | VARIANT_NONE, 1.11331 + nsCSSProps::kFontSynthesisKTable)) { 1.11332 + return false; 1.11333 + } 1.11334 + 1.11335 + // first value 'none' ==> done 1.11336 + if (eCSSUnit_None == aValue.GetUnit() || 1.11337 + eCSSUnit_Initial == aValue.GetUnit() || 1.11338 + eCSSUnit_Inherit == aValue.GetUnit() || 1.11339 + eCSSUnit_Unset == aValue.GetUnit()) 1.11340 + { 1.11341 + return true; 1.11342 + } 1.11343 + 1.11344 + // look for a second value 1.11345 + int32_t intValue = aValue.GetIntValue(); 1.11346 + nsCSSValue nextValue; 1.11347 + 1.11348 + if (ParseEnum(nextValue, nsCSSProps::kFontSynthesisKTable)) { 1.11349 + int32_t nextIntValue = nextValue.GetIntValue(); 1.11350 + if (nextIntValue & intValue) { 1.11351 + return false; 1.11352 + } 1.11353 + aValue.SetIntValue(nextIntValue | intValue, eCSSUnit_Enumerated); 1.11354 + } 1.11355 + 1.11356 + return true; 1.11357 +} 1.11358 + 1.11359 +// font-variant-alternates allows for a combination of multiple 1.11360 +// simple enumerated values and functional values. Functional values have 1.11361 +// parameter lists with one or more idents which are later resolved 1.11362 +// based on values defined in @font-feature-value rules. 1.11363 +// 1.11364 +// font-variant-alternates: swash(flowing), historical-forms, styleset(alt-g, alt-m); 1.11365 +// 1.11366 +// So for this the nsCSSValue is set to a pair value, with one 1.11367 +// value for a bitmask of both simple and functional property values 1.11368 +// and another value containing a ValuePairList with lists of idents 1.11369 +// for each functional property value. 1.11370 +// 1.11371 +// pairValue 1.11372 +// o intValue 1.11373 +// NS_FONT_VARIANT_ALTERNATES_SWASH | 1.11374 +// NS_FONT_VARIANT_ALTERNATES_STYLESET 1.11375 +// o valuePairList, each element with 1.11376 +// - intValue - indicates which alternate 1.11377 +// - string or valueList of strings 1.11378 +// 1.11379 +// Note: when only 'historical-forms' is specified, there are no 1.11380 +// functional values to store, in which case the valuePairList is a 1.11381 +// single element dummy list. In all other cases, the length of the 1.11382 +// list will match the number of functional values. 1.11383 + 1.11384 +#define MAX_ALLOWED_FEATURES 512 1.11385 + 1.11386 +bool 1.11387 +CSSParserImpl::ParseSingleAlternate(int32_t& aWhichFeature, 1.11388 + nsCSSValue& aValue) 1.11389 +{ 1.11390 + if (!GetToken(true)) { 1.11391 + return false; 1.11392 + } 1.11393 + 1.11394 + bool isIdent = (mToken.mType == eCSSToken_Ident); 1.11395 + if (mToken.mType != eCSSToken_Function && !isIdent) { 1.11396 + UngetToken(); 1.11397 + return false; 1.11398 + } 1.11399 + 1.11400 + // ident ==> simple enumerated prop val (e.g. historical-forms) 1.11401 + // function ==> e.g. swash(flowing) styleset(alt-g, alt-m) 1.11402 + 1.11403 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); 1.11404 + if (!(eCSSKeyword_UNKNOWN < keyword && 1.11405 + nsCSSProps::FindKeyword(keyword, 1.11406 + (isIdent ? 1.11407 + nsCSSProps::kFontVariantAlternatesKTable : 1.11408 + nsCSSProps::kFontVariantAlternatesFuncsKTable), 1.11409 + aWhichFeature))) 1.11410 + { 1.11411 + // failed, pop token 1.11412 + UngetToken(); 1.11413 + return false; 1.11414 + } 1.11415 + 1.11416 + if (isIdent) { 1.11417 + aValue.SetIntValue(aWhichFeature, eCSSUnit_Enumerated); 1.11418 + return true; 1.11419 + } 1.11420 + 1.11421 + uint16_t maxElems = 1; 1.11422 + if (keyword == eCSSKeyword_styleset || 1.11423 + keyword == eCSSKeyword_character_variant) { 1.11424 + maxElems = MAX_ALLOWED_FEATURES; 1.11425 + } 1.11426 + return ParseFunction(keyword, nullptr, VARIANT_IDENTIFIER, 1.11427 + 1, maxElems, aValue); 1.11428 +} 1.11429 + 1.11430 +bool 1.11431 +CSSParserImpl::ParseFontVariantAlternates(nsCSSValue& aValue) 1.11432 +{ 1.11433 + if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) { 1.11434 + return true; 1.11435 + } 1.11436 + 1.11437 + // iterate through parameters 1.11438 + nsCSSValue listValue; 1.11439 + int32_t feature, featureFlags = 0; 1.11440 + 1.11441 + // if no functional values, this may be a list with a single, unused element 1.11442 + listValue.SetListValue(); 1.11443 + 1.11444 + nsCSSValueList* list = nullptr; 1.11445 + nsCSSValue value; 1.11446 + while (ParseSingleAlternate(feature, value)) { 1.11447 + 1.11448 + // check to make sure value not already set 1.11449 + if (feature == 0 || 1.11450 + feature & featureFlags) { 1.11451 + return false; 1.11452 + } 1.11453 + 1.11454 + featureFlags |= feature; 1.11455 + 1.11456 + // if function, need to add to the list of functions 1.11457 + if (value.GetUnit() == eCSSUnit_Function) { 1.11458 + if (!list) { 1.11459 + list = listValue.GetListValue(); 1.11460 + } else { 1.11461 + list->mNext = new nsCSSValueList; 1.11462 + list = list->mNext; 1.11463 + } 1.11464 + list->mValue = value; 1.11465 + } 1.11466 + } 1.11467 + 1.11468 + if (featureFlags == 0) { 1.11469 + // ParseSingleAlternate failed the first time through the loop. 1.11470 + return false; 1.11471 + } 1.11472 + 1.11473 + nsCSSValue featureValue; 1.11474 + featureValue.SetIntValue(featureFlags, eCSSUnit_Enumerated); 1.11475 + aValue.SetPairValue(featureValue, listValue); 1.11476 + 1.11477 + return true; 1.11478 +} 1.11479 + 1.11480 +// aMasks - array of masks for mutually-exclusive property values, 1.11481 +// e.g. proportial-nums, tabular-nums 1.11482 + 1.11483 +bool 1.11484 +CSSParserImpl::ParseBitmaskValues(nsCSSValue& aValue, 1.11485 + const KTableValue aKeywordTable[], 1.11486 + const int32_t aMasks[]) 1.11487 +{ 1.11488 + // Parse at least one keyword 1.11489 + if (!ParseEnum(aValue, aKeywordTable)) { 1.11490 + return false; 1.11491 + } 1.11492 + 1.11493 + // look for more values 1.11494 + nsCSSValue nextValue; 1.11495 + int32_t mergedValue = aValue.GetIntValue(); 1.11496 + 1.11497 + while (ParseEnum(nextValue, aKeywordTable)) 1.11498 + { 1.11499 + int32_t nextIntValue = nextValue.GetIntValue(); 1.11500 + 1.11501 + // check to make sure value not already set 1.11502 + if (nextIntValue & mergedValue) { 1.11503 + return false; 1.11504 + } 1.11505 + 1.11506 + const int32_t *m = aMasks; 1.11507 + int32_t c = 0; 1.11508 + 1.11509 + while (*m != MASK_END_VALUE) { 1.11510 + if (*m & nextIntValue) { 1.11511 + c = mergedValue & *m; 1.11512 + break; 1.11513 + } 1.11514 + m++; 1.11515 + } 1.11516 + 1.11517 + if (c) { 1.11518 + return false; 1.11519 + } 1.11520 + 1.11521 + mergedValue |= nextIntValue; 1.11522 + } 1.11523 + 1.11524 + aValue.SetIntValue(mergedValue, eCSSUnit_Enumerated); 1.11525 + 1.11526 + return true; 1.11527 +} 1.11528 + 1.11529 +static const int32_t maskEastAsian[] = { 1.11530 + NS_FONT_VARIANT_EAST_ASIAN_VARIANT_MASK, 1.11531 + NS_FONT_VARIANT_EAST_ASIAN_WIDTH_MASK, 1.11532 + MASK_END_VALUE 1.11533 +}; 1.11534 + 1.11535 +bool 1.11536 +CSSParserImpl::ParseFontVariantEastAsian(nsCSSValue& aValue) 1.11537 +{ 1.11538 + if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) { 1.11539 + return true; 1.11540 + } 1.11541 + 1.11542 + NS_ASSERTION(maskEastAsian[ArrayLength(maskEastAsian) - 1] == 1.11543 + MASK_END_VALUE, 1.11544 + "incorrectly terminated array"); 1.11545 + 1.11546 + return ParseBitmaskValues(aValue, nsCSSProps::kFontVariantEastAsianKTable, 1.11547 + maskEastAsian); 1.11548 +} 1.11549 + 1.11550 +static const int32_t maskLigatures[] = { 1.11551 + NS_FONT_VARIANT_LIGATURES_COMMON_MASK, 1.11552 + NS_FONT_VARIANT_LIGATURES_DISCRETIONARY_MASK, 1.11553 + NS_FONT_VARIANT_LIGATURES_HISTORICAL_MASK, 1.11554 + NS_FONT_VARIANT_LIGATURES_CONTEXTUAL_MASK, 1.11555 + MASK_END_VALUE 1.11556 +}; 1.11557 + 1.11558 +bool 1.11559 +CSSParserImpl::ParseFontVariantLigatures(nsCSSValue& aValue) 1.11560 +{ 1.11561 + if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) { 1.11562 + return true; 1.11563 + } 1.11564 + 1.11565 + NS_ASSERTION(maskLigatures[ArrayLength(maskLigatures) - 1] == 1.11566 + MASK_END_VALUE, 1.11567 + "incorrectly terminated array"); 1.11568 + 1.11569 + bool parsed = 1.11570 + ParseBitmaskValues(aValue, nsCSSProps::kFontVariantLigaturesKTable, 1.11571 + maskLigatures); 1.11572 + 1.11573 + // if none value included, no other values are possible 1.11574 + if (parsed && eCSSUnit_Enumerated == aValue.GetUnit()) { 1.11575 + int32_t val = aValue.GetIntValue(); 1.11576 + if ((val & NS_FONT_VARIANT_LIGATURES_NONE) && 1.11577 + (val & ~int32_t(NS_FONT_VARIANT_LIGATURES_NONE))) { 1.11578 + parsed = false; 1.11579 + } 1.11580 + } 1.11581 + 1.11582 + return parsed; 1.11583 +} 1.11584 + 1.11585 +static const int32_t maskNumeric[] = { 1.11586 + NS_FONT_VARIANT_NUMERIC_FIGURE_MASK, 1.11587 + NS_FONT_VARIANT_NUMERIC_SPACING_MASK, 1.11588 + NS_FONT_VARIANT_NUMERIC_FRACTION_MASK, 1.11589 + MASK_END_VALUE 1.11590 +}; 1.11591 + 1.11592 +bool 1.11593 +CSSParserImpl::ParseFontVariantNumeric(nsCSSValue& aValue) 1.11594 +{ 1.11595 + if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) { 1.11596 + return true; 1.11597 + } 1.11598 + 1.11599 + NS_ASSERTION(maskNumeric[ArrayLength(maskNumeric) - 1] == 1.11600 + MASK_END_VALUE, 1.11601 + "incorrectly terminated array"); 1.11602 + 1.11603 + return ParseBitmaskValues(aValue, nsCSSProps::kFontVariantNumericKTable, 1.11604 + maskNumeric); 1.11605 +} 1.11606 + 1.11607 +bool 1.11608 +CSSParserImpl::ParseFontWeight(nsCSSValue& aValue) 1.11609 +{ 1.11610 + if (ParseVariant(aValue, VARIANT_HKI | VARIANT_SYSFONT, 1.11611 + nsCSSProps::kFontWeightKTable)) { 1.11612 + if (eCSSUnit_Integer == aValue.GetUnit()) { // ensure unit value 1.11613 + int32_t intValue = aValue.GetIntValue(); 1.11614 + if ((100 <= intValue) && 1.11615 + (intValue <= 900) && 1.11616 + (0 == (intValue % 100))) { 1.11617 + return true; 1.11618 + } else { 1.11619 + UngetToken(); 1.11620 + return false; 1.11621 + } 1.11622 + } 1.11623 + return true; 1.11624 + } 1.11625 + return false; 1.11626 +} 1.11627 + 1.11628 +bool 1.11629 +CSSParserImpl::ParseOneFamily(nsAString& aFamily, bool& aOneKeyword) 1.11630 +{ 1.11631 + if (!GetToken(true)) 1.11632 + return false; 1.11633 + 1.11634 + nsCSSToken* tk = &mToken; 1.11635 + 1.11636 + aOneKeyword = false; 1.11637 + if (eCSSToken_Ident == tk->mType) { 1.11638 + aOneKeyword = true; 1.11639 + aFamily.Append(tk->mIdent); 1.11640 + for (;;) { 1.11641 + if (!GetToken(false)) 1.11642 + break; 1.11643 + 1.11644 + if (eCSSToken_Ident == tk->mType) { 1.11645 + aOneKeyword = false; 1.11646 + // We had at least another keyword before. 1.11647 + // "If a sequence of identifiers is given as a font family name, 1.11648 + // the computed value is the name converted to a string by joining 1.11649 + // all the identifiers in the sequence by single spaces." 1.11650 + // -- CSS 2.1, section 15.3 1.11651 + // Whitespace tokens do not actually matter, 1.11652 + // identifier tokens can be separated by comments. 1.11653 + aFamily.Append(char16_t(' ')); 1.11654 + aFamily.Append(tk->mIdent); 1.11655 + } else if (eCSSToken_Whitespace != tk->mType) { 1.11656 + UngetToken(); 1.11657 + break; 1.11658 + } 1.11659 + } 1.11660 + return true; 1.11661 + 1.11662 + } else if (eCSSToken_String == tk->mType) { 1.11663 + aFamily.Append(tk->mSymbol); // replace the quotes 1.11664 + aFamily.Append(tk->mIdent); // XXX What if it had escaped quotes? 1.11665 + aFamily.Append(tk->mSymbol); 1.11666 + return true; 1.11667 + 1.11668 + } else { 1.11669 + UngetToken(); 1.11670 + return false; 1.11671 + } 1.11672 +} 1.11673 + 1.11674 +bool 1.11675 +CSSParserImpl::ParseFamily(nsCSSValue& aValue) 1.11676 +{ 1.11677 + nsAutoString family; 1.11678 + bool single; 1.11679 + 1.11680 + // keywords only have meaning in the first position 1.11681 + if (!ParseOneFamily(family, single)) 1.11682 + return false; 1.11683 + 1.11684 + // check for keywords, but only when keywords appear by themselves 1.11685 + // i.e. not in compounds such as font-family: default blah; 1.11686 + if (single) { 1.11687 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(family); 1.11688 + if (keyword == eCSSKeyword_inherit) { 1.11689 + aValue.SetInheritValue(); 1.11690 + return true; 1.11691 + } 1.11692 + // 605231 - don't parse unquoted 'default' reserved keyword 1.11693 + if (keyword == eCSSKeyword_default) { 1.11694 + return false; 1.11695 + } 1.11696 + if (keyword == eCSSKeyword_initial) { 1.11697 + aValue.SetInitialValue(); 1.11698 + return true; 1.11699 + } 1.11700 + if (keyword == eCSSKeyword_unset && 1.11701 + nsLayoutUtils::UnsetValueEnabled()) { 1.11702 + aValue.SetUnsetValue(); 1.11703 + return true; 1.11704 + } 1.11705 + if (keyword == eCSSKeyword__moz_use_system_font && 1.11706 + !IsParsingCompoundProperty()) { 1.11707 + aValue.SetSystemFontValue(); 1.11708 + return true; 1.11709 + } 1.11710 + } 1.11711 + 1.11712 + for (;;) { 1.11713 + if (!ExpectSymbol(',', true)) 1.11714 + break; 1.11715 + 1.11716 + family.Append(char16_t(',')); 1.11717 + 1.11718 + nsAutoString nextFamily; 1.11719 + if (!ParseOneFamily(nextFamily, single)) 1.11720 + return false; 1.11721 + 1.11722 + // at this point unquoted keywords are not allowed 1.11723 + // as font family names but can appear within names 1.11724 + if (single) { 1.11725 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(nextFamily); 1.11726 + switch (keyword) { 1.11727 + case eCSSKeyword_inherit: 1.11728 + case eCSSKeyword_initial: 1.11729 + case eCSSKeyword_default: 1.11730 + case eCSSKeyword__moz_use_system_font: 1.11731 + return false; 1.11732 + case eCSSKeyword_unset: 1.11733 + if (nsLayoutUtils::UnsetValueEnabled()) { 1.11734 + return false; 1.11735 + } 1.11736 + // fall through 1.11737 + default: 1.11738 + break; 1.11739 + } 1.11740 + } 1.11741 + 1.11742 + family.Append(nextFamily); 1.11743 + } 1.11744 + 1.11745 + if (family.IsEmpty()) { 1.11746 + return false; 1.11747 + } 1.11748 + aValue.SetStringValue(family, eCSSUnit_Families); 1.11749 + return true; 1.11750 +} 1.11751 + 1.11752 +// src: ( uri-src | local-src ) (',' ( uri-src | local-src ) )* 1.11753 +// uri-src: uri [ 'format(' string ( ',' string )* ')' ] 1.11754 +// local-src: 'local(' ( string | ident ) ')' 1.11755 + 1.11756 +bool 1.11757 +CSSParserImpl::ParseFontSrc(nsCSSValue& aValue) 1.11758 +{ 1.11759 + // could we maybe turn nsCSSValue::Array into InfallibleTArray<nsCSSValue>? 1.11760 + InfallibleTArray<nsCSSValue> values; 1.11761 + nsCSSValue cur; 1.11762 + for (;;) { 1.11763 + if (!GetToken(true)) 1.11764 + break; 1.11765 + 1.11766 + if (mToken.mType == eCSSToken_URL) { 1.11767 + SetValueToURL(cur, mToken.mIdent); 1.11768 + values.AppendElement(cur); 1.11769 + if (!ParseFontSrcFormat(values)) 1.11770 + return false; 1.11771 + 1.11772 + } else if (mToken.mType == eCSSToken_Function && 1.11773 + mToken.mIdent.LowerCaseEqualsLiteral("local")) { 1.11774 + // css3-fonts does not specify a formal grammar for local(). 1.11775 + // The text permits both unquoted identifiers and quoted 1.11776 + // strings. We resolve this ambiguity in the spec by 1.11777 + // assuming that the appropriate production is a single 1.11778 + // <family-name>, possibly surrounded by whitespace. 1.11779 + 1.11780 + nsAutoString family; 1.11781 + bool single; 1.11782 + if (!ParseOneFamily(family, single)) { 1.11783 + SkipUntil(')'); 1.11784 + return false; 1.11785 + } 1.11786 + if (!ExpectSymbol(')', true)) { 1.11787 + SkipUntil(')'); 1.11788 + return false; 1.11789 + } 1.11790 + 1.11791 + // XXX: Getting closer... 1.11792 + // the style parameters to the nsFont constructor are ignored, 1.11793 + // because it's only being used to call EnumerateFamilies 1.11794 + nsFont font(family, 0, 0, 0, 0, 0, 0); 1.11795 + ExtractFirstFamilyData dat; 1.11796 + 1.11797 + font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat); 1.11798 + if (!dat.mGood) 1.11799 + return false; 1.11800 + 1.11801 + cur.SetStringValue(dat.mFamilyName, eCSSUnit_Local_Font); 1.11802 + values.AppendElement(cur); 1.11803 + } else { 1.11804 + // We don't know what to do with this token; unget it and error out 1.11805 + UngetToken(); 1.11806 + return false; 1.11807 + } 1.11808 + 1.11809 + if (!ExpectSymbol(',', true)) 1.11810 + break; 1.11811 + } 1.11812 + 1.11813 + if (values.Length() == 0) 1.11814 + return false; 1.11815 + 1.11816 + nsRefPtr<nsCSSValue::Array> srcVals 1.11817 + = nsCSSValue::Array::Create(values.Length()); 1.11818 + 1.11819 + uint32_t i; 1.11820 + for (i = 0; i < values.Length(); i++) 1.11821 + srcVals->Item(i) = values[i]; 1.11822 + aValue.SetArrayValue(srcVals, eCSSUnit_Array); 1.11823 + return true; 1.11824 +} 1.11825 + 1.11826 +bool 1.11827 +CSSParserImpl::ParseFontSrcFormat(InfallibleTArray<nsCSSValue> & values) 1.11828 +{ 1.11829 + if (!GetToken(true)) 1.11830 + return true; // EOF harmless here 1.11831 + if (mToken.mType != eCSSToken_Function || 1.11832 + !mToken.mIdent.LowerCaseEqualsLiteral("format")) { 1.11833 + UngetToken(); 1.11834 + return true; 1.11835 + } 1.11836 + 1.11837 + do { 1.11838 + if (!GetToken(true)) 1.11839 + return false; // EOF - no need for SkipUntil 1.11840 + 1.11841 + if (mToken.mType != eCSSToken_String) { 1.11842 + UngetToken(); 1.11843 + SkipUntil(')'); 1.11844 + return false; 1.11845 + } 1.11846 + 1.11847 + nsCSSValue cur(mToken.mIdent, eCSSUnit_Font_Format); 1.11848 + values.AppendElement(cur); 1.11849 + } while (ExpectSymbol(',', true)); 1.11850 + 1.11851 + if (!ExpectSymbol(')', true)) { 1.11852 + SkipUntil(')'); 1.11853 + return false; 1.11854 + } 1.11855 + 1.11856 + return true; 1.11857 +} 1.11858 + 1.11859 +// font-ranges: urange ( ',' urange )* 1.11860 +bool 1.11861 +CSSParserImpl::ParseFontRanges(nsCSSValue& aValue) 1.11862 +{ 1.11863 + InfallibleTArray<uint32_t> ranges; 1.11864 + for (;;) { 1.11865 + if (!GetToken(true)) 1.11866 + break; 1.11867 + 1.11868 + if (mToken.mType != eCSSToken_URange) { 1.11869 + UngetToken(); 1.11870 + break; 1.11871 + } 1.11872 + 1.11873 + // An invalid range token is a parsing error, causing the entire 1.11874 + // descriptor to be ignored. 1.11875 + if (!mToken.mIntegerValid) 1.11876 + return false; 1.11877 + 1.11878 + uint32_t low = mToken.mInteger; 1.11879 + uint32_t high = mToken.mInteger2; 1.11880 + 1.11881 + // A range that descends, or a range that is entirely outside the 1.11882 + // current range of Unicode (U+0-10FFFF) is ignored, but does not 1.11883 + // invalidate the descriptor. A range that straddles the high end 1.11884 + // is clipped. 1.11885 + if (low <= 0x10FFFF && low <= high) { 1.11886 + if (high > 0x10FFFF) 1.11887 + high = 0x10FFFF; 1.11888 + 1.11889 + ranges.AppendElement(low); 1.11890 + ranges.AppendElement(high); 1.11891 + } 1.11892 + if (!ExpectSymbol(',', true)) 1.11893 + break; 1.11894 + } 1.11895 + 1.11896 + if (ranges.Length() == 0) 1.11897 + return false; 1.11898 + 1.11899 + nsRefPtr<nsCSSValue::Array> srcVals 1.11900 + = nsCSSValue::Array::Create(ranges.Length()); 1.11901 + 1.11902 + for (uint32_t i = 0; i < ranges.Length(); i++) 1.11903 + srcVals->Item(i).SetIntValue(ranges[i], eCSSUnit_Integer); 1.11904 + aValue.SetArrayValue(srcVals, eCSSUnit_Array); 1.11905 + return true; 1.11906 +} 1.11907 + 1.11908 +// font-feature-settings: normal | <feature-tag-value> [, <feature-tag-value>]* 1.11909 +// <feature-tag-value> = <string> [ <integer> | on | off ]? 1.11910 + 1.11911 +// minimum - "tagx", "tagy", "tagz" 1.11912 +// edge error case - "tagx" on 1, "tagx" "tagy", "tagx" -1, "tagx" big 1.11913 + 1.11914 +// pair value is always x = string, y = int 1.11915 + 1.11916 +// font feature tags must be four ASCII characters 1.11917 +#define FEATURE_TAG_LENGTH 4 1.11918 + 1.11919 +static bool 1.11920 +ValidFontFeatureTag(const nsString& aTag) 1.11921 +{ 1.11922 + if (aTag.Length() != FEATURE_TAG_LENGTH) { 1.11923 + return false; 1.11924 + } 1.11925 + uint32_t i; 1.11926 + for (i = 0; i < FEATURE_TAG_LENGTH; i++) { 1.11927 + uint32_t ch = aTag[i]; 1.11928 + if (ch < 0x20 || ch > 0x7e) { 1.11929 + return false; 1.11930 + } 1.11931 + } 1.11932 + return true; 1.11933 +} 1.11934 + 1.11935 +bool 1.11936 +CSSParserImpl::ParseFontFeatureSettings(nsCSSValue& aValue) 1.11937 +{ 1.11938 + if (ParseVariant(aValue, VARIANT_INHERIT | VARIANT_NORMAL, nullptr)) { 1.11939 + return true; 1.11940 + } 1.11941 + 1.11942 + nsCSSValuePairList *cur = aValue.SetPairListValue(); 1.11943 + for (;;) { 1.11944 + // feature tag 1.11945 + if (!GetToken(true)) { 1.11946 + return false; 1.11947 + } 1.11948 + 1.11949 + if (mToken.mType != eCSSToken_String || 1.11950 + !ValidFontFeatureTag(mToken.mIdent)) { 1.11951 + UngetToken(); 1.11952 + return false; 1.11953 + } 1.11954 + cur->mXValue.SetStringValue(mToken.mIdent, eCSSUnit_String); 1.11955 + 1.11956 + if (!GetToken(true)) { 1.11957 + cur->mYValue.SetIntValue(1, eCSSUnit_Integer); 1.11958 + break; 1.11959 + } 1.11960 + 1.11961 + // optional value or on/off keyword 1.11962 + if (mToken.mType == eCSSToken_Number && mToken.mIntegerValid && 1.11963 + mToken.mInteger >= 0) { 1.11964 + cur->mYValue.SetIntValue(mToken.mInteger, eCSSUnit_Integer); 1.11965 + } else if (mToken.mType == eCSSToken_Ident && 1.11966 + mToken.mIdent.LowerCaseEqualsLiteral("on")) { 1.11967 + cur->mYValue.SetIntValue(1, eCSSUnit_Integer); 1.11968 + } else if (mToken.mType == eCSSToken_Ident && 1.11969 + mToken.mIdent.LowerCaseEqualsLiteral("off")) { 1.11970 + cur->mYValue.SetIntValue(0, eCSSUnit_Integer); 1.11971 + } else { 1.11972 + // something other than value/on/off, set default value 1.11973 + cur->mYValue.SetIntValue(1, eCSSUnit_Integer); 1.11974 + UngetToken(); 1.11975 + } 1.11976 + 1.11977 + if (!ExpectSymbol(',', true)) { 1.11978 + break; 1.11979 + } 1.11980 + 1.11981 + cur->mNext = new nsCSSValuePairList; 1.11982 + cur = cur->mNext; 1.11983 + } 1.11984 + 1.11985 + return true; 1.11986 +} 1.11987 + 1.11988 +bool 1.11989 +CSSParserImpl::ParseListStyle() 1.11990 +{ 1.11991 + // 'list-style' can accept 'none' for two different subproperties, 1.11992 + // 'list-style-type' and 'list-style-position'. In order to accept 1.11993 + // 'none' as the value of either but still allow another value for 1.11994 + // either, we need to ensure that the first 'none' we find gets 1.11995 + // allocated to a dummy property instead. 1.11996 + static const nsCSSProperty listStyleIDs[] = { 1.11997 + eCSSPropertyExtra_x_none_value, 1.11998 + eCSSProperty_list_style_type, 1.11999 + eCSSProperty_list_style_position, 1.12000 + eCSSProperty_list_style_image 1.12001 + }; 1.12002 + 1.12003 + nsCSSValue values[MOZ_ARRAY_LENGTH(listStyleIDs)]; 1.12004 + int32_t found = 1.12005 + ParseChoice(values, listStyleIDs, ArrayLength(listStyleIDs)); 1.12006 + if (found < 1) { 1.12007 + return false; 1.12008 + } 1.12009 + 1.12010 + if ((found & (1|2|8)) == (1|2|8)) { 1.12011 + if (values[0].GetUnit() == eCSSUnit_None) { 1.12012 + // We found a 'none' plus another value for both of 1.12013 + // 'list-style-type' and 'list-style-image'. This is a parse 1.12014 + // error, since the 'none' has to count for at least one of them. 1.12015 + return false; 1.12016 + } else { 1.12017 + NS_ASSERTION(found == (1|2|4|8) && values[0] == values[1] && 1.12018 + values[0] == values[2] && values[0] == values[3], 1.12019 + "should be a special value"); 1.12020 + } 1.12021 + } 1.12022 + 1.12023 + // Provide default values 1.12024 + if ((found & 2) == 0) { 1.12025 + if (found & 1) { 1.12026 + values[1].SetIntValue(NS_STYLE_LIST_STYLE_NONE, eCSSUnit_Enumerated); 1.12027 + } else { 1.12028 + values[1].SetIntValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated); 1.12029 + } 1.12030 + } 1.12031 + if ((found & 4) == 0) { 1.12032 + values[2].SetIntValue(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE, 1.12033 + eCSSUnit_Enumerated); 1.12034 + } 1.12035 + if ((found & 8) == 0) { 1.12036 + values[3].SetNoneValue(); 1.12037 + } 1.12038 + 1.12039 + // Start at 1 to avoid appending fake value. 1.12040 + for (uint32_t index = 1; index < ArrayLength(listStyleIDs); ++index) { 1.12041 + AppendValue(listStyleIDs[index], values[index]); 1.12042 + } 1.12043 + return true; 1.12044 +} 1.12045 + 1.12046 +bool 1.12047 +CSSParserImpl::ParseMargin() 1.12048 +{ 1.12049 + static const nsCSSProperty kMarginSideIDs[] = { 1.12050 + eCSSProperty_margin_top, 1.12051 + eCSSProperty_margin_right_value, 1.12052 + eCSSProperty_margin_bottom, 1.12053 + eCSSProperty_margin_left_value 1.12054 + }; 1.12055 + static const nsCSSProperty kMarginSources[] = { 1.12056 + eCSSProperty_margin_left_ltr_source, 1.12057 + eCSSProperty_margin_left_rtl_source, 1.12058 + eCSSProperty_margin_right_ltr_source, 1.12059 + eCSSProperty_margin_right_rtl_source, 1.12060 + eCSSProperty_UNKNOWN 1.12061 + }; 1.12062 + 1.12063 + // do this now, in case 4 values weren't specified 1.12064 + InitBoxPropsAsPhysical(kMarginSources); 1.12065 + return ParseBoxProperties(kMarginSideIDs); 1.12066 +} 1.12067 + 1.12068 +bool 1.12069 +CSSParserImpl::ParseMarks(nsCSSValue& aValue) 1.12070 +{ 1.12071 + if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kPageMarksKTable)) { 1.12072 + if (eCSSUnit_Enumerated == aValue.GetUnit()) { 1.12073 + if (NS_STYLE_PAGE_MARKS_NONE != aValue.GetIntValue() && 1.12074 + false == CheckEndProperty()) { 1.12075 + nsCSSValue second; 1.12076 + if (ParseEnum(second, nsCSSProps::kPageMarksKTable)) { 1.12077 + // 'none' keyword in conjuction with others is not allowed 1.12078 + if (NS_STYLE_PAGE_MARKS_NONE != second.GetIntValue()) { 1.12079 + aValue.SetIntValue(aValue.GetIntValue() | second.GetIntValue(), 1.12080 + eCSSUnit_Enumerated); 1.12081 + return true; 1.12082 + } 1.12083 + } 1.12084 + return false; 1.12085 + } 1.12086 + } 1.12087 + return true; 1.12088 + } 1.12089 + return false; 1.12090 +} 1.12091 + 1.12092 +bool 1.12093 +CSSParserImpl::ParseOutline() 1.12094 +{ 1.12095 + const int32_t numProps = 3; 1.12096 + static const nsCSSProperty kOutlineIDs[] = { 1.12097 + eCSSProperty_outline_color, 1.12098 + eCSSProperty_outline_style, 1.12099 + eCSSProperty_outline_width 1.12100 + }; 1.12101 + 1.12102 + nsCSSValue values[numProps]; 1.12103 + int32_t found = ParseChoice(values, kOutlineIDs, numProps); 1.12104 + if (found < 1) { 1.12105 + return false; 1.12106 + } 1.12107 + 1.12108 + // Provide default values 1.12109 + if ((found & 1) == 0) { // Provide default outline-color 1.12110 + values[0].SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated); 1.12111 + } 1.12112 + if ((found & 2) == 0) { // Provide default outline-style 1.12113 + values[1].SetIntValue(NS_STYLE_BORDER_STYLE_NONE, eCSSUnit_Enumerated); 1.12114 + } 1.12115 + if ((found & 4) == 0) { // Provide default outline-width 1.12116 + values[2].SetIntValue(NS_STYLE_BORDER_WIDTH_MEDIUM, eCSSUnit_Enumerated); 1.12117 + } 1.12118 + 1.12119 + int32_t index; 1.12120 + for (index = 0; index < numProps; index++) { 1.12121 + AppendValue(kOutlineIDs[index], values[index]); 1.12122 + } 1.12123 + return true; 1.12124 +} 1.12125 + 1.12126 +bool 1.12127 +CSSParserImpl::ParseOverflow() 1.12128 +{ 1.12129 + nsCSSValue overflow; 1.12130 + if (!ParseVariant(overflow, VARIANT_HK, nsCSSProps::kOverflowKTable)) { 1.12131 + return false; 1.12132 + } 1.12133 + 1.12134 + nsCSSValue overflowX(overflow); 1.12135 + nsCSSValue overflowY(overflow); 1.12136 + if (eCSSUnit_Enumerated == overflow.GetUnit()) 1.12137 + switch(overflow.GetIntValue()) { 1.12138 + case NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL: 1.12139 + overflowX.SetIntValue(NS_STYLE_OVERFLOW_SCROLL, eCSSUnit_Enumerated); 1.12140 + overflowY.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN, eCSSUnit_Enumerated); 1.12141 + break; 1.12142 + case NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL: 1.12143 + overflowX.SetIntValue(NS_STYLE_OVERFLOW_HIDDEN, eCSSUnit_Enumerated); 1.12144 + overflowY.SetIntValue(NS_STYLE_OVERFLOW_SCROLL, eCSSUnit_Enumerated); 1.12145 + break; 1.12146 + } 1.12147 + AppendValue(eCSSProperty_overflow_x, overflowX); 1.12148 + AppendValue(eCSSProperty_overflow_y, overflowY); 1.12149 + return true; 1.12150 +} 1.12151 + 1.12152 +bool 1.12153 +CSSParserImpl::ParsePadding() 1.12154 +{ 1.12155 + static const nsCSSProperty kPaddingSideIDs[] = { 1.12156 + eCSSProperty_padding_top, 1.12157 + eCSSProperty_padding_right_value, 1.12158 + eCSSProperty_padding_bottom, 1.12159 + eCSSProperty_padding_left_value 1.12160 + }; 1.12161 + static const nsCSSProperty kPaddingSources[] = { 1.12162 + eCSSProperty_padding_left_ltr_source, 1.12163 + eCSSProperty_padding_left_rtl_source, 1.12164 + eCSSProperty_padding_right_ltr_source, 1.12165 + eCSSProperty_padding_right_rtl_source, 1.12166 + eCSSProperty_UNKNOWN 1.12167 + }; 1.12168 + 1.12169 + // do this now, in case 4 values weren't specified 1.12170 + InitBoxPropsAsPhysical(kPaddingSources); 1.12171 + return ParseBoxProperties(kPaddingSideIDs); 1.12172 +} 1.12173 + 1.12174 +bool 1.12175 +CSSParserImpl::ParseQuotes() 1.12176 +{ 1.12177 + nsCSSValue value; 1.12178 + if (!ParseVariant(value, VARIANT_HOS, nullptr)) { 1.12179 + return false; 1.12180 + } 1.12181 + if (value.GetUnit() == eCSSUnit_String) { 1.12182 + nsCSSValue open = value; 1.12183 + nsCSSValuePairList* quotes = value.SetPairListValue(); 1.12184 + for (;;) { 1.12185 + quotes->mXValue = open; 1.12186 + // get mandatory close 1.12187 + if (!ParseVariant(quotes->mYValue, VARIANT_STRING, nullptr)) { 1.12188 + return false; 1.12189 + } 1.12190 + // look for another open 1.12191 + if (!ParseVariant(open, VARIANT_STRING, nullptr)) { 1.12192 + break; 1.12193 + } 1.12194 + quotes->mNext = new nsCSSValuePairList; 1.12195 + quotes = quotes->mNext; 1.12196 + } 1.12197 + } 1.12198 + AppendValue(eCSSProperty_quotes, value); 1.12199 + return true; 1.12200 +} 1.12201 + 1.12202 +bool 1.12203 +CSSParserImpl::ParseSize() 1.12204 +{ 1.12205 + nsCSSValue width, height; 1.12206 + if (!ParseVariant(width, VARIANT_AHKL, nsCSSProps::kPageSizeKTable)) { 1.12207 + return false; 1.12208 + } 1.12209 + if (width.IsLengthUnit()) { 1.12210 + ParseVariant(height, VARIANT_LENGTH, nullptr); 1.12211 + } 1.12212 + 1.12213 + if (width == height || height.GetUnit() == eCSSUnit_Null) { 1.12214 + AppendValue(eCSSProperty_size, width); 1.12215 + } else { 1.12216 + nsCSSValue pair; 1.12217 + pair.SetPairValue(width, height); 1.12218 + AppendValue(eCSSProperty_size, pair); 1.12219 + } 1.12220 + return true; 1.12221 +} 1.12222 + 1.12223 +bool 1.12224 +CSSParserImpl::ParseTextDecoration() 1.12225 +{ 1.12226 + enum { 1.12227 + eDecorationNone = NS_STYLE_TEXT_DECORATION_LINE_NONE, 1.12228 + eDecorationUnderline = NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, 1.12229 + eDecorationOverline = NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, 1.12230 + eDecorationLineThrough = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, 1.12231 + eDecorationBlink = NS_STYLE_TEXT_DECORATION_LINE_BLINK, 1.12232 + eDecorationPrefAnchors = NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS 1.12233 + }; 1.12234 + static_assert((eDecorationNone ^ eDecorationUnderline ^ 1.12235 + eDecorationOverline ^ eDecorationLineThrough ^ 1.12236 + eDecorationBlink ^ eDecorationPrefAnchors) == 1.12237 + (eDecorationNone | eDecorationUnderline | 1.12238 + eDecorationOverline | eDecorationLineThrough | 1.12239 + eDecorationBlink | eDecorationPrefAnchors), 1.12240 + "text decoration constants need to be bitmasks"); 1.12241 + 1.12242 + static const KTableValue kTextDecorationKTable[] = { 1.12243 + eCSSKeyword_none, eDecorationNone, 1.12244 + eCSSKeyword_underline, eDecorationUnderline, 1.12245 + eCSSKeyword_overline, eDecorationOverline, 1.12246 + eCSSKeyword_line_through, eDecorationLineThrough, 1.12247 + eCSSKeyword_blink, eDecorationBlink, 1.12248 + eCSSKeyword__moz_anchor_decoration, eDecorationPrefAnchors, 1.12249 + eCSSKeyword_UNKNOWN,-1 1.12250 + }; 1.12251 + 1.12252 + nsCSSValue value; 1.12253 + if (!ParseVariant(value, VARIANT_HK, kTextDecorationKTable)) { 1.12254 + return false; 1.12255 + } 1.12256 + 1.12257 + nsCSSValue line, style, color; 1.12258 + switch (value.GetUnit()) { 1.12259 + case eCSSUnit_Enumerated: { 1.12260 + // We shouldn't accept decoration line style and color via 1.12261 + // text-decoration. 1.12262 + color.SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, 1.12263 + eCSSUnit_Enumerated); 1.12264 + style.SetIntValue(NS_STYLE_TEXT_DECORATION_STYLE_SOLID, 1.12265 + eCSSUnit_Enumerated); 1.12266 + 1.12267 + int32_t intValue = value.GetIntValue(); 1.12268 + if (intValue == eDecorationNone) { 1.12269 + line.SetIntValue(NS_STYLE_TEXT_DECORATION_LINE_NONE, 1.12270 + eCSSUnit_Enumerated); 1.12271 + break; 1.12272 + } 1.12273 + 1.12274 + // look for more keywords 1.12275 + nsCSSValue keyword; 1.12276 + int32_t index; 1.12277 + for (index = 0; index < 3; index++) { 1.12278 + if (!ParseEnum(keyword, kTextDecorationKTable)) { 1.12279 + break; 1.12280 + } 1.12281 + int32_t newValue = keyword.GetIntValue(); 1.12282 + if (newValue == eDecorationNone || newValue & intValue) { 1.12283 + // 'none' keyword in conjuction with others is not allowed, and 1.12284 + // duplicate keyword is not allowed. 1.12285 + return false; 1.12286 + } 1.12287 + intValue |= newValue; 1.12288 + } 1.12289 + 1.12290 + line.SetIntValue(intValue, eCSSUnit_Enumerated); 1.12291 + break; 1.12292 + } 1.12293 + default: 1.12294 + line = color = style = value; 1.12295 + break; 1.12296 + } 1.12297 + 1.12298 + AppendValue(eCSSProperty_text_decoration_line, line); 1.12299 + AppendValue(eCSSProperty_text_decoration_color, color); 1.12300 + AppendValue(eCSSProperty_text_decoration_style, style); 1.12301 + 1.12302 + return true; 1.12303 +} 1.12304 + 1.12305 +bool 1.12306 +CSSParserImpl::ParseTextAlign(nsCSSValue& aValue, const KTableValue aTable[]) 1.12307 +{ 1.12308 + if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) { 1.12309 + // 'inherit', 'initial' and 'unset' must be alone 1.12310 + return true; 1.12311 + } 1.12312 + 1.12313 + nsCSSValue left; 1.12314 + if (!ParseVariant(left, VARIANT_KEYWORD, aTable)) { 1.12315 + return false; 1.12316 + } 1.12317 + 1.12318 + if (!nsLayoutUtils::IsTextAlignTrueValueEnabled()) { 1.12319 + aValue = left; 1.12320 + return true; 1.12321 + } 1.12322 + 1.12323 + nsCSSValue right; 1.12324 + if (ParseVariant(right, VARIANT_KEYWORD, aTable)) { 1.12325 + // 'true' must be combined with some other value than 'true'. 1.12326 + if (left.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE && 1.12327 + right.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) { 1.12328 + return false; 1.12329 + } 1.12330 + aValue.SetPairValue(left, right); 1.12331 + } else { 1.12332 + // Single value 'true' is not allowed. 1.12333 + if (left.GetIntValue() == NS_STYLE_TEXT_ALIGN_TRUE) { 1.12334 + return false; 1.12335 + } 1.12336 + aValue = left; 1.12337 + } 1.12338 + return true; 1.12339 +} 1.12340 + 1.12341 +bool 1.12342 +CSSParserImpl::ParseTextAlign(nsCSSValue& aValue) 1.12343 +{ 1.12344 + return ParseTextAlign(aValue, nsCSSProps::kTextAlignKTable); 1.12345 +} 1.12346 + 1.12347 +bool 1.12348 +CSSParserImpl::ParseTextAlignLast(nsCSSValue& aValue) 1.12349 +{ 1.12350 + return ParseTextAlign(aValue, nsCSSProps::kTextAlignLastKTable); 1.12351 +} 1.12352 + 1.12353 +bool 1.12354 +CSSParserImpl::ParseTextDecorationLine(nsCSSValue& aValue) 1.12355 +{ 1.12356 + if (ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTextDecorationLineKTable)) { 1.12357 + if (eCSSUnit_Enumerated == aValue.GetUnit()) { 1.12358 + int32_t intValue = aValue.GetIntValue(); 1.12359 + if (intValue != NS_STYLE_TEXT_DECORATION_LINE_NONE) { 1.12360 + // look for more keywords 1.12361 + nsCSSValue keyword; 1.12362 + int32_t index; 1.12363 + for (index = 0; index < 3; index++) { 1.12364 + if (ParseEnum(keyword, nsCSSProps::kTextDecorationLineKTable)) { 1.12365 + int32_t newValue = keyword.GetIntValue(); 1.12366 + if (newValue == NS_STYLE_TEXT_DECORATION_LINE_NONE || 1.12367 + newValue & intValue) { 1.12368 + // 'none' keyword in conjuction with others is not allowed, and 1.12369 + // duplicate keyword is not allowed. 1.12370 + return false; 1.12371 + } 1.12372 + intValue |= newValue; 1.12373 + } 1.12374 + else { 1.12375 + break; 1.12376 + } 1.12377 + } 1.12378 + aValue.SetIntValue(intValue, eCSSUnit_Enumerated); 1.12379 + } 1.12380 + } 1.12381 + return true; 1.12382 + } 1.12383 + return false; 1.12384 +} 1.12385 + 1.12386 +bool 1.12387 +CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue) 1.12388 +{ 1.12389 + if (ParseVariant(aValue, VARIANT_INHERIT, nullptr)) { 1.12390 + // 'inherit', 'initial' and 'unset' must be alone 1.12391 + return true; 1.12392 + } 1.12393 + 1.12394 + nsCSSValue left; 1.12395 + if (!ParseVariant(left, VARIANT_KEYWORD | VARIANT_STRING, 1.12396 + nsCSSProps::kTextOverflowKTable)) 1.12397 + return false; 1.12398 + 1.12399 + nsCSSValue right; 1.12400 + if (ParseVariant(right, VARIANT_KEYWORD | VARIANT_STRING, 1.12401 + nsCSSProps::kTextOverflowKTable)) 1.12402 + aValue.SetPairValue(left, right); 1.12403 + else { 1.12404 + aValue = left; 1.12405 + } 1.12406 + return true; 1.12407 +} 1.12408 + 1.12409 +bool 1.12410 +CSSParserImpl::ParseTouchAction(nsCSSValue& aValue) 1.12411 +{ 1.12412 + // Avaliable values of property touch-action: 1.12413 + // auto | none | [pan-x || pan-y] | manipulation 1.12414 + 1.12415 + if (!ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTouchActionKTable)) { 1.12416 + return false; 1.12417 + } 1.12418 + 1.12419 + // Auto and None keywords aren't allowed in conjunction with others. 1.12420 + // Also inherit, initial and unset values are available. 1.12421 + if (eCSSUnit_Enumerated != aValue.GetUnit()) { 1.12422 + return true; 1.12423 + } 1.12424 + 1.12425 + int32_t intValue = aValue.GetIntValue(); 1.12426 + nsCSSValue nextValue; 1.12427 + if (ParseEnum(nextValue, nsCSSProps::kTouchActionKTable)) { 1.12428 + int32_t nextIntValue = nextValue.GetIntValue(); 1.12429 + 1.12430 + // duplicates aren't allowed. 1.12431 + if (nextIntValue & intValue) { 1.12432 + return false; 1.12433 + } 1.12434 + 1.12435 + // Auto and None and Manipulation is not allowed in conjunction with others. 1.12436 + if ((intValue | nextIntValue) & (NS_STYLE_TOUCH_ACTION_NONE | 1.12437 + NS_STYLE_TOUCH_ACTION_AUTO | 1.12438 + NS_STYLE_TOUCH_ACTION_MANIPULATION)) { 1.12439 + return false; 1.12440 + } 1.12441 + 1.12442 + aValue.SetIntValue(nextIntValue | intValue, eCSSUnit_Enumerated); 1.12443 + } 1.12444 + 1.12445 + return true; 1.12446 +} 1.12447 + 1.12448 +bool 1.12449 +CSSParserImpl::ParseTextCombineUpright(nsCSSValue& aValue) 1.12450 +{ 1.12451 + if (!ParseVariant(aValue, VARIANT_HK, 1.12452 + nsCSSProps::kTextCombineUprightKTable)) { 1.12453 + return false; 1.12454 + } 1.12455 + 1.12456 + // if 'digits', need to check for an explicit number [2, 3, 4] 1.12457 + if (eCSSUnit_Enumerated == aValue.GetUnit() && 1.12458 + aValue.GetIntValue() == NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) { 1.12459 + if (!GetToken(true)) { 1.12460 + return true; 1.12461 + } 1.12462 + if (mToken.mType == eCSSToken_Number && mToken.mIntegerValid) { 1.12463 + switch (mToken.mInteger) { 1.12464 + case 2: // already set, nothing to do 1.12465 + break; 1.12466 + case 3: 1.12467 + aValue.SetIntValue(NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3, 1.12468 + eCSSUnit_Enumerated); 1.12469 + break; 1.12470 + case 4: 1.12471 + aValue.SetIntValue(NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_4, 1.12472 + eCSSUnit_Enumerated); 1.12473 + break; 1.12474 + default: 1.12475 + // invalid digits value 1.12476 + return false; 1.12477 + } 1.12478 + } else { 1.12479 + UngetToken(); 1.12480 + } 1.12481 + } 1.12482 + return true; 1.12483 +} 1.12484 + 1.12485 +/////////////////////////////////////////////////////// 1.12486 +// transform Parsing Implementation 1.12487 + 1.12488 +/* Reads a function list of arguments and consumes the closing parenthesis. 1.12489 + * Do not call this function directly; it's meant to be called from 1.12490 + * ParseFunction. 1.12491 + */ 1.12492 +bool 1.12493 +CSSParserImpl::ParseFunctionInternals(const int32_t aVariantMask[], 1.12494 + int32_t aVariantMaskAll, 1.12495 + uint16_t aMinElems, 1.12496 + uint16_t aMaxElems, 1.12497 + InfallibleTArray<nsCSSValue> &aOutput) 1.12498 +{ 1.12499 + NS_ASSERTION((aVariantMask && !aVariantMaskAll) || 1.12500 + (!aVariantMask && aVariantMaskAll), 1.12501 + "only one of the two variant mask parameters can be set"); 1.12502 + 1.12503 + for (uint16_t index = 0; index < aMaxElems; ++index) { 1.12504 + nsCSSValue newValue; 1.12505 + int32_t m = aVariantMaskAll ? aVariantMaskAll : aVariantMask[index]; 1.12506 + if (!ParseVariant(newValue, m, nullptr)) { 1.12507 + break; 1.12508 + } 1.12509 + 1.12510 + aOutput.AppendElement(newValue); 1.12511 + 1.12512 + if (ExpectSymbol(',', true)) { 1.12513 + // Move on to the next argument if we see a comma. 1.12514 + continue; 1.12515 + } 1.12516 + 1.12517 + if (ExpectSymbol(')', true)) { 1.12518 + // Make sure we've read enough symbols if we see a closing parenthesis. 1.12519 + return (index + 1) >= aMinElems; 1.12520 + } 1.12521 + 1.12522 + // Only a comma or a closing parenthesis is valid after an argument. 1.12523 + break; 1.12524 + } 1.12525 + 1.12526 + // If we're here, we've hit an error without seeing a closing parenthesis or 1.12527 + // we've read too many elements without seeing a closing parenthesis. 1.12528 + SkipUntil(')'); 1.12529 + return false; 1.12530 +} 1.12531 + 1.12532 +/* Parses a function [ input of the form (a [, b]*) ] and stores it 1.12533 + * as an nsCSSValue that holds a function of the form 1.12534 + * function-name arg1 arg2 ... argN 1.12535 + * 1.12536 + * On error, the return value is false. 1.12537 + * 1.12538 + * @param aFunction The name of the function that we're reading. 1.12539 + * @param aAllowedTypes An array of values corresponding to the legal 1.12540 + * types for each element in the function. The zeroth element in the 1.12541 + * array corresponds to the first function parameter, etc. The length 1.12542 + * of this array _must_ be greater than or equal to aMaxElems or the 1.12543 + * behavior is undefined. If not null, aAllowTypesAll must be 0. 1.12544 + * @param aAllowedTypesAll If set, every element tested for these types 1.12545 + * @param aMinElems Minimum number of elements to read. Reading fewer than 1.12546 + * this many elements will result in the function failing. 1.12547 + * @param aMaxElems Maximum number of elements to read. Reading more than 1.12548 + * this many elements will result in the function failing. 1.12549 + * @param aValue (out) The value that was parsed. 1.12550 + */ 1.12551 +bool 1.12552 +CSSParserImpl::ParseFunction(nsCSSKeyword aFunction, 1.12553 + const int32_t aAllowedTypes[], 1.12554 + int32_t aAllowedTypesAll, 1.12555 + uint16_t aMinElems, uint16_t aMaxElems, 1.12556 + nsCSSValue &aValue) 1.12557 +{ 1.12558 + NS_ASSERTION((aAllowedTypes && !aAllowedTypesAll) || 1.12559 + (!aAllowedTypes && aAllowedTypesAll), 1.12560 + "only one of the two allowed type parameter can be set"); 1.12561 + typedef InfallibleTArray<nsCSSValue>::size_type arrlen_t; 1.12562 + 1.12563 + /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1 1.12564 + * elements stored in the the nsCSSValue::Array. 1.12565 + */ 1.12566 + static const arrlen_t MAX_ALLOWED_ELEMS = 0xFFFE; 1.12567 + 1.12568 + /* Read in a list of values as an array, failing if we can't or if 1.12569 + * it's out of bounds. 1.12570 + * 1.12571 + * We reserve 16 entries in the foundValues array in order to avoid 1.12572 + * having to resize the array dynamically when parsing some well-formed 1.12573 + * functions. The number 16 is coming from the number of arguments that 1.12574 + * matrix3d() accepts. 1.12575 + */ 1.12576 + AutoInfallibleTArray<nsCSSValue, 16> foundValues; 1.12577 + if (!ParseFunctionInternals(aAllowedTypes, aAllowedTypesAll, aMinElems, 1.12578 + aMaxElems, foundValues)) { 1.12579 + return false; 1.12580 + } 1.12581 + 1.12582 + /* 1.12583 + * In case the user has given us more than 2^16 - 2 arguments, 1.12584 + * we'll truncate them at 2^16 - 2 arguments. 1.12585 + */ 1.12586 + uint16_t numArgs = std::min(foundValues.Length(), MAX_ALLOWED_ELEMS); 1.12587 + nsRefPtr<nsCSSValue::Array> convertedArray = 1.12588 + aValue.InitFunction(aFunction, numArgs); 1.12589 + 1.12590 + /* Copy things over. */ 1.12591 + for (uint16_t index = 0; index < numArgs; ++index) 1.12592 + convertedArray->Item(index + 1) = foundValues[static_cast<arrlen_t>(index)]; 1.12593 + 1.12594 + /* Return it! */ 1.12595 + return true; 1.12596 +} 1.12597 + 1.12598 +/** 1.12599 + * Given a token, determines the minimum and maximum number of function 1.12600 + * parameters to read, along with the mask that should be used to read 1.12601 + * those function parameters. If the token isn't a transform function, 1.12602 + * returns an error. 1.12603 + * 1.12604 + * @param aToken The token identifying the function. 1.12605 + * @param aMinElems [out] The minimum number of elements to read. 1.12606 + * @param aMaxElems [out] The maximum number of elements to read 1.12607 + * @param aVariantMask [out] The variant mask to use during parsing 1.12608 + * @return Whether the information was loaded successfully. 1.12609 + */ 1.12610 +static bool GetFunctionParseInformation(nsCSSKeyword aToken, 1.12611 + bool aIsPrefixed, 1.12612 + uint16_t &aMinElems, 1.12613 + uint16_t &aMaxElems, 1.12614 + const int32_t *& aVariantMask) 1.12615 +{ 1.12616 +/* These types represent the common variant masks that will be used to 1.12617 + * parse out the individual functions. The order in the enumeration 1.12618 + * must match the order in which the masks are declared. 1.12619 + */ 1.12620 + enum { eLengthPercentCalc, 1.12621 + eLengthCalc, 1.12622 + eTwoLengthPercentCalcs, 1.12623 + eTwoLengthPercentCalcsOneLengthCalc, 1.12624 + eAngle, 1.12625 + eTwoAngles, 1.12626 + eNumber, 1.12627 + ePositiveLength, 1.12628 + eTwoNumbers, 1.12629 + eThreeNumbers, 1.12630 + eThreeNumbersOneAngle, 1.12631 + eMatrix, 1.12632 + eMatrixPrefixed, 1.12633 + eMatrix3d, 1.12634 + eMatrix3dPrefixed, 1.12635 + eNumVariantMasks }; 1.12636 + static const int32_t kMaxElemsPerFunction = 16; 1.12637 + static const int32_t kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = { 1.12638 + {VARIANT_LPCALC}, 1.12639 + {VARIANT_LENGTH|VARIANT_CALC}, 1.12640 + {VARIANT_LPCALC, VARIANT_LPCALC}, 1.12641 + {VARIANT_LPCALC, VARIANT_LPCALC, VARIANT_LENGTH|VARIANT_CALC}, 1.12642 + {VARIANT_ANGLE_OR_ZERO}, 1.12643 + {VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO}, 1.12644 + {VARIANT_NUMBER}, 1.12645 + {VARIANT_LENGTH|VARIANT_POSITIVE_DIMENSION}, 1.12646 + {VARIANT_NUMBER, VARIANT_NUMBER}, 1.12647 + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}, 1.12648 + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO}, 1.12649 + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12650 + VARIANT_NUMBER, VARIANT_NUMBER}, 1.12651 + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12652 + VARIANT_LPNCALC, VARIANT_LPNCALC}, 1.12653 + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12654 + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12655 + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12656 + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}, 1.12657 + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12658 + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12659 + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, 1.12660 + VARIANT_LPNCALC, VARIANT_LPNCALC, VARIANT_LNCALC, VARIANT_NUMBER}}; 1.12661 + 1.12662 +#ifdef DEBUG 1.12663 + static const uint8_t kVariantMaskLengths[eNumVariantMasks] = 1.12664 + {1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 6, 16, 16}; 1.12665 +#endif 1.12666 + 1.12667 + int32_t variantIndex = eNumVariantMasks; 1.12668 + 1.12669 + switch (aToken) { 1.12670 + case eCSSKeyword_translatex: 1.12671 + case eCSSKeyword_translatey: 1.12672 + /* Exactly one length or percent. */ 1.12673 + variantIndex = eLengthPercentCalc; 1.12674 + aMinElems = 1U; 1.12675 + aMaxElems = 1U; 1.12676 + break; 1.12677 + case eCSSKeyword_translatez: 1.12678 + /* Exactly one length */ 1.12679 + variantIndex = eLengthCalc; 1.12680 + aMinElems = 1U; 1.12681 + aMaxElems = 1U; 1.12682 + break; 1.12683 + case eCSSKeyword_translate3d: 1.12684 + /* Exactly two lengthds or percents and a number */ 1.12685 + variantIndex = eTwoLengthPercentCalcsOneLengthCalc; 1.12686 + aMinElems = 3U; 1.12687 + aMaxElems = 3U; 1.12688 + break; 1.12689 + case eCSSKeyword_scalez: 1.12690 + case eCSSKeyword_scalex: 1.12691 + case eCSSKeyword_scaley: 1.12692 + /* Exactly one scale factor. */ 1.12693 + variantIndex = eNumber; 1.12694 + aMinElems = 1U; 1.12695 + aMaxElems = 1U; 1.12696 + break; 1.12697 + case eCSSKeyword_scale3d: 1.12698 + /* Exactly three scale factors. */ 1.12699 + variantIndex = eThreeNumbers; 1.12700 + aMinElems = 3U; 1.12701 + aMaxElems = 3U; 1.12702 + break; 1.12703 + case eCSSKeyword_rotatex: 1.12704 + case eCSSKeyword_rotatey: 1.12705 + case eCSSKeyword_rotate: 1.12706 + case eCSSKeyword_rotatez: 1.12707 + /* Exactly one angle. */ 1.12708 + variantIndex = eAngle; 1.12709 + aMinElems = 1U; 1.12710 + aMaxElems = 1U; 1.12711 + break; 1.12712 + case eCSSKeyword_rotate3d: 1.12713 + variantIndex = eThreeNumbersOneAngle; 1.12714 + aMinElems = 4U; 1.12715 + aMaxElems = 4U; 1.12716 + break; 1.12717 + case eCSSKeyword_translate: 1.12718 + /* One or two lengths or percents. */ 1.12719 + variantIndex = eTwoLengthPercentCalcs; 1.12720 + aMinElems = 1U; 1.12721 + aMaxElems = 2U; 1.12722 + break; 1.12723 + case eCSSKeyword_skew: 1.12724 + /* Exactly one or two angles. */ 1.12725 + variantIndex = eTwoAngles; 1.12726 + aMinElems = 1U; 1.12727 + aMaxElems = 2U; 1.12728 + break; 1.12729 + case eCSSKeyword_scale: 1.12730 + /* One or two scale factors. */ 1.12731 + variantIndex = eTwoNumbers; 1.12732 + aMinElems = 1U; 1.12733 + aMaxElems = 2U; 1.12734 + break; 1.12735 + case eCSSKeyword_skewx: 1.12736 + /* Exactly one angle. */ 1.12737 + variantIndex = eAngle; 1.12738 + aMinElems = 1U; 1.12739 + aMaxElems = 1U; 1.12740 + break; 1.12741 + case eCSSKeyword_skewy: 1.12742 + /* Exactly one angle. */ 1.12743 + variantIndex = eAngle; 1.12744 + aMinElems = 1U; 1.12745 + aMaxElems = 1U; 1.12746 + break; 1.12747 + case eCSSKeyword_matrix: 1.12748 + /* Six values, all numbers. */ 1.12749 + variantIndex = aIsPrefixed ? eMatrixPrefixed : eMatrix; 1.12750 + aMinElems = 6U; 1.12751 + aMaxElems = 6U; 1.12752 + break; 1.12753 + case eCSSKeyword_matrix3d: 1.12754 + /* 16 matrix values, all numbers */ 1.12755 + variantIndex = aIsPrefixed ? eMatrix3dPrefixed : eMatrix3d; 1.12756 + aMinElems = 16U; 1.12757 + aMaxElems = 16U; 1.12758 + break; 1.12759 + case eCSSKeyword_perspective: 1.12760 + /* Exactly one scale number. */ 1.12761 + variantIndex = ePositiveLength; 1.12762 + aMinElems = 1U; 1.12763 + aMaxElems = 1U; 1.12764 + break; 1.12765 + default: 1.12766 + /* Oh dear, we didn't match. Report an error. */ 1.12767 + return false; 1.12768 + } 1.12769 + 1.12770 + NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!"); 1.12771 + NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!"); 1.12772 + NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!"); 1.12773 + NS_ASSERTION(variantIndex >= 0, "Invalid variant mask!"); 1.12774 + NS_ASSERTION(variantIndex < eNumVariantMasks, "Invalid variant mask!"); 1.12775 +#ifdef DEBUG 1.12776 + NS_ASSERTION(aMaxElems <= kVariantMaskLengths[variantIndex], 1.12777 + "Invalid aMaxElems for this variant mask."); 1.12778 +#endif 1.12779 + 1.12780 + // Convert the index into a mask. 1.12781 + aVariantMask = kVariantMasks[variantIndex]; 1.12782 + 1.12783 + return true; 1.12784 +} 1.12785 + 1.12786 +bool CSSParserImpl::ParseWillChange() 1.12787 +{ 1.12788 + nsCSSValue listValue; 1.12789 + nsCSSValueList* currentListValue = listValue.SetListValue(); 1.12790 + bool first = true; 1.12791 + for (;;) { 1.12792 + const uint32_t variantMask = VARIANT_IDENTIFIER | 1.12793 + VARIANT_INHERIT | 1.12794 + VARIANT_NONE | 1.12795 + VARIANT_ALL | 1.12796 + VARIANT_AUTO; 1.12797 + nsCSSValue value; 1.12798 + if (!ParseVariant(value, variantMask, nullptr)) { 1.12799 + return false; 1.12800 + } 1.12801 + 1.12802 + if (value.GetUnit() == eCSSUnit_None || 1.12803 + value.GetUnit() == eCSSUnit_All) 1.12804 + { 1.12805 + return false; 1.12806 + } 1.12807 + 1.12808 + if (value.GetUnit() != eCSSUnit_Ident) { 1.12809 + if (first) { 1.12810 + AppendValue(eCSSProperty_will_change, value); 1.12811 + return true; 1.12812 + } else { 1.12813 + return false; 1.12814 + } 1.12815 + } 1.12816 + 1.12817 + nsString str; 1.12818 + value.GetStringValue(str); 1.12819 + if (str.LowerCaseEqualsLiteral("default")) { 1.12820 + return false; 1.12821 + } 1.12822 + 1.12823 + currentListValue->mValue = value; 1.12824 + 1.12825 + if (!ExpectSymbol(',', true)) { 1.12826 + break; 1.12827 + } 1.12828 + currentListValue->mNext = new nsCSSValueList; 1.12829 + currentListValue = currentListValue->mNext; 1.12830 + first = false; 1.12831 + } 1.12832 + 1.12833 + AppendValue(eCSSProperty_will_change, listValue); 1.12834 + return true; 1.12835 +} 1.12836 + 1.12837 +/* Reads a single transform function from the tokenizer stream, reporting an 1.12838 + * error if something goes wrong. 1.12839 + */ 1.12840 +bool 1.12841 +CSSParserImpl::ParseSingleTransform(bool aIsPrefixed, nsCSSValue& aValue) 1.12842 +{ 1.12843 + if (!GetToken(true)) 1.12844 + return false; 1.12845 + 1.12846 + if (mToken.mType != eCSSToken_Function) { 1.12847 + UngetToken(); 1.12848 + return false; 1.12849 + } 1.12850 + 1.12851 + const int32_t* variantMask; 1.12852 + uint16_t minElems, maxElems; 1.12853 + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); 1.12854 + 1.12855 + if (!GetFunctionParseInformation(keyword, aIsPrefixed, 1.12856 + minElems, maxElems, variantMask)) 1.12857 + return false; 1.12858 + 1.12859 + return ParseFunction(keyword, variantMask, 0, minElems, maxElems, aValue); 1.12860 +} 1.12861 + 1.12862 +/* Parses a transform property list by continuously reading in properties 1.12863 + * and constructing a matrix from it. 1.12864 + */ 1.12865 +bool CSSParserImpl::ParseTransform(bool aIsPrefixed) 1.12866 +{ 1.12867 + nsCSSValue value; 1.12868 + // 'inherit', 'initial', 'unset' and 'none' must be alone 1.12869 + if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.12870 + nsCSSValueSharedList* list = new nsCSSValueSharedList; 1.12871 + value.SetSharedListValue(list); 1.12872 + list->mHead = new nsCSSValueList; 1.12873 + nsCSSValueList* cur = list->mHead; 1.12874 + for (;;) { 1.12875 + if (!ParseSingleTransform(aIsPrefixed, cur->mValue)) { 1.12876 + return false; 1.12877 + } 1.12878 + if (CheckEndProperty()) { 1.12879 + break; 1.12880 + } 1.12881 + cur->mNext = new nsCSSValueList; 1.12882 + cur = cur->mNext; 1.12883 + } 1.12884 + } 1.12885 + AppendValue(eCSSProperty_transform, value); 1.12886 + return true; 1.12887 +} 1.12888 + 1.12889 +bool CSSParserImpl::ParseTransformOrigin(bool aPerspective) 1.12890 +{ 1.12891 + nsCSSValuePair position; 1.12892 + if (!ParseBoxPositionValues(position, true)) 1.12893 + return false; 1.12894 + 1.12895 + nsCSSProperty prop = eCSSProperty_transform_origin; 1.12896 + if (aPerspective) { 1.12897 + prop = eCSSProperty_perspective_origin; 1.12898 + } 1.12899 + 1.12900 + // Unlike many other uses of pairs, this position should always be stored 1.12901 + // as a pair, even if the values are the same, so it always serializes as 1.12902 + // a pair, and to keep the computation code simple. 1.12903 + if (position.mXValue.GetUnit() == eCSSUnit_Inherit || 1.12904 + position.mXValue.GetUnit() == eCSSUnit_Initial || 1.12905 + position.mXValue.GetUnit() == eCSSUnit_Unset) { 1.12906 + NS_ABORT_IF_FALSE(position.mXValue == position.mYValue, 1.12907 + "inherit/initial/unset only half?"); 1.12908 + AppendValue(prop, position.mXValue); 1.12909 + } else { 1.12910 + nsCSSValue value; 1.12911 + if (aPerspective) { 1.12912 + value.SetPairValue(position.mXValue, position.mYValue); 1.12913 + } else { 1.12914 + nsCSSValue depth; 1.12915 + if (!ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nullptr)) { 1.12916 + depth.SetFloatValue(0.0f, eCSSUnit_Pixel); 1.12917 + } 1.12918 + value.SetTripletValue(position.mXValue, position.mYValue, depth); 1.12919 + } 1.12920 + 1.12921 + AppendValue(prop, value); 1.12922 + } 1.12923 + return true; 1.12924 +} 1.12925 + 1.12926 +/** 1.12927 + * Reads a drop-shadow value. At the moment the Filter Effects specification 1.12928 + * just expects one shadow item. Should this ever change to a list of shadow 1.12929 + * items, use ParseShadowList instead. 1.12930 + */ 1.12931 +bool 1.12932 +CSSParserImpl::ParseDropShadow(nsCSSValue* aValue) 1.12933 +{ 1.12934 + // Use nsCSSValueList to reuse the shadow resolving code in 1.12935 + // nsRuleNode and nsComputedDOMStyle. 1.12936 + nsCSSValue shadow; 1.12937 + nsCSSValueList* cur = shadow.SetListValue(); 1.12938 + if (!ParseShadowItem(cur->mValue, false)) 1.12939 + return false; 1.12940 + 1.12941 + if (!ExpectSymbol(')', true)) 1.12942 + return false; 1.12943 + 1.12944 + nsCSSValue::Array* dropShadow = aValue->InitFunction(eCSSKeyword_drop_shadow, 1); 1.12945 + 1.12946 + // Copy things over. 1.12947 + dropShadow->Item(1) = shadow; 1.12948 + 1.12949 + return true; 1.12950 +} 1.12951 + 1.12952 +/** 1.12953 + * Reads a single url or filter function from the tokenizer stream, reporting an 1.12954 + * error if something goes wrong. 1.12955 + */ 1.12956 +bool 1.12957 +CSSParserImpl::ParseSingleFilter(nsCSSValue* aValue) 1.12958 +{ 1.12959 + if (ParseVariant(*aValue, VARIANT_URL, nullptr)) { 1.12960 + return true; 1.12961 + } 1.12962 + 1.12963 + if (!nsLayoutUtils::CSSFiltersEnabled()) { 1.12964 + // With CSS Filters disabled, we should only accept an SVG reference filter. 1.12965 + REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURL); 1.12966 + return false; 1.12967 + } 1.12968 + 1.12969 + if (!GetToken(true)) { 1.12970 + REPORT_UNEXPECTED_EOF(PEFilterEOF); 1.12971 + return false; 1.12972 + } 1.12973 + 1.12974 + if (mToken.mType != eCSSToken_Function) { 1.12975 + REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURLOrFilterFunction); 1.12976 + return false; 1.12977 + } 1.12978 + 1.12979 + nsCSSKeyword functionName = nsCSSKeywords::LookupKeyword(mToken.mIdent); 1.12980 + // Parse drop-shadow independently of the other filter functions 1.12981 + // because of its more complex characteristics. 1.12982 + if (functionName == eCSSKeyword_drop_shadow) { 1.12983 + if (ParseDropShadow(aValue)) { 1.12984 + return true; 1.12985 + } else { 1.12986 + // Unrecognized filter function. 1.12987 + REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURLOrFilterFunction); 1.12988 + SkipUntil(')'); 1.12989 + return false; 1.12990 + } 1.12991 + } 1.12992 + 1.12993 + // Set up the parsing rules based on the filter function. 1.12994 + int32_t variantMask = VARIANT_PN; 1.12995 + bool rejectNegativeArgument = true; 1.12996 + bool clampArgumentToOne = false; 1.12997 + switch (functionName) { 1.12998 + case eCSSKeyword_blur: 1.12999 + variantMask = VARIANT_LCALC | VARIANT_NONNEGATIVE_DIMENSION; 1.13000 + // VARIANT_NONNEGATIVE_DIMENSION will already reject negative lengths. 1.13001 + rejectNegativeArgument = false; 1.13002 + break; 1.13003 + case eCSSKeyword_brightness: 1.13004 + case eCSSKeyword_contrast: 1.13005 + case eCSSKeyword_saturate: 1.13006 + break; 1.13007 + case eCSSKeyword_grayscale: 1.13008 + case eCSSKeyword_invert: 1.13009 + case eCSSKeyword_sepia: 1.13010 + case eCSSKeyword_opacity: 1.13011 + clampArgumentToOne = true; 1.13012 + break; 1.13013 + case eCSSKeyword_hue_rotate: 1.13014 + variantMask = VARIANT_ANGLE; 1.13015 + rejectNegativeArgument = false; 1.13016 + break; 1.13017 + default: 1.13018 + // Unrecognized filter function. 1.13019 + REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURLOrFilterFunction); 1.13020 + SkipUntil(')'); 1.13021 + return false; 1.13022 + } 1.13023 + 1.13024 + // Parse the function. 1.13025 + uint16_t minElems = 1U; 1.13026 + uint16_t maxElems = 1U; 1.13027 + uint32_t allVariants = 0; 1.13028 + if (!ParseFunction(functionName, &variantMask, allVariants, 1.13029 + minElems, maxElems, *aValue)) { 1.13030 + REPORT_UNEXPECTED(PEFilterFunctionArgumentsParsingError); 1.13031 + return false; 1.13032 + } 1.13033 + 1.13034 + // Get the first and only argument to the filter function. 1.13035 + NS_ABORT_IF_FALSE(aValue->GetUnit() == eCSSUnit_Function, 1.13036 + "expected a filter function"); 1.13037 + NS_ABORT_IF_FALSE(aValue->UnitHasArrayValue(), 1.13038 + "filter function should be an array"); 1.13039 + NS_ABORT_IF_FALSE(aValue->GetArrayValue()->Count() == 2, 1.13040 + "filter function should have exactly one argument"); 1.13041 + nsCSSValue& arg = aValue->GetArrayValue()->Item(1); 1.13042 + 1.13043 + if (rejectNegativeArgument && 1.13044 + ((arg.GetUnit() == eCSSUnit_Percent && arg.GetPercentValue() < 0.0f) || 1.13045 + (arg.GetUnit() == eCSSUnit_Number && arg.GetFloatValue() < 0.0f))) { 1.13046 + REPORT_UNEXPECTED(PEExpectedNonnegativeNP); 1.13047 + return false; 1.13048 + } 1.13049 + 1.13050 + if (clampArgumentToOne) { 1.13051 + if (arg.GetUnit() == eCSSUnit_Number && 1.13052 + arg.GetFloatValue() > 1.0f) { 1.13053 + arg.SetFloatValue(1.0f, arg.GetUnit()); 1.13054 + } else if (arg.GetUnit() == eCSSUnit_Percent && 1.13055 + arg.GetPercentValue() > 1.0f) { 1.13056 + arg.SetPercentValue(1.0f); 1.13057 + } 1.13058 + } 1.13059 + 1.13060 + return true; 1.13061 +} 1.13062 + 1.13063 +/** 1.13064 + * Parses a filter property value by continuously reading in urls and/or filter 1.13065 + * functions and constructing a list. 1.13066 + * 1.13067 + * When CSS Filters are enabled, the filter property accepts one or more SVG 1.13068 + * reference filters and/or CSS filter functions. 1.13069 + * e.g. filter: url(#my-filter-1) blur(3px) url(#my-filter-2) grayscale(50%); 1.13070 + * 1.13071 + * When CSS Filters are disabled, the filter property only accepts one SVG 1.13072 + * reference filter. 1.13073 + * e.g. filter: url(#my-filter); 1.13074 + */ 1.13075 +bool 1.13076 +CSSParserImpl::ParseFilter() 1.13077 +{ 1.13078 + nsCSSValue value; 1.13079 + // 'inherit', 'initial', 'unset' and 'none' must be alone 1.13080 + if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.13081 + nsCSSValueList* cur = value.SetListValue(); 1.13082 + while (cur) { 1.13083 + if (!ParseSingleFilter(&cur->mValue)) { 1.13084 + return false; 1.13085 + } 1.13086 + if (CheckEndProperty()) { 1.13087 + break; 1.13088 + } 1.13089 + if (!nsLayoutUtils::CSSFiltersEnabled()) { 1.13090 + // With CSS Filters disabled, we should only accept one SVG reference 1.13091 + // filter. 1.13092 + REPORT_UNEXPECTED_TOKEN(PEExpectEndValue); 1.13093 + return false; 1.13094 + } 1.13095 + cur->mNext = new nsCSSValueList; 1.13096 + cur = cur->mNext; 1.13097 + } 1.13098 + } 1.13099 + AppendValue(eCSSProperty_filter, value); 1.13100 + return true; 1.13101 +} 1.13102 + 1.13103 +bool 1.13104 +CSSParserImpl::ParseTransitionProperty() 1.13105 +{ 1.13106 + nsCSSValue value; 1.13107 + // 'inherit', 'initial', 'unset' and 'none' must be alone 1.13108 + if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.13109 + // Accept a list of arbitrary identifiers. They should be 1.13110 + // CSS properties, but we want to accept any so that we 1.13111 + // accept properties that we don't know about yet, e.g. 1.13112 + // transition-property: invalid-property, left, opacity; 1.13113 + nsCSSValueList* cur = value.SetListValue(); 1.13114 + for (;;) { 1.13115 + if (!ParseVariant(cur->mValue, VARIANT_IDENTIFIER | VARIANT_ALL, nullptr)) { 1.13116 + return false; 1.13117 + } 1.13118 + if (cur->mValue.GetUnit() == eCSSUnit_Ident) { 1.13119 + nsDependentString str(cur->mValue.GetStringBufferValue()); 1.13120 + // Exclude 'none', 'inherit', 'initial' and 'unset' according to the 1.13121 + // same rules as for 'counter-reset' in CSS 2.1. 1.13122 + if (str.LowerCaseEqualsLiteral("none") || 1.13123 + str.LowerCaseEqualsLiteral("inherit") || 1.13124 + str.LowerCaseEqualsLiteral("initial") || 1.13125 + (str.LowerCaseEqualsLiteral("unset") && 1.13126 + nsLayoutUtils::UnsetValueEnabled())) { 1.13127 + return false; 1.13128 + } 1.13129 + } 1.13130 + if (!ExpectSymbol(',', true)) { 1.13131 + break; 1.13132 + } 1.13133 + cur->mNext = new nsCSSValueList; 1.13134 + cur = cur->mNext; 1.13135 + } 1.13136 + } 1.13137 + AppendValue(eCSSProperty_transition_property, value); 1.13138 + return true; 1.13139 +} 1.13140 + 1.13141 +bool 1.13142 +CSSParserImpl::ParseTransitionTimingFunctionValues(nsCSSValue& aValue) 1.13143 +{ 1.13144 + NS_ASSERTION(!mHavePushBack && 1.13145 + mToken.mType == eCSSToken_Function && 1.13146 + mToken.mIdent.LowerCaseEqualsLiteral("cubic-bezier"), 1.13147 + "unexpected initial state"); 1.13148 + 1.13149 + nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(4); 1.13150 + 1.13151 + float x1, x2, y1, y2; 1.13152 + if (!ParseTransitionTimingFunctionValueComponent(x1, ',', true) || 1.13153 + !ParseTransitionTimingFunctionValueComponent(y1, ',', false) || 1.13154 + !ParseTransitionTimingFunctionValueComponent(x2, ',', true) || 1.13155 + !ParseTransitionTimingFunctionValueComponent(y2, ')', false)) { 1.13156 + return false; 1.13157 + } 1.13158 + 1.13159 + val->Item(0).SetFloatValue(x1, eCSSUnit_Number); 1.13160 + val->Item(1).SetFloatValue(y1, eCSSUnit_Number); 1.13161 + val->Item(2).SetFloatValue(x2, eCSSUnit_Number); 1.13162 + val->Item(3).SetFloatValue(y2, eCSSUnit_Number); 1.13163 + 1.13164 + aValue.SetArrayValue(val, eCSSUnit_Cubic_Bezier); 1.13165 + 1.13166 + return true; 1.13167 +} 1.13168 + 1.13169 +bool 1.13170 +CSSParserImpl::ParseTransitionTimingFunctionValueComponent(float& aComponent, 1.13171 + char aStop, 1.13172 + bool aCheckRange) 1.13173 +{ 1.13174 + if (!GetToken(true)) { 1.13175 + return false; 1.13176 + } 1.13177 + nsCSSToken* tk = &mToken; 1.13178 + if (tk->mType == eCSSToken_Number) { 1.13179 + float num = tk->mNumber; 1.13180 + if (aCheckRange && (num < 0.0 || num > 1.0)) { 1.13181 + return false; 1.13182 + } 1.13183 + aComponent = num; 1.13184 + if (ExpectSymbol(aStop, true)) { 1.13185 + return true; 1.13186 + } 1.13187 + } 1.13188 + return false; 1.13189 +} 1.13190 + 1.13191 +bool 1.13192 +CSSParserImpl::ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue) 1.13193 +{ 1.13194 + NS_ASSERTION(!mHavePushBack && 1.13195 + mToken.mType == eCSSToken_Function && 1.13196 + mToken.mIdent.LowerCaseEqualsLiteral("steps"), 1.13197 + "unexpected initial state"); 1.13198 + 1.13199 + nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(2); 1.13200 + 1.13201 + if (!ParseOneOrLargerVariant(val->Item(0), VARIANT_INTEGER, nullptr)) { 1.13202 + return false; 1.13203 + } 1.13204 + 1.13205 + int32_t type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END; 1.13206 + if (ExpectSymbol(',', true)) { 1.13207 + if (!GetToken(true)) { 1.13208 + return false; 1.13209 + } 1.13210 + type = -1; 1.13211 + if (mToken.mType == eCSSToken_Ident) { 1.13212 + if (mToken.mIdent.LowerCaseEqualsLiteral("start")) { 1.13213 + type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START; 1.13214 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("end")) { 1.13215 + type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END; 1.13216 + } 1.13217 + } 1.13218 + if (type == -1) { 1.13219 + UngetToken(); 1.13220 + return false; 1.13221 + } 1.13222 + } 1.13223 + val->Item(1).SetIntValue(type, eCSSUnit_Enumerated); 1.13224 + 1.13225 + if (!ExpectSymbol(')', true)) { 1.13226 + return false; 1.13227 + } 1.13228 + 1.13229 + aValue.SetArrayValue(val, eCSSUnit_Steps); 1.13230 + return true; 1.13231 +} 1.13232 + 1.13233 +static nsCSSValueList* 1.13234 +AppendValueToList(nsCSSValue& aContainer, 1.13235 + nsCSSValueList* aTail, 1.13236 + const nsCSSValue& aValue) 1.13237 +{ 1.13238 + nsCSSValueList* entry; 1.13239 + if (aContainer.GetUnit() == eCSSUnit_Null) { 1.13240 + NS_ABORT_IF_FALSE(!aTail, "should not have an entry"); 1.13241 + entry = aContainer.SetListValue(); 1.13242 + } else { 1.13243 + NS_ABORT_IF_FALSE(!aTail->mNext, "should not have a next entry"); 1.13244 + NS_ABORT_IF_FALSE(aContainer.GetUnit() == eCSSUnit_List, "not a list"); 1.13245 + entry = new nsCSSValueList; 1.13246 + aTail->mNext = entry; 1.13247 + } 1.13248 + entry->mValue = aValue; 1.13249 + return entry; 1.13250 +} 1.13251 + 1.13252 +CSSParserImpl::ParseAnimationOrTransitionShorthandResult 1.13253 +CSSParserImpl::ParseAnimationOrTransitionShorthand( 1.13254 + const nsCSSProperty* aProperties, 1.13255 + const nsCSSValue* aInitialValues, 1.13256 + nsCSSValue* aValues, 1.13257 + size_t aNumProperties) 1.13258 +{ 1.13259 + nsCSSValue tempValue; 1.13260 + // first see if 'inherit', 'initial' or 'unset' is specified. If one is, 1.13261 + // it can be the only thing specified, so don't attempt to parse any 1.13262 + // additional properties 1.13263 + if (ParseVariant(tempValue, VARIANT_INHERIT, nullptr)) { 1.13264 + for (uint32_t i = 0; i < aNumProperties; ++i) { 1.13265 + AppendValue(aProperties[i], tempValue); 1.13266 + } 1.13267 + return eParseAnimationOrTransitionShorthand_Inherit; 1.13268 + } 1.13269 + 1.13270 + static const size_t maxNumProperties = 7; 1.13271 + NS_ABORT_IF_FALSE(aNumProperties <= maxNumProperties, 1.13272 + "can't handle this many properties"); 1.13273 + nsCSSValueList *cur[maxNumProperties]; 1.13274 + bool parsedProperty[maxNumProperties]; 1.13275 + 1.13276 + for (size_t i = 0; i < aNumProperties; ++i) { 1.13277 + cur[i] = nullptr; 1.13278 + } 1.13279 + bool atEOP = false; // at end of property? 1.13280 + for (;;) { // loop over comma-separated transitions or animations 1.13281 + // whether a particular subproperty was specified for this 1.13282 + // transition or animation 1.13283 + bool haveAnyProperty = false; 1.13284 + for (size_t i = 0; i < aNumProperties; ++i) { 1.13285 + parsedProperty[i] = false; 1.13286 + } 1.13287 + for (;;) { // loop over values within a transition or animation 1.13288 + bool foundProperty = false; 1.13289 + // check to see if we're at the end of one full transition or 1.13290 + // animation definition (either because we hit a comma or because 1.13291 + // we hit the end of the property definition) 1.13292 + if (ExpectSymbol(',', true)) 1.13293 + break; 1.13294 + if (CheckEndProperty()) { 1.13295 + atEOP = true; 1.13296 + break; 1.13297 + } 1.13298 + 1.13299 + // else, try to parse the next transition or animation sub-property 1.13300 + for (uint32_t i = 0; !foundProperty && i < aNumProperties; ++i) { 1.13301 + if (!parsedProperty[i]) { 1.13302 + // if we haven't found this property yet, try to parse it 1.13303 + if (ParseSingleValueProperty(tempValue, aProperties[i])) { 1.13304 + parsedProperty[i] = true; 1.13305 + cur[i] = AppendValueToList(aValues[i], cur[i], tempValue); 1.13306 + foundProperty = true; 1.13307 + haveAnyProperty = true; 1.13308 + break; // out of inner loop; continue looking for next sub-property 1.13309 + } 1.13310 + } 1.13311 + } 1.13312 + if (!foundProperty) { 1.13313 + // We're not at a ',' or at the end of the property, but we couldn't 1.13314 + // parse any of the sub-properties, so the declaration is invalid. 1.13315 + return eParseAnimationOrTransitionShorthand_Error; 1.13316 + } 1.13317 + } 1.13318 + 1.13319 + if (!haveAnyProperty) { 1.13320 + // Got an empty item. 1.13321 + return eParseAnimationOrTransitionShorthand_Error; 1.13322 + } 1.13323 + 1.13324 + // We hit the end of the property or the end of one transition 1.13325 + // or animation definition, add its components to the list. 1.13326 + for (uint32_t i = 0; i < aNumProperties; ++i) { 1.13327 + // If all of the subproperties were not explicitly specified, fill 1.13328 + // in the missing ones with initial values. 1.13329 + if (!parsedProperty[i]) { 1.13330 + cur[i] = AppendValueToList(aValues[i], cur[i], aInitialValues[i]); 1.13331 + } 1.13332 + } 1.13333 + 1.13334 + if (atEOP) 1.13335 + break; 1.13336 + // else we just hit a ',' so continue parsing the next compound transition 1.13337 + } 1.13338 + 1.13339 + return eParseAnimationOrTransitionShorthand_Values; 1.13340 +} 1.13341 + 1.13342 +bool 1.13343 +CSSParserImpl::ParseTransition() 1.13344 +{ 1.13345 + static const nsCSSProperty kTransitionProperties[] = { 1.13346 + eCSSProperty_transition_duration, 1.13347 + eCSSProperty_transition_timing_function, 1.13348 + // Must check 'transition-delay' after 'transition-duration', since 1.13349 + // that's our assumption about what the spec means for the shorthand 1.13350 + // syntax (the first time given is the duration, and the second 1.13351 + // given is the delay). 1.13352 + eCSSProperty_transition_delay, 1.13353 + // Must check 'transition-property' after 1.13354 + // 'transition-timing-function' since 'transition-property' accepts 1.13355 + // any keyword. 1.13356 + eCSSProperty_transition_property 1.13357 + }; 1.13358 + static const uint32_t numProps = MOZ_ARRAY_LENGTH(kTransitionProperties); 1.13359 + // this is a shorthand property that accepts -property, -delay, 1.13360 + // -duration, and -timing-function with some components missing. 1.13361 + // there can be multiple transitions, separated with commas 1.13362 + 1.13363 + nsCSSValue initialValues[numProps]; 1.13364 + initialValues[0].SetFloatValue(0.0, eCSSUnit_Seconds); 1.13365 + initialValues[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE, 1.13366 + eCSSUnit_Enumerated); 1.13367 + initialValues[2].SetFloatValue(0.0, eCSSUnit_Seconds); 1.13368 + initialValues[3].SetAllValue(); 1.13369 + 1.13370 + nsCSSValue values[numProps]; 1.13371 + 1.13372 + ParseAnimationOrTransitionShorthandResult spres = 1.13373 + ParseAnimationOrTransitionShorthand(kTransitionProperties, 1.13374 + initialValues, values, numProps); 1.13375 + if (spres != eParseAnimationOrTransitionShorthand_Values) { 1.13376 + return spres != eParseAnimationOrTransitionShorthand_Error; 1.13377 + } 1.13378 + 1.13379 + // Make two checks on the list for 'transition-property': 1.13380 + // + If there is more than one item, then none of the items can be 1.13381 + // 'none'. 1.13382 + // + None of the items can be 'inherit', 'initial' or 'unset'. 1.13383 + { 1.13384 + NS_ABORT_IF_FALSE(kTransitionProperties[3] == 1.13385 + eCSSProperty_transition_property, 1.13386 + "array index mismatch"); 1.13387 + nsCSSValueList *l = values[3].GetListValue(); 1.13388 + bool multipleItems = !!l->mNext; 1.13389 + do { 1.13390 + const nsCSSValue& val = l->mValue; 1.13391 + if (val.GetUnit() == eCSSUnit_None) { 1.13392 + if (multipleItems) { 1.13393 + // This is a syntax error. 1.13394 + return false; 1.13395 + } 1.13396 + 1.13397 + // Unbox a solitary 'none'. 1.13398 + values[3].SetNoneValue(); 1.13399 + break; 1.13400 + } 1.13401 + if (val.GetUnit() == eCSSUnit_Ident) { 1.13402 + nsDependentString str(val.GetStringBufferValue()); 1.13403 + if (str.EqualsLiteral("inherit") || 1.13404 + str.EqualsLiteral("initial") || 1.13405 + (str.EqualsLiteral("unset") && 1.13406 + nsLayoutUtils::UnsetValueEnabled())) { 1.13407 + return false; 1.13408 + } 1.13409 + } 1.13410 + } while ((l = l->mNext)); 1.13411 + } 1.13412 + 1.13413 + // Save all parsed transition sub-properties in mTempData 1.13414 + for (uint32_t i = 0; i < numProps; ++i) { 1.13415 + AppendValue(kTransitionProperties[i], values[i]); 1.13416 + } 1.13417 + return true; 1.13418 +} 1.13419 + 1.13420 +bool 1.13421 +CSSParserImpl::ParseAnimation() 1.13422 +{ 1.13423 + static const nsCSSProperty kAnimationProperties[] = { 1.13424 + eCSSProperty_animation_duration, 1.13425 + eCSSProperty_animation_timing_function, 1.13426 + // Must check 'animation-delay' after 'animation-duration', since 1.13427 + // that's our assumption about what the spec means for the shorthand 1.13428 + // syntax (the first time given is the duration, and the second 1.13429 + // given is the delay). 1.13430 + eCSSProperty_animation_delay, 1.13431 + eCSSProperty_animation_direction, 1.13432 + eCSSProperty_animation_fill_mode, 1.13433 + eCSSProperty_animation_iteration_count, 1.13434 + // Must check 'animation-name' after 'animation-timing-function', 1.13435 + // 'animation-direction', 'animation-fill-mode', 1.13436 + // 'animation-iteration-count', and 'animation-play-state' since 1.13437 + // 'animation-name' accepts any keyword. 1.13438 + eCSSProperty_animation_name 1.13439 + }; 1.13440 + static const uint32_t numProps = MOZ_ARRAY_LENGTH(kAnimationProperties); 1.13441 + // this is a shorthand property that accepts -property, -delay, 1.13442 + // -duration, and -timing-function with some components missing. 1.13443 + // there can be multiple animations, separated with commas 1.13444 + 1.13445 + nsCSSValue initialValues[numProps]; 1.13446 + initialValues[0].SetFloatValue(0.0, eCSSUnit_Seconds); 1.13447 + initialValues[1].SetIntValue(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE, 1.13448 + eCSSUnit_Enumerated); 1.13449 + initialValues[2].SetFloatValue(0.0, eCSSUnit_Seconds); 1.13450 + initialValues[3].SetIntValue(NS_STYLE_ANIMATION_DIRECTION_NORMAL, eCSSUnit_Enumerated); 1.13451 + initialValues[4].SetIntValue(NS_STYLE_ANIMATION_FILL_MODE_NONE, eCSSUnit_Enumerated); 1.13452 + initialValues[5].SetFloatValue(1.0f, eCSSUnit_Number); 1.13453 + initialValues[6].SetNoneValue(); 1.13454 + 1.13455 + nsCSSValue values[numProps]; 1.13456 + 1.13457 + ParseAnimationOrTransitionShorthandResult spres = 1.13458 + ParseAnimationOrTransitionShorthand(kAnimationProperties, 1.13459 + initialValues, values, numProps); 1.13460 + if (spres != eParseAnimationOrTransitionShorthand_Values) { 1.13461 + return spres != eParseAnimationOrTransitionShorthand_Error; 1.13462 + } 1.13463 + 1.13464 + // Save all parsed animation sub-properties in mTempData 1.13465 + for (uint32_t i = 0; i < numProps; ++i) { 1.13466 + AppendValue(kAnimationProperties[i], values[i]); 1.13467 + } 1.13468 + return true; 1.13469 +} 1.13470 + 1.13471 +bool 1.13472 +CSSParserImpl::ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow) 1.13473 +{ 1.13474 + // A shadow list item is an array, with entries in this sequence: 1.13475 + enum { 1.13476 + IndexX, 1.13477 + IndexY, 1.13478 + IndexRadius, 1.13479 + IndexSpread, // only for box-shadow 1.13480 + IndexColor, 1.13481 + IndexInset // only for box-shadow 1.13482 + }; 1.13483 + 1.13484 + nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(6); 1.13485 + 1.13486 + if (aIsBoxShadow) { 1.13487 + // Optional inset keyword (ignore errors) 1.13488 + ParseVariant(val->Item(IndexInset), VARIANT_KEYWORD, 1.13489 + nsCSSProps::kBoxShadowTypeKTable); 1.13490 + } 1.13491 + 1.13492 + nsCSSValue xOrColor; 1.13493 + bool haveColor = false; 1.13494 + if (!ParseVariant(xOrColor, VARIANT_COLOR | VARIANT_LENGTH | VARIANT_CALC, 1.13495 + nullptr)) { 1.13496 + return false; 1.13497 + } 1.13498 + if (xOrColor.IsLengthUnit() || xOrColor.IsCalcUnit()) { 1.13499 + val->Item(IndexX) = xOrColor; 1.13500 + } else { 1.13501 + // Must be a color (as string or color value) 1.13502 + NS_ASSERTION(xOrColor.GetUnit() == eCSSUnit_Ident || 1.13503 + xOrColor.GetUnit() == eCSSUnit_EnumColor || 1.13504 + xOrColor.IsNumericColorUnit(), 1.13505 + "Must be a color value"); 1.13506 + val->Item(IndexColor) = xOrColor; 1.13507 + haveColor = true; 1.13508 + 1.13509 + // X coordinate mandatory after color 1.13510 + if (!ParseVariant(val->Item(IndexX), VARIANT_LENGTH | VARIANT_CALC, 1.13511 + nullptr)) { 1.13512 + return false; 1.13513 + } 1.13514 + } 1.13515 + 1.13516 + // Y coordinate; mandatory 1.13517 + if (!ParseVariant(val->Item(IndexY), VARIANT_LENGTH | VARIANT_CALC, 1.13518 + nullptr)) { 1.13519 + return false; 1.13520 + } 1.13521 + 1.13522 + // Optional radius. Ignore errors except if they pass a negative 1.13523 + // value which we must reject. If we use ParseNonNegativeVariant 1.13524 + // we can't tell the difference between an unspecified radius 1.13525 + // and a negative radius. 1.13526 + if (ParseVariant(val->Item(IndexRadius), VARIANT_LENGTH | VARIANT_CALC, 1.13527 + nullptr) && 1.13528 + val->Item(IndexRadius).IsLengthUnit() && 1.13529 + val->Item(IndexRadius).GetFloatValue() < 0) { 1.13530 + return false; 1.13531 + } 1.13532 + 1.13533 + if (aIsBoxShadow) { 1.13534 + // Optional spread 1.13535 + ParseVariant(val->Item(IndexSpread), VARIANT_LENGTH | VARIANT_CALC, nullptr); 1.13536 + } 1.13537 + 1.13538 + if (!haveColor) { 1.13539 + // Optional color 1.13540 + ParseVariant(val->Item(IndexColor), VARIANT_COLOR, nullptr); 1.13541 + } 1.13542 + 1.13543 + if (aIsBoxShadow && val->Item(IndexInset).GetUnit() == eCSSUnit_Null) { 1.13544 + // Optional inset keyword 1.13545 + ParseVariant(val->Item(IndexInset), VARIANT_KEYWORD, 1.13546 + nsCSSProps::kBoxShadowTypeKTable); 1.13547 + } 1.13548 + 1.13549 + aValue.SetArrayValue(val, eCSSUnit_Array); 1.13550 + return true; 1.13551 +} 1.13552 + 1.13553 +bool 1.13554 +CSSParserImpl::ParseShadowList(nsCSSProperty aProperty) 1.13555 +{ 1.13556 + nsAutoParseCompoundProperty compound(this); 1.13557 + bool isBoxShadow = aProperty == eCSSProperty_box_shadow; 1.13558 + 1.13559 + nsCSSValue value; 1.13560 + // 'inherit', 'initial', 'unset' and 'none' must be alone 1.13561 + if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { 1.13562 + nsCSSValueList* cur = value.SetListValue(); 1.13563 + for (;;) { 1.13564 + if (!ParseShadowItem(cur->mValue, isBoxShadow)) { 1.13565 + return false; 1.13566 + } 1.13567 + if (!ExpectSymbol(',', true)) { 1.13568 + break; 1.13569 + } 1.13570 + cur->mNext = new nsCSSValueList; 1.13571 + cur = cur->mNext; 1.13572 + } 1.13573 + } 1.13574 + AppendValue(aProperty, value); 1.13575 + return true; 1.13576 +} 1.13577 + 1.13578 +int32_t 1.13579 +CSSParserImpl::GetNamespaceIdForPrefix(const nsString& aPrefix) 1.13580 +{ 1.13581 + NS_PRECONDITION(!aPrefix.IsEmpty(), "Must have a prefix here"); 1.13582 + 1.13583 + int32_t nameSpaceID = kNameSpaceID_Unknown; 1.13584 + if (mNameSpaceMap) { 1.13585 + // user-specified identifiers are case-sensitive (bug 416106) 1.13586 + nsCOMPtr<nsIAtom> prefix = do_GetAtom(aPrefix); 1.13587 + if (!prefix) { 1.13588 + NS_RUNTIMEABORT("do_GetAtom failed - out of memory?"); 1.13589 + } 1.13590 + nameSpaceID = mNameSpaceMap->FindNameSpaceID(prefix); 1.13591 + } 1.13592 + // else no declared namespaces 1.13593 + 1.13594 + if (nameSpaceID == kNameSpaceID_Unknown) { // unknown prefix, dump it 1.13595 + REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, aPrefix); 1.13596 + } 1.13597 + 1.13598 + return nameSpaceID; 1.13599 +} 1.13600 + 1.13601 +void 1.13602 +CSSParserImpl::SetDefaultNamespaceOnSelector(nsCSSSelector& aSelector) 1.13603 +{ 1.13604 + if (mNameSpaceMap) { 1.13605 + aSelector.SetNameSpace(mNameSpaceMap->FindNameSpaceID(nullptr)); 1.13606 + } else { 1.13607 + aSelector.SetNameSpace(kNameSpaceID_Unknown); // wildcard 1.13608 + } 1.13609 +} 1.13610 + 1.13611 +bool 1.13612 +CSSParserImpl::ParsePaint(nsCSSProperty aPropID) 1.13613 +{ 1.13614 + nsCSSValue x, y; 1.13615 + 1.13616 + if (!ParseVariant(x, VARIANT_HC | VARIANT_NONE | VARIANT_URL | 1.13617 + VARIANT_OPENTYPE_SVG_KEYWORD, 1.13618 + nsCSSProps::kContextPatternKTable)) { 1.13619 + return false; 1.13620 + } 1.13621 + 1.13622 + bool canHaveFallback = x.GetUnit() == eCSSUnit_URL || 1.13623 + x.GetUnit() == eCSSUnit_Enumerated; 1.13624 + if (canHaveFallback) { 1.13625 + if (!ParseVariant(y, VARIANT_COLOR | VARIANT_NONE, nullptr)) 1.13626 + y.SetNoneValue(); 1.13627 + } 1.13628 + 1.13629 + if (!canHaveFallback) { 1.13630 + AppendValue(aPropID, x); 1.13631 + } else { 1.13632 + nsCSSValue val; 1.13633 + val.SetPairValue(x, y); 1.13634 + AppendValue(aPropID, val); 1.13635 + } 1.13636 + return true; 1.13637 +} 1.13638 + 1.13639 +bool 1.13640 +CSSParserImpl::ParseDasharray() 1.13641 +{ 1.13642 + nsCSSValue value; 1.13643 + 1.13644 + // 'inherit', 'initial', 'unset' and 'none' are only allowed on their own 1.13645 + if (!ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE | 1.13646 + VARIANT_OPENTYPE_SVG_KEYWORD, 1.13647 + nsCSSProps::kStrokeContextValueKTable)) { 1.13648 + nsCSSValueList *cur = value.SetListValue(); 1.13649 + for (;;) { 1.13650 + if (!ParseNonNegativeVariant(cur->mValue, VARIANT_LPN, nullptr)) { 1.13651 + return false; 1.13652 + } 1.13653 + if (CheckEndProperty()) { 1.13654 + break; 1.13655 + } 1.13656 + // skip optional commas between elements 1.13657 + (void)ExpectSymbol(',', true); 1.13658 + 1.13659 + cur->mNext = new nsCSSValueList; 1.13660 + cur = cur->mNext; 1.13661 + } 1.13662 + } 1.13663 + AppendValue(eCSSProperty_stroke_dasharray, value); 1.13664 + return true; 1.13665 +} 1.13666 + 1.13667 +bool 1.13668 +CSSParserImpl::ParseMarker() 1.13669 +{ 1.13670 + nsCSSValue marker; 1.13671 + if (ParseSingleValueProperty(marker, eCSSProperty_marker_end)) { 1.13672 + AppendValue(eCSSProperty_marker_end, marker); 1.13673 + AppendValue(eCSSProperty_marker_mid, marker); 1.13674 + AppendValue(eCSSProperty_marker_start, marker); 1.13675 + return true; 1.13676 + } 1.13677 + return false; 1.13678 +} 1.13679 + 1.13680 +bool 1.13681 +CSSParserImpl::ParsePaintOrder() 1.13682 +{ 1.13683 + static_assert 1.13684 + ((1 << NS_STYLE_PAINT_ORDER_BITWIDTH) > NS_STYLE_PAINT_ORDER_LAST_VALUE, 1.13685 + "bitfield width insufficient for paint-order constants"); 1.13686 + 1.13687 + static const KTableValue kPaintOrderKTable[] = { 1.13688 + eCSSKeyword_normal, NS_STYLE_PAINT_ORDER_NORMAL, 1.13689 + eCSSKeyword_fill, NS_STYLE_PAINT_ORDER_FILL, 1.13690 + eCSSKeyword_stroke, NS_STYLE_PAINT_ORDER_STROKE, 1.13691 + eCSSKeyword_markers, NS_STYLE_PAINT_ORDER_MARKERS, 1.13692 + eCSSKeyword_UNKNOWN,-1 1.13693 + }; 1.13694 + 1.13695 + static_assert(MOZ_ARRAY_LENGTH(kPaintOrderKTable) == 1.13696 + 2 * (NS_STYLE_PAINT_ORDER_LAST_VALUE + 2), 1.13697 + "missing paint-order values in kPaintOrderKTable"); 1.13698 + 1.13699 + nsCSSValue value; 1.13700 + if (!ParseVariant(value, VARIANT_HK, kPaintOrderKTable)) { 1.13701 + return false; 1.13702 + } 1.13703 + 1.13704 + uint32_t seen = 0; 1.13705 + uint32_t order = 0; 1.13706 + uint32_t position = 0; 1.13707 + 1.13708 + // Ensure that even cast to a signed int32_t when stored in CSSValue, 1.13709 + // we have enough space for the entire paint-order value. 1.13710 + static_assert 1.13711 + (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE < 32, 1.13712 + "seen and order not big enough"); 1.13713 + 1.13714 + if (value.GetUnit() == eCSSUnit_Enumerated) { 1.13715 + uint32_t component = static_cast<uint32_t>(value.GetIntValue()); 1.13716 + if (component != NS_STYLE_PAINT_ORDER_NORMAL) { 1.13717 + bool parsedOK = true; 1.13718 + for (;;) { 1.13719 + if (seen & (1 << component)) { 1.13720 + // Already seen this component. 1.13721 + UngetToken(); 1.13722 + parsedOK = false; 1.13723 + break; 1.13724 + } 1.13725 + seen |= (1 << component); 1.13726 + order |= (component << position); 1.13727 + position += NS_STYLE_PAINT_ORDER_BITWIDTH; 1.13728 + if (!ParseEnum(value, kPaintOrderKTable)) { 1.13729 + break; 1.13730 + } 1.13731 + component = value.GetIntValue(); 1.13732 + if (component == NS_STYLE_PAINT_ORDER_NORMAL) { 1.13733 + // Can't have "normal" in the middle of the list of paint components. 1.13734 + UngetToken(); 1.13735 + parsedOK = false; 1.13736 + break; 1.13737 + } 1.13738 + } 1.13739 + 1.13740 + // Fill in the remaining paint-order components in the order of their 1.13741 + // constant values. 1.13742 + if (parsedOK) { 1.13743 + for (component = 1; 1.13744 + component <= NS_STYLE_PAINT_ORDER_LAST_VALUE; 1.13745 + component++) { 1.13746 + if (!(seen & (1 << component))) { 1.13747 + order |= (component << position); 1.13748 + position += NS_STYLE_PAINT_ORDER_BITWIDTH; 1.13749 + } 1.13750 + } 1.13751 + } 1.13752 + } 1.13753 + 1.13754 + static_assert(NS_STYLE_PAINT_ORDER_NORMAL == 0, 1.13755 + "unexpected value for NS_STYLE_PAINT_ORDER_NORMAL"); 1.13756 + value.SetIntValue(static_cast<int32_t>(order), eCSSUnit_Enumerated); 1.13757 + } 1.13758 + 1.13759 + AppendValue(eCSSProperty_paint_order, value); 1.13760 + return true; 1.13761 +} 1.13762 + 1.13763 +bool 1.13764 +CSSParserImpl::BackslashDropped() 1.13765 +{ 1.13766 + return mScanner->GetEOFCharacters() & 1.13767 + nsCSSScanner::eEOFCharacters_DropBackslash; 1.13768 +} 1.13769 + 1.13770 +void 1.13771 +CSSParserImpl::AppendImpliedEOFCharacters(nsAString& aResult) 1.13772 +{ 1.13773 + nsCSSScanner::AppendImpliedEOFCharacters(mScanner->GetEOFCharacters(), 1.13774 + aResult); 1.13775 +} 1.13776 + 1.13777 +bool 1.13778 +CSSParserImpl::ParseAll() 1.13779 +{ 1.13780 + nsCSSValue value; 1.13781 + if (!ParseVariant(value, VARIANT_INHERIT, nullptr)) { 1.13782 + return false; 1.13783 + } 1.13784 + 1.13785 + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, eCSSProperty_all) { 1.13786 + AppendValue(*p, value); 1.13787 + } 1.13788 + return true; 1.13789 +} 1.13790 + 1.13791 +bool 1.13792 +CSSParserImpl::ParseVariableDeclaration(CSSVariableDeclarations::Type* aType, 1.13793 + nsString& aValue) 1.13794 +{ 1.13795 + CSSVariableDeclarations::Type type; 1.13796 + nsString variableValue; 1.13797 + bool dropBackslash; 1.13798 + nsString impliedCharacters; 1.13799 + 1.13800 + // Record the token stream while parsing a variable value. 1.13801 + if (!mInSupportsCondition) { 1.13802 + mScanner->StartRecording(); 1.13803 + } 1.13804 + if (!ParseValueWithVariables(&type, &dropBackslash, impliedCharacters, 1.13805 + nullptr, nullptr)) { 1.13806 + if (!mInSupportsCondition) { 1.13807 + mScanner->StopRecording(); 1.13808 + } 1.13809 + return false; 1.13810 + } 1.13811 + 1.13812 + if (!mInSupportsCondition) { 1.13813 + if (type == CSSVariableDeclarations::eTokenStream) { 1.13814 + // This was indeed a token stream value, so store it in variableValue. 1.13815 + mScanner->StopRecording(variableValue); 1.13816 + if (dropBackslash) { 1.13817 + MOZ_ASSERT(!variableValue.IsEmpty() && 1.13818 + variableValue[variableValue.Length() - 1] == '\\'); 1.13819 + variableValue.Truncate(variableValue.Length() - 1); 1.13820 + } 1.13821 + variableValue.Append(impliedCharacters); 1.13822 + } else { 1.13823 + // This was either 'inherit' or 'initial'; we don't need the recorded 1.13824 + // input. 1.13825 + mScanner->StopRecording(); 1.13826 + } 1.13827 + } 1.13828 + 1.13829 + if (mHavePushBack && type == CSSVariableDeclarations::eTokenStream) { 1.13830 + // If we came to the end of a valid variable declaration and a token was 1.13831 + // pushed back, then it would have been ended by '!', ')', ';', ']' or '}'. 1.13832 + // We need to remove it from the recorded variable value. 1.13833 + MOZ_ASSERT(mToken.IsSymbol('!') || 1.13834 + mToken.IsSymbol(')') || 1.13835 + mToken.IsSymbol(';') || 1.13836 + mToken.IsSymbol(']') || 1.13837 + mToken.IsSymbol('}')); 1.13838 + if (!mInSupportsCondition) { 1.13839 + MOZ_ASSERT(!variableValue.IsEmpty()); 1.13840 + MOZ_ASSERT(variableValue[variableValue.Length() - 1] == mToken.mSymbol); 1.13841 + variableValue.Truncate(variableValue.Length() - 1); 1.13842 + } 1.13843 + } 1.13844 + 1.13845 + *aType = type; 1.13846 + aValue = variableValue; 1.13847 + return true; 1.13848 +} 1.13849 + 1.13850 +bool 1.13851 +CSSParserImpl::ParseValueWithVariables(CSSVariableDeclarations::Type* aType, 1.13852 + bool* aDropBackslash, 1.13853 + nsString& aImpliedCharacters, 1.13854 + void (*aFunc)(const nsAString&, void*), 1.13855 + void* aData) 1.13856 +{ 1.13857 + // A property value is invalid if it contains variable references and also: 1.13858 + // 1.13859 + // * has unbalanced parens, brackets or braces 1.13860 + // * has any BAD_STRING or BAD_URL tokens 1.13861 + // * has any ';' or '!' tokens at the top level of a variable reference's 1.13862 + // fallback 1.13863 + // 1.13864 + // If the property is a custom property (i.e. a variable declaration), then 1.13865 + // it is also invalid if it consists of no tokens, such as: 1.13866 + // 1.13867 + // --invalid:; 1.13868 + // 1.13869 + // Note that is valid for a custom property to have a value that consists 1.13870 + // solely of white space, such as: 1.13871 + // 1.13872 + // --valid: ; 1.13873 + 1.13874 + // Stack of closing characters for currently open constructs. 1.13875 + StopSymbolCharStack stack; 1.13876 + 1.13877 + // Indexes into ')' characters in |stack| that correspond to "var(". This 1.13878 + // is used to stop parsing when we encounter a '!' or ';' at the top level 1.13879 + // of a variable reference's fallback. 1.13880 + nsAutoTArray<uint32_t, 16> references; 1.13881 + 1.13882 + if (!GetToken(false)) { 1.13883 + // Variable value was empty since we reached EOF. 1.13884 + REPORT_UNEXPECTED_EOF(PEVariableEOF); 1.13885 + return false; 1.13886 + } 1.13887 + 1.13888 + if (mToken.mType == eCSSToken_Symbol && 1.13889 + (mToken.mSymbol == '!' || 1.13890 + mToken.mSymbol == ')' || 1.13891 + mToken.mSymbol == ';' || 1.13892 + mToken.mSymbol == ']' || 1.13893 + mToken.mSymbol == '}')) { 1.13894 + // Variable value was empty since we reached the end of the construct. 1.13895 + UngetToken(); 1.13896 + REPORT_UNEXPECTED_TOKEN(PEVariableEmpty); 1.13897 + return false; 1.13898 + } 1.13899 + 1.13900 + if (mToken.mType == eCSSToken_Whitespace) { 1.13901 + if (!GetToken(true)) { 1.13902 + // Variable value was white space only. This is valid. 1.13903 + MOZ_ASSERT(!BackslashDropped()); 1.13904 + *aType = CSSVariableDeclarations::eTokenStream; 1.13905 + *aDropBackslash = false; 1.13906 + AppendImpliedEOFCharacters(aImpliedCharacters); 1.13907 + return true; 1.13908 + } 1.13909 + } 1.13910 + 1.13911 + // Look for 'initial', 'inherit' or 'unset' as the first non-white space 1.13912 + // token. 1.13913 + CSSVariableDeclarations::Type type = CSSVariableDeclarations::eTokenStream; 1.13914 + if (mToken.mType == eCSSToken_Ident) { 1.13915 + if (mToken.mIdent.LowerCaseEqualsLiteral("initial")) { 1.13916 + type = CSSVariableDeclarations::eInitial; 1.13917 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("inherit")) { 1.13918 + type = CSSVariableDeclarations::eInherit; 1.13919 + } else if (mToken.mIdent.LowerCaseEqualsLiteral("unset")) { 1.13920 + type = CSSVariableDeclarations::eUnset; 1.13921 + } 1.13922 + } 1.13923 + 1.13924 + if (type != CSSVariableDeclarations::eTokenStream) { 1.13925 + if (!GetToken(true)) { 1.13926 + // Variable value was 'initial' or 'inherit' followed by EOF. 1.13927 + MOZ_ASSERT(!BackslashDropped()); 1.13928 + *aType = type; 1.13929 + *aDropBackslash = false; 1.13930 + AppendImpliedEOFCharacters(aImpliedCharacters); 1.13931 + return true; 1.13932 + } 1.13933 + UngetToken(); 1.13934 + if (mToken.mType == eCSSToken_Symbol && 1.13935 + (mToken.mSymbol == '!' || 1.13936 + mToken.mSymbol == ')' || 1.13937 + mToken.mSymbol == ';' || 1.13938 + mToken.mSymbol == ']' || 1.13939 + mToken.mSymbol == '}')) { 1.13940 + // Variable value was 'initial' or 'inherit' followed by the end 1.13941 + // of the declaration. 1.13942 + MOZ_ASSERT(!BackslashDropped()); 1.13943 + *aType = type; 1.13944 + *aDropBackslash = false; 1.13945 + return true; 1.13946 + } 1.13947 + } 1.13948 + 1.13949 + do { 1.13950 + switch (mToken.mType) { 1.13951 + case eCSSToken_Symbol: 1.13952 + if (mToken.mSymbol == '(') { 1.13953 + stack.AppendElement(')'); 1.13954 + } else if (mToken.mSymbol == '[') { 1.13955 + stack.AppendElement(']'); 1.13956 + } else if (mToken.mSymbol == '{') { 1.13957 + stack.AppendElement('}'); 1.13958 + } else if (mToken.mSymbol == ';' || 1.13959 + mToken.mSymbol == '!') { 1.13960 + if (stack.IsEmpty()) { 1.13961 + UngetToken(); 1.13962 + MOZ_ASSERT(!BackslashDropped()); 1.13963 + *aType = CSSVariableDeclarations::eTokenStream; 1.13964 + *aDropBackslash = false; 1.13965 + return true; 1.13966 + } else if (!references.IsEmpty() && 1.13967 + references.LastElement() == stack.Length() - 1) { 1.13968 + REPORT_UNEXPECTED_TOKEN(PEInvalidVariableTokenFallback); 1.13969 + SkipUntilAllOf(stack); 1.13970 + return false; 1.13971 + } 1.13972 + } else if (mToken.mSymbol == ')' || 1.13973 + mToken.mSymbol == ']' || 1.13974 + mToken.mSymbol == '}') { 1.13975 + for (;;) { 1.13976 + if (stack.IsEmpty()) { 1.13977 + UngetToken(); 1.13978 + MOZ_ASSERT(!BackslashDropped()); 1.13979 + *aType = CSSVariableDeclarations::eTokenStream; 1.13980 + *aDropBackslash = false; 1.13981 + return true; 1.13982 + } 1.13983 + char16_t c = stack.LastElement(); 1.13984 + stack.TruncateLength(stack.Length() - 1); 1.13985 + if (!references.IsEmpty() && 1.13986 + references.LastElement() == stack.Length()) { 1.13987 + references.TruncateLength(references.Length() - 1); 1.13988 + } 1.13989 + if (mToken.mSymbol == c) { 1.13990 + break; 1.13991 + } 1.13992 + } 1.13993 + } 1.13994 + break; 1.13995 + 1.13996 + case eCSSToken_Function: 1.13997 + if (mToken.mIdent.LowerCaseEqualsLiteral("var")) { 1.13998 + if (!GetToken(true)) { 1.13999 + // EOF directly after "var(". 1.14000 + REPORT_UNEXPECTED_EOF(PEExpectedVariableNameEOF); 1.14001 + return false; 1.14002 + } 1.14003 + if (mToken.mType != eCSSToken_Ident || 1.14004 + !nsCSSProps::IsCustomPropertyName(mToken.mIdent)) { 1.14005 + // There must be an identifier directly after the "var(" and 1.14006 + // it must be a custom property name. 1.14007 + UngetToken(); 1.14008 + REPORT_UNEXPECTED_TOKEN(PEExpectedVariableName); 1.14009 + SkipUntil(')'); 1.14010 + SkipUntilAllOf(stack); 1.14011 + return false; 1.14012 + } 1.14013 + if (aFunc) { 1.14014 + MOZ_ASSERT(Substring(mToken.mIdent, 0, 1.14015 + CSS_CUSTOM_NAME_PREFIX_LENGTH). 1.14016 + EqualsLiteral("--")); 1.14017 + // remove '--' 1.14018 + const nsDependentSubstring varName = 1.14019 + Substring(mToken.mIdent, CSS_CUSTOM_NAME_PREFIX_LENGTH); 1.14020 + aFunc(varName, aData); 1.14021 + } 1.14022 + if (!GetToken(true)) { 1.14023 + // EOF right after "var(<ident>". 1.14024 + stack.AppendElement(')'); 1.14025 + } else if (mToken.IsSymbol(',')) { 1.14026 + // Variable reference with fallback. 1.14027 + if (!GetToken(false) || mToken.IsSymbol(')')) { 1.14028 + // Comma must be followed by at least one fallback token. 1.14029 + REPORT_UNEXPECTED(PEExpectedVariableFallback); 1.14030 + SkipUntilAllOf(stack); 1.14031 + return false; 1.14032 + } 1.14033 + UngetToken(); 1.14034 + references.AppendElement(stack.Length()); 1.14035 + stack.AppendElement(')'); 1.14036 + } else if (mToken.IsSymbol(')')) { 1.14037 + // Correctly closed variable reference. 1.14038 + } else { 1.14039 + // Malformed variable reference. 1.14040 + REPORT_UNEXPECTED_TOKEN(PEExpectedVariableCommaOrCloseParen); 1.14041 + SkipUntil(')'); 1.14042 + SkipUntilAllOf(stack); 1.14043 + return false; 1.14044 + } 1.14045 + } else { 1.14046 + stack.AppendElement(')'); 1.14047 + } 1.14048 + break; 1.14049 + 1.14050 + case eCSSToken_Bad_String: 1.14051 + SkipUntilAllOf(stack); 1.14052 + return false; 1.14053 + 1.14054 + case eCSSToken_Bad_URL: 1.14055 + SkipUntil(')'); 1.14056 + SkipUntilAllOf(stack); 1.14057 + return false; 1.14058 + 1.14059 + default: 1.14060 + break; 1.14061 + } 1.14062 + } while (GetToken(true)); 1.14063 + 1.14064 + // Append any implied closing characters. 1.14065 + *aDropBackslash = BackslashDropped(); 1.14066 + AppendImpliedEOFCharacters(aImpliedCharacters); 1.14067 + uint32_t i = stack.Length(); 1.14068 + while (i--) { 1.14069 + aImpliedCharacters.Append(stack[i]); 1.14070 + } 1.14071 + 1.14072 + *aType = type; 1.14073 + return true; 1.14074 +} 1.14075 + 1.14076 +} // anonymous namespace 1.14077 + 1.14078 +// Recycling of parser implementation objects 1.14079 + 1.14080 +static CSSParserImpl* gFreeList = nullptr; 1.14081 + 1.14082 +nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader, 1.14083 + nsCSSStyleSheet* aSheet) 1.14084 +{ 1.14085 + CSSParserImpl *impl = gFreeList; 1.14086 + if (impl) { 1.14087 + gFreeList = impl->mNextFree; 1.14088 + impl->mNextFree = nullptr; 1.14089 + } else { 1.14090 + impl = new CSSParserImpl(); 1.14091 + } 1.14092 + 1.14093 + if (aLoader) { 1.14094 + impl->SetChildLoader(aLoader); 1.14095 + impl->SetQuirkMode(aLoader->GetCompatibilityMode() == 1.14096 + eCompatibility_NavQuirks); 1.14097 + } 1.14098 + if (aSheet) { 1.14099 + impl->SetStyleSheet(aSheet); 1.14100 + } 1.14101 + 1.14102 + mImpl = static_cast<void*>(impl); 1.14103 +} 1.14104 + 1.14105 +nsCSSParser::~nsCSSParser() 1.14106 +{ 1.14107 + CSSParserImpl *impl = static_cast<CSSParserImpl*>(mImpl); 1.14108 + impl->Reset(); 1.14109 + impl->mNextFree = gFreeList; 1.14110 + gFreeList = impl; 1.14111 +} 1.14112 + 1.14113 +/* static */ void 1.14114 +nsCSSParser::Shutdown() 1.14115 +{ 1.14116 + CSSParserImpl *tofree = gFreeList; 1.14117 + CSSParserImpl *next; 1.14118 + while (tofree) 1.14119 + { 1.14120 + next = tofree->mNextFree; 1.14121 + delete tofree; 1.14122 + tofree = next; 1.14123 + } 1.14124 +} 1.14125 + 1.14126 +// Wrapper methods 1.14127 + 1.14128 +nsresult 1.14129 +nsCSSParser::SetStyleSheet(nsCSSStyleSheet* aSheet) 1.14130 +{ 1.14131 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14132 + SetStyleSheet(aSheet); 1.14133 +} 1.14134 + 1.14135 +nsresult 1.14136 +nsCSSParser::SetQuirkMode(bool aQuirkMode) 1.14137 +{ 1.14138 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14139 + SetQuirkMode(aQuirkMode); 1.14140 +} 1.14141 + 1.14142 +nsresult 1.14143 +nsCSSParser::SetChildLoader(mozilla::css::Loader* aChildLoader) 1.14144 +{ 1.14145 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14146 + SetChildLoader(aChildLoader); 1.14147 +} 1.14148 + 1.14149 +nsresult 1.14150 +nsCSSParser::ParseSheet(const nsAString& aInput, 1.14151 + nsIURI* aSheetURI, 1.14152 + nsIURI* aBaseURI, 1.14153 + nsIPrincipal* aSheetPrincipal, 1.14154 + uint32_t aLineNumber, 1.14155 + bool aAllowUnsafeRules) 1.14156 +{ 1.14157 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14158 + ParseSheet(aInput, aSheetURI, aBaseURI, aSheetPrincipal, aLineNumber, 1.14159 + aAllowUnsafeRules); 1.14160 +} 1.14161 + 1.14162 +nsresult 1.14163 +nsCSSParser::ParseStyleAttribute(const nsAString& aAttributeValue, 1.14164 + nsIURI* aDocURI, 1.14165 + nsIURI* aBaseURI, 1.14166 + nsIPrincipal* aNodePrincipal, 1.14167 + css::StyleRule** aResult) 1.14168 +{ 1.14169 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14170 + ParseStyleAttribute(aAttributeValue, aDocURI, aBaseURI, 1.14171 + aNodePrincipal, aResult); 1.14172 +} 1.14173 + 1.14174 +nsresult 1.14175 +nsCSSParser::ParseDeclarations(const nsAString& aBuffer, 1.14176 + nsIURI* aSheetURI, 1.14177 + nsIURI* aBaseURI, 1.14178 + nsIPrincipal* aSheetPrincipal, 1.14179 + css::Declaration* aDeclaration, 1.14180 + bool* aChanged) 1.14181 +{ 1.14182 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14183 + ParseDeclarations(aBuffer, aSheetURI, aBaseURI, aSheetPrincipal, 1.14184 + aDeclaration, aChanged); 1.14185 +} 1.14186 + 1.14187 +nsresult 1.14188 +nsCSSParser::ParseRule(const nsAString& aRule, 1.14189 + nsIURI* aSheetURI, 1.14190 + nsIURI* aBaseURI, 1.14191 + nsIPrincipal* aSheetPrincipal, 1.14192 + css::Rule** aResult) 1.14193 +{ 1.14194 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14195 + ParseRule(aRule, aSheetURI, aBaseURI, aSheetPrincipal, aResult); 1.14196 +} 1.14197 + 1.14198 +nsresult 1.14199 +nsCSSParser::ParseProperty(const nsCSSProperty aPropID, 1.14200 + const nsAString& aPropValue, 1.14201 + nsIURI* aSheetURI, 1.14202 + nsIURI* aBaseURI, 1.14203 + nsIPrincipal* aSheetPrincipal, 1.14204 + css::Declaration* aDeclaration, 1.14205 + bool* aChanged, 1.14206 + bool aIsImportant, 1.14207 + bool aIsSVGMode) 1.14208 +{ 1.14209 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14210 + ParseProperty(aPropID, aPropValue, aSheetURI, aBaseURI, 1.14211 + aSheetPrincipal, aDeclaration, aChanged, 1.14212 + aIsImportant, aIsSVGMode); 1.14213 +} 1.14214 + 1.14215 +nsresult 1.14216 +nsCSSParser::ParseVariable(const nsAString& aVariableName, 1.14217 + const nsAString& aPropValue, 1.14218 + nsIURI* aSheetURI, 1.14219 + nsIURI* aBaseURI, 1.14220 + nsIPrincipal* aSheetPrincipal, 1.14221 + css::Declaration* aDeclaration, 1.14222 + bool* aChanged, 1.14223 + bool aIsImportant) 1.14224 +{ 1.14225 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14226 + ParseVariable(aVariableName, aPropValue, aSheetURI, aBaseURI, 1.14227 + aSheetPrincipal, aDeclaration, aChanged, aIsImportant); 1.14228 +} 1.14229 + 1.14230 +void 1.14231 +nsCSSParser::ParseMediaList(const nsSubstring& aBuffer, 1.14232 + nsIURI* aURI, 1.14233 + uint32_t aLineNumber, 1.14234 + nsMediaList* aMediaList, 1.14235 + bool aHTMLMode) 1.14236 +{ 1.14237 + static_cast<CSSParserImpl*>(mImpl)-> 1.14238 + ParseMediaList(aBuffer, aURI, aLineNumber, aMediaList, aHTMLMode); 1.14239 +} 1.14240 + 1.14241 +bool 1.14242 +nsCSSParser::ParseColorString(const nsSubstring& aBuffer, 1.14243 + nsIURI* aURI, 1.14244 + uint32_t aLineNumber, 1.14245 + nsCSSValue& aValue) 1.14246 +{ 1.14247 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14248 + ParseColorString(aBuffer, aURI, aLineNumber, aValue); 1.14249 +} 1.14250 + 1.14251 +nsresult 1.14252 +nsCSSParser::ParseSelectorString(const nsSubstring& aSelectorString, 1.14253 + nsIURI* aURI, 1.14254 + uint32_t aLineNumber, 1.14255 + nsCSSSelectorList** aSelectorList) 1.14256 +{ 1.14257 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14258 + ParseSelectorString(aSelectorString, aURI, aLineNumber, aSelectorList); 1.14259 +} 1.14260 + 1.14261 +already_AddRefed<nsCSSKeyframeRule> 1.14262 +nsCSSParser::ParseKeyframeRule(const nsSubstring& aBuffer, 1.14263 + nsIURI* aURI, 1.14264 + uint32_t aLineNumber) 1.14265 +{ 1.14266 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14267 + ParseKeyframeRule(aBuffer, aURI, aLineNumber); 1.14268 +} 1.14269 + 1.14270 +bool 1.14271 +nsCSSParser::ParseKeyframeSelectorString(const nsSubstring& aSelectorString, 1.14272 + nsIURI* aURI, 1.14273 + uint32_t aLineNumber, 1.14274 + InfallibleTArray<float>& aSelectorList) 1.14275 +{ 1.14276 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14277 + ParseKeyframeSelectorString(aSelectorString, aURI, aLineNumber, 1.14278 + aSelectorList); 1.14279 +} 1.14280 + 1.14281 +bool 1.14282 +nsCSSParser::EvaluateSupportsDeclaration(const nsAString& aProperty, 1.14283 + const nsAString& aValue, 1.14284 + nsIURI* aDocURL, 1.14285 + nsIURI* aBaseURL, 1.14286 + nsIPrincipal* aDocPrincipal) 1.14287 +{ 1.14288 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14289 + EvaluateSupportsDeclaration(aProperty, aValue, aDocURL, aBaseURL, 1.14290 + aDocPrincipal); 1.14291 +} 1.14292 + 1.14293 +bool 1.14294 +nsCSSParser::EvaluateSupportsCondition(const nsAString& aCondition, 1.14295 + nsIURI* aDocURL, 1.14296 + nsIURI* aBaseURL, 1.14297 + nsIPrincipal* aDocPrincipal) 1.14298 +{ 1.14299 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14300 + EvaluateSupportsCondition(aCondition, aDocURL, aBaseURL, aDocPrincipal); 1.14301 +} 1.14302 + 1.14303 +bool 1.14304 +nsCSSParser::EnumerateVariableReferences(const nsAString& aPropertyValue, 1.14305 + VariableEnumFunc aFunc, 1.14306 + void* aData) 1.14307 +{ 1.14308 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14309 + EnumerateVariableReferences(aPropertyValue, aFunc, aData); 1.14310 +} 1.14311 + 1.14312 +bool 1.14313 +nsCSSParser::ResolveVariableValue(const nsAString& aPropertyValue, 1.14314 + const CSSVariableValues* aVariables, 1.14315 + nsString& aResult, 1.14316 + nsCSSTokenSerializationType& aFirstToken, 1.14317 + nsCSSTokenSerializationType& aLastToken) 1.14318 +{ 1.14319 + return static_cast<CSSParserImpl*>(mImpl)-> 1.14320 + ResolveVariableValue(aPropertyValue, aVariables, 1.14321 + aResult, aFirstToken, aLastToken); 1.14322 +} 1.14323 + 1.14324 +void 1.14325 +nsCSSParser::ParsePropertyWithVariableReferences( 1.14326 + nsCSSProperty aPropertyID, 1.14327 + nsCSSProperty aShorthandPropertyID, 1.14328 + const nsAString& aValue, 1.14329 + const CSSVariableValues* aVariables, 1.14330 + nsRuleData* aRuleData, 1.14331 + nsIURI* aDocURL, 1.14332 + nsIURI* aBaseURL, 1.14333 + nsIPrincipal* aDocPrincipal, 1.14334 + nsCSSStyleSheet* aSheet, 1.14335 + uint32_t aLineNumber, 1.14336 + uint32_t aLineOffset) 1.14337 +{ 1.14338 + static_cast<CSSParserImpl*>(mImpl)-> 1.14339 + ParsePropertyWithVariableReferences(aPropertyID, aShorthandPropertyID, 1.14340 + aValue, aVariables, aRuleData, aDocURL, 1.14341 + aBaseURL, aDocPrincipal, aSheet, 1.14342 + aLineNumber, aLineOffset); 1.14343 +}